From 0e1324c258a7d16dede893bf5dba3bba22749de4 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Wed, 4 May 2011 18:01:12 +0200 Subject: [PATCH 01/31] xbmc: add patch to enable caching on LAN for testing Signed-off-by: Stephan Raue --- ...xbmc-10.1-Dharma-455-enable_lan_caching-0.1.patch | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-455-enable_lan_caching-0.1.patch diff --git a/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-455-enable_lan_caching-0.1.patch b/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-455-enable_lan_caching-0.1.patch new file mode 100644 index 0000000000..8b43986437 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-455-enable_lan_caching-0.1.patch @@ -0,0 +1,12 @@ +diff -Naur xbmc-10.1-Dharma/xbmc/FileSystem/File.cpp xbmc-10.1-Dharma.patch/xbmc/FileSystem/File.cpp +--- xbmc-10.1-Dharma/xbmc/FileSystem/File.cpp 2011-03-08 02:49:14.000000000 +0100 ++++ xbmc-10.1-Dharma.patch/xbmc/FileSystem/File.cpp 2011-05-04 17:59:12.093724017 +0200 +@@ -217,7 +217,7 @@ + return false; + } + +- if ( (flags & READ_NO_CACHE) == 0 && CUtil::IsInternetStream(strFileName) && !CUtil::IsPicture(strFileName) ) ++ if ( (flags & READ_NO_CACHE) == 0 && CUtil::IsInternetStream(strFileName) || CUtil::IsOnLAN(strFileName) && !CUtil::IsPicture(strFileName) ) + m_flags |= READ_CACHED; + + CURL url(strFileName); From 744f7ec2deff17e06944d2ed312e96f5cc73bc7e Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Wed, 4 May 2011 19:58:09 +0200 Subject: [PATCH 02/31] xbmc: fix caching patch Signed-off-by: Stephan Raue --- .../patches/xbmc-10.1-Dharma-455-enable_lan_caching-0.1.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-455-enable_lan_caching-0.1.patch b/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-455-enable_lan_caching-0.1.patch index 8b43986437..3d99ba963d 100644 --- a/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-455-enable_lan_caching-0.1.patch +++ b/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-455-enable_lan_caching-0.1.patch @@ -6,7 +6,7 @@ diff -Naur xbmc-10.1-Dharma/xbmc/FileSystem/File.cpp xbmc-10.1-Dharma.patch/xbmc } - if ( (flags & READ_NO_CACHE) == 0 && CUtil::IsInternetStream(strFileName) && !CUtil::IsPicture(strFileName) ) -+ if ( (flags & READ_NO_CACHE) == 0 && CUtil::IsInternetStream(strFileName) || CUtil::IsOnLAN(strFileName) && !CUtil::IsPicture(strFileName) ) ++ if ( (flags & READ_NO_CACHE) == 0 && ( CUtil::IsInternetStream(strFileName) || CUtil::IsOnLAN(strFileName) ) && !CUtil::IsPicture(strFileName) ) m_flags |= READ_CACHED; CURL url(strFileName); From 955bfbe35b597c8a48f17cd732698fb7a77f5fe4 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Wed, 4 May 2011 20:04:12 +0200 Subject: [PATCH 03/31] linux: readd patch to fix failed xfermode on DVR-216 DVD devices Signed-off-by: Stephan Raue --- ...rc6-062-Pioneer_DVR-216D_failed_xfermode-0.1.patch | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/linux/patches/linux-2.6.39-rc6-062-Pioneer_DVR-216D_failed_xfermode-0.1.patch diff --git a/packages/linux/patches/linux-2.6.39-rc6-062-Pioneer_DVR-216D_failed_xfermode-0.1.patch b/packages/linux/patches/linux-2.6.39-rc6-062-Pioneer_DVR-216D_failed_xfermode-0.1.patch new file mode 100644 index 0000000000..60fecc3968 --- /dev/null +++ b/packages/linux/patches/linux-2.6.39-rc6-062-Pioneer_DVR-216D_failed_xfermode-0.1.patch @@ -0,0 +1,11 @@ +diff -Naur linux-2.6.39-rc6/drivers/ata/libata-core.c linux-2.6.39-rc6.patch/drivers/ata/libata-core.c +--- linux-2.6.39-rc6/drivers/ata/libata-core.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.patch/drivers/ata/libata-core.c 2011-05-04 19:59:38.952317088 +0200 +@@ -4139,6 +4139,7 @@ + */ + { "PIONEER DVD-RW DVRTD08", "1.00", ATA_HORKAGE_NOSETXFER }, + { "PIONEER DVD-RW DVR-212D", "1.28", ATA_HORKAGE_NOSETXFER }, ++ { "PIONEER DVD-RW DVR-216D", "1.07", ATA_HORKAGE_NOSETXFER }, + { "PIONEER DVD-RW DVR-216D", "1.08", ATA_HORKAGE_NOSETXFER }, + + /* End Marker */ From f2f7d0db32ad54eebb9053584fb02596c5f0632e Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Wed, 4 May 2011 20:06:43 +0200 Subject: [PATCH 04/31] lcdproc: enable syslog logging Signed-off-by: Stephan Raue --- packages/sysutils/lcdproc/init.d/63_lcdproc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sysutils/lcdproc/init.d/63_lcdproc b/packages/sysutils/lcdproc/init.d/63_lcdproc index 68974c315c..f8bcf55c73 100644 --- a/packages/sysutils/lcdproc/init.d/63_lcdproc +++ b/packages/sysutils/lcdproc/init.d/63_lcdproc @@ -43,7 +43,7 @@ # sleep another 3sec. to for irserver loading usleep 3000000 - LCDd -c $LCD_CONFIG -d $LCD_DRIVER > /dev/null 2>&1 + LCDd -c $LCD_CONFIG -d $LCD_DRIVER -s true > /dev/null 2>&1 fi fi )& From 4b7cba348c18a3143014779d994f60ec749f78c1 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Wed, 4 May 2011 22:48:46 +0200 Subject: [PATCH 05/31] upower: update to upower-0.9.10 Signed-off-by: Stephan Raue --- packages/sysutils/upower/meta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sysutils/upower/meta b/packages/sysutils/upower/meta index cf02bfc34c..aa85b66e5c 100644 --- a/packages/sysutils/upower/meta +++ b/packages/sysutils/upower/meta @@ -19,7 +19,7 @@ ################################################################################ PKG_NAME="upower" -PKG_VERSION="0.9.9" +PKG_VERSION="0.9.10" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" From 5074b8372a66fc930f38755bdc93faf24595b275 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Wed, 4 May 2011 22:49:21 +0200 Subject: [PATCH 06/31] ConsoleKit: update to ConsoleKit-0.4.5 Signed-off-by: Stephan Raue --- packages/sysutils/ConsoleKit/meta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sysutils/ConsoleKit/meta b/packages/sysutils/ConsoleKit/meta index e05f57d946..2d5d6e3746 100644 --- a/packages/sysutils/ConsoleKit/meta +++ b/packages/sysutils/ConsoleKit/meta @@ -19,7 +19,7 @@ ################################################################################ PKG_NAME="ConsoleKit" -PKG_VERSION="0.4.4" +PKG_VERSION="0.4.5" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" From 0b260b2ce5ec0cde5d98473b4bf20127e7c29041 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Fri, 6 May 2011 02:03:49 +0200 Subject: [PATCH 07/31] xbmc: add patch to fix XBMC ticket #7338 Signed-off-by: Stephan Raue --- ...-331-fix_playpause_problem_ticket_7338-0.1.patch | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-331-fix_playpause_problem_ticket_7338-0.1.patch diff --git a/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-331-fix_playpause_problem_ticket_7338-0.1.patch b/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-331-fix_playpause_problem_ticket_7338-0.1.patch new file mode 100644 index 0000000000..63b04cb3e0 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-331-fix_playpause_problem_ticket_7338-0.1.patch @@ -0,0 +1,13 @@ +diff -Naur xbmc-10.1-Dharma/xbmc/Application.cpp xbmc-10.1-Dharma.patch/xbmc/Application.cpp +--- xbmc-10.1-Dharma/xbmc/Application.cpp 2011-03-08 02:49:14.000000000 +0100 ++++ xbmc-10.1-Dharma.patch/xbmc/Application.cpp 2011-05-06 01:41:52.853741840 +0200 +@@ -2515,8 +2515,8 @@ + if (!m_pPlayer->IsPaused()) + { // unpaused - set the playspeed back to normal + SetPlaySpeed(1); ++ g_audioManager.Enable(m_pPlayer->IsPaused() && !g_audioContext.IsPassthroughActive()); + } +- g_audioManager.Enable(m_pPlayer->IsPaused() && !g_audioContext.IsPassthroughActive()); + return true; + } + if (!m_pPlayer->IsPaused()) From 1114623361074e85bdd468d83aa2af21f56188d4 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Fri, 6 May 2011 16:58:43 +0200 Subject: [PATCH 08/31] busybox: add init script to setup some cdrom related options Signed-off-by: Stephan Raue --- packages/sysutils/busybox/init.d/10_cdrom | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 packages/sysutils/busybox/init.d/10_cdrom diff --git a/packages/sysutils/busybox/init.d/10_cdrom b/packages/sysutils/busybox/init.d/10_cdrom new file mode 100644 index 0000000000..545552bd24 --- /dev/null +++ b/packages/sysutils/busybox/init.d/10_cdrom @@ -0,0 +1,27 @@ +################################################################################ +# This file is part of OpenELEC - http://www.openelec.tv +# Copyright (C) 2009-2011 Stephan Raue (stephan@openelec.tv) +# +# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +################################################################################ + +# +# setup cdrom settings +# +# runlevels: openelec, installer, textmode + +progress "Setup some CDROM settings" + sysctl -w dev.cdrom.lock=0 > /dev/null 2>&1 & From 6c56da75491ca8312f1c9bb56cdbf12c6683e9b9 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Fri, 6 May 2011 17:34:36 +0200 Subject: [PATCH 09/31] distribute: update to distribute-0.6.16 Signed-off-by: Stephan Raue --- packages/python/devel/distribute/meta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/python/devel/distribute/meta b/packages/python/devel/distribute/meta index e11b069a2f..e771259b2c 100644 --- a/packages/python/devel/distribute/meta +++ b/packages/python/devel/distribute/meta @@ -19,7 +19,7 @@ ################################################################################ PKG_NAME="distribute" -PKG_VERSION="0.6.15" +PKG_VERSION="0.6.16" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="OSS" From aa7b7114dc802c587628c891d35d1a0774502355 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Fri, 6 May 2011 17:37:31 +0200 Subject: [PATCH 10/31] pixman: update to pixman-0.22.0 Signed-off-by: Stephan Raue --- packages/x11/lib/pixman/meta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x11/lib/pixman/meta b/packages/x11/lib/pixman/meta index 94d6420b97..9ceee6020c 100644 --- a/packages/x11/lib/pixman/meta +++ b/packages/x11/lib/pixman/meta @@ -19,7 +19,7 @@ ################################################################################ PKG_NAME="pixman" -PKG_VERSION="0.21.8" +PKG_VERSION="0.22.0" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="OSS" From 63f1b9e8a32ed75c6cae32e3c1a10881387ee191 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Fri, 6 May 2011 17:49:52 +0200 Subject: [PATCH 11/31] glew: update to glew-1.6.0 Signed-off-by: Stephan Raue --- packages/graphics/glew/build | 12 +++++---- packages/graphics/glew/install | 6 ----- packages/graphics/glew/meta | 2 +- .../glew-1.5.8-010_crosscompiling.patch | 25 ------------------- 4 files changed, 8 insertions(+), 37 deletions(-) delete mode 100644 packages/graphics/glew/patches/glew-1.5.8-010_crosscompiling.patch diff --git a/packages/graphics/glew/build b/packages/graphics/glew/build index adef31a06c..d8e88973d9 100755 --- a/packages/graphics/glew/build +++ b/packages/graphics/glew/build @@ -23,10 +23,12 @@ . config/options $1 cd $PKG_BUILD -make SYSTEM=linux GLEW_DEST=/usr CC=$TARGET_CC -mkdir -p $SYSROOT_PREFIX/usr/lib - cp -PR lib/* $SYSROOT_PREFIX/usr/lib +make GLEW_DEST="/usr" \ + CC="$CC" \ + LD="$CC" \ + AR="$AR" \ + POPT="$CFLAGS" \ + LDFLAGS.EXTRA="$LDFLAGS" -mkdir -p $SYSROOT_PREFIX/usr/include - cp -PR include/* $SYSROOT_PREFIX/usr/include +make GLEW_DEST="$SYSROOT_PREFIX/usr" install diff --git a/packages/graphics/glew/install b/packages/graphics/glew/install index c7d1a5a41d..ab2fe8fbcd 100755 --- a/packages/graphics/glew/install +++ b/packages/graphics/glew/install @@ -22,11 +22,5 @@ . config/options $1 -$SCRIPTS/install libX11 -$SCRIPTS/install libXext -$SCRIPTS/install libXi -$SCRIPTS/install libXmu -$SCRIPTS/install Mesa - mkdir -p $INSTALL/usr/lib cp -PR $PKG_BUILD/lib/lib*.so* $INSTALL/usr/lib diff --git a/packages/graphics/glew/meta b/packages/graphics/glew/meta index a0eaa79f09..fe8f03a054 100644 --- a/packages/graphics/glew/meta +++ b/packages/graphics/glew/meta @@ -19,7 +19,7 @@ ################################################################################ PKG_NAME="glew" -PKG_VERSION="1.5.8" +PKG_VERSION="1.6.0" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="BSD" diff --git a/packages/graphics/glew/patches/glew-1.5.8-010_crosscompiling.patch b/packages/graphics/glew/patches/glew-1.5.8-010_crosscompiling.patch deleted file mode 100644 index 2c9d65b92a..0000000000 --- a/packages/graphics/glew/patches/glew-1.5.8-010_crosscompiling.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Naur glew-1.5.2/config/Makefile.linux glew-1.5.2.patch/config/Makefile.linux ---- glew-1.5.2/config/Makefile.linux 2009-12-31 18:06:19.000000000 +0100 -+++ glew-1.5.2.patch/config/Makefile.linux 2010-02-25 17:56:39.061037970 +0100 -@@ -1,19 +1,13 @@ - NAME = $(GLEW_NAME) --CC = cc --LD = cc -+CC = $(CC) -+LD = $(CC) - ifneq (undefined, $(origin GLEW_MX)) - CFLAGS.EXTRA = -DGLEW_MX - endif - PICFLAG = -fPIC - LDFLAGS.SO = -shared -Wl,-soname=$(LIB.SONAME) - M_ARCH ?= $(shell uname -m) --ifeq (x86_64,${M_ARCH}) --LDFLAGS.EXTRA = -L/usr/X11R6/lib64 --LIBDIR = $(GLEW_DEST)/lib64 --else --LDFLAGS.EXTRA = -L/usr/X11R6/lib - LIBDIR = $(GLEW_DEST)/lib --endif - LDFLAGS.GL = -lXmu -lXi -lGLU -lGL -lXext -lX11 - LDFLAGS.STATIC = -Wl,-Bstatic - LDFLAGS.DYNAMIC = -Wl,-Bdynamic From 35694b7c2185ddb7692145f3d6aa7a6dec023e9c Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Fri, 6 May 2011 17:53:11 +0200 Subject: [PATCH 12/31] mpfr: update upstream patches Signed-off-by: Stephan Raue --- .../mpfr-3.0.1-allpatches_20110412.patch | 137 -------- .../mpfr-3.0.1-allpatches_20110505.patch | 320 ++++++++++++++++++ 2 files changed, 320 insertions(+), 137 deletions(-) delete mode 100644 packages/toolchain/math/mpfr/patches/mpfr-3.0.1-allpatches_20110412.patch create mode 100644 packages/toolchain/math/mpfr/patches/mpfr-3.0.1-allpatches_20110505.patch diff --git a/packages/toolchain/math/mpfr/patches/mpfr-3.0.1-allpatches_20110412.patch b/packages/toolchain/math/mpfr/patches/mpfr-3.0.1-allpatches_20110412.patch deleted file mode 100644 index d79a6f9f24..0000000000 --- a/packages/toolchain/math/mpfr/patches/mpfr-3.0.1-allpatches_20110412.patch +++ /dev/null @@ -1,137 +0,0 @@ -diff -Naurd mpfr-3.0.1-a/PATCHES mpfr-3.0.1-b/PATCHES ---- mpfr-3.0.1-a/PATCHES 2011-04-12 10:50:02.000000000 +0000 -+++ mpfr-3.0.1-b/PATCHES 2011-04-12 10:50:02.000000000 +0000 -@@ -0,0 +1 @@ -+asin_exprange -diff -Naurd mpfr-3.0.1-a/VERSION mpfr-3.0.1-b/VERSION ---- mpfr-3.0.1-a/VERSION 2011-04-04 10:19:18.000000000 +0000 -+++ mpfr-3.0.1-b/VERSION 2011-04-12 10:50:02.000000000 +0000 -@@ -1 +1 @@ --3.0.1 -+3.0.1-p1 -diff -Naurd mpfr-3.0.1-a/asin.c mpfr-3.0.1-b/asin.c ---- mpfr-3.0.1-a/asin.c 2011-04-04 10:19:18.000000000 +0000 -+++ mpfr-3.0.1-b/asin.c 2011-04-12 10:50:02.000000000 +0000 -@@ -63,11 +63,14 @@ - - compared = mpfr_cmp_ui (xp, 1); - -+ MPFR_SAVE_EXPO_MARK (expo); -+ - if (MPFR_UNLIKELY (compared >= 0)) - { - mpfr_clear (xp); - if (compared > 0) /* asin(x) = NaN for |x| > 1 */ - { -+ MPFR_SAVE_EXPO_FREE (expo); - MPFR_SET_NAN (asin); - MPFR_RET_NAN; - } -@@ -80,13 +83,11 @@ - inexact = -mpfr_const_pi (asin, MPFR_INVERT_RND(rnd_mode)); - MPFR_CHANGE_SIGN (asin); - } -- mpfr_div_2ui (asin, asin, 1, rnd_mode); /* May underflow */ -- return inexact; -+ mpfr_div_2ui (asin, asin, 1, rnd_mode); - } - } -- -- MPFR_SAVE_EXPO_MARK (expo); -- -+ else -+ { - /* Compute exponent of 1 - ABS(x) */ - mpfr_ui_sub (xp, 1, xp, MPFR_RNDD); - MPFR_ASSERTD (MPFR_GET_EXP (xp) <= 0); -@@ -115,6 +116,7 @@ - inexact = mpfr_set (asin, xp, rnd_mode); - - mpfr_clear (xp); -+ } - - MPFR_SAVE_EXPO_FREE (expo); - return mpfr_check_range (asin, inexact, rnd_mode); -diff -Naurd mpfr-3.0.1-a/mpfr.h mpfr-3.0.1-b/mpfr.h ---- mpfr-3.0.1-a/mpfr.h 2011-04-04 10:19:18.000000000 +0000 -+++ mpfr-3.0.1-b/mpfr.h 2011-04-12 10:50:02.000000000 +0000 -@@ -27,7 +27,7 @@ - #define MPFR_VERSION_MAJOR 3 - #define MPFR_VERSION_MINOR 0 - #define MPFR_VERSION_PATCHLEVEL 1 --#define MPFR_VERSION_STRING "3.0.1" -+#define MPFR_VERSION_STRING "3.0.1-p1" - - /* Macros dealing with MPFR VERSION */ - #define MPFR_VERSION_NUM(a,b,c) (((a) << 16L) | ((b) << 8) | (c)) -diff -Naurd mpfr-3.0.1-a/tests/tasin.c mpfr-3.0.1-b/tests/tasin.c ---- mpfr-3.0.1-a/tests/tasin.c 2011-04-04 10:19:17.000000000 +0000 -+++ mpfr-3.0.1-b/tests/tasin.c 2011-04-12 10:50:02.000000000 +0000 -@@ -219,6 +219,49 @@ - mpfr_clear (y); - } - -+static void -+reduced_expo_range (void) -+{ -+ mpfr_exp_t emin, emax; -+ mpfr_t x, y, ex_y; -+ int inex, ex_inex; -+ unsigned int flags, ex_flags; -+ -+ emin = mpfr_get_emin (); -+ emax = mpfr_get_emax (); -+ -+ mpfr_inits2 (4, x, y, ex_y, (mpfr_ptr) 0); -+ mpfr_set_str (x, "-0.1e1", 2, MPFR_RNDN); -+ -+ mpfr_set_emin (1); -+ mpfr_set_emax (1); -+ mpfr_clear_flags (); -+ inex = mpfr_asin (y, x, MPFR_RNDA); -+ flags = __gmpfr_flags; -+ mpfr_set_emin (emin); -+ mpfr_set_emax (emax); -+ -+ mpfr_set_str (ex_y, "-0.1101e1", 2, MPFR_RNDN); -+ ex_inex = -1; -+ ex_flags = MPFR_FLAGS_INEXACT; -+ -+ if (SIGN (inex) != ex_inex || flags != ex_flags || -+ ! mpfr_equal_p (y, ex_y)) -+ { -+ printf ("Error in reduced_expo_range\non x = "); -+ mpfr_dump (x); -+ printf ("Expected y = "); -+ mpfr_out_str (stdout, 2, 0, ex_y, MPFR_RNDN); -+ printf ("\n inex = %d, flags = %u\n", ex_inex, ex_flags); -+ printf ("Got y = "); -+ mpfr_out_str (stdout, 2, 0, y, MPFR_RNDN); -+ printf ("\n inex = %d, flags = %u\n", SIGN (inex), flags); -+ exit (1); -+ } -+ -+ mpfr_clears (x, y, ex_y, (mpfr_ptr) 0); -+} -+ - int - main (void) - { -@@ -226,6 +269,7 @@ - - special (); - special_overflow (); -+ reduced_expo_range (); - - test_generic (2, 100, 15); - -diff -Naurd mpfr-3.0.1-a/version.c mpfr-3.0.1-b/version.c ---- mpfr-3.0.1-a/version.c 2011-04-04 10:19:18.000000000 +0000 -+++ mpfr-3.0.1-b/version.c 2011-04-12 10:50:02.000000000 +0000 -@@ -25,5 +25,5 @@ - const char * - mpfr_get_version (void) - { -- return "3.0.1"; -+ return "3.0.1-p1"; - } diff --git a/packages/toolchain/math/mpfr/patches/mpfr-3.0.1-allpatches_20110505.patch b/packages/toolchain/math/mpfr/patches/mpfr-3.0.1-allpatches_20110505.patch new file mode 100644 index 0000000000..59d7a8578d --- /dev/null +++ b/packages/toolchain/math/mpfr/patches/mpfr-3.0.1-allpatches_20110505.patch @@ -0,0 +1,320 @@ +diff -Naurd mpfr-3.0.1-a/PATCHES mpfr-3.0.1-b/PATCHES +--- mpfr-3.0.1-a/PATCHES 2011-04-12 10:50:02.000000000 +0000 ++++ mpfr-3.0.1-b/PATCHES 2011-04-12 10:50:02.000000000 +0000 +@@ -0,0 +1 @@ ++asin_exprange +diff -Naurd mpfr-3.0.1-a/VERSION mpfr-3.0.1-b/VERSION +--- mpfr-3.0.1-a/VERSION 2011-04-04 10:19:18.000000000 +0000 ++++ mpfr-3.0.1-b/VERSION 2011-04-12 10:50:02.000000000 +0000 +@@ -1 +1 @@ +-3.0.1 ++3.0.1-p1 +diff -Naurd mpfr-3.0.1-a/asin.c mpfr-3.0.1-b/asin.c +--- mpfr-3.0.1-a/asin.c 2011-04-04 10:19:18.000000000 +0000 ++++ mpfr-3.0.1-b/asin.c 2011-04-12 10:50:02.000000000 +0000 +@@ -63,11 +63,14 @@ + + compared = mpfr_cmp_ui (xp, 1); + ++ MPFR_SAVE_EXPO_MARK (expo); ++ + if (MPFR_UNLIKELY (compared >= 0)) + { + mpfr_clear (xp); + if (compared > 0) /* asin(x) = NaN for |x| > 1 */ + { ++ MPFR_SAVE_EXPO_FREE (expo); + MPFR_SET_NAN (asin); + MPFR_RET_NAN; + } +@@ -80,13 +83,11 @@ + inexact = -mpfr_const_pi (asin, MPFR_INVERT_RND(rnd_mode)); + MPFR_CHANGE_SIGN (asin); + } +- mpfr_div_2ui (asin, asin, 1, rnd_mode); /* May underflow */ +- return inexact; ++ mpfr_div_2ui (asin, asin, 1, rnd_mode); + } + } +- +- MPFR_SAVE_EXPO_MARK (expo); +- ++ else ++ { + /* Compute exponent of 1 - ABS(x) */ + mpfr_ui_sub (xp, 1, xp, MPFR_RNDD); + MPFR_ASSERTD (MPFR_GET_EXP (xp) <= 0); +@@ -115,6 +116,7 @@ + inexact = mpfr_set (asin, xp, rnd_mode); + + mpfr_clear (xp); ++ } + + MPFR_SAVE_EXPO_FREE (expo); + return mpfr_check_range (asin, inexact, rnd_mode); +diff -Naurd mpfr-3.0.1-a/mpfr.h mpfr-3.0.1-b/mpfr.h +--- mpfr-3.0.1-a/mpfr.h 2011-04-04 10:19:18.000000000 +0000 ++++ mpfr-3.0.1-b/mpfr.h 2011-04-12 10:50:02.000000000 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 3 + #define MPFR_VERSION_MINOR 0 + #define MPFR_VERSION_PATCHLEVEL 1 +-#define MPFR_VERSION_STRING "3.0.1" ++#define MPFR_VERSION_STRING "3.0.1-p1" + + /* Macros dealing with MPFR VERSION */ + #define MPFR_VERSION_NUM(a,b,c) (((a) << 16L) | ((b) << 8) | (c)) +diff -Naurd mpfr-3.0.1-a/tests/tasin.c mpfr-3.0.1-b/tests/tasin.c +--- mpfr-3.0.1-a/tests/tasin.c 2011-04-04 10:19:17.000000000 +0000 ++++ mpfr-3.0.1-b/tests/tasin.c 2011-04-12 10:50:02.000000000 +0000 +@@ -219,6 +219,49 @@ + mpfr_clear (y); + } + ++static void ++reduced_expo_range (void) ++{ ++ mpfr_exp_t emin, emax; ++ mpfr_t x, y, ex_y; ++ int inex, ex_inex; ++ unsigned int flags, ex_flags; ++ ++ emin = mpfr_get_emin (); ++ emax = mpfr_get_emax (); ++ ++ mpfr_inits2 (4, x, y, ex_y, (mpfr_ptr) 0); ++ mpfr_set_str (x, "-0.1e1", 2, MPFR_RNDN); ++ ++ mpfr_set_emin (1); ++ mpfr_set_emax (1); ++ mpfr_clear_flags (); ++ inex = mpfr_asin (y, x, MPFR_RNDA); ++ flags = __gmpfr_flags; ++ mpfr_set_emin (emin); ++ mpfr_set_emax (emax); ++ ++ mpfr_set_str (ex_y, "-0.1101e1", 2, MPFR_RNDN); ++ ex_inex = -1; ++ ex_flags = MPFR_FLAGS_INEXACT; ++ ++ if (SIGN (inex) != ex_inex || flags != ex_flags || ++ ! mpfr_equal_p (y, ex_y)) ++ { ++ printf ("Error in reduced_expo_range\non x = "); ++ mpfr_dump (x); ++ printf ("Expected y = "); ++ mpfr_out_str (stdout, 2, 0, ex_y, MPFR_RNDN); ++ printf ("\n inex = %d, flags = %u\n", ex_inex, ex_flags); ++ printf ("Got y = "); ++ mpfr_out_str (stdout, 2, 0, y, MPFR_RNDN); ++ printf ("\n inex = %d, flags = %u\n", SIGN (inex), flags); ++ exit (1); ++ } ++ ++ mpfr_clears (x, y, ex_y, (mpfr_ptr) 0); ++} ++ + int + main (void) + { +@@ -226,6 +269,7 @@ + + special (); + special_overflow (); ++ reduced_expo_range (); + + test_generic (2, 100, 15); + +diff -Naurd mpfr-3.0.1-a/version.c mpfr-3.0.1-b/version.c +--- mpfr-3.0.1-a/version.c 2011-04-04 10:19:18.000000000 +0000 ++++ mpfr-3.0.1-b/version.c 2011-04-12 10:50:02.000000000 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "3.0.1"; ++ return "3.0.1-p1"; + } +diff -Naurd mpfr-3.0.1-a/PATCHES mpfr-3.0.1-b/PATCHES +--- mpfr-3.0.1-a/PATCHES 2011-05-04 11:18:33.000000000 +0000 ++++ mpfr-3.0.1-b/PATCHES 2011-05-04 11:18:33.000000000 +0000 +@@ -0,0 +1 @@ ++rec_sqrt-carry +diff -Naurd mpfr-3.0.1-a/VERSION mpfr-3.0.1-b/VERSION +--- mpfr-3.0.1-a/VERSION 2011-04-12 10:50:02.000000000 +0000 ++++ mpfr-3.0.1-b/VERSION 2011-05-04 11:18:33.000000000 +0000 +@@ -1 +1 @@ +-3.0.1-p1 ++3.0.1-p2 +diff -Naurd mpfr-3.0.1-a/mpfr.h mpfr-3.0.1-b/mpfr.h +--- mpfr-3.0.1-a/mpfr.h 2011-04-12 10:50:02.000000000 +0000 ++++ mpfr-3.0.1-b/mpfr.h 2011-05-04 11:18:33.000000000 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 3 + #define MPFR_VERSION_MINOR 0 + #define MPFR_VERSION_PATCHLEVEL 1 +-#define MPFR_VERSION_STRING "3.0.1-p1" ++#define MPFR_VERSION_STRING "3.0.1-p2" + + /* Macros dealing with MPFR VERSION */ + #define MPFR_VERSION_NUM(a,b,c) (((a) << 16L) | ((b) << 8) | (c)) +diff -Naurd mpfr-3.0.1-a/rec_sqrt.c mpfr-3.0.1-b/rec_sqrt.c +--- mpfr-3.0.1-a/rec_sqrt.c 2011-04-04 10:19:18.000000000 +0000 ++++ mpfr-3.0.1-b/rec_sqrt.c 2011-05-04 11:18:33.000000000 +0000 +@@ -375,20 +375,37 @@ + MPFR_ASSERTD(un == ln + 1 || un == ln + 2); + /* the high un-ln limbs of u will overlap the low part of {x+ln,xn}, + we need to add or subtract the overlapping part {u + ln, un - ln} */ ++ /* Warning! th may be 0, in which case the mpn_add_1 and mpn_sub_1 ++ below (with size = th) mustn't be used. In such a case, the limb ++ (carry) will be 0, so that this is semantically a no-op, but if ++ mpn_add_1 and mpn_sub_1 are used, GMP (currently) still does a ++ non-atomic read/write in a place that is not always allocated, ++ with the possible consequences: a crash if the corresponding ++ address is not mapped, or (rather unlikely) memory corruption ++ if another process/thread writes at the same place; things may ++ be worse with future GMP versions. Hence the tests carry != 0. */ + if (neg == 0) + { + if (ln > 0) + MPN_COPY (x, u, ln); + cy = mpn_add (x + ln, x + ln, xn, u + ln, un - ln); + /* add cu at x+un */ +- cy += mpn_add_1 (x + un, x + un, th, cu); ++ if (cu != 0) ++ { ++ MPFR_ASSERTD (th != 0); ++ cy += mpn_add_1 (x + un, x + un, th, cu); ++ } + } + else /* negative case */ + { + /* subtract {u+ln, un-ln} from {x+ln,un} */ + cy = mpn_sub (x + ln, x + ln, xn, u + ln, un - ln); + /* carry cy is at x+un, like cu */ +- cy = mpn_sub_1 (x + un, x + un, th, cy + cu); /* n - un = th */ ++ if (cy + cu != 0) ++ { ++ MPFR_ASSERTD (th != 0); ++ cy = mpn_sub_1 (x + un, x + un, th, cy + cu); /* n - un = th */ ++ } + /* cy cannot be zero, since the most significant bit of Xh is 1, + and the correction is bounded by 2^{-h+3} */ + MPFR_ASSERTD(cy == 0); +diff -Naurd mpfr-3.0.1-a/version.c mpfr-3.0.1-b/version.c +--- mpfr-3.0.1-a/version.c 2011-04-12 10:50:02.000000000 +0000 ++++ mpfr-3.0.1-b/version.c 2011-05-04 11:18:33.000000000 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "3.0.1-p1"; ++ return "3.0.1-p2"; + } +diff -Naurd mpfr-3.0.1-a/PATCHES mpfr-3.0.1-b/PATCHES +--- mpfr-3.0.1-a/PATCHES 2011-05-05 00:00:35.000000000 +0000 ++++ mpfr-3.0.1-b/PATCHES 2011-05-05 00:00:35.000000000 +0000 +@@ -0,0 +1 @@ ++atan-expo-range +diff -Naurd mpfr-3.0.1-a/VERSION mpfr-3.0.1-b/VERSION +--- mpfr-3.0.1-a/VERSION 2011-05-04 11:18:33.000000000 +0000 ++++ mpfr-3.0.1-b/VERSION 2011-05-05 00:00:35.000000000 +0000 +@@ -1 +1 @@ +-3.0.1-p2 ++3.0.1-p3 +diff -Naurd mpfr-3.0.1-a/atan.c mpfr-3.0.1-b/atan.c +--- mpfr-3.0.1-a/atan.c 2011-04-04 10:19:18.000000000 +0000 ++++ mpfr-3.0.1-b/atan.c 2011-05-05 00:00:35.000000000 +0000 +@@ -431,5 +431,5 @@ + MPFR_GROUP_CLEAR (group); + + MPFR_SAVE_EXPO_FREE (expo); +- return mpfr_check_range (arctgt, inexact, rnd_mode); ++ return mpfr_check_range (atan, inexact, rnd_mode); + } +diff -Naurd mpfr-3.0.1-a/mpfr.h mpfr-3.0.1-b/mpfr.h +--- mpfr-3.0.1-a/mpfr.h 2011-05-04 11:18:33.000000000 +0000 ++++ mpfr-3.0.1-b/mpfr.h 2011-05-05 00:00:35.000000000 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 3 + #define MPFR_VERSION_MINOR 0 + #define MPFR_VERSION_PATCHLEVEL 1 +-#define MPFR_VERSION_STRING "3.0.1-p2" ++#define MPFR_VERSION_STRING "3.0.1-p3" + + /* Macros dealing with MPFR VERSION */ + #define MPFR_VERSION_NUM(a,b,c) (((a) << 16L) | ((b) << 8) | (c)) +diff -Naurd mpfr-3.0.1-a/tests/tatan.c mpfr-3.0.1-b/tests/tatan.c +--- mpfr-3.0.1-a/tests/tatan.c 2011-04-04 10:19:17.000000000 +0000 ++++ mpfr-3.0.1-b/tests/tatan.c 2011-05-05 00:00:35.000000000 +0000 +@@ -535,6 +535,52 @@ + mpfr_clears (a, x, y, (mpfr_ptr) 0); + } + ++/* http://websympa.loria.fr/wwsympa/arc/mpfr/2011-05/msg00008.html ++ * Incorrect flags (in debug mode on a 32-bit machine, assertion failure). ++ */ ++static void ++reduced_expo_range (void) ++{ ++ mpfr_exp_t emin, emax; ++ mpfr_t x, y, ex_y; ++ int inex, ex_inex; ++ unsigned int flags, ex_flags; ++ ++ emin = mpfr_get_emin (); ++ emax = mpfr_get_emax (); ++ ++ mpfr_inits2 (12, x, y, ex_y, (mpfr_ptr) 0); ++ mpfr_set_str (x, "0.1e-5", 2, MPFR_RNDN); ++ ++ mpfr_set_emin (-5); ++ mpfr_set_emax (-5); ++ mpfr_clear_flags (); ++ inex = mpfr_atan (y, x, MPFR_RNDN); ++ flags = __gmpfr_flags; ++ mpfr_set_emin (emin); ++ mpfr_set_emax (emax); ++ ++ mpfr_set_str (ex_y, "0.1e-5", 2, MPFR_RNDN); ++ ex_inex = 1; ++ ex_flags = MPFR_FLAGS_INEXACT; ++ ++ if (SIGN (inex) != ex_inex || flags != ex_flags || ++ ! mpfr_equal_p (y, ex_y)) ++ { ++ printf ("Error in reduced_expo_range\non x = "); ++ mpfr_dump (x); ++ printf ("Expected y = "); ++ mpfr_out_str (stdout, 2, 0, ex_y, MPFR_RNDN); ++ printf ("\n inex = %d, flags = %u\n", ex_inex, ex_flags); ++ printf ("Got y = "); ++ mpfr_out_str (stdout, 2, 0, y, MPFR_RNDN); ++ printf ("\n inex = %d, flags = %u\n", SIGN (inex), flags); ++ exit (1); ++ } ++ ++ mpfr_clears (x, y, ex_y, (mpfr_ptr) 0); ++} ++ + int + main (int argc, char *argv[]) + { +@@ -546,6 +592,7 @@ + smallvals_atan2 (); + atan2_bug_20071003 (); + atan2_different_prec (); ++ reduced_expo_range (); + + test_generic_atan (2, 200, 17); + test_generic_atan2 (2, 200, 17); +diff -Naurd mpfr-3.0.1-a/version.c mpfr-3.0.1-b/version.c +--- mpfr-3.0.1-a/version.c 2011-05-04 11:18:33.000000000 +0000 ++++ mpfr-3.0.1-b/version.c 2011-05-05 00:00:35.000000000 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "3.0.1-p2"; ++ return "3.0.1-p3"; + } From 08d6cabde80dd1de54369dc471b666ecb421e865 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Fri, 6 May 2011 19:58:46 +0200 Subject: [PATCH 13/31] scripts/unpack: fix handling of plain source packages Signed-off-by: Stephan Raue --- scripts/unpack | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/unpack b/scripts/unpack index 6cd837bd76..a3e9d3455b 100755 --- a/scripts/unpack +++ b/scripts/unpack @@ -64,8 +64,8 @@ if [ -n "$PKG_URL" ]; then fi if [ -d "$PKG_DIR/sources" ]; then - [ ! -d "$BUILD/$1*" ] && mkdir -p $BUILD/$1 - cp -PRf $PKG_DIR/sources/* $BUILD/$1*/ + [ ! -d "$BUILD/${PKG_NAME}-${PKG_VERSION}" ] && mkdir -p $BUILD/${PKG_NAME}-${PKG_VERSION} + cp -PRf $PKG_DIR/sources/* $BUILD/${PKG_NAME}-${PKG_VERSION} fi [ -d $BUILD/${PKG_NAME}[-_.]${PKG_VERSION} ] && PKG_BUILD=`ls -d $BUILD/${PKG_NAME}[-_.]${PKG_VERSION}` From d43168997a091bfd3a22e4c0b73494d53cdd9f1f Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Fri, 6 May 2011 22:05:55 +0200 Subject: [PATCH 14/31] new package: add package 'speedcontrol' Signed-off-by: Stephan Raue --- packages/sysutils/busybox/meta | 2 +- packages/sysutils/speedcontrol/build | 27 ++++++++++++++ .../sysutils/speedcontrol/init.d/10_cdrom | 27 ++++++++++++++ packages/sysutils/speedcontrol/install | 26 ++++++++++++++ packages/sysutils/speedcontrol/meta | 36 +++++++++++++++++++ .../speedcontrol/udev.d/61-cdrom.rules | 27 ++++++++++++++ 6 files changed, 144 insertions(+), 1 deletion(-) create mode 100755 packages/sysutils/speedcontrol/build create mode 100644 packages/sysutils/speedcontrol/init.d/10_cdrom create mode 100755 packages/sysutils/speedcontrol/install create mode 100644 packages/sysutils/speedcontrol/meta create mode 100644 packages/sysutils/speedcontrol/udev.d/61-cdrom.rules diff --git a/packages/sysutils/busybox/meta b/packages/sysutils/busybox/meta index fdad569d3f..2a8d554877 100644 --- a/packages/sysutils/busybox/meta +++ b/packages/sysutils/busybox/meta @@ -25,7 +25,7 @@ PKG_ARCH="any" PKG_LICENSE="GPL" PKG_SITE="http://www.busybox.net" PKG_URL="http://busybox.net/downloads/$PKG_NAME-$PKG_VERSION.tar.bz2" -PKG_DEPENDS="grep hdparm" +PKG_DEPENDS="grep hdparm speedcontrol" PKG_BUILD_DEPENDS="toolchain busybox-hosttools" PKG_PRIORITY="required" PKG_SECTION="system" diff --git a/packages/sysutils/speedcontrol/build b/packages/sysutils/speedcontrol/build new file mode 100755 index 0000000000..0e839063f4 --- /dev/null +++ b/packages/sysutils/speedcontrol/build @@ -0,0 +1,27 @@ +#!/bin/sh + +################################################################################ +# This file is part of OpenELEC - http://www.openelec.tv +# Copyright (C) 2009-2011 Stephan Raue (stephan@openelec.tv) +# +# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +################################################################################ + +. config/options $1 + +cd $PKG_BUILD + +$CC -o $1 $1.c diff --git a/packages/sysutils/speedcontrol/init.d/10_cdrom b/packages/sysutils/speedcontrol/init.d/10_cdrom new file mode 100644 index 0000000000..767a6f44d1 --- /dev/null +++ b/packages/sysutils/speedcontrol/init.d/10_cdrom @@ -0,0 +1,27 @@ +################################################################################ +# This file is part of OpenELEC - http://www.openelec.tv +# Copyright (C) 2009-2011 Stephan Raue (stephan@openelec.tv) +# +# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +################################################################################ + +# +# setup cdrom settings +# +# runlevels: openelec, installer, textmode + +progress "Deactivate CDROM lock" + sysctl -w dev.cdrom.lock=0 > /dev/null 2>&1 & diff --git a/packages/sysutils/speedcontrol/install b/packages/sysutils/speedcontrol/install new file mode 100755 index 0000000000..e12e24a089 --- /dev/null +++ b/packages/sysutils/speedcontrol/install @@ -0,0 +1,26 @@ +#!/bin/sh + +################################################################################ +# This file is part of OpenELEC - http://www.openelec.tv +# Copyright (C) 2009-2011 Stephan Raue (stephan@openelec.tv) +# +# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +################################################################################ + +. config/options $1 + +mkdir -p $INSTALL/usr/bin + cp $PKG_BUILD/$1 $INSTALL/usr/bin diff --git a/packages/sysutils/speedcontrol/meta b/packages/sysutils/speedcontrol/meta new file mode 100644 index 0000000000..2bb928123b --- /dev/null +++ b/packages/sysutils/speedcontrol/meta @@ -0,0 +1,36 @@ +################################################################################ +# This file is part of OpenELEC - http://www.openelec.tv +# Copyright (C) 2009-2011 Stephan Raue (stephan@openelec.tv) +# +# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +################################################################################ + +PKG_NAME="speedcontrol" +PKG_VERSION="1" +PKG_REV="1" +PKG_ARCH="any" +PKG_LICENSE="GPL" +PKG_SITE="http://noto.de" +PKG_URL="" +PKG_DEPENDS="" +PKG_BUILD_DEPENDS="toolchain" +PKG_PRIORITY="optional" +PKG_SECTION="system" +PKG_SHORTDESC="speedcontrol: a tool to setup cdrom drive speed" +PKG_LONGDESC="speedcontrol is a tool to setup cdrom drive speed" +PKG_IS_ADDON="no" + +PKG_AUTORECONF="no" diff --git a/packages/sysutils/speedcontrol/udev.d/61-cdrom.rules b/packages/sysutils/speedcontrol/udev.d/61-cdrom.rules new file mode 100644 index 0000000000..b472ce0f40 --- /dev/null +++ b/packages/sysutils/speedcontrol/udev.d/61-cdrom.rules @@ -0,0 +1,27 @@ +################################################################################ +# This file is part of OpenELEC - http://www.openelec.tv +# Copyright (C) 2009-2011 Stephan Raue (stephan@openelec.tv) +# +# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +################################################################################ + +# only do anything on block devices which are not removed +ACTION!="add|change", GOTO="cdrom_end" + +# set CDROM speed +KERNEL=="sr*", RUN+="/usr/bin/speedcontrol -x8 /dev/%k" + +LABEL="cdrom_end" From 590461ff06908a9223b4c17303a39dee509367c5 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Fri, 6 May 2011 22:07:15 +0200 Subject: [PATCH 15/31] busybox: add applet 'basename' and 'realpath' Signed-off-by: Stephan Raue --- packages/sysutils/busybox/config/busybox.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sysutils/busybox/config/busybox.conf b/packages/sysutils/busybox/config/busybox.conf index b61494e50c..ed311b9c76 100644 --- a/packages/sysutils/busybox/config/busybox.conf +++ b/packages/sysutils/busybox/config/busybox.conf @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.18.4 -# Tue May 3 19:22:30 2011 +# Fri May 6 21:33:25 2011 # CONFIG_HAVE_DOT_CONFIG=y @@ -163,7 +163,7 @@ CONFIG_XZ=y # # Coreutils # -# CONFIG_BASENAME is not set +CONFIG_BASENAME=y CONFIG_CAT=y CONFIG_DATE=y CONFIG_FEATURE_DATE_ISOFMT=y @@ -242,7 +242,7 @@ CONFIG_PRINTF=y CONFIG_PWD=y CONFIG_READLINK=y CONFIG_FEATURE_READLINK_FOLLOW=y -# CONFIG_REALPATH is not set +CONFIG_REALPATH=y CONFIG_RM=y CONFIG_RMDIR=y CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y From 95057f6f21e14be5815e19641556cdc60d0b1fa7 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Fri, 6 May 2011 22:58:46 +0200 Subject: [PATCH 16/31] linux: add patch to add RTL8192SE OSS driver, backported from 2.6.40 Signed-off-by: Stephan Raue --- ....39-rc6-041-add_rtl8192se_driver-0.2.patch | 107576 +++++++++++++++ projects/ATV/linux/linux.i386.conf | 9 +- projects/ATV/options | 3 +- projects/Generic/linux/linux.i386.conf | 9 +- projects/Generic/options | 5 +- projects/ION/linux/linux.i386.conf | 9 +- projects/ION/linux/linux.x86_64.conf | 9 +- projects/ION/options | 5 +- projects/Intel/linux/linux.i386.conf | 9 +- projects/Intel/linux/linux.x86_64.conf | 9 +- projects/Intel/options | 5 +- 11 files changed, 107613 insertions(+), 35 deletions(-) create mode 100644 packages/linux/patches/linux-2.6.39-rc6-041-add_rtl8192se_driver-0.2.patch diff --git a/packages/linux/patches/linux-2.6.39-rc6-041-add_rtl8192se_driver-0.2.patch b/packages/linux/patches/linux-2.6.39-rc6-041-add_rtl8192se_driver-0.2.patch new file mode 100644 index 0000000000..21aefadd88 --- /dev/null +++ b/packages/linux/patches/linux-2.6.39-rc6-041-add_rtl8192se_driver-0.2.patch @@ -0,0 +1,107576 @@ +diff -Naur linux-2.6.39-rc6/Documentation/feature-removal-schedule.txt linux-2.6.39-rc6.rtl8192se/Documentation/feature-removal-schedule.txt +--- linux-2.6.39-rc6/Documentation/feature-removal-schedule.txt 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/Documentation/feature-removal-schedule.txt 2011-05-05 23:30:16.046811005 +0200 +@@ -35,17 +35,6 @@ + + --------------------------- + +-What: AR9170USB +-When: 2.6.40 +- +-Why: This driver is deprecated and the firmware is no longer +- maintained. The replacement driver "carl9170" has been +- around for a while, so the devices are still supported. +- +-Who: Christian Lamparter +- +---------------------------- +- + What: IRQF_SAMPLE_RANDOM + Check: IRQF_SAMPLE_RANDOM + When: July 2009 +diff -Naur linux-2.6.39-rc6/drivers/bluetooth/ath3k.c linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/ath3k.c +--- linux-2.6.39-rc6/drivers/bluetooth/ath3k.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/ath3k.c 2011-05-05 23:29:49.570491221 +0200 +@@ -138,9 +138,6 @@ + count -= size; + } + +- kfree(send_buf); +- return 0; +- + error: + kfree(send_buf); + return err; +diff -Naur linux-2.6.39-rc6/drivers/bluetooth/btmrvl_sdio.c linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/btmrvl_sdio.c +--- linux-2.6.39-rc6/drivers/bluetooth/btmrvl_sdio.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/btmrvl_sdio.c 2011-05-05 23:29:49.552491003 +0200 +@@ -49,15 +49,59 @@ + static u8 user_rmmod; + static u8 sdio_ireg; + ++static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = { ++ .cfg = 0x03, ++ .host_int_mask = 0x04, ++ .host_intstatus = 0x05, ++ .card_status = 0x20, ++ .sq_read_base_addr_a0 = 0x10, ++ .sq_read_base_addr_a1 = 0x11, ++ .card_fw_status0 = 0x40, ++ .card_fw_status1 = 0x41, ++ .card_rx_len = 0x42, ++ .card_rx_unit = 0x43, ++ .io_port_0 = 0x00, ++ .io_port_1 = 0x01, ++ .io_port_2 = 0x02, ++}; ++static const struct btmrvl_sdio_card_reg btmrvl_reg_8787 = { ++ .cfg = 0x00, ++ .host_int_mask = 0x02, ++ .host_intstatus = 0x03, ++ .card_status = 0x30, ++ .sq_read_base_addr_a0 = 0x40, ++ .sq_read_base_addr_a1 = 0x41, ++ .card_revision = 0x5c, ++ .card_fw_status0 = 0x60, ++ .card_fw_status1 = 0x61, ++ .card_rx_len = 0x62, ++ .card_rx_unit = 0x63, ++ .io_port_0 = 0x78, ++ .io_port_1 = 0x79, ++ .io_port_2 = 0x7a, ++}; ++ + static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = { + .helper = "sd8688_helper.bin", + .firmware = "sd8688.bin", ++ .reg = &btmrvl_reg_8688, ++ .sd_blksz_fw_dl = 64, ++}; ++ ++static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { ++ .helper = NULL, ++ .firmware = "mrvl/sd8787_uapsta.bin", ++ .reg = &btmrvl_reg_8787, ++ .sd_blksz_fw_dl = 256, + }; + + static const struct sdio_device_id btmrvl_sdio_ids[] = { + /* Marvell SD8688 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105), + .driver_data = (unsigned long) &btmrvl_sdio_sd6888 }, ++ /* Marvell SD8787 Bluetooth device */ ++ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A), ++ .driver_data = (unsigned long) &btmrvl_sdio_sd8787 }, + + { } /* Terminating entry */ + }; +@@ -69,7 +113,7 @@ + u8 reg; + int ret; + +- reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret); ++ reg = sdio_readb(card->func, card->reg->card_rx_unit, &ret); + if (!ret) + card->rx_unit = reg; + +@@ -83,11 +127,11 @@ + + *dat = 0; + +- fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret); ++ fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret); + if (ret) + return -EIO; + +- fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret); ++ fws1 = sdio_readb(card->func, card->reg->card_fw_status1, &ret); + if (ret) + return -EIO; + +@@ -101,7 +145,7 @@ + u8 reg; + int ret; + +- reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret); ++ reg = sdio_readb(card->func, card->reg->card_rx_len, &ret); + if (!ret) + *dat = (u16) reg << card->rx_unit; + +@@ -113,7 +157,7 @@ + { + int ret; + +- sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret); ++ sdio_writeb(card->func, mask, card->reg->host_int_mask, &ret); + if (ret) { + BT_ERR("Unable to enable the host interrupt!"); + ret = -EIO; +@@ -128,13 +172,13 @@ + u8 host_int_mask; + int ret; + +- host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret); ++ host_int_mask = sdio_readb(card->func, card->reg->host_int_mask, &ret); + if (ret) + return -EIO; + + host_int_mask &= ~mask; + +- sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret); ++ sdio_writeb(card->func, host_int_mask, card->reg->host_int_mask, &ret); + if (ret < 0) { + BT_ERR("Unable to disable the host interrupt!"); + return -EIO; +@@ -150,7 +194,7 @@ + int ret; + + for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) { +- status = sdio_readb(card->func, CARD_STATUS_REG, &ret); ++ status = sdio_readb(card->func, card->reg->card_status, &ret); + if (ret) + goto failed; + if ((status & bits) == bits) +@@ -299,7 +343,7 @@ + u8 base0, base1; + void *tmpfwbuf = NULL; + u8 *fwbuf; +- u16 len; ++ u16 len, blksz_dl = card->sd_blksz_fw_dl; + int txlen = 0, tx_blocks = 0, count = 0; + + ret = request_firmware(&fw_firmware, card->firmware, +@@ -345,7 +389,7 @@ + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + base0 = sdio_readb(card->func, +- SQ_READ_BASE_ADDRESS_A0_REG, &ret); ++ card->reg->sq_read_base_addr_a0, &ret); + if (ret) { + BT_ERR("BASE0 register read failed:" + " base0 = 0x%04X(%d)." +@@ -355,7 +399,7 @@ + goto done; + } + base1 = sdio_readb(card->func, +- SQ_READ_BASE_ADDRESS_A1_REG, &ret); ++ card->reg->sq_read_base_addr_a1, &ret); + if (ret) { + BT_ERR("BASE1 register read failed:" + " base1 = 0x%04X(%d)." +@@ -403,20 +447,19 @@ + if (firmwarelen - offset < txlen) + txlen = firmwarelen - offset; + +- tx_blocks = +- (txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE; ++ tx_blocks = (txlen + blksz_dl - 1) / blksz_dl; + + memcpy(fwbuf, &firmware[offset], txlen); + } + + ret = sdio_writesb(card->func, card->ioport, fwbuf, +- tx_blocks * SDIO_BLOCK_SIZE); ++ tx_blocks * blksz_dl); + + if (ret < 0) { + BT_ERR("FW download, writesb(%d) failed @%d", + count, offset); +- sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG, +- &ret); ++ sdio_writeb(card->func, HOST_CMD53_FIN, ++ card->reg->cfg, &ret); + if (ret) + BT_ERR("writeb failed (CFG)"); + } +@@ -597,7 +640,7 @@ + + priv = card->priv; + +- ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret); ++ ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret); + if (ret) { + BT_ERR("sdio_readb: read int status register failed"); + return; +@@ -613,7 +656,7 @@ + + sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS | + UP_LD_HOST_INT_STATUS), +- HOST_INTSTATUS_REG, &ret); ++ card->reg->host_intstatus, &ret); + if (ret) { + BT_ERR("sdio_writeb: clear int status register failed"); + return; +@@ -664,7 +707,7 @@ + goto release_irq; + } + +- reg = sdio_readb(func, IO_PORT_0_REG, &ret); ++ reg = sdio_readb(func, card->reg->io_port_0, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; +@@ -672,7 +715,7 @@ + + card->ioport = reg; + +- reg = sdio_readb(func, IO_PORT_1_REG, &ret); ++ reg = sdio_readb(func, card->reg->io_port_1, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; +@@ -680,7 +723,7 @@ + + card->ioport |= (reg << 8); + +- reg = sdio_readb(func, IO_PORT_2_REG, &ret); ++ reg = sdio_readb(func, card->reg->io_port_2, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; +@@ -815,6 +858,8 @@ + static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) + { + int ret = 0; ++ u8 fws0; ++ int pollnum = MAX_POLL_TRIES; + + if (!card || !card->func) { + BT_ERR("card or function is NULL!"); +@@ -827,20 +872,36 @@ + goto done; + } + +- ret = btmrvl_sdio_download_helper(card); ++ /* Check if other function driver is downloading the firmware */ ++ fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret); + if (ret) { +- BT_ERR("Failed to download helper!"); ++ BT_ERR("Failed to read FW downloading status!"); + ret = -EIO; + goto done; + } ++ if (fws0) { ++ BT_DBG("BT not the winner (%#x). Skip FW downloading", fws0); + +- if (btmrvl_sdio_download_fw_w_helper(card)) { +- BT_ERR("Failed to download firmware!"); +- ret = -EIO; +- goto done; ++ /* Give other function more time to download the firmware */ ++ pollnum *= 10; ++ } else { ++ if (card->helper) { ++ ret = btmrvl_sdio_download_helper(card); ++ if (ret) { ++ BT_ERR("Failed to download helper!"); ++ ret = -EIO; ++ goto done; ++ } ++ } ++ ++ if (btmrvl_sdio_download_fw_w_helper(card)) { ++ BT_ERR("Failed to download firmware!"); ++ ret = -EIO; ++ goto done; ++ } + } + +- if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) { ++ if (btmrvl_sdio_verify_fw_download(card, pollnum)) { + BT_ERR("FW failed to be active in time!"); + ret = -ETIMEDOUT; + goto done; +@@ -864,7 +925,7 @@ + + sdio_claim_host(card->func); + +- sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret); ++ sdio_writeb(card->func, HOST_POWER_UP, card->reg->cfg, &ret); + + sdio_release_host(card->func); + +@@ -893,8 +954,10 @@ + + if (id->driver_data) { + struct btmrvl_sdio_device *data = (void *) id->driver_data; +- card->helper = data->helper; ++ card->helper = data->helper; + card->firmware = data->firmware; ++ card->reg = data->reg; ++ card->sd_blksz_fw_dl = data->sd_blksz_fw_dl; + } + + if (btmrvl_sdio_register_dev(card) < 0) { +@@ -1011,3 +1074,4 @@ + MODULE_LICENSE("GPL v2"); + MODULE_FIRMWARE("sd8688_helper.bin"); + MODULE_FIRMWARE("sd8688.bin"); ++MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); +diff -Naur linux-2.6.39-rc6/drivers/bluetooth/btmrvl_sdio.h linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/btmrvl_sdio.h +--- linux-2.6.39-rc6/drivers/bluetooth/btmrvl_sdio.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/btmrvl_sdio.h 2011-05-05 23:29:49.571491233 +0200 +@@ -47,44 +47,46 @@ + /* Max retry number of CMD53 write */ + #define MAX_WRITE_IOMEM_RETRY 2 + +-/* Host Control Registers */ +-#define IO_PORT_0_REG 0x00 +-#define IO_PORT_1_REG 0x01 +-#define IO_PORT_2_REG 0x02 +- +-#define CONFIG_REG 0x03 +-#define HOST_POWER_UP BIT(1) +-#define HOST_CMD53_FIN BIT(2) +- +-#define HOST_INT_MASK_REG 0x04 +-#define HIM_DISABLE 0xff +-#define HIM_ENABLE (BIT(0) | BIT(1)) +- +-#define HOST_INTSTATUS_REG 0x05 +-#define UP_LD_HOST_INT_STATUS BIT(0) +-#define DN_LD_HOST_INT_STATUS BIT(1) +- +-/* Card Control Registers */ +-#define SQ_READ_BASE_ADDRESS_A0_REG 0x10 +-#define SQ_READ_BASE_ADDRESS_A1_REG 0x11 +- +-#define CARD_STATUS_REG 0x20 +-#define DN_LD_CARD_RDY BIT(0) +-#define CARD_IO_READY BIT(3) +- +-#define CARD_FW_STATUS0_REG 0x40 +-#define CARD_FW_STATUS1_REG 0x41 +-#define FIRMWARE_READY 0xfedc +- +-#define CARD_RX_LEN_REG 0x42 +-#define CARD_RX_UNIT_REG 0x43 +- ++/* register bitmasks */ ++#define HOST_POWER_UP BIT(1) ++#define HOST_CMD53_FIN BIT(2) ++ ++#define HIM_DISABLE 0xff ++#define HIM_ENABLE (BIT(0) | BIT(1)) ++ ++#define UP_LD_HOST_INT_STATUS BIT(0) ++#define DN_LD_HOST_INT_STATUS BIT(1) ++ ++#define DN_LD_CARD_RDY BIT(0) ++#define CARD_IO_READY BIT(3) ++ ++#define FIRMWARE_READY 0xfedc ++ ++ ++struct btmrvl_sdio_card_reg { ++ u8 cfg; ++ u8 host_int_mask; ++ u8 host_intstatus; ++ u8 card_status; ++ u8 sq_read_base_addr_a0; ++ u8 sq_read_base_addr_a1; ++ u8 card_revision; ++ u8 card_fw_status0; ++ u8 card_fw_status1; ++ u8 card_rx_len; ++ u8 card_rx_unit; ++ u8 io_port_0; ++ u8 io_port_1; ++ u8 io_port_2; ++}; + + struct btmrvl_sdio_card { + struct sdio_func *func; + u32 ioport; + const char *helper; + const char *firmware; ++ const struct btmrvl_sdio_card_reg *reg; ++ u16 sd_blksz_fw_dl; + u8 rx_unit; + struct btmrvl_private *priv; + }; +@@ -92,6 +94,8 @@ + struct btmrvl_sdio_device { + const char *helper; + const char *firmware; ++ const struct btmrvl_sdio_card_reg *reg; ++ u16 sd_blksz_fw_dl; + }; + + +diff -Naur linux-2.6.39-rc6/drivers/bluetooth/hci_ath.c linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/hci_ath.c +--- linux-2.6.39-rc6/drivers/bluetooth/hci_ath.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/hci_ath.c 2011-05-05 23:29:49.554491027 +0200 +@@ -201,8 +201,13 @@ + /* Recv data */ + static int ath_recv(struct hci_uart *hu, void *data, int count) + { +- if (hci_recv_stream_fragment(hu->hdev, data, count) < 0) ++ int ret; ++ ++ ret = hci_recv_stream_fragment(hu->hdev, data, count); ++ if (ret < 0) { + BT_ERR("Frame Reassembly Failed"); ++ return ret; ++ } + + return count; + } +diff -Naur linux-2.6.39-rc6/drivers/bluetooth/hci_h4.c linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/hci_h4.c +--- linux-2.6.39-rc6/drivers/bluetooth/hci_h4.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/hci_h4.c 2011-05-05 23:29:49.566491173 +0200 +@@ -151,8 +151,13 @@ + /* Recv data */ + static int h4_recv(struct hci_uart *hu, void *data, int count) + { +- if (hci_recv_stream_fragment(hu->hdev, data, count) < 0) ++ int ret; ++ ++ ret = hci_recv_stream_fragment(hu->hdev, data, count); ++ if (ret < 0) { + BT_ERR("Frame Reassembly Failed"); ++ return ret; ++ } + + return count; + } +diff -Naur linux-2.6.39-rc6/drivers/bluetooth/hci_ldisc.c linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/hci_ldisc.c +--- linux-2.6.39-rc6/drivers/bluetooth/hci_ldisc.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/hci_ldisc.c 2011-05-05 23:29:49.567491185 +0200 +@@ -359,6 +359,7 @@ + */ + static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) + { ++ int ret; + struct hci_uart *hu = (void *)tty->disc_data; + + if (!hu || tty != hu->tty) +@@ -368,8 +369,9 @@ + return; + + spin_lock(&hu->rx_lock); +- hu->proto->recv(hu, (void *) data, count); +- hu->hdev->stat.byte_rx += count; ++ ret = hu->proto->recv(hu, (void *) data, count); ++ if (ret > 0) ++ hu->hdev->stat.byte_rx += count; + spin_unlock(&hu->rx_lock); + + tty_unthrottle(tty); +diff -Naur linux-2.6.39-rc6/drivers/bluetooth/Kconfig linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/Kconfig +--- linux-2.6.39-rc6/drivers/bluetooth/Kconfig 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/bluetooth/Kconfig 2011-05-05 23:29:49.570491221 +0200 +@@ -188,7 +188,7 @@ + The core driver to support Marvell Bluetooth devices. + + This driver is required if you want to support +- Marvell Bluetooth devices, such as 8688. ++ Marvell Bluetooth devices, such as 8688/8787. + + Say Y here to compile Marvell Bluetooth driver + into the kernel or say M to compile it as module. +@@ -201,7 +201,7 @@ + The driver for Marvell Bluetooth chipsets with SDIO interface. + + This driver is required if you want to use Marvell Bluetooth +- devices with SDIO interface. Currently only SD8688 chipset is ++ devices with SDIO interface. Currently SD8688/SD8787 chipsets are + supported. + + Say Y here to compile support for Marvell BT-over-SDIO driver +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/ar9170.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/ar9170.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/ar9170.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/ar9170.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,258 +0,0 @@ +-/* +- * Atheros AR9170 driver +- * +- * Driver specific definitions +- * +- * Copyright 2008, Johannes Berg +- * +- * 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; see the file COPYING. If not, see +- * http://www.gnu.org/licenses/. +- * +- * This file incorporates work covered by the following copyright and +- * permission notice: +- * Copyright (c) 2007-2008 Atheros Communications, Inc. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +-#ifndef __AR9170_H +-#define __AR9170_H +- +-#include +-#include +-#include +-#include +-#ifdef CONFIG_AR9170_LEDS +-#include +-#endif /* CONFIG_AR9170_LEDS */ +-#include "eeprom.h" +-#include "hw.h" +- +-#include "../regd.h" +- +-#define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1) +- +-enum ar9170_bw { +- AR9170_BW_20, +- AR9170_BW_40_BELOW, +- AR9170_BW_40_ABOVE, +- +- __AR9170_NUM_BW, +-}; +- +-static inline enum ar9170_bw nl80211_to_ar9170(enum nl80211_channel_type type) +-{ +- switch (type) { +- case NL80211_CHAN_NO_HT: +- case NL80211_CHAN_HT20: +- return AR9170_BW_20; +- case NL80211_CHAN_HT40MINUS: +- return AR9170_BW_40_BELOW; +- case NL80211_CHAN_HT40PLUS: +- return AR9170_BW_40_ABOVE; +- default: +- BUG(); +- } +-} +- +-enum ar9170_rf_init_mode { +- AR9170_RFI_NONE, +- AR9170_RFI_WARM, +- AR9170_RFI_COLD, +-}; +- +-#define AR9170_MAX_RX_BUFFER_SIZE 8192 +- +-#ifdef CONFIG_AR9170_LEDS +-struct ar9170; +- +-struct ar9170_led { +- struct ar9170 *ar; +- struct led_classdev l; +- char name[32]; +- unsigned int toggled; +- bool last_state; +- bool registered; +-}; +- +-#endif /* CONFIG_AR9170_LEDS */ +- +-enum ar9170_device_state { +- AR9170_UNKNOWN_STATE, +- AR9170_STOPPED, +- AR9170_IDLE, +- AR9170_STARTED, +-}; +- +-struct ar9170_rxstream_mpdu_merge { +- struct ar9170_rx_head plcp; +- bool has_plcp; +-}; +- +-struct ar9170_tx_queue_stats { +- unsigned int len; +- unsigned int limit; +- unsigned int count; +-}; +- +-#define AR9170_QUEUE_TIMEOUT 64 +-#define AR9170_TX_TIMEOUT 8 +-#define AR9170_JANITOR_DELAY 128 +-#define AR9170_TX_INVALID_RATE 0xffffffff +- +-#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH +-#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10) +- +-struct ar9170 { +- struct ieee80211_hw *hw; +- struct ath_common common; +- struct mutex mutex; +- enum ar9170_device_state state; +- bool registered; +- unsigned long bad_hw_nagger; +- +- int (*open)(struct ar9170 *); +- void (*stop)(struct ar9170 *); +- int (*tx)(struct ar9170 *, struct sk_buff *); +- int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 , +- void *, u32 , void *); +- void (*callback_cmd)(struct ar9170 *, u32 , void *); +- int (*flush)(struct ar9170 *); +- +- /* interface mode settings */ +- struct ieee80211_vif *vif; +- +- /* beaconing */ +- struct sk_buff *beacon; +- struct work_struct beacon_work; +- bool enable_beacon; +- +- /* cryptographic engine */ +- u64 usedkeys; +- bool rx_software_decryption; +- bool disable_offload; +- +- /* filter settings */ +- u64 cur_mc_hash; +- u32 cur_filter; +- unsigned int filter_state; +- bool sniffer_enabled; +- +- /* PHY */ +- struct ieee80211_channel *channel; +- int noise[4]; +- +- /* power calibration data */ +- u8 power_5G_leg[4]; +- u8 power_2G_cck[4]; +- u8 power_2G_ofdm[4]; +- u8 power_5G_ht20[8]; +- u8 power_5G_ht40[8]; +- u8 power_2G_ht20[8]; +- u8 power_2G_ht40[8]; +- +- u8 phy_heavy_clip; +- +-#ifdef CONFIG_AR9170_LEDS +- struct delayed_work led_work; +- struct ar9170_led leds[AR9170_NUM_LEDS]; +-#endif /* CONFIG_AR9170_LEDS */ +- +- /* qos queue settings */ +- spinlock_t tx_stats_lock; +- struct ar9170_tx_queue_stats tx_stats[5]; +- struct ieee80211_tx_queue_params edcf[5]; +- +- spinlock_t cmdlock; +- __le32 cmdbuf[PAYLOAD_MAX + 1]; +- +- /* MAC statistics */ +- struct ieee80211_low_level_stats stats; +- +- /* EEPROM */ +- struct ar9170_eeprom eeprom; +- +- /* tx queues - as seen by hw - */ +- struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; +- struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; +- struct delayed_work tx_janitor; +- +- /* rxstream mpdu merge */ +- struct ar9170_rxstream_mpdu_merge rx_mpdu; +- struct sk_buff *rx_failover; +- int rx_failover_missing; +- +- /* (cached) HW A-MPDU settings */ +- u8 global_ampdu_density; +- u8 global_ampdu_factor; +-}; +- +-struct ar9170_tx_info { +- unsigned long timeout; +-}; +- +-#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) +-#define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE) +- +-/* exported interface */ +-void *ar9170_alloc(size_t priv_size); +-int ar9170_register(struct ar9170 *ar, struct device *pdev); +-void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); +-void ar9170_unregister(struct ar9170 *ar); +-void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb); +-void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); +-int ar9170_nag_limiter(struct ar9170 *ar); +- +-/* MAC */ +-void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); +-int ar9170_init_mac(struct ar9170 *ar); +-int ar9170_set_qos(struct ar9170 *ar); +-int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast); +-int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter); +-int ar9170_set_operating_mode(struct ar9170 *ar); +-int ar9170_set_beacon_timers(struct ar9170 *ar); +-int ar9170_set_dyn_sifs_ack(struct ar9170 *ar); +-int ar9170_set_slot_time(struct ar9170 *ar); +-int ar9170_set_basic_rates(struct ar9170 *ar); +-int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); +-int ar9170_update_beacon(struct ar9170 *ar); +-void ar9170_new_beacon(struct work_struct *work); +-int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, +- u8 keyidx, u8 *keydata, int keylen); +-int ar9170_disable_key(struct ar9170 *ar, u8 id); +- +-/* LEDs */ +-#ifdef CONFIG_AR9170_LEDS +-int ar9170_register_leds(struct ar9170 *ar); +-void ar9170_unregister_leds(struct ar9170 *ar); +-#endif /* CONFIG_AR9170_LEDS */ +-int ar9170_init_leds(struct ar9170 *ar); +-int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state); +- +-/* PHY / RF */ +-int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band); +-int ar9170_init_rf(struct ar9170 *ar); +-int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, +- enum ar9170_rf_init_mode rfi, enum ar9170_bw bw); +- +-#endif /* __AR9170_H */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/cmd.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/cmd.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/cmd.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/cmd.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,127 +0,0 @@ +-/* +- * Atheros AR9170 driver +- * +- * Basic HW register/memory/command access functions +- * +- * Copyright 2008, Johannes Berg +- * +- * 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; see the file COPYING. If not, see +- * http://www.gnu.org/licenses/. +- * +- * This file incorporates work covered by the following copyright and +- * permission notice: +- * Copyright (c) 2007-2008 Atheros Communications, Inc. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-#include "ar9170.h" +-#include "cmd.h" +- +-int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len) +-{ +- int err; +- +- if (unlikely(!IS_ACCEPTING_CMD(ar))) +- return 0; +- +- err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL); +- if (err) +- wiphy_debug(ar->hw->wiphy, "writing memory failed\n"); +- return err; +-} +- +-int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val) +-{ +- const __le32 buf[2] = { +- cpu_to_le32(reg), +- cpu_to_le32(val), +- }; +- int err; +- +- if (unlikely(!IS_ACCEPTING_CMD(ar))) +- return 0; +- +- err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf), +- (u8 *) buf, 0, NULL); +- if (err) +- wiphy_debug(ar->hw->wiphy, "writing reg %#x (val %#x) failed\n", +- reg, val); +- return err; +-} +- +-int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out) +-{ +- int i, err; +- __le32 *offs, *res; +- +- if (unlikely(!IS_ACCEPTING_CMD(ar))) +- return 0; +- +- /* abuse "out" for the register offsets, must be same length */ +- offs = (__le32 *)out; +- for (i = 0; i < nregs; i++) +- offs[i] = cpu_to_le32(regs[i]); +- +- /* also use the same buffer for the input */ +- res = (__le32 *)out; +- +- err = ar->exec_cmd(ar, AR9170_CMD_RREG, +- 4 * nregs, (u8 *)offs, +- 4 * nregs, (u8 *)res); +- if (err) +- return err; +- +- /* convert result to cpu endian */ +- for (i = 0; i < nregs; i++) +- out[i] = le32_to_cpu(res[i]); +- +- return 0; +-} +- +-int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val) +-{ +- return ar9170_read_mreg(ar, 1, ®, val); +-} +- +-int ar9170_echo_test(struct ar9170 *ar, u32 v) +-{ +- __le32 echobuf = cpu_to_le32(v); +- __le32 echores; +- int err; +- +- if (unlikely(!IS_ACCEPTING_CMD(ar))) +- return -ENODEV; +- +- err = ar->exec_cmd(ar, AR9170_CMD_ECHO, +- 4, (u8 *)&echobuf, +- 4, (u8 *)&echores); +- if (err) +- return err; +- +- if (echobuf != echores) +- return -EINVAL; +- +- return 0; +-} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/cmd.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/cmd.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/cmd.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/cmd.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,92 +0,0 @@ +-/* +- * Atheros AR9170 driver +- * +- * Basic HW register/memory/command access functions +- * +- * Copyright 2008, Johannes Berg +- * +- * 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; see the file COPYING. If not, see +- * http://www.gnu.org/licenses/. +- * +- * This file incorporates work covered by the following copyright and +- * permission notice: +- * Copyright (c) 2007-2008 Atheros Communications, Inc. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +-#ifndef __CMD_H +-#define __CMD_H +- +-#include "ar9170.h" +- +-/* basic HW access */ +-int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len); +-int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val); +-int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val); +-int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out); +-int ar9170_echo_test(struct ar9170 *ar, u32 v); +- +-/* +- * Macros to facilitate writing multiple registers in a single +- * write-combining USB command. Note that when the first group +- * fails the whole thing will fail without any others attempted, +- * but you won't know which write in the group failed. +- */ +-#define ar9170_regwrite_begin(ar) \ +-do { \ +- int __nreg = 0, __err = 0; \ +- struct ar9170 *__ar = ar; +- +-#define ar9170_regwrite(r, v) do { \ +- __ar->cmdbuf[2 * __nreg + 1] = cpu_to_le32(r); \ +- __ar->cmdbuf[2 * __nreg + 2] = cpu_to_le32(v); \ +- __nreg++; \ +- if ((__nreg >= PAYLOAD_MAX/2)) { \ +- if (IS_ACCEPTING_CMD(__ar)) \ +- __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ +- 8 * __nreg, \ +- (u8 *) &__ar->cmdbuf[1], \ +- 0, NULL); \ +- __nreg = 0; \ +- if (__err) \ +- goto __regwrite_out; \ +- } \ +-} while (0) +- +-#define ar9170_regwrite_finish() \ +-__regwrite_out : \ +- if (__nreg) { \ +- if (IS_ACCEPTING_CMD(__ar)) \ +- __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ +- 8 * __nreg, \ +- (u8 *) &__ar->cmdbuf[1], \ +- 0, NULL); \ +- __nreg = 0; \ +- } +- +-#define ar9170_regwrite_result() \ +- __err; \ +-} while (0); +- +-#endif /* __CMD_H */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/eeprom.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/eeprom.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/eeprom.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/eeprom.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,179 +0,0 @@ +-/* +- * Atheros AR9170 driver +- * +- * EEPROM layout +- * +- * Copyright 2008, Johannes Berg +- * +- * 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; see the file COPYING. If not, see +- * http://www.gnu.org/licenses/. +- * +- * This file incorporates work covered by the following copyright and +- * permission notice: +- * Copyright (c) 2007-2008 Atheros Communications, Inc. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +-#ifndef __AR9170_EEPROM_H +-#define __AR9170_EEPROM_H +- +-#define AR5416_MAX_CHAINS 2 +-#define AR5416_MODAL_SPURS 5 +- +-struct ar9170_eeprom_modal { +- __le32 antCtrlChain[AR5416_MAX_CHAINS]; +- __le32 antCtrlCommon; +- s8 antennaGainCh[AR5416_MAX_CHAINS]; +- u8 switchSettling; +- u8 txRxAttenCh[AR5416_MAX_CHAINS]; +- u8 rxTxMarginCh[AR5416_MAX_CHAINS]; +- s8 adcDesiredSize; +- s8 pgaDesiredSize; +- u8 xlnaGainCh[AR5416_MAX_CHAINS]; +- u8 txEndToXpaOff; +- u8 txEndToRxOn; +- u8 txFrameToXpaOn; +- u8 thresh62; +- s8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; +- u8 xpdGain; +- u8 xpd; +- s8 iqCalICh[AR5416_MAX_CHAINS]; +- s8 iqCalQCh[AR5416_MAX_CHAINS]; +- u8 pdGainOverlap; +- u8 ob; +- u8 db; +- u8 xpaBiasLvl; +- u8 pwrDecreaseFor2Chain; +- u8 pwrDecreaseFor3Chain; +- u8 txFrameToDataStart; +- u8 txFrameToPaOn; +- u8 ht40PowerIncForPdadc; +- u8 bswAtten[AR5416_MAX_CHAINS]; +- u8 bswMargin[AR5416_MAX_CHAINS]; +- u8 swSettleHt40; +- u8 reserved[22]; +- struct spur_channel { +- __le16 spurChan; +- u8 spurRangeLow; +- u8 spurRangeHigh; +- } __packed spur_channels[AR5416_MODAL_SPURS]; +-} __packed; +- +-#define AR5416_NUM_PD_GAINS 4 +-#define AR5416_PD_GAIN_ICEPTS 5 +- +-struct ar9170_calibration_data_per_freq { +- u8 pwr_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; +- u8 vpd_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; +-} __packed; +- +-#define AR5416_NUM_5G_CAL_PIERS 8 +-#define AR5416_NUM_2G_CAL_PIERS 4 +- +-#define AR5416_NUM_5G_TARGET_PWRS 8 +-#define AR5416_NUM_2G_CCK_TARGET_PWRS 3 +-#define AR5416_NUM_2G_OFDM_TARGET_PWRS 4 +-#define AR5416_MAX_NUM_TGT_PWRS 8 +- +-struct ar9170_calibration_target_power_legacy { +- u8 freq; +- u8 power[4]; +-} __packed; +- +-struct ar9170_calibration_target_power_ht { +- u8 freq; +- u8 power[8]; +-} __packed; +- +-#define AR5416_NUM_CTLS 24 +- +-struct ar9170_calctl_edges { +- u8 channel; +-#define AR9170_CALCTL_EDGE_FLAGS 0xC0 +- u8 power_flags; +-} __packed; +- +-#define AR5416_NUM_BAND_EDGES 8 +- +-struct ar9170_calctl_data { +- struct ar9170_calctl_edges +- control_edges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; +-} __packed; +- +- +-struct ar9170_eeprom { +- __le16 length; +- __le16 checksum; +- __le16 version; +- u8 operating_flags; +-#define AR9170_OPFLAG_5GHZ 1 +-#define AR9170_OPFLAG_2GHZ 2 +- u8 misc; +- __le16 reg_domain[2]; +- u8 mac_address[6]; +- u8 rx_mask; +- u8 tx_mask; +- __le16 rf_silent; +- __le16 bluetooth_options; +- __le16 device_capabilities; +- __le32 build_number; +- u8 deviceType; +- u8 reserved[33]; +- +- u8 customer_data[64]; +- +- struct ar9170_eeprom_modal +- modal_header[2]; +- +- u8 cal_freq_pier_5G[AR5416_NUM_5G_CAL_PIERS]; +- u8 cal_freq_pier_2G[AR5416_NUM_2G_CAL_PIERS]; +- +- struct ar9170_calibration_data_per_freq +- cal_pier_data_5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS], +- cal_pier_data_2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; +- +- /* power calibration data */ +- struct ar9170_calibration_target_power_legacy +- cal_tgt_pwr_5G[AR5416_NUM_5G_TARGET_PWRS]; +- struct ar9170_calibration_target_power_ht +- cal_tgt_pwr_5G_ht20[AR5416_NUM_5G_TARGET_PWRS], +- cal_tgt_pwr_5G_ht40[AR5416_NUM_5G_TARGET_PWRS]; +- +- struct ar9170_calibration_target_power_legacy +- cal_tgt_pwr_2G_cck[AR5416_NUM_2G_CCK_TARGET_PWRS], +- cal_tgt_pwr_2G_ofdm[AR5416_NUM_2G_OFDM_TARGET_PWRS]; +- struct ar9170_calibration_target_power_ht +- cal_tgt_pwr_2G_ht20[AR5416_NUM_2G_OFDM_TARGET_PWRS], +- cal_tgt_pwr_2G_ht40[AR5416_NUM_2G_OFDM_TARGET_PWRS]; +- +- /* conformance testing limits */ +- u8 ctl_index[AR5416_NUM_CTLS]; +- struct ar9170_calctl_data +- ctl_data[AR5416_NUM_CTLS]; +- +- u8 pad; +- __le16 subsystem_id; +-} __packed; +- +-#endif /* __AR9170_EEPROM_H */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/hw.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/hw.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/hw.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/hw.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,430 +0,0 @@ +-/* +- * Atheros AR9170 driver +- * +- * Hardware-specific definitions +- * +- * Copyright 2008, Johannes Berg +- * +- * 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; see the file COPYING. If not, see +- * http://www.gnu.org/licenses/. +- * +- * This file incorporates work covered by the following copyright and +- * permission notice: +- * Copyright (c) 2007-2008 Atheros Communications, Inc. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +-#ifndef __AR9170_HW_H +-#define __AR9170_HW_H +- +-#define AR9170_MAX_CMD_LEN 64 +- +-enum ar9170_cmd { +- AR9170_CMD_RREG = 0x00, +- AR9170_CMD_WREG = 0x01, +- AR9170_CMD_RMEM = 0x02, +- AR9170_CMD_WMEM = 0x03, +- AR9170_CMD_BITAND = 0x04, +- AR9170_CMD_BITOR = 0x05, +- AR9170_CMD_EKEY = 0x28, +- AR9170_CMD_DKEY = 0x29, +- AR9170_CMD_FREQUENCY = 0x30, +- AR9170_CMD_RF_INIT = 0x31, +- AR9170_CMD_SYNTH = 0x32, +- AR9170_CMD_FREQ_START = 0x33, +- AR9170_CMD_ECHO = 0x80, +- AR9170_CMD_TALLY = 0x81, +- AR9170_CMD_TALLY_APD = 0x82, +- AR9170_CMD_CONFIG = 0x83, +- AR9170_CMD_RESET = 0x90, +- AR9170_CMD_DKRESET = 0x91, +- AR9170_CMD_DKTX_STATUS = 0x92, +- AR9170_CMD_FDC = 0xA0, +- AR9170_CMD_WREEPROM = 0xB0, +- AR9170_CMD_WFLASH = 0xB0, +- AR9170_CMD_FLASH_ERASE = 0xB1, +- AR9170_CMD_FLASH_PROG = 0xB2, +- AR9170_CMD_FLASH_CHKSUM = 0xB3, +- AR9170_CMD_FLASH_READ = 0xB4, +- AR9170_CMD_FW_DL_INIT = 0xB5, +- AR9170_CMD_MEM_WREEPROM = 0xBB, +-}; +- +-/* endpoints */ +-#define AR9170_EP_TX 1 +-#define AR9170_EP_RX 2 +-#define AR9170_EP_IRQ 3 +-#define AR9170_EP_CMD 4 +- +-#define AR9170_EEPROM_START 0x1600 +- +-#define AR9170_GPIO_REG_BASE 0x1d0100 +-#define AR9170_GPIO_REG_PORT_TYPE AR9170_GPIO_REG_BASE +-#define AR9170_GPIO_REG_DATA (AR9170_GPIO_REG_BASE + 4) +-#define AR9170_NUM_LEDS 2 +- +- +-#define AR9170_USB_REG_BASE 0x1e1000 +-#define AR9170_USB_REG_DMA_CTL (AR9170_USB_REG_BASE + 0x108) +-#define AR9170_DMA_CTL_ENABLE_TO_DEVICE 0x1 +-#define AR9170_DMA_CTL_ENABLE_FROM_DEVICE 0x2 +-#define AR9170_DMA_CTL_HIGH_SPEED 0x4 +-#define AR9170_DMA_CTL_PACKET_MODE 0x8 +- +-#define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110) +-#define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114) +- +- +- +-#define AR9170_MAC_REG_BASE 0x1c3000 +- +-#define AR9170_MAC_REG_TSF_L (AR9170_MAC_REG_BASE + 0x514) +-#define AR9170_MAC_REG_TSF_H (AR9170_MAC_REG_BASE + 0x518) +- +-#define AR9170_MAC_REG_ATIM_WINDOW (AR9170_MAC_REG_BASE + 0x51C) +-#define AR9170_MAC_REG_BCN_PERIOD (AR9170_MAC_REG_BASE + 0x520) +-#define AR9170_MAC_REG_PRETBTT (AR9170_MAC_REG_BASE + 0x524) +- +-#define AR9170_MAC_REG_MAC_ADDR_L (AR9170_MAC_REG_BASE + 0x610) +-#define AR9170_MAC_REG_MAC_ADDR_H (AR9170_MAC_REG_BASE + 0x614) +-#define AR9170_MAC_REG_BSSID_L (AR9170_MAC_REG_BASE + 0x618) +-#define AR9170_MAC_REG_BSSID_H (AR9170_MAC_REG_BASE + 0x61c) +- +-#define AR9170_MAC_REG_GROUP_HASH_TBL_L (AR9170_MAC_REG_BASE + 0x624) +-#define AR9170_MAC_REG_GROUP_HASH_TBL_H (AR9170_MAC_REG_BASE + 0x628) +- +-#define AR9170_MAC_REG_RX_TIMEOUT (AR9170_MAC_REG_BASE + 0x62C) +- +-#define AR9170_MAC_REG_BASIC_RATE (AR9170_MAC_REG_BASE + 0x630) +-#define AR9170_MAC_REG_MANDATORY_RATE (AR9170_MAC_REG_BASE + 0x634) +-#define AR9170_MAC_REG_RTS_CTS_RATE (AR9170_MAC_REG_BASE + 0x638) +-#define AR9170_MAC_REG_BACKOFF_PROTECT (AR9170_MAC_REG_BASE + 0x63c) +-#define AR9170_MAC_REG_RX_THRESHOLD (AR9170_MAC_REG_BASE + 0x640) +-#define AR9170_MAC_REG_RX_PE_DELAY (AR9170_MAC_REG_BASE + 0x64C) +- +-#define AR9170_MAC_REG_DYNAMIC_SIFS_ACK (AR9170_MAC_REG_BASE + 0x658) +-#define AR9170_MAC_REG_SNIFFER (AR9170_MAC_REG_BASE + 0x674) +-#define AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC BIT(0) +-#define AR9170_MAC_REG_SNIFFER_DEFAULTS 0x02000000 +-#define AR9170_MAC_REG_ENCRYPTION (AR9170_MAC_REG_BASE + 0x678) +-#define AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE BIT(3) +-#define AR9170_MAC_REG_ENCRYPTION_DEFAULTS 0x70 +- +-#define AR9170_MAC_REG_MISC_680 (AR9170_MAC_REG_BASE + 0x680) +-#define AR9170_MAC_REG_TX_UNDERRUN (AR9170_MAC_REG_BASE + 0x688) +- +-#define AR9170_MAC_REG_FRAMETYPE_FILTER (AR9170_MAC_REG_BASE + 0x68c) +-#define AR9170_MAC_REG_FTF_ASSOC_REQ BIT(0) +-#define AR9170_MAC_REG_FTF_ASSOC_RESP BIT(1) +-#define AR9170_MAC_REG_FTF_REASSOC_REQ BIT(2) +-#define AR9170_MAC_REG_FTF_REASSOC_RESP BIT(3) +-#define AR9170_MAC_REG_FTF_PRB_REQ BIT(4) +-#define AR9170_MAC_REG_FTF_PRB_RESP BIT(5) +-#define AR9170_MAC_REG_FTF_BIT6 BIT(6) +-#define AR9170_MAC_REG_FTF_BIT7 BIT(7) +-#define AR9170_MAC_REG_FTF_BEACON BIT(8) +-#define AR9170_MAC_REG_FTF_ATIM BIT(9) +-#define AR9170_MAC_REG_FTF_DEASSOC BIT(10) +-#define AR9170_MAC_REG_FTF_AUTH BIT(11) +-#define AR9170_MAC_REG_FTF_DEAUTH BIT(12) +-#define AR9170_MAC_REG_FTF_BIT13 BIT(13) +-#define AR9170_MAC_REG_FTF_BIT14 BIT(14) +-#define AR9170_MAC_REG_FTF_BIT15 BIT(15) +-#define AR9170_MAC_REG_FTF_BAR BIT(24) +-#define AR9170_MAC_REG_FTF_BA BIT(25) +-#define AR9170_MAC_REG_FTF_PSPOLL BIT(26) +-#define AR9170_MAC_REG_FTF_RTS BIT(27) +-#define AR9170_MAC_REG_FTF_CTS BIT(28) +-#define AR9170_MAC_REG_FTF_ACK BIT(29) +-#define AR9170_MAC_REG_FTF_CFE BIT(30) +-#define AR9170_MAC_REG_FTF_CFE_ACK BIT(31) +-#define AR9170_MAC_REG_FTF_DEFAULTS 0x0700ffff +-#define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff +- +-#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0) +-#define AR9170_MAC_REG_RX_CRC32 (AR9170_MAC_REG_BASE + 0x6A4) +-#define AR9170_MAC_REG_RX_CRC16 (AR9170_MAC_REG_BASE + 0x6A8) +-#define AR9170_MAC_REG_RX_ERR_DECRYPTION_UNI (AR9170_MAC_REG_BASE + 0x6AC) +-#define AR9170_MAC_REG_RX_OVERRUN (AR9170_MAC_REG_BASE + 0x6B0) +-#define AR9170_MAC_REG_RX_ERR_DECRYPTION_MUL (AR9170_MAC_REG_BASE + 0x6BC) +-#define AR9170_MAC_REG_TX_RETRY (AR9170_MAC_REG_BASE + 0x6CC) +-#define AR9170_MAC_REG_TX_TOTAL (AR9170_MAC_REG_BASE + 0x6F4) +- +- +-#define AR9170_MAC_REG_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0x690) +-#define AR9170_MAC_REG_EIFS_AND_SIFS (AR9170_MAC_REG_BASE + 0x698) +- +-#define AR9170_MAC_REG_SLOT_TIME (AR9170_MAC_REG_BASE + 0x6F0) +- +-#define AR9170_MAC_REG_POWERMANAGEMENT (AR9170_MAC_REG_BASE + 0x700) +-#define AR9170_MAC_REG_POWERMGT_IBSS 0xe0 +-#define AR9170_MAC_REG_POWERMGT_AP 0xa1 +-#define AR9170_MAC_REG_POWERMGT_STA 0x2 +-#define AR9170_MAC_REG_POWERMGT_AP_WDS 0x3 +-#define AR9170_MAC_REG_POWERMGT_DEFAULTS (0xf << 24) +- +-#define AR9170_MAC_REG_ROLL_CALL_TBL_L (AR9170_MAC_REG_BASE + 0x704) +-#define AR9170_MAC_REG_ROLL_CALL_TBL_H (AR9170_MAC_REG_BASE + 0x708) +- +-#define AR9170_MAC_REG_AC0_CW (AR9170_MAC_REG_BASE + 0xB00) +-#define AR9170_MAC_REG_AC1_CW (AR9170_MAC_REG_BASE + 0xB04) +-#define AR9170_MAC_REG_AC2_CW (AR9170_MAC_REG_BASE + 0xB08) +-#define AR9170_MAC_REG_AC3_CW (AR9170_MAC_REG_BASE + 0xB0C) +-#define AR9170_MAC_REG_AC4_CW (AR9170_MAC_REG_BASE + 0xB10) +-#define AR9170_MAC_REG_AC1_AC0_AIFS (AR9170_MAC_REG_BASE + 0xB14) +-#define AR9170_MAC_REG_AC3_AC2_AIFS (AR9170_MAC_REG_BASE + 0xB18) +- +-#define AR9170_MAC_REG_RETRY_MAX (AR9170_MAC_REG_BASE + 0xB28) +- +-#define AR9170_MAC_REG_FCS_SELECT (AR9170_MAC_REG_BASE + 0xBB0) +-#define AR9170_MAC_FCS_SWFCS 0x1 +-#define AR9170_MAC_FCS_FIFO_PROT 0x4 +- +- +-#define AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND (AR9170_MAC_REG_BASE + 0xB30) +- +-#define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) +-#define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) +- +-#define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xB9C) +-#define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xBA0) +- +-#define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) +-#define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) +- +-#define AR9170_MAC_REG_TXRX_MPI (AR9170_MAC_REG_BASE + 0xD7C) +-#define AR9170_MAC_TXRX_MPI_TX_MPI_MASK 0x0000000f +-#define AR9170_MAC_TXRX_MPI_TX_TO_MASK 0x0000fff0 +-#define AR9170_MAC_TXRX_MPI_RX_MPI_MASK 0x000f0000 +-#define AR9170_MAC_TXRX_MPI_RX_TO_MASK 0xfff00000 +- +-#define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xD84) +-#define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xD88) +-#define AR9170_MAC_REG_BCN_PLCP (AR9170_MAC_REG_BASE + 0xD90) +-#define AR9170_MAC_REG_BCN_CTRL (AR9170_MAC_REG_BASE + 0xD94) +-#define AR9170_MAC_REG_BCN_HT1 (AR9170_MAC_REG_BASE + 0xDA0) +-#define AR9170_MAC_REG_BCN_HT2 (AR9170_MAC_REG_BASE + 0xDA4) +- +- +-#define AR9170_PWR_REG_BASE 0x1D4000 +- +-#define AR9170_PWR_REG_CLOCK_SEL (AR9170_PWR_REG_BASE + 0x008) +-#define AR9170_PWR_CLK_AHB_40MHZ 0 +-#define AR9170_PWR_CLK_AHB_20_22MHZ 1 +-#define AR9170_PWR_CLK_AHB_40_44MHZ 2 +-#define AR9170_PWR_CLK_AHB_80_88MHZ 3 +-#define AR9170_PWR_CLK_DAC_160_INV_DLY 0x70 +- +- +-/* put beacon here in memory */ +-#define AR9170_BEACON_BUFFER_ADDRESS 0x117900 +- +- +-struct ar9170_tx_control { +- __le16 length; +- __le16 mac_control; +- __le32 phy_control; +- u8 frame_data[0]; +-} __packed; +- +-/* these are either-or */ +-#define AR9170_TX_MAC_PROT_RTS 0x0001 +-#define AR9170_TX_MAC_PROT_CTS 0x0002 +- +-#define AR9170_TX_MAC_NO_ACK 0x0004 +-/* if unset, MAC will only do SIFS space before frame */ +-#define AR9170_TX_MAC_BACKOFF 0x0008 +-#define AR9170_TX_MAC_BURST 0x0010 +-#define AR9170_TX_MAC_AGGR 0x0020 +- +-/* encryption is a two-bit field */ +-#define AR9170_TX_MAC_ENCR_NONE 0x0000 +-#define AR9170_TX_MAC_ENCR_RC4 0x0040 +-#define AR9170_TX_MAC_ENCR_CENC 0x0080 +-#define AR9170_TX_MAC_ENCR_AES 0x00c0 +- +-#define AR9170_TX_MAC_MMIC 0x0100 +-#define AR9170_TX_MAC_HW_DURATION 0x0200 +-#define AR9170_TX_MAC_QOS_SHIFT 10 +-#define AR9170_TX_MAC_QOS_MASK (3 << AR9170_TX_MAC_QOS_SHIFT) +-#define AR9170_TX_MAC_AGGR_QOS_BIT1 0x0400 +-#define AR9170_TX_MAC_AGGR_QOS_BIT2 0x0800 +-#define AR9170_TX_MAC_DISABLE_TXOP 0x1000 +-#define AR9170_TX_MAC_TXOP_RIFS 0x2000 +-#define AR9170_TX_MAC_IMM_AMPDU 0x4000 +-#define AR9170_TX_MAC_RATE_PROBE 0x8000 +- +-/* either-or */ +-#define AR9170_TX_PHY_MOD_MASK 0x00000003 +-#define AR9170_TX_PHY_MOD_CCK 0x00000000 +-#define AR9170_TX_PHY_MOD_OFDM 0x00000001 +-#define AR9170_TX_PHY_MOD_HT 0x00000002 +- +-/* depends on modulation */ +-#define AR9170_TX_PHY_SHORT_PREAMBLE 0x00000004 +-#define AR9170_TX_PHY_GREENFIELD 0x00000004 +- +-#define AR9170_TX_PHY_BW_SHIFT 3 +-#define AR9170_TX_PHY_BW_MASK (3 << AR9170_TX_PHY_BW_SHIFT) +-#define AR9170_TX_PHY_BW_20MHZ 0 +-#define AR9170_TX_PHY_BW_40MHZ 2 +-#define AR9170_TX_PHY_BW_40MHZ_DUP 3 +- +-#define AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT 6 +-#define AR9170_TX_PHY_TX_HEAVY_CLIP_MASK (7 << AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT) +- +-#define AR9170_TX_PHY_TX_PWR_SHIFT 9 +-#define AR9170_TX_PHY_TX_PWR_MASK (0x3f << AR9170_TX_PHY_TX_PWR_SHIFT) +- +-/* not part of the hw-spec */ +-#define AR9170_TX_PHY_QOS_SHIFT 25 +-#define AR9170_TX_PHY_QOS_MASK (3 << AR9170_TX_PHY_QOS_SHIFT) +- +-#define AR9170_TX_PHY_TXCHAIN_SHIFT 15 +-#define AR9170_TX_PHY_TXCHAIN_MASK (7 << AR9170_TX_PHY_TXCHAIN_SHIFT) +-#define AR9170_TX_PHY_TXCHAIN_1 1 +-/* use for cck, ofdm 6/9/12/18/24 and HT if capable */ +-#define AR9170_TX_PHY_TXCHAIN_2 5 +- +-#define AR9170_TX_PHY_MCS_SHIFT 18 +-#define AR9170_TX_PHY_MCS_MASK (0x7f << AR9170_TX_PHY_MCS_SHIFT) +- +-#define AR9170_TX_PHY_SHORT_GI 0x80000000 +- +-#define AR5416_MAX_RATE_POWER 63 +- +-struct ar9170_rx_head { +- u8 plcp[12]; +-} __packed; +- +-struct ar9170_rx_phystatus { +- union { +- struct { +- u8 rssi_ant0, rssi_ant1, rssi_ant2, +- rssi_ant0x, rssi_ant1x, rssi_ant2x, +- rssi_combined; +- } __packed; +- u8 rssi[7]; +- } __packed; +- +- u8 evm_stream0[6], evm_stream1[6]; +- u8 phy_err; +-} __packed; +- +-struct ar9170_rx_macstatus { +- u8 SAidx, DAidx; +- u8 error; +- u8 status; +-} __packed; +- +-#define AR9170_ENC_ALG_NONE 0x0 +-#define AR9170_ENC_ALG_WEP64 0x1 +-#define AR9170_ENC_ALG_TKIP 0x2 +-#define AR9170_ENC_ALG_AESCCMP 0x4 +-#define AR9170_ENC_ALG_WEP128 0x5 +-#define AR9170_ENC_ALG_WEP256 0x6 +-#define AR9170_ENC_ALG_CENC 0x7 +- +-#define AR9170_RX_ENC_SOFTWARE 0x8 +- +-static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t) +-{ +- return (t->SAidx & 0xc0) >> 4 | +- (t->DAidx & 0xc0) >> 6; +-} +- +-#define AR9170_RX_STATUS_MODULATION_MASK 0x03 +-#define AR9170_RX_STATUS_MODULATION_CCK 0x00 +-#define AR9170_RX_STATUS_MODULATION_OFDM 0x01 +-#define AR9170_RX_STATUS_MODULATION_HT 0x02 +-#define AR9170_RX_STATUS_MODULATION_DUPOFDM 0x03 +- +-/* depends on modulation */ +-#define AR9170_RX_STATUS_SHORT_PREAMBLE 0x08 +-#define AR9170_RX_STATUS_GREENFIELD 0x08 +- +-#define AR9170_RX_STATUS_MPDU_MASK 0x30 +-#define AR9170_RX_STATUS_MPDU_SINGLE 0x00 +-#define AR9170_RX_STATUS_MPDU_FIRST 0x20 +-#define AR9170_RX_STATUS_MPDU_MIDDLE 0x30 +-#define AR9170_RX_STATUS_MPDU_LAST 0x10 +- +-#define AR9170_RX_ERROR_RXTO 0x01 +-#define AR9170_RX_ERROR_OVERRUN 0x02 +-#define AR9170_RX_ERROR_DECRYPT 0x04 +-#define AR9170_RX_ERROR_FCS 0x08 +-#define AR9170_RX_ERROR_WRONG_RA 0x10 +-#define AR9170_RX_ERROR_PLCP 0x20 +-#define AR9170_RX_ERROR_MMIC 0x40 +-#define AR9170_RX_ERROR_FATAL 0x80 +- +-struct ar9170_cmd_tx_status { +- u8 dst[ETH_ALEN]; +- __le32 rate; +- __le16 status; +-} __packed; +- +-#define AR9170_TX_STATUS_COMPLETE 0x00 +-#define AR9170_TX_STATUS_RETRY 0x01 +-#define AR9170_TX_STATUS_FAILED 0x02 +- +-struct ar9170_cmd_ba_failed_count { +- __le16 failed; +- __le16 rate; +-} __packed; +- +-struct ar9170_cmd_response { +- u8 flag; +- u8 type; +- __le16 padding; +- +- union { +- struct ar9170_cmd_tx_status tx_status; +- struct ar9170_cmd_ba_failed_count ba_fail_cnt; +- u8 data[0]; +- }; +-} __packed; +- +-/* QoS */ +- +-/* mac80211 queue to HW/FW map */ +-static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 }; +- +-/* HW/FW queue to mac80211 map */ +-static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 }; +- +-enum ar9170_txq { +- AR9170_TXQ_BE, +- AR9170_TXQ_BK, +- AR9170_TXQ_VI, +- AR9170_TXQ_VO, +- +- __AR9170_NUM_TXQ, +-}; +- +-#define AR9170_TXQ_DEPTH 32 +-#define AR9170_TX_MAX_PENDING 128 +-#define AR9170_RX_STREAM_MAX_SIZE 65535 +- +-#endif /* __AR9170_HW_H */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/Kconfig linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/Kconfig +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/Kconfig 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/Kconfig 1970-01-01 01:00:00.000000000 +0100 +@@ -1,20 +0,0 @@ +-config AR9170_USB +- tristate "Atheros AR9170 802.11n USB support (OBSOLETE)" +- depends on USB && MAC80211 +- select FW_LOADER +- help +- This driver is going to get replaced by carl9170. +- +- This is a driver for the Atheros "otus" 802.11n USB devices. +- +- These devices require additional firmware (2 files). +- For now, these files can be downloaded from here: +- +- http://wireless.kernel.org/en/users/Drivers/ar9170 +- +- If you choose to build a module, it'll be called ar9170usb. +- +-config AR9170_LEDS +- bool +- depends on AR9170_USB && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = AR9170_USB) +- default y +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/led.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/led.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/led.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/led.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,181 +0,0 @@ +-/* +- * Atheros AR9170 driver +- * +- * LED handling +- * +- * Copyright 2008, Johannes Berg +- * +- * 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; see the file COPYING. If not, see +- * http://www.gnu.org/licenses/. +- * +- * This file incorporates work covered by the following copyright and +- * permission notice: +- * Copyright (c) 2007-2008 Atheros Communications, Inc. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-#include "ar9170.h" +-#include "cmd.h" +- +-int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state) +-{ +- return ar9170_write_reg(ar, AR9170_GPIO_REG_DATA, led_state); +-} +- +-int ar9170_init_leds(struct ar9170 *ar) +-{ +- int err; +- +- /* disable LEDs */ +- /* GPIO [0/1 mode: output, 2/3: input] */ +- err = ar9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3); +- if (err) +- goto out; +- +- /* GPIO 0/1 value: off */ +- err = ar9170_set_leds_state(ar, 0); +- +-out: +- return err; +-} +- +-#ifdef CONFIG_AR9170_LEDS +-static void ar9170_update_leds(struct work_struct *work) +-{ +- struct ar9170 *ar = container_of(work, struct ar9170, led_work.work); +- int i, tmp, blink_delay = 1000; +- u32 led_val = 0; +- bool rerun = false; +- +- if (unlikely(!IS_ACCEPTING_CMD(ar))) +- return ; +- +- mutex_lock(&ar->mutex); +- for (i = 0; i < AR9170_NUM_LEDS; i++) +- if (ar->leds[i].registered && ar->leds[i].toggled) { +- led_val |= 1 << i; +- +- tmp = 70 + 200 / (ar->leds[i].toggled); +- if (tmp < blink_delay) +- blink_delay = tmp; +- +- if (ar->leds[i].toggled > 1) +- ar->leds[i].toggled = 0; +- +- rerun = true; +- } +- +- ar9170_set_leds_state(ar, led_val); +- mutex_unlock(&ar->mutex); +- +- if (!rerun) +- return; +- +- ieee80211_queue_delayed_work(ar->hw, +- &ar->led_work, +- msecs_to_jiffies(blink_delay)); +-} +- +-static void ar9170_led_brightness_set(struct led_classdev *led, +- enum led_brightness brightness) +-{ +- struct ar9170_led *arl = container_of(led, struct ar9170_led, l); +- struct ar9170 *ar = arl->ar; +- +- if (unlikely(!arl->registered)) +- return ; +- +- if (arl->last_state != !!brightness) { +- arl->toggled++; +- arl->last_state = !!brightness; +- } +- +- if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled)) +- ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10); +-} +- +-static int ar9170_register_led(struct ar9170 *ar, int i, char *name, +- char *trigger) +-{ +- int err; +- +- snprintf(ar->leds[i].name, sizeof(ar->leds[i].name), +- "ar9170-%s::%s", wiphy_name(ar->hw->wiphy), name); +- +- ar->leds[i].ar = ar; +- ar->leds[i].l.name = ar->leds[i].name; +- ar->leds[i].l.brightness_set = ar9170_led_brightness_set; +- ar->leds[i].l.brightness = 0; +- ar->leds[i].l.default_trigger = trigger; +- +- err = led_classdev_register(wiphy_dev(ar->hw->wiphy), +- &ar->leds[i].l); +- if (err) +- wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n", +- ar->leds[i].name, err); +- else +- ar->leds[i].registered = true; +- +- return err; +-} +- +-void ar9170_unregister_leds(struct ar9170 *ar) +-{ +- int i; +- +- for (i = 0; i < AR9170_NUM_LEDS; i++) +- if (ar->leds[i].registered) { +- led_classdev_unregister(&ar->leds[i].l); +- ar->leds[i].registered = false; +- ar->leds[i].toggled = 0; +- } +- +- cancel_delayed_work_sync(&ar->led_work); +-} +- +-int ar9170_register_leds(struct ar9170 *ar) +-{ +- int err; +- +- INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds); +- +- err = ar9170_register_led(ar, 0, "tx", +- ieee80211_get_tx_led_name(ar->hw)); +- if (err) +- goto fail; +- +- err = ar9170_register_led(ar, 1, "assoc", +- ieee80211_get_assoc_led_name(ar->hw)); +- if (err) +- goto fail; +- +- return 0; +- +-fail: +- ar9170_unregister_leds(ar); +- return err; +-} +- +-#endif /* CONFIG_AR9170_LEDS */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/mac.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/mac.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/mac.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/mac.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,519 +0,0 @@ +-/* +- * Atheros AR9170 driver +- * +- * MAC programming +- * +- * Copyright 2008, Johannes Berg +- * +- * 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; see the file COPYING. If not, see +- * http://www.gnu.org/licenses/. +- * +- * This file incorporates work covered by the following copyright and +- * permission notice: +- * Copyright (c) 2007-2008 Atheros Communications, Inc. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-#include +- +-#include "ar9170.h" +-#include "cmd.h" +- +-int ar9170_set_dyn_sifs_ack(struct ar9170 *ar) +-{ +- u32 val; +- +- if (conf_is_ht40(&ar->hw->conf)) +- val = 0x010a; +- else { +- if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) +- val = 0x105; +- else +- val = 0x104; +- } +- +- return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val); +-} +- +-int ar9170_set_slot_time(struct ar9170 *ar) +-{ +- u32 slottime = 20; +- +- if (!ar->vif) +- return 0; +- +- if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) || +- ar->vif->bss_conf.use_short_slot) +- slottime = 9; +- +- return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10); +-} +- +-int ar9170_set_basic_rates(struct ar9170 *ar) +-{ +- u8 cck, ofdm; +- +- if (!ar->vif) +- return 0; +- +- ofdm = ar->vif->bss_conf.basic_rates >> 4; +- +- /* FIXME: is still necessary? */ +- if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) +- cck = 0; +- else +- cck = ar->vif->bss_conf.basic_rates & 0xf; +- +- return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE, +- ofdm << 8 | cck); +-} +- +-int ar9170_set_qos(struct ar9170 *ar) +-{ +- ar9170_regwrite_begin(ar); +- +- ar9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min | +- (ar->edcf[0].cw_max << 16)); +- ar9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min | +- (ar->edcf[1].cw_max << 16)); +- ar9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min | +- (ar->edcf[2].cw_max << 16)); +- ar9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min | +- (ar->edcf[3].cw_max << 16)); +- ar9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min | +- (ar->edcf[4].cw_max << 16)); +- +- ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_AIFS, +- ((ar->edcf[0].aifs * 9 + 10)) | +- ((ar->edcf[1].aifs * 9 + 10) << 12) | +- ((ar->edcf[2].aifs * 9 + 10) << 24)); +- ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_AIFS, +- ((ar->edcf[2].aifs * 9 + 10) >> 8) | +- ((ar->edcf[3].aifs * 9 + 10) << 4) | +- ((ar->edcf[4].aifs * 9 + 10) << 16)); +- +- ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP, +- ar->edcf[0].txop | ar->edcf[1].txop << 16); +- ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP, +- ar->edcf[2].txop | ar->edcf[3].txop << 16); +- +- ar9170_regwrite_finish(); +- +- return ar9170_regwrite_result(); +-} +- +-static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity) +-{ +- u32 val; +- +- /* don't allow AMPDU density > 8us */ +- if (mpdudensity > 6) +- return -EINVAL; +- +- /* Watch out! Otus uses slightly different density values. */ +- val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0); +- +- ar9170_regwrite_begin(ar); +- ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val); +- ar9170_regwrite_finish(); +- +- return ar9170_regwrite_result(); +-} +- +-int ar9170_init_mac(struct ar9170 *ar) +-{ +- ar9170_regwrite_begin(ar); +- +- ar9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40); +- +- ar9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0); +- +- /* enable MMIC */ +- ar9170_regwrite(AR9170_MAC_REG_SNIFFER, +- AR9170_MAC_REG_SNIFFER_DEFAULTS); +- +- ar9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80); +- +- ar9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70); +- ar9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000); +- ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10); +- +- /* CF-END mode */ +- ar9170_regwrite(0x1c3b2c, 0x19000000); +- +- /* NAV protects ACK only (in TXOP) */ +- ar9170_regwrite(0x1c3b38, 0x201); +- +- /* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */ +- /* OTUS set AM to 0x1 */ +- ar9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170); +- +- ar9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105); +- +- /* AGG test code*/ +- /* Aggregation MAX number and timeout */ +- ar9170_regwrite(0x1c3b9c, 0x10000a); +- +- ar9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER, +- AR9170_MAC_REG_FTF_DEFAULTS); +- +- /* Enable deaggregator, response in sniffer mode */ +- ar9170_regwrite(0x1c3c40, 0x1 | 1<<30); +- +- /* rate sets */ +- ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f); +- ar9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f); +- ar9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x10b01bb); +- +- /* MIMO response control */ +- ar9170_regwrite(0x1c3694, 0x4003C1E);/* bit 26~28 otus-AM */ +- +- /* switch MAC to OTUS interface */ +- ar9170_regwrite(0x1c3600, 0x3); +- +- ar9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff); +- +- /* set PHY register read timeout (??) */ +- ar9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008); +- +- /* Disable Rx TimeOut, workaround for BB. */ +- ar9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0); +- +- /* Set CPU clock frequency to 88/80MHz */ +- ar9170_regwrite(AR9170_PWR_REG_CLOCK_SEL, +- AR9170_PWR_CLK_AHB_80_88MHZ | +- AR9170_PWR_CLK_DAC_160_INV_DLY); +- +- /* Set WLAN DMA interrupt mode: generate int per packet */ +- ar9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011); +- +- ar9170_regwrite(AR9170_MAC_REG_FCS_SELECT, +- AR9170_MAC_FCS_FIFO_PROT); +- +- /* Disables the CF_END frame, undocumented register */ +- ar9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND, +- 0x141E0F48); +- +- ar9170_regwrite_finish(); +- +- return ar9170_regwrite_result(); +-} +- +-static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac) +-{ +- static const u8 zero[ETH_ALEN] = { 0 }; +- +- if (!mac) +- mac = zero; +- +- ar9170_regwrite_begin(ar); +- +- ar9170_regwrite(reg, get_unaligned_le32(mac)); +- ar9170_regwrite(reg + 4, get_unaligned_le16(mac + 4)); +- +- ar9170_regwrite_finish(); +- +- return ar9170_regwrite_result(); +-} +- +-int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hash) +-{ +- int err; +- +- ar9170_regwrite_begin(ar); +- ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32); +- ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash); +- ar9170_regwrite_finish(); +- err = ar9170_regwrite_result(); +- if (err) +- return err; +- +- ar->cur_mc_hash = mc_hash; +- return 0; +-} +- +-int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter) +-{ +- int err; +- +- err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, filter); +- if (err) +- return err; +- +- ar->cur_filter = filter; +- return 0; +-} +- +-static int ar9170_set_promiscouous(struct ar9170 *ar) +-{ +- u32 encr_mode, sniffer; +- int err; +- +- err = ar9170_read_reg(ar, AR9170_MAC_REG_SNIFFER, &sniffer); +- if (err) +- return err; +- +- err = ar9170_read_reg(ar, AR9170_MAC_REG_ENCRYPTION, &encr_mode); +- if (err) +- return err; +- +- if (ar->sniffer_enabled) { +- sniffer |= AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; +- +- /* +- * Rx decryption works in place. +- * +- * If we don't disable it, the hardware will render all +- * encrypted frames which are encrypted with an unknown +- * key useless. +- */ +- +- encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; +- ar->sniffer_enabled = true; +- } else { +- sniffer &= ~AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; +- +- if (ar->rx_software_decryption) +- encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; +- else +- encr_mode &= ~AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; +- } +- +- ar9170_regwrite_begin(ar); +- ar9170_regwrite(AR9170_MAC_REG_ENCRYPTION, encr_mode); +- ar9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer); +- ar9170_regwrite_finish(); +- +- return ar9170_regwrite_result(); +-} +- +-int ar9170_set_operating_mode(struct ar9170 *ar) +-{ +- struct ath_common *common = &ar->common; +- u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS; +- u8 *mac_addr, *bssid; +- int err; +- +- if (ar->vif) { +- mac_addr = common->macaddr; +- bssid = common->curbssid; +- +- switch (ar->vif->type) { +- case NL80211_IFTYPE_MESH_POINT: +- case NL80211_IFTYPE_ADHOC: +- pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS; +- break; +- case NL80211_IFTYPE_AP: +- pm_mode |= AR9170_MAC_REG_POWERMGT_AP; +- break; +- case NL80211_IFTYPE_WDS: +- pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS; +- break; +- case NL80211_IFTYPE_MONITOR: +- ar->sniffer_enabled = true; +- ar->rx_software_decryption = true; +- break; +- default: +- pm_mode |= AR9170_MAC_REG_POWERMGT_STA; +- break; +- } +- } else { +- mac_addr = NULL; +- bssid = NULL; +- } +- +- err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr); +- if (err) +- return err; +- +- err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, bssid); +- if (err) +- return err; +- +- err = ar9170_set_promiscouous(ar); +- if (err) +- return err; +- +- /* set AMPDU density to 8us. */ +- err = ar9170_set_ampdu_density(ar, 6); +- if (err) +- return err; +- +- ar9170_regwrite_begin(ar); +- +- ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode); +- ar9170_regwrite_finish(); +- +- return ar9170_regwrite_result(); +-} +- +-int ar9170_set_hwretry_limit(struct ar9170 *ar, unsigned int max_retry) +-{ +- u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111); +- +- return ar9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, tmp); +-} +- +-int ar9170_set_beacon_timers(struct ar9170 *ar) +-{ +- u32 v = 0; +- u32 pretbtt = 0; +- +- if (ar->vif) { +- v |= ar->vif->bss_conf.beacon_int; +- +- if (ar->enable_beacon) { +- switch (ar->vif->type) { +- case NL80211_IFTYPE_MESH_POINT: +- case NL80211_IFTYPE_ADHOC: +- v |= BIT(25); +- break; +- case NL80211_IFTYPE_AP: +- v |= BIT(24); +- pretbtt = (ar->vif->bss_conf.beacon_int - 6) << +- 16; +- break; +- default: +- break; +- } +- } +- +- v |= ar->vif->bss_conf.dtim_period << 16; +- } +- +- ar9170_regwrite_begin(ar); +- ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt); +- ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v); +- ar9170_regwrite_finish(); +- return ar9170_regwrite_result(); +-} +- +-int ar9170_update_beacon(struct ar9170 *ar) +-{ +- struct sk_buff *skb; +- __le32 *data, *old = NULL; +- u32 word; +- int i; +- +- skb = ieee80211_beacon_get(ar->hw, ar->vif); +- if (!skb) +- return -ENOMEM; +- +- data = (__le32 *)skb->data; +- if (ar->beacon) +- old = (__le32 *)ar->beacon->data; +- +- ar9170_regwrite_begin(ar); +- for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { +- /* +- * XXX: This accesses beyond skb data for up +- * to the last 3 bytes!! +- */ +- +- if (old && (data[i] == old[i])) +- continue; +- +- word = le32_to_cpu(data[i]); +- ar9170_regwrite(AR9170_BEACON_BUFFER_ADDRESS + 4 * i, word); +- } +- +- /* XXX: use skb->cb info */ +- if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) +- ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, +- ((skb->len + 4) << (3 + 16)) + 0x0400); +- else +- ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, +- ((skb->len + 4) << 16) + 0x001b); +- +- ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); +- ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); +- ar9170_regwrite(AR9170_MAC_REG_BCN_CTRL, 1); +- +- ar9170_regwrite_finish(); +- +- dev_kfree_skb(ar->beacon); +- ar->beacon = skb; +- +- return ar9170_regwrite_result(); +-} +- +-void ar9170_new_beacon(struct work_struct *work) +-{ +- struct ar9170 *ar = container_of(work, struct ar9170, +- beacon_work); +- struct sk_buff *skb; +- +- if (unlikely(!IS_STARTED(ar))) +- return ; +- +- mutex_lock(&ar->mutex); +- +- if (!ar->vif) +- goto out; +- +- ar9170_update_beacon(ar); +- +- rcu_read_lock(); +- while ((skb = ieee80211_get_buffered_bc(ar->hw, ar->vif))) +- ar9170_op_tx(ar->hw, skb); +- +- rcu_read_unlock(); +- +- out: +- mutex_unlock(&ar->mutex); +-} +- +-int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, +- u8 keyidx, u8 *keydata, int keylen) +-{ +- __le32 vals[7]; +- static const u8 bcast[ETH_ALEN] = +- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +- u8 dummy; +- +- mac = mac ? : bcast; +- +- vals[0] = cpu_to_le32((keyidx << 16) + id); +- vals[1] = cpu_to_le32(mac[1] << 24 | mac[0] << 16 | ktype); +- vals[2] = cpu_to_le32(mac[5] << 24 | mac[4] << 16 | +- mac[3] << 8 | mac[2]); +- memset(&vals[3], 0, 16); +- if (keydata) +- memcpy(&vals[3], keydata, keylen); +- +- return ar->exec_cmd(ar, AR9170_CMD_EKEY, +- sizeof(vals), (u8 *)vals, +- 1, &dummy); +-} +- +-int ar9170_disable_key(struct ar9170 *ar, u8 id) +-{ +- __le32 val = cpu_to_le32(id); +- u8 dummy; +- +- return ar->exec_cmd(ar, AR9170_CMD_EKEY, +- sizeof(val), (u8 *)&val, +- 1, &dummy); +-} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/main.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/main.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/main.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/main.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,2190 +0,0 @@ +-/* +- * Atheros AR9170 driver +- * +- * mac80211 interaction code +- * +- * Copyright 2008, Johannes Berg +- * Copyright 2009, Christian Lamparter +- * +- * 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; see the file COPYING. If not, see +- * http://www.gnu.org/licenses/. +- * +- * This file incorporates work covered by the following copyright and +- * permission notice: +- * Copyright (c) 2007-2008 Atheros Communications, Inc. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include "ar9170.h" +-#include "hw.h" +-#include "cmd.h" +- +-static int modparam_nohwcrypt; +-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +-MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); +- +-#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ +- .bitrate = (_bitrate), \ +- .flags = (_flags), \ +- .hw_value = (_hw_rate) | (_txpidx) << 4, \ +-} +- +-static struct ieee80211_rate __ar9170_ratetable[] = { +- RATE(10, 0, 0, 0), +- RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE), +- RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE), +- RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE), +- RATE(60, 0xb, 0, 0), +- RATE(90, 0xf, 0, 0), +- RATE(120, 0xa, 0, 0), +- RATE(180, 0xe, 0, 0), +- RATE(240, 0x9, 0, 0), +- RATE(360, 0xd, 1, 0), +- RATE(480, 0x8, 2, 0), +- RATE(540, 0xc, 3, 0), +-}; +-#undef RATE +- +-#define ar9170_g_ratetable (__ar9170_ratetable + 0) +-#define ar9170_g_ratetable_size 12 +-#define ar9170_a_ratetable (__ar9170_ratetable + 4) +-#define ar9170_a_ratetable_size 8 +- +-/* +- * NB: The hw_value is used as an index into the ar9170_phy_freq_params +- * array in phy.c so that we don't have to do frequency lookups! +- */ +-#define CHAN(_freq, _idx) { \ +- .center_freq = (_freq), \ +- .hw_value = (_idx), \ +- .max_power = 18, /* XXX */ \ +-} +- +-static struct ieee80211_channel ar9170_2ghz_chantable[] = { +- CHAN(2412, 0), +- CHAN(2417, 1), +- CHAN(2422, 2), +- CHAN(2427, 3), +- CHAN(2432, 4), +- CHAN(2437, 5), +- CHAN(2442, 6), +- CHAN(2447, 7), +- CHAN(2452, 8), +- CHAN(2457, 9), +- CHAN(2462, 10), +- CHAN(2467, 11), +- CHAN(2472, 12), +- CHAN(2484, 13), +-}; +- +-static struct ieee80211_channel ar9170_5ghz_chantable[] = { +- CHAN(4920, 14), +- CHAN(4940, 15), +- CHAN(4960, 16), +- CHAN(4980, 17), +- CHAN(5040, 18), +- CHAN(5060, 19), +- CHAN(5080, 20), +- CHAN(5180, 21), +- CHAN(5200, 22), +- CHAN(5220, 23), +- CHAN(5240, 24), +- CHAN(5260, 25), +- CHAN(5280, 26), +- CHAN(5300, 27), +- CHAN(5320, 28), +- CHAN(5500, 29), +- CHAN(5520, 30), +- CHAN(5540, 31), +- CHAN(5560, 32), +- CHAN(5580, 33), +- CHAN(5600, 34), +- CHAN(5620, 35), +- CHAN(5640, 36), +- CHAN(5660, 37), +- CHAN(5680, 38), +- CHAN(5700, 39), +- CHAN(5745, 40), +- CHAN(5765, 41), +- CHAN(5785, 42), +- CHAN(5805, 43), +- CHAN(5825, 44), +- CHAN(5170, 45), +- CHAN(5190, 46), +- CHAN(5210, 47), +- CHAN(5230, 48), +-}; +-#undef CHAN +- +-#define AR9170_HT_CAP \ +-{ \ +- .ht_supported = true, \ +- .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ +- IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ +- IEEE80211_HT_CAP_SGI_40 | \ +- IEEE80211_HT_CAP_GRN_FLD | \ +- IEEE80211_HT_CAP_DSSSCCK40 | \ +- IEEE80211_HT_CAP_SM_PS, \ +- .ampdu_factor = 3, \ +- .ampdu_density = 6, \ +- .mcs = { \ +- .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \ +- .rx_highest = cpu_to_le16(300), \ +- .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ +- }, \ +-} +- +-static struct ieee80211_supported_band ar9170_band_2GHz = { +- .channels = ar9170_2ghz_chantable, +- .n_channels = ARRAY_SIZE(ar9170_2ghz_chantable), +- .bitrates = ar9170_g_ratetable, +- .n_bitrates = ar9170_g_ratetable_size, +- .ht_cap = AR9170_HT_CAP, +-}; +- +-static struct ieee80211_supported_band ar9170_band_5GHz = { +- .channels = ar9170_5ghz_chantable, +- .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable), +- .bitrates = ar9170_a_ratetable, +- .n_bitrates = ar9170_a_ratetable_size, +- .ht_cap = AR9170_HT_CAP, +-}; +- +-static void ar9170_tx(struct ar9170 *ar); +- +-static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr) +-{ +- return le16_to_cpu(hdr->seq_ctrl) >> 4; +-} +- +-static inline u16 ar9170_get_seq(struct sk_buff *skb) +-{ +- struct ar9170_tx_control *txc = (void *) skb->data; +- return ar9170_get_seq_h((void *) txc->frame_data); +-} +- +-#ifdef AR9170_QUEUE_DEBUG +-static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) +-{ +- struct ar9170_tx_control *txc = (void *) skb->data; +- struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); +- struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; +- struct ieee80211_hdr *hdr = (void *) txc->frame_data; +- +- wiphy_debug(ar->hw->wiphy, +- "=> FRAME [skb:%p, q:%d, DA:[%pM] s:%d " +- "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", +- skb, skb_get_queue_mapping(skb), +- ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr), +- le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), +- jiffies_to_msecs(arinfo->timeout - jiffies)); +-} +- +-static void __ar9170_dump_txqueue(struct ar9170 *ar, +- struct sk_buff_head *queue) +-{ +- struct sk_buff *skb; +- int i = 0; +- +- printk(KERN_DEBUG "---[ cut here ]---\n"); +- wiphy_debug(ar->hw->wiphy, "%d entries in queue.\n", +- skb_queue_len(queue)); +- +- skb_queue_walk(queue, skb) { +- printk(KERN_DEBUG "index:%d =>\n", i++); +- ar9170_print_txheader(ar, skb); +- } +- if (i != skb_queue_len(queue)) +- printk(KERN_DEBUG "WARNING: queue frame counter " +- "mismatch %d != %d\n", skb_queue_len(queue), i); +- printk(KERN_DEBUG "---[ end ]---\n"); +-} +-#endif /* AR9170_QUEUE_DEBUG */ +- +-#ifdef AR9170_QUEUE_DEBUG +-static void ar9170_dump_txqueue(struct ar9170 *ar, +- struct sk_buff_head *queue) +-{ +- unsigned long flags; +- +- spin_lock_irqsave(&queue->lock, flags); +- __ar9170_dump_txqueue(ar, queue); +- spin_unlock_irqrestore(&queue->lock, flags); +-} +-#endif /* AR9170_QUEUE_DEBUG */ +- +-#ifdef AR9170_QUEUE_STOP_DEBUG +-static void __ar9170_dump_txstats(struct ar9170 *ar) +-{ +- int i; +- +- wiphy_debug(ar->hw->wiphy, "QoS queue stats\n"); +- +- for (i = 0; i < __AR9170_NUM_TXQ; i++) +- wiphy_debug(ar->hw->wiphy, +- "queue:%d limit:%d len:%d waitack:%d stopped:%d\n", +- i, ar->tx_stats[i].limit, ar->tx_stats[i].len, +- skb_queue_len(&ar->tx_status[i]), +- ieee80211_queue_stopped(ar->hw, i)); +-} +-#endif /* AR9170_QUEUE_STOP_DEBUG */ +- +-/* caller must guarantee exclusive access for _bin_ queue. */ +-static void ar9170_recycle_expired(struct ar9170 *ar, +- struct sk_buff_head *queue, +- struct sk_buff_head *bin) +-{ +- struct sk_buff *skb, *old = NULL; +- unsigned long flags; +- +- spin_lock_irqsave(&queue->lock, flags); +- while ((skb = skb_peek(queue))) { +- struct ieee80211_tx_info *txinfo; +- struct ar9170_tx_info *arinfo; +- +- txinfo = IEEE80211_SKB_CB(skb); +- arinfo = (void *) txinfo->rate_driver_data; +- +- if (time_is_before_jiffies(arinfo->timeout)) { +-#ifdef AR9170_QUEUE_DEBUG +- wiphy_debug(ar->hw->wiphy, +- "[%ld > %ld] frame expired => recycle\n", +- jiffies, arinfo->timeout); +- ar9170_print_txheader(ar, skb); +-#endif /* AR9170_QUEUE_DEBUG */ +- __skb_unlink(skb, queue); +- __skb_queue_tail(bin, skb); +- } else { +- break; +- } +- +- if (unlikely(old == skb)) { +- /* bail out - queue is shot. */ +- +- WARN_ON(1); +- break; +- } +- old = skb; +- } +- spin_unlock_irqrestore(&queue->lock, flags); +-} +- +-static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, +- u16 tx_status) +-{ +- struct ieee80211_tx_info *txinfo; +- unsigned int retries = 0; +- +- txinfo = IEEE80211_SKB_CB(skb); +- ieee80211_tx_info_clear_status(txinfo); +- +- switch (tx_status) { +- case AR9170_TX_STATUS_RETRY: +- retries = 2; +- case AR9170_TX_STATUS_COMPLETE: +- txinfo->flags |= IEEE80211_TX_STAT_ACK; +- break; +- +- case AR9170_TX_STATUS_FAILED: +- retries = ar->hw->conf.long_frame_max_tx_count; +- break; +- +- default: +- wiphy_err(ar->hw->wiphy, +- "invalid tx_status response (%x)\n", tx_status); +- break; +- } +- +- txinfo->status.rates[0].count = retries + 1; +- skb_pull(skb, sizeof(struct ar9170_tx_control)); +- ieee80211_tx_status_irqsafe(ar->hw, skb); +-} +- +-void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) +-{ +- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +- struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data; +- unsigned int queue = skb_get_queue_mapping(skb); +- unsigned long flags; +- +- spin_lock_irqsave(&ar->tx_stats_lock, flags); +- ar->tx_stats[queue].len--; +- +- if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) { +-#ifdef AR9170_QUEUE_STOP_DEBUG +- wiphy_debug(ar->hw->wiphy, "wake queue %d\n", queue); +- __ar9170_dump_txstats(ar); +-#endif /* AR9170_QUEUE_STOP_DEBUG */ +- ieee80211_wake_queue(ar->hw, queue); +- } +- spin_unlock_irqrestore(&ar->tx_stats_lock, flags); +- +- if (info->flags & IEEE80211_TX_CTL_NO_ACK) { +- ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); +- } else { +- arinfo->timeout = jiffies + +- msecs_to_jiffies(AR9170_TX_TIMEOUT); +- +- skb_queue_tail(&ar->tx_status[queue], skb); +- } +- +- if (!ar->tx_stats[queue].len && +- !skb_queue_empty(&ar->tx_pending[queue])) { +- ar9170_tx(ar); +- } +-} +- +-static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, +- const u8 *mac, +- struct sk_buff_head *queue, +- const u32 rate) +-{ +- unsigned long flags; +- struct sk_buff *skb; +- +- /* +- * Unfortunately, the firmware does not tell to which (queued) frame +- * this transmission status report belongs to. +- * +- * So we have to make risky guesses - with the scarce information +- * the firmware provided (-> destination MAC, and phy_control) - +- * and hope that we picked the right one... +- */ +- +- spin_lock_irqsave(&queue->lock, flags); +- skb_queue_walk(queue, skb) { +- struct ar9170_tx_control *txc = (void *) skb->data; +- struct ieee80211_hdr *hdr = (void *) txc->frame_data; +- u32 r; +- +- if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) { +-#ifdef AR9170_QUEUE_DEBUG +- wiphy_debug(ar->hw->wiphy, +- "skip frame => DA %pM != %pM\n", +- mac, ieee80211_get_DA(hdr)); +- ar9170_print_txheader(ar, skb); +-#endif /* AR9170_QUEUE_DEBUG */ +- continue; +- } +- +- r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >> +- AR9170_TX_PHY_MCS_SHIFT; +- +- if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) { +-#ifdef AR9170_QUEUE_DEBUG +- wiphy_debug(ar->hw->wiphy, +- "skip frame => rate %d != %d\n", rate, r); +- ar9170_print_txheader(ar, skb); +-#endif /* AR9170_QUEUE_DEBUG */ +- continue; +- } +- +- __skb_unlink(skb, queue); +- spin_unlock_irqrestore(&queue->lock, flags); +- return skb; +- } +- +-#ifdef AR9170_QUEUE_DEBUG +- wiphy_err(ar->hw->wiphy, +- "ESS:[%pM] does not have any outstanding frames in queue.\n", +- mac); +- __ar9170_dump_txqueue(ar, queue); +-#endif /* AR9170_QUEUE_DEBUG */ +- spin_unlock_irqrestore(&queue->lock, flags); +- +- return NULL; +-} +- +-/* +- * This worker tries to keeps an maintain tx_status queues. +- * So we can guarantee that incoming tx_status reports are +- * actually for a pending frame. +- */ +- +-static void ar9170_tx_janitor(struct work_struct *work) +-{ +- struct ar9170 *ar = container_of(work, struct ar9170, +- tx_janitor.work); +- struct sk_buff_head waste; +- unsigned int i; +- bool resched = false; +- +- if (unlikely(!IS_STARTED(ar))) +- return ; +- +- skb_queue_head_init(&waste); +- +- for (i = 0; i < __AR9170_NUM_TXQ; i++) { +-#ifdef AR9170_QUEUE_DEBUG +- wiphy_debug(ar->hw->wiphy, "garbage collector scans queue:%d\n", +- i); +- ar9170_dump_txqueue(ar, &ar->tx_pending[i]); +- ar9170_dump_txqueue(ar, &ar->tx_status[i]); +-#endif /* AR9170_QUEUE_DEBUG */ +- +- ar9170_recycle_expired(ar, &ar->tx_status[i], &waste); +- ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste); +- skb_queue_purge(&waste); +- +- if (!skb_queue_empty(&ar->tx_status[i]) || +- !skb_queue_empty(&ar->tx_pending[i])) +- resched = true; +- } +- +- if (!resched) +- return; +- +- ieee80211_queue_delayed_work(ar->hw, +- &ar->tx_janitor, +- msecs_to_jiffies(AR9170_JANITOR_DELAY)); +-} +- +-void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) +-{ +- struct ar9170_cmd_response *cmd = (void *) buf; +- +- if ((cmd->type & 0xc0) != 0xc0) { +- ar->callback_cmd(ar, len, buf); +- return; +- } +- +- /* hardware event handlers */ +- switch (cmd->type) { +- case 0xc1: { +- /* +- * TX status notification: +- * bytes: 0c c1 XX YY M1 M2 M3 M4 M5 M6 R4 R3 R2 R1 S2 S1 +- * +- * XX always 81 +- * YY always 00 +- * M1-M6 is the MAC address +- * R1-R4 is the transmit rate +- * S1-S2 is the transmit status +- */ +- +- struct sk_buff *skb; +- u32 phy = le32_to_cpu(cmd->tx_status.rate); +- u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >> +- AR9170_TX_PHY_QOS_SHIFT; +-#ifdef AR9170_QUEUE_DEBUG +- wiphy_debug(ar->hw->wiphy, +- "recv tx_status for %pm, p:%08x, q:%d\n", +- cmd->tx_status.dst, phy, q); +-#endif /* AR9170_QUEUE_DEBUG */ +- +- skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst, +- &ar->tx_status[q], +- AR9170_TX_INVALID_RATE); +- if (unlikely(!skb)) +- return ; +- +- ar9170_tx_status(ar, skb, le16_to_cpu(cmd->tx_status.status)); +- break; +- } +- +- case 0xc0: +- /* +- * pre-TBTT event +- */ +- if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP) +- ieee80211_queue_work(ar->hw, &ar->beacon_work); +- break; +- +- case 0xc2: +- /* +- * (IBSS) beacon send notification +- * bytes: 04 c2 XX YY B4 B3 B2 B1 +- * +- * XX always 80 +- * YY always 00 +- * B1-B4 "should" be the number of send out beacons. +- */ +- break; +- +- case 0xc3: +- /* End of Atim Window */ +- break; +- +- case 0xc4: +- /* BlockACK bitmap */ +- break; +- +- case 0xc5: +- /* BlockACK events */ +- break; +- +- case 0xc6: +- /* Watchdog Interrupt */ +- break; +- +- case 0xc9: +- /* retransmission issue / SIFS/EIFS collision ?! */ +- break; +- +- /* firmware debug */ +- case 0xca: +- printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, +- (char *)buf + 4); +- break; +- case 0xcb: +- len -= 4; +- +- switch (len) { +- case 1: +- printk(KERN_DEBUG "ar9170 FW: u8: %#.2x\n", +- *((char *)buf + 4)); +- break; +- case 2: +- printk(KERN_DEBUG "ar9170 FW: u8: %#.4x\n", +- le16_to_cpup((__le16 *)((char *)buf + 4))); +- break; +- case 4: +- printk(KERN_DEBUG "ar9170 FW: u8: %#.8x\n", +- le32_to_cpup((__le32 *)((char *)buf + 4))); +- break; +- case 8: +- printk(KERN_DEBUG "ar9170 FW: u8: %#.16lx\n", +- (unsigned long)le64_to_cpup( +- (__le64 *)((char *)buf + 4))); +- break; +- } +- break; +- case 0xcc: +- print_hex_dump_bytes("ar9170 FW:", DUMP_PREFIX_NONE, +- (char *)buf + 4, len - 4); +- break; +- +- default: +- pr_info("received unhandled event %x\n", cmd->type); +- print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); +- break; +- } +-} +- +-static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar) +-{ +- memset(&ar->rx_mpdu.plcp, 0, sizeof(struct ar9170_rx_head)); +- ar->rx_mpdu.has_plcp = false; +-} +- +-int ar9170_nag_limiter(struct ar9170 *ar) +-{ +- bool print_message; +- +- /* +- * we expect all sorts of errors in promiscuous mode. +- * don't bother with it, it's OK! +- */ +- if (ar->sniffer_enabled) +- return false; +- +- /* +- * only go for frequent errors! The hardware tends to +- * do some stupid thing once in a while under load, in +- * noisy environments or just for fun! +- */ +- if (time_before(jiffies, ar->bad_hw_nagger) && net_ratelimit()) +- print_message = true; +- else +- print_message = false; +- +- /* reset threshold for "once in a while" */ +- ar->bad_hw_nagger = jiffies + HZ / 4; +- return print_message; +-} +- +-static int ar9170_rx_mac_status(struct ar9170 *ar, +- struct ar9170_rx_head *head, +- struct ar9170_rx_macstatus *mac, +- struct ieee80211_rx_status *status) +-{ +- u8 error, decrypt; +- +- BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); +- BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4); +- +- error = mac->error; +- if (error & AR9170_RX_ERROR_MMIC) { +- status->flag |= RX_FLAG_MMIC_ERROR; +- error &= ~AR9170_RX_ERROR_MMIC; +- } +- +- if (error & AR9170_RX_ERROR_PLCP) { +- status->flag |= RX_FLAG_FAILED_PLCP_CRC; +- error &= ~AR9170_RX_ERROR_PLCP; +- +- if (!(ar->filter_state & FIF_PLCPFAIL)) +- return -EINVAL; +- } +- +- if (error & AR9170_RX_ERROR_FCS) { +- status->flag |= RX_FLAG_FAILED_FCS_CRC; +- error &= ~AR9170_RX_ERROR_FCS; +- +- if (!(ar->filter_state & FIF_FCSFAIL)) +- return -EINVAL; +- } +- +- decrypt = ar9170_get_decrypt_type(mac); +- if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && +- decrypt != AR9170_ENC_ALG_NONE) +- status->flag |= RX_FLAG_DECRYPTED; +- +- /* ignore wrong RA errors */ +- error &= ~AR9170_RX_ERROR_WRONG_RA; +- +- if (error & AR9170_RX_ERROR_DECRYPT) { +- error &= ~AR9170_RX_ERROR_DECRYPT; +- /* +- * Rx decryption is done in place, +- * the original data is lost anyway. +- */ +- +- return -EINVAL; +- } +- +- /* drop any other error frames */ +- if (unlikely(error)) { +- /* TODO: update netdevice's RX dropped/errors statistics */ +- +- if (ar9170_nag_limiter(ar)) +- wiphy_debug(ar->hw->wiphy, +- "received frame with suspicious error code (%#x).\n", +- error); +- +- return -EINVAL; +- } +- +- status->band = ar->channel->band; +- status->freq = ar->channel->center_freq; +- +- switch (mac->status & AR9170_RX_STATUS_MODULATION_MASK) { +- case AR9170_RX_STATUS_MODULATION_CCK: +- if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE) +- status->flag |= RX_FLAG_SHORTPRE; +- switch (head->plcp[0]) { +- case 0x0a: +- status->rate_idx = 0; +- break; +- case 0x14: +- status->rate_idx = 1; +- break; +- case 0x37: +- status->rate_idx = 2; +- break; +- case 0x6e: +- status->rate_idx = 3; +- break; +- default: +- if (ar9170_nag_limiter(ar)) +- wiphy_err(ar->hw->wiphy, +- "invalid plcp cck rate (%x).\n", +- head->plcp[0]); +- return -EINVAL; +- } +- break; +- +- case AR9170_RX_STATUS_MODULATION_DUPOFDM: +- case AR9170_RX_STATUS_MODULATION_OFDM: +- switch (head->plcp[0] & 0xf) { +- case 0xb: +- status->rate_idx = 0; +- break; +- case 0xf: +- status->rate_idx = 1; +- break; +- case 0xa: +- status->rate_idx = 2; +- break; +- case 0xe: +- status->rate_idx = 3; +- break; +- case 0x9: +- status->rate_idx = 4; +- break; +- case 0xd: +- status->rate_idx = 5; +- break; +- case 0x8: +- status->rate_idx = 6; +- break; +- case 0xc: +- status->rate_idx = 7; +- break; +- default: +- if (ar9170_nag_limiter(ar)) +- wiphy_err(ar->hw->wiphy, +- "invalid plcp ofdm rate (%x).\n", +- head->plcp[0]); +- return -EINVAL; +- } +- if (status->band == IEEE80211_BAND_2GHZ) +- status->rate_idx += 4; +- break; +- +- case AR9170_RX_STATUS_MODULATION_HT: +- if (head->plcp[3] & 0x80) +- status->flag |= RX_FLAG_40MHZ; +- if (head->plcp[6] & 0x80) +- status->flag |= RX_FLAG_SHORT_GI; +- +- status->rate_idx = clamp(0, 75, head->plcp[6] & 0x7f); +- status->flag |= RX_FLAG_HT; +- break; +- +- default: +- if (ar9170_nag_limiter(ar)) +- wiphy_err(ar->hw->wiphy, "invalid modulation\n"); +- return -EINVAL; +- } +- +- return 0; +-} +- +-static void ar9170_rx_phy_status(struct ar9170 *ar, +- struct ar9170_rx_phystatus *phy, +- struct ieee80211_rx_status *status) +-{ +- int i; +- +- BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20); +- +- for (i = 0; i < 3; i++) +- if (phy->rssi[i] != 0x80) +- status->antenna |= BIT(i); +- +- /* post-process RSSI */ +- for (i = 0; i < 7; i++) +- if (phy->rssi[i] & 0x80) +- phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f; +- +- /* TODO: we could do something with phy_errors */ +- status->signal = ar->noise[0] + phy->rssi_combined; +-} +- +-static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len) +-{ +- struct sk_buff *skb; +- int reserved = 0; +- struct ieee80211_hdr *hdr = (void *) buf; +- +- if (ieee80211_is_data_qos(hdr->frame_control)) { +- u8 *qc = ieee80211_get_qos_ctl(hdr); +- reserved += NET_IP_ALIGN; +- +- if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) +- reserved += NET_IP_ALIGN; +- } +- +- if (ieee80211_has_a4(hdr->frame_control)) +- reserved += NET_IP_ALIGN; +- +- reserved = 32 + (reserved & NET_IP_ALIGN); +- +- skb = dev_alloc_skb(len + reserved); +- if (likely(skb)) { +- skb_reserve(skb, reserved); +- memcpy(skb_put(skb, len), buf, len); +- } +- +- return skb; +-} +- +-/* +- * If the frame alignment is right (or the kernel has +- * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there +- * is only a single MPDU in the USB frame, then we could +- * submit to mac80211 the SKB directly. However, since +- * there may be multiple packets in one SKB in stream +- * mode, and we need to observe the proper ordering, +- * this is non-trivial. +- */ +- +-static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) +-{ +- struct ar9170_rx_head *head; +- struct ar9170_rx_macstatus *mac; +- struct ar9170_rx_phystatus *phy = NULL; +- struct ieee80211_rx_status status; +- struct sk_buff *skb; +- int mpdu_len; +- +- if (unlikely(!IS_STARTED(ar) || len < (sizeof(*mac)))) +- return ; +- +- /* Received MPDU */ +- mpdu_len = len - sizeof(*mac); +- +- mac = (void *)(buf + mpdu_len); +- if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) { +- /* this frame is too damaged and can't be used - drop it */ +- +- return ; +- } +- +- switch (mac->status & AR9170_RX_STATUS_MPDU_MASK) { +- case AR9170_RX_STATUS_MPDU_FIRST: +- /* first mpdu packet has the plcp header */ +- if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { +- head = (void *) buf; +- memcpy(&ar->rx_mpdu.plcp, (void *) buf, +- sizeof(struct ar9170_rx_head)); +- +- mpdu_len -= sizeof(struct ar9170_rx_head); +- buf += sizeof(struct ar9170_rx_head); +- ar->rx_mpdu.has_plcp = true; +- } else { +- if (ar9170_nag_limiter(ar)) +- wiphy_err(ar->hw->wiphy, +- "plcp info is clipped.\n"); +- return ; +- } +- break; +- +- case AR9170_RX_STATUS_MPDU_LAST: +- /* last mpdu has a extra tail with phy status information */ +- +- if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { +- mpdu_len -= sizeof(struct ar9170_rx_phystatus); +- phy = (void *)(buf + mpdu_len); +- } else { +- if (ar9170_nag_limiter(ar)) +- wiphy_err(ar->hw->wiphy, +- "frame tail is clipped.\n"); +- return ; +- } +- +- case AR9170_RX_STATUS_MPDU_MIDDLE: +- /* middle mpdus are just data */ +- if (unlikely(!ar->rx_mpdu.has_plcp)) { +- if (!ar9170_nag_limiter(ar)) +- return ; +- +- wiphy_err(ar->hw->wiphy, +- "rx stream did not start with a first_mpdu frame tag.\n"); +- +- return ; +- } +- +- head = &ar->rx_mpdu.plcp; +- break; +- +- case AR9170_RX_STATUS_MPDU_SINGLE: +- /* single mpdu - has plcp (head) and phy status (tail) */ +- head = (void *) buf; +- +- mpdu_len -= sizeof(struct ar9170_rx_head); +- mpdu_len -= sizeof(struct ar9170_rx_phystatus); +- +- buf += sizeof(struct ar9170_rx_head); +- phy = (void *)(buf + mpdu_len); +- break; +- +- default: +- BUG_ON(1); +- break; +- } +- +- if (unlikely(mpdu_len < FCS_LEN)) +- return ; +- +- memset(&status, 0, sizeof(status)); +- if (unlikely(ar9170_rx_mac_status(ar, head, mac, &status))) +- return ; +- +- if (phy) +- ar9170_rx_phy_status(ar, phy, &status); +- +- skb = ar9170_rx_copy_data(buf, mpdu_len); +- if (likely(skb)) { +- memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); +- ieee80211_rx_irqsafe(ar->hw, skb); +- } +-} +- +-void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) +-{ +- unsigned int i, tlen, resplen, wlen = 0, clen = 0; +- u8 *tbuf, *respbuf; +- +- tbuf = skb->data; +- tlen = skb->len; +- +- while (tlen >= 4) { +- clen = tbuf[1] << 8 | tbuf[0]; +- wlen = ALIGN(clen, 4); +- +- /* check if this is stream has a valid tag.*/ +- if (tbuf[2] != 0 || tbuf[3] != 0x4e) { +- /* +- * TODO: handle the highly unlikely event that the +- * corrupted stream has the TAG at the right position. +- */ +- +- /* check if the frame can be repaired. */ +- if (!ar->rx_failover_missing) { +- /* this is no "short read". */ +- if (ar9170_nag_limiter(ar)) { +- wiphy_err(ar->hw->wiphy, +- "missing tag!\n"); +- goto err_telluser; +- } else +- goto err_silent; +- } +- +- if (ar->rx_failover_missing > tlen) { +- if (ar9170_nag_limiter(ar)) { +- wiphy_err(ar->hw->wiphy, +- "possible multi stream corruption!\n"); +- goto err_telluser; +- } else +- goto err_silent; +- } +- +- memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); +- ar->rx_failover_missing -= tlen; +- +- if (ar->rx_failover_missing <= 0) { +- /* +- * nested ar9170_rx call! +- * termination is guaranteed, even when the +- * combined frame also have a element with +- * a bad tag. +- */ +- +- ar->rx_failover_missing = 0; +- ar9170_rx(ar, ar->rx_failover); +- +- skb_reset_tail_pointer(ar->rx_failover); +- skb_trim(ar->rx_failover, 0); +- } +- +- return ; +- } +- +- /* check if stream is clipped */ +- if (wlen > tlen - 4) { +- if (ar->rx_failover_missing) { +- /* TODO: handle double stream corruption. */ +- if (ar9170_nag_limiter(ar)) { +- wiphy_err(ar->hw->wiphy, +- "double rx stream corruption!\n"); +- goto err_telluser; +- } else +- goto err_silent; +- } +- +- /* +- * save incomplete data set. +- * the firmware will resend the missing bits when +- * the rx - descriptor comes round again. +- */ +- +- memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); +- ar->rx_failover_missing = clen - tlen; +- return ; +- } +- resplen = clen; +- respbuf = tbuf + 4; +- tbuf += wlen + 4; +- tlen -= wlen + 4; +- +- i = 0; +- +- /* weird thing, but this is the same in the original driver */ +- while (resplen > 2 && i < 12 && +- respbuf[0] == 0xff && respbuf[1] == 0xff) { +- i += 2; +- resplen -= 2; +- respbuf += 2; +- } +- +- if (resplen < 4) +- continue; +- +- /* found the 6 * 0xffff marker? */ +- if (i == 12) +- ar9170_handle_command_response(ar, respbuf, resplen); +- else +- ar9170_handle_mpdu(ar, respbuf, clen); +- } +- +- if (tlen) { +- if (net_ratelimit()) +- wiphy_err(ar->hw->wiphy, +- "%d bytes of unprocessed data left in rx stream!\n", +- tlen); +- +- goto err_telluser; +- } +- +- return ; +- +-err_telluser: +- wiphy_err(ar->hw->wiphy, +- "damaged RX stream data [want:%d, data:%d, rx:%d, pending:%d ]\n", +- clen, wlen, tlen, ar->rx_failover_missing); +- +- if (ar->rx_failover_missing) +- print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET, +- ar->rx_failover->data, +- ar->rx_failover->len); +- +- print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET, +- skb->data, skb->len); +- +- wiphy_err(ar->hw->wiphy, +- "If you see this message frequently, please check your hardware and cables.\n"); +- +-err_silent: +- if (ar->rx_failover_missing) { +- skb_reset_tail_pointer(ar->rx_failover); +- skb_trim(ar->rx_failover, 0); +- ar->rx_failover_missing = 0; +- } +-} +- +-#define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \ +-do { \ +- queue.aifs = ai_fs; \ +- queue.cw_min = cwmin; \ +- queue.cw_max = cwmax; \ +- queue.txop = _txop; \ +-} while (0) +- +-static int ar9170_op_start(struct ieee80211_hw *hw) +-{ +- struct ar9170 *ar = hw->priv; +- int err, i; +- +- mutex_lock(&ar->mutex); +- +- /* reinitialize queues statistics */ +- memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); +- for (i = 0; i < __AR9170_NUM_TXQ; i++) +- ar->tx_stats[i].limit = AR9170_TXQ_DEPTH; +- +- /* reset QoS defaults */ +- AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/ +- AR9170_FILL_QUEUE(ar->edcf[1], 7, 15, 1023, 0); /* BACKGROUND */ +- AR9170_FILL_QUEUE(ar->edcf[2], 2, 7, 15, 94); /* VIDEO */ +- AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ +- AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ +- +- /* set sane AMPDU defaults */ +- ar->global_ampdu_density = 6; +- ar->global_ampdu_factor = 3; +- +- ar->bad_hw_nagger = jiffies; +- +- err = ar->open(ar); +- if (err) +- goto out; +- +- err = ar9170_init_mac(ar); +- if (err) +- goto out; +- +- err = ar9170_set_qos(ar); +- if (err) +- goto out; +- +- err = ar9170_init_phy(ar, IEEE80211_BAND_2GHZ); +- if (err) +- goto out; +- +- err = ar9170_init_rf(ar); +- if (err) +- goto out; +- +- /* start DMA */ +- err = ar9170_write_reg(ar, 0x1c3d30, 0x100); +- if (err) +- goto out; +- +- ar->state = AR9170_STARTED; +- +-out: +- mutex_unlock(&ar->mutex); +- return err; +-} +- +-static void ar9170_op_stop(struct ieee80211_hw *hw) +-{ +- struct ar9170 *ar = hw->priv; +- unsigned int i; +- +- if (IS_STARTED(ar)) +- ar->state = AR9170_IDLE; +- +- cancel_delayed_work_sync(&ar->tx_janitor); +-#ifdef CONFIG_AR9170_LEDS +- cancel_delayed_work_sync(&ar->led_work); +-#endif +- cancel_work_sync(&ar->beacon_work); +- +- mutex_lock(&ar->mutex); +- +- if (IS_ACCEPTING_CMD(ar)) { +- ar9170_set_leds_state(ar, 0); +- +- /* stop DMA */ +- ar9170_write_reg(ar, 0x1c3d30, 0); +- ar->stop(ar); +- } +- +- for (i = 0; i < __AR9170_NUM_TXQ; i++) { +- skb_queue_purge(&ar->tx_pending[i]); +- skb_queue_purge(&ar->tx_status[i]); +- } +- +- mutex_unlock(&ar->mutex); +-} +- +-static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) +-{ +- struct ieee80211_hdr *hdr; +- struct ar9170_tx_control *txc; +- struct ieee80211_tx_info *info; +- struct ieee80211_tx_rate *txrate; +- struct ar9170_tx_info *arinfo; +- unsigned int queue = skb_get_queue_mapping(skb); +- u16 keytype = 0; +- u16 len, icv = 0; +- +- BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); +- +- hdr = (void *)skb->data; +- info = IEEE80211_SKB_CB(skb); +- len = skb->len; +- +- txc = (void *)skb_push(skb, sizeof(*txc)); +- +- if (info->control.hw_key) { +- icv = info->control.hw_key->icv_len; +- +- switch (info->control.hw_key->cipher) { +- case WLAN_CIPHER_SUITE_WEP40: +- case WLAN_CIPHER_SUITE_WEP104: +- case WLAN_CIPHER_SUITE_TKIP: +- keytype = AR9170_TX_MAC_ENCR_RC4; +- break; +- case WLAN_CIPHER_SUITE_CCMP: +- keytype = AR9170_TX_MAC_ENCR_AES; +- break; +- default: +- WARN_ON(1); +- goto err_out; +- } +- } +- +- /* Length */ +- txc->length = cpu_to_le16(len + icv + 4); +- +- txc->mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION | +- AR9170_TX_MAC_BACKOFF); +- txc->mac_control |= cpu_to_le16(ar9170_qos_hwmap[queue] << +- AR9170_TX_MAC_QOS_SHIFT); +- txc->mac_control |= cpu_to_le16(keytype); +- txc->phy_control = cpu_to_le32(0); +- +- if (info->flags & IEEE80211_TX_CTL_NO_ACK) +- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); +- +- txrate = &info->control.rates[0]; +- if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) +- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); +- else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) +- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); +- +- arinfo = (void *)info->rate_driver_data; +- arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_QUEUE_TIMEOUT); +- +- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && +- (is_valid_ether_addr(ieee80211_get_DA(hdr)))) { +- /* +- * WARNING: +- * Putting the QoS queue bits into an unexplored territory is +- * certainly not elegant. +- * +- * In my defense: This idea provides a reasonable way to +- * smuggle valuable information to the tx_status callback. +- * Also, the idea behind this bit-abuse came straight from +- * the original driver code. +- */ +- +- txc->phy_control |= +- cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); +- +- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); +- } +- +- return 0; +- +-err_out: +- skb_pull(skb, sizeof(*txc)); +- return -EINVAL; +-} +- +-static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb) +-{ +- struct ar9170_tx_control *txc; +- struct ieee80211_tx_info *info; +- struct ieee80211_rate *rate = NULL; +- struct ieee80211_tx_rate *txrate; +- u32 power, chains; +- +- txc = (void *) skb->data; +- info = IEEE80211_SKB_CB(skb); +- txrate = &info->control.rates[0]; +- +- if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) +- txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); +- +- if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) +- txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE); +- +- if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) +- txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ); +- /* this works because 40 MHz is 2 and dup is 3 */ +- if (txrate->flags & IEEE80211_TX_RC_DUP_DATA) +- txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ_DUP); +- +- if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) +- txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI); +- +- if (txrate->flags & IEEE80211_TX_RC_MCS) { +- u32 r = txrate->idx; +- u8 *txpower; +- +- /* heavy clip control */ +- txc->phy_control |= cpu_to_le32((r & 0x7) << 7); +- +- r <<= AR9170_TX_PHY_MCS_SHIFT; +- BUG_ON(r & ~AR9170_TX_PHY_MCS_MASK); +- +- txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); +- txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); +- +- if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { +- if (info->band == IEEE80211_BAND_5GHZ) +- txpower = ar->power_5G_ht40; +- else +- txpower = ar->power_2G_ht40; +- } else { +- if (info->band == IEEE80211_BAND_5GHZ) +- txpower = ar->power_5G_ht20; +- else +- txpower = ar->power_2G_ht20; +- } +- +- power = txpower[(txrate->idx) & 7]; +- } else { +- u8 *txpower; +- u32 mod; +- u32 phyrate; +- u8 idx = txrate->idx; +- +- if (info->band != IEEE80211_BAND_2GHZ) { +- idx += 4; +- txpower = ar->power_5G_leg; +- mod = AR9170_TX_PHY_MOD_OFDM; +- } else { +- if (idx < 4) { +- txpower = ar->power_2G_cck; +- mod = AR9170_TX_PHY_MOD_CCK; +- } else { +- mod = AR9170_TX_PHY_MOD_OFDM; +- txpower = ar->power_2G_ofdm; +- } +- } +- +- rate = &__ar9170_ratetable[idx]; +- +- phyrate = rate->hw_value & 0xF; +- power = txpower[(rate->hw_value & 0x30) >> 4]; +- phyrate <<= AR9170_TX_PHY_MCS_SHIFT; +- +- txc->phy_control |= cpu_to_le32(mod); +- txc->phy_control |= cpu_to_le32(phyrate); +- } +- +- power <<= AR9170_TX_PHY_TX_PWR_SHIFT; +- power &= AR9170_TX_PHY_TX_PWR_MASK; +- txc->phy_control |= cpu_to_le32(power); +- +- /* set TX chains */ +- if (ar->eeprom.tx_mask == 1) { +- chains = AR9170_TX_PHY_TXCHAIN_1; +- } else { +- chains = AR9170_TX_PHY_TXCHAIN_2; +- +- /* >= 36M legacy OFDM - use only one chain */ +- if (rate && rate->bitrate >= 360) +- chains = AR9170_TX_PHY_TXCHAIN_1; +- } +- txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); +-} +- +-static void ar9170_tx(struct ar9170 *ar) +-{ +- struct sk_buff *skb; +- unsigned long flags; +- struct ieee80211_tx_info *info; +- struct ar9170_tx_info *arinfo; +- unsigned int i, frames, frames_failed, remaining_space; +- int err; +- bool schedule_garbagecollector = false; +- +- BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); +- +- if (unlikely(!IS_STARTED(ar))) +- return ; +- +- remaining_space = AR9170_TX_MAX_PENDING; +- +- for (i = 0; i < __AR9170_NUM_TXQ; i++) { +- spin_lock_irqsave(&ar->tx_stats_lock, flags); +- frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, +- skb_queue_len(&ar->tx_pending[i])); +- +- if (remaining_space < frames) { +-#ifdef AR9170_QUEUE_DEBUG +- wiphy_debug(ar->hw->wiphy, +- "tx quota reached queue:%d, " +- "remaining slots:%d, needed:%d\n", +- i, remaining_space, frames); +-#endif /* AR9170_QUEUE_DEBUG */ +- frames = remaining_space; +- } +- +- ar->tx_stats[i].len += frames; +- ar->tx_stats[i].count += frames; +- if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) { +-#ifdef AR9170_QUEUE_DEBUG +- wiphy_debug(ar->hw->wiphy, "queue %d full\n", i); +- wiphy_debug(ar->hw->wiphy, "stuck frames: ===>\n"); +- ar9170_dump_txqueue(ar, &ar->tx_pending[i]); +- ar9170_dump_txqueue(ar, &ar->tx_status[i]); +-#endif /* AR9170_QUEUE_DEBUG */ +- +-#ifdef AR9170_QUEUE_STOP_DEBUG +- wiphy_debug(ar->hw->wiphy, "stop queue %d\n", i); +- __ar9170_dump_txstats(ar); +-#endif /* AR9170_QUEUE_STOP_DEBUG */ +- ieee80211_stop_queue(ar->hw, i); +- } +- +- spin_unlock_irqrestore(&ar->tx_stats_lock, flags); +- +- if (!frames) +- continue; +- +- frames_failed = 0; +- while (frames) { +- skb = skb_dequeue(&ar->tx_pending[i]); +- if (unlikely(!skb)) { +- frames_failed += frames; +- frames = 0; +- break; +- } +- +- info = IEEE80211_SKB_CB(skb); +- arinfo = (void *) info->rate_driver_data; +- +- /* TODO: cancel stuck frames */ +- arinfo->timeout = jiffies + +- msecs_to_jiffies(AR9170_TX_TIMEOUT); +- +-#ifdef AR9170_QUEUE_DEBUG +- wiphy_debug(ar->hw->wiphy, "send frame q:%d =>\n", i); +- ar9170_print_txheader(ar, skb); +-#endif /* AR9170_QUEUE_DEBUG */ +- +- err = ar->tx(ar, skb); +- if (unlikely(err)) { +- frames_failed++; +- dev_kfree_skb_any(skb); +- } else { +- remaining_space--; +- schedule_garbagecollector = true; +- } +- +- frames--; +- } +- +-#ifdef AR9170_QUEUE_DEBUG +- wiphy_debug(ar->hw->wiphy, +- "ar9170_tx report for queue %d\n", i); +- +- wiphy_debug(ar->hw->wiphy, +- "unprocessed pending frames left:\n"); +- ar9170_dump_txqueue(ar, &ar->tx_pending[i]); +-#endif /* AR9170_QUEUE_DEBUG */ +- +- if (unlikely(frames_failed)) { +-#ifdef AR9170_QUEUE_DEBUG +- wiphy_debug(ar->hw->wiphy, +- "frames failed %d =>\n", frames_failed); +-#endif /* AR9170_QUEUE_DEBUG */ +- +- spin_lock_irqsave(&ar->tx_stats_lock, flags); +- ar->tx_stats[i].len -= frames_failed; +- ar->tx_stats[i].count -= frames_failed; +-#ifdef AR9170_QUEUE_STOP_DEBUG +- wiphy_debug(ar->hw->wiphy, "wake queue %d\n", i); +- __ar9170_dump_txstats(ar); +-#endif /* AR9170_QUEUE_STOP_DEBUG */ +- ieee80211_wake_queue(ar->hw, i); +- spin_unlock_irqrestore(&ar->tx_stats_lock, flags); +- } +- } +- +- if (!schedule_garbagecollector) +- return; +- +- ieee80211_queue_delayed_work(ar->hw, +- &ar->tx_janitor, +- msecs_to_jiffies(AR9170_JANITOR_DELAY)); +-} +- +-void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +-{ +- struct ar9170 *ar = hw->priv; +- struct ieee80211_tx_info *info; +- unsigned int queue; +- +- if (unlikely(!IS_STARTED(ar))) +- goto err_free; +- +- if (unlikely(ar9170_tx_prepare(ar, skb))) +- goto err_free; +- +- queue = skb_get_queue_mapping(skb); +- info = IEEE80211_SKB_CB(skb); +- ar9170_tx_prepare_phy(ar, skb); +- skb_queue_tail(&ar->tx_pending[queue], skb); +- +- ar9170_tx(ar); +- return; +- +-err_free: +- dev_kfree_skb_any(skb); +-} +- +-static int ar9170_op_add_interface(struct ieee80211_hw *hw, +- struct ieee80211_vif *vif) +-{ +- struct ar9170 *ar = hw->priv; +- struct ath_common *common = &ar->common; +- int err = 0; +- +- mutex_lock(&ar->mutex); +- +- if (ar->vif) { +- err = -EBUSY; +- goto unlock; +- } +- +- ar->vif = vif; +- memcpy(common->macaddr, vif->addr, ETH_ALEN); +- +- if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { +- ar->rx_software_decryption = true; +- ar->disable_offload = true; +- } +- +- ar->cur_filter = 0; +- err = ar9170_update_frame_filter(ar, AR9170_MAC_REG_FTF_DEFAULTS); +- if (err) +- goto unlock; +- +- err = ar9170_set_operating_mode(ar); +- +-unlock: +- mutex_unlock(&ar->mutex); +- return err; +-} +- +-static void ar9170_op_remove_interface(struct ieee80211_hw *hw, +- struct ieee80211_vif *vif) +-{ +- struct ar9170 *ar = hw->priv; +- +- mutex_lock(&ar->mutex); +- ar->vif = NULL; +- ar9170_update_frame_filter(ar, 0); +- ar9170_set_beacon_timers(ar); +- dev_kfree_skb(ar->beacon); +- ar->beacon = NULL; +- ar->sniffer_enabled = false; +- ar->rx_software_decryption = false; +- ar9170_set_operating_mode(ar); +- mutex_unlock(&ar->mutex); +-} +- +-static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) +-{ +- struct ar9170 *ar = hw->priv; +- int err = 0; +- +- mutex_lock(&ar->mutex); +- +- if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { +- /* TODO */ +- err = 0; +- } +- +- if (changed & IEEE80211_CONF_CHANGE_PS) { +- /* TODO */ +- err = 0; +- } +- +- if (changed & IEEE80211_CONF_CHANGE_POWER) { +- /* TODO */ +- err = 0; +- } +- +- if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { +- /* +- * is it long_frame_max_tx_count or short_frame_max_tx_count? +- */ +- +- err = ar9170_set_hwretry_limit(ar, +- ar->hw->conf.long_frame_max_tx_count); +- if (err) +- goto out; +- } +- +- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { +- +- /* adjust slot time for 5 GHz */ +- err = ar9170_set_slot_time(ar); +- if (err) +- goto out; +- +- err = ar9170_set_dyn_sifs_ack(ar); +- if (err) +- goto out; +- +- err = ar9170_set_channel(ar, hw->conf.channel, +- AR9170_RFI_NONE, +- nl80211_to_ar9170(hw->conf.channel_type)); +- if (err) +- goto out; +- } +- +-out: +- mutex_unlock(&ar->mutex); +- return err; +-} +- +-static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, +- struct netdev_hw_addr_list *mc_list) +-{ +- u64 mchash; +- struct netdev_hw_addr *ha; +- +- /* always get broadcast frames */ +- mchash = 1ULL << (0xff >> 2); +- +- netdev_hw_addr_list_for_each(ha, mc_list) +- mchash |= 1ULL << (ha->addr[5] >> 2); +- +- return mchash; +-} +- +-static void ar9170_op_configure_filter(struct ieee80211_hw *hw, +- unsigned int changed_flags, +- unsigned int *new_flags, +- u64 multicast) +-{ +- struct ar9170 *ar = hw->priv; +- +- if (unlikely(!IS_ACCEPTING_CMD(ar))) +- return ; +- +- mutex_lock(&ar->mutex); +- +- /* mask supported flags */ +- *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | +- FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL; +- ar->filter_state = *new_flags; +- /* +- * We can support more by setting the sniffer bit and +- * then checking the error flags, later. +- */ +- +- if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) +- multicast = ~0ULL; +- +- if (multicast != ar->cur_mc_hash) +- ar9170_update_multicast(ar, multicast); +- +- if (changed_flags & FIF_CONTROL) { +- u32 filter = AR9170_MAC_REG_FTF_PSPOLL | +- AR9170_MAC_REG_FTF_RTS | +- AR9170_MAC_REG_FTF_CTS | +- AR9170_MAC_REG_FTF_ACK | +- AR9170_MAC_REG_FTF_CFE | +- AR9170_MAC_REG_FTF_CFE_ACK; +- +- if (*new_flags & FIF_CONTROL) +- filter |= ar->cur_filter; +- else +- filter &= (~ar->cur_filter); +- +- ar9170_update_frame_filter(ar, filter); +- } +- +- if (changed_flags & FIF_PROMISC_IN_BSS) { +- ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; +- ar9170_set_operating_mode(ar); +- } +- +- mutex_unlock(&ar->mutex); +-} +- +- +-static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, +- struct ieee80211_vif *vif, +- struct ieee80211_bss_conf *bss_conf, +- u32 changed) +-{ +- struct ar9170 *ar = hw->priv; +- struct ath_common *common = &ar->common; +- int err = 0; +- +- mutex_lock(&ar->mutex); +- +- if (changed & BSS_CHANGED_BSSID) { +- memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); +- err = ar9170_set_operating_mode(ar); +- if (err) +- goto out; +- } +- +- if (changed & BSS_CHANGED_BEACON_ENABLED) +- ar->enable_beacon = bss_conf->enable_beacon; +- +- if (changed & BSS_CHANGED_BEACON) { +- err = ar9170_update_beacon(ar); +- if (err) +- goto out; +- } +- +- if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON | +- BSS_CHANGED_BEACON_INT)) { +- err = ar9170_set_beacon_timers(ar); +- if (err) +- goto out; +- } +- +- if (changed & BSS_CHANGED_ASSOC) { +-#ifndef CONFIG_AR9170_LEDS +- /* enable assoc LED. */ +- err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); +-#endif /* CONFIG_AR9170_LEDS */ +- } +- +- if (changed & BSS_CHANGED_HT) { +- /* TODO */ +- err = 0; +- } +- +- if (changed & BSS_CHANGED_ERP_SLOT) { +- err = ar9170_set_slot_time(ar); +- if (err) +- goto out; +- } +- +- if (changed & BSS_CHANGED_BASIC_RATES) { +- err = ar9170_set_basic_rates(ar); +- if (err) +- goto out; +- } +- +-out: +- mutex_unlock(&ar->mutex); +-} +- +-static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw) +-{ +- struct ar9170 *ar = hw->priv; +- int err; +- u64 tsf; +-#define NR 3 +- static const u32 addr[NR] = { AR9170_MAC_REG_TSF_H, +- AR9170_MAC_REG_TSF_L, +- AR9170_MAC_REG_TSF_H }; +- u32 val[NR]; +- int loops = 0; +- +- mutex_lock(&ar->mutex); +- +- while (loops++ < 10) { +- err = ar9170_read_mreg(ar, NR, addr, val); +- if (err || val[0] == val[2]) +- break; +- } +- +- mutex_unlock(&ar->mutex); +- +- if (WARN_ON(err)) +- return 0; +- tsf = val[0]; +- tsf = (tsf << 32) | val[1]; +- return tsf; +-#undef NR +-} +- +-static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +- struct ieee80211_vif *vif, struct ieee80211_sta *sta, +- struct ieee80211_key_conf *key) +-{ +- struct ar9170 *ar = hw->priv; +- int err = 0, i; +- u8 ktype; +- +- if ((!ar->vif) || (ar->disable_offload)) +- return -EOPNOTSUPP; +- +- switch (key->cipher) { +- case WLAN_CIPHER_SUITE_WEP40: +- ktype = AR9170_ENC_ALG_WEP64; +- break; +- case WLAN_CIPHER_SUITE_WEP104: +- ktype = AR9170_ENC_ALG_WEP128; +- break; +- case WLAN_CIPHER_SUITE_TKIP: +- ktype = AR9170_ENC_ALG_TKIP; +- break; +- case WLAN_CIPHER_SUITE_CCMP: +- ktype = AR9170_ENC_ALG_AESCCMP; +- break; +- default: +- return -EOPNOTSUPP; +- } +- +- mutex_lock(&ar->mutex); +- if (cmd == SET_KEY) { +- if (unlikely(!IS_STARTED(ar))) { +- err = -EOPNOTSUPP; +- goto out; +- } +- +- /* group keys need all-zeroes address */ +- if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) +- sta = NULL; +- +- if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { +- for (i = 0; i < 64; i++) +- if (!(ar->usedkeys & BIT(i))) +- break; +- if (i == 64) { +- ar->rx_software_decryption = true; +- ar9170_set_operating_mode(ar); +- err = -ENOSPC; +- goto out; +- } +- } else { +- i = 64 + key->keyidx; +- } +- +- key->hw_key_idx = i; +- +- err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, ktype, 0, +- key->key, min_t(u8, 16, key->keylen)); +- if (err) +- goto out; +- +- if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { +- err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, +- ktype, 1, key->key + 16, 16); +- if (err) +- goto out; +- +- /* +- * hardware is not capable generating the MMIC +- * for fragmented frames! +- */ +- key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; +- } +- +- if (i < 64) +- ar->usedkeys |= BIT(i); +- +- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; +- } else { +- if (unlikely(!IS_STARTED(ar))) { +- /* The device is gone... together with the key ;-) */ +- err = 0; +- goto out; +- } +- +- err = ar9170_disable_key(ar, key->hw_key_idx); +- if (err) +- goto out; +- +- if (key->hw_key_idx < 64) { +- ar->usedkeys &= ~BIT(key->hw_key_idx); +- } else { +- err = ar9170_upload_key(ar, key->hw_key_idx, NULL, +- AR9170_ENC_ALG_NONE, 0, +- NULL, 0); +- if (err) +- goto out; +- +- if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { +- err = ar9170_upload_key(ar, key->hw_key_idx, +- NULL, +- AR9170_ENC_ALG_NONE, 1, +- NULL, 0); +- if (err) +- goto out; +- } +- +- } +- } +- +- ar9170_regwrite_begin(ar); +- ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_L, ar->usedkeys); +- ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_H, ar->usedkeys >> 32); +- ar9170_regwrite_finish(); +- err = ar9170_regwrite_result(); +- +-out: +- mutex_unlock(&ar->mutex); +- +- return err; +-} +- +-static int ar9170_get_stats(struct ieee80211_hw *hw, +- struct ieee80211_low_level_stats *stats) +-{ +- struct ar9170 *ar = hw->priv; +- u32 val; +- int err; +- +- mutex_lock(&ar->mutex); +- err = ar9170_read_reg(ar, AR9170_MAC_REG_TX_RETRY, &val); +- ar->stats.dot11ACKFailureCount += val; +- +- memcpy(stats, &ar->stats, sizeof(*stats)); +- mutex_unlock(&ar->mutex); +- +- return 0; +-} +- +-static int ar9170_get_survey(struct ieee80211_hw *hw, int idx, +- struct survey_info *survey) +-{ +- struct ar9170 *ar = hw->priv; +- struct ieee80211_conf *conf = &hw->conf; +- +- if (idx != 0) +- return -ENOENT; +- +- /* TODO: update noise value, e.g. call ar9170_set_channel */ +- +- survey->channel = conf->channel; +- survey->filled = SURVEY_INFO_NOISE_DBM; +- survey->noise = ar->noise[0]; +- +- return 0; +-} +- +-static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, +- const struct ieee80211_tx_queue_params *param) +-{ +- struct ar9170 *ar = hw->priv; +- int ret; +- +- mutex_lock(&ar->mutex); +- if (queue < __AR9170_NUM_TXQ) { +- memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], +- param, sizeof(*param)); +- +- ret = ar9170_set_qos(ar); +- } else { +- ret = -EINVAL; +- } +- +- mutex_unlock(&ar->mutex); +- return ret; +-} +- +-static int ar9170_ampdu_action(struct ieee80211_hw *hw, +- struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size) +-{ +- switch (action) { +- case IEEE80211_AMPDU_RX_START: +- case IEEE80211_AMPDU_RX_STOP: +- /* Handled by firmware */ +- break; +- +- default: +- return -EOPNOTSUPP; +- } +- +- return 0; +-} +- +-static const struct ieee80211_ops ar9170_ops = { +- .start = ar9170_op_start, +- .stop = ar9170_op_stop, +- .tx = ar9170_op_tx, +- .add_interface = ar9170_op_add_interface, +- .remove_interface = ar9170_op_remove_interface, +- .config = ar9170_op_config, +- .prepare_multicast = ar9170_op_prepare_multicast, +- .configure_filter = ar9170_op_configure_filter, +- .conf_tx = ar9170_conf_tx, +- .bss_info_changed = ar9170_op_bss_info_changed, +- .get_tsf = ar9170_op_get_tsf, +- .set_key = ar9170_set_key, +- .get_stats = ar9170_get_stats, +- .get_survey = ar9170_get_survey, +- .ampdu_action = ar9170_ampdu_action, +-}; +- +-void *ar9170_alloc(size_t priv_size) +-{ +- struct ieee80211_hw *hw; +- struct ar9170 *ar; +- struct sk_buff *skb; +- int i; +- +- /* +- * this buffer is used for rx stream reconstruction. +- * Under heavy load this device (or the transport layer?) +- * tends to split the streams into separate rx descriptors. +- */ +- +- skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL); +- if (!skb) +- goto err_nomem; +- +- hw = ieee80211_alloc_hw(priv_size, &ar9170_ops); +- if (!hw) +- goto err_nomem; +- +- ar = hw->priv; +- ar->hw = hw; +- ar->rx_failover = skb; +- +- mutex_init(&ar->mutex); +- spin_lock_init(&ar->cmdlock); +- spin_lock_init(&ar->tx_stats_lock); +- for (i = 0; i < __AR9170_NUM_TXQ; i++) { +- skb_queue_head_init(&ar->tx_status[i]); +- skb_queue_head_init(&ar->tx_pending[i]); +- } +- ar9170_rx_reset_rx_mpdu(ar); +- INIT_WORK(&ar->beacon_work, ar9170_new_beacon); +- INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); +- +- /* all hw supports 2.4 GHz, so set channel to 1 by default */ +- ar->channel = &ar9170_2ghz_chantable[0]; +- +- /* first part of wiphy init */ +- ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | +- BIT(NL80211_IFTYPE_WDS) | +- BIT(NL80211_IFTYPE_ADHOC); +- ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | +- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | +- IEEE80211_HW_SIGNAL_DBM; +- +- ar->hw->queues = __AR9170_NUM_TXQ; +- ar->hw->extra_tx_headroom = 8; +- +- ar->hw->max_rates = 1; +- ar->hw->max_rate_tries = 3; +- +- for (i = 0; i < ARRAY_SIZE(ar->noise); i++) +- ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ +- +- return ar; +- +-err_nomem: +- kfree_skb(skb); +- return ERR_PTR(-ENOMEM); +-} +- +-static int ar9170_read_eeprom(struct ar9170 *ar) +-{ +-#define RW 8 /* number of words to read at once */ +-#define RB (sizeof(u32) * RW) +- struct ath_regulatory *regulatory = &ar->common.regulatory; +- u8 *eeprom = (void *)&ar->eeprom; +- u8 *addr = ar->eeprom.mac_address; +- __le32 offsets[RW]; +- unsigned int rx_streams, tx_streams, tx_params = 0; +- int i, j, err, bands = 0; +- +- BUILD_BUG_ON(sizeof(ar->eeprom) & 3); +- +- BUILD_BUG_ON(RB > AR9170_MAX_CMD_LEN - 4); +-#ifndef __CHECKER__ +- /* don't want to handle trailing remains */ +- BUILD_BUG_ON(sizeof(ar->eeprom) % RB); +-#endif +- +- for (i = 0; i < sizeof(ar->eeprom)/RB; i++) { +- for (j = 0; j < RW; j++) +- offsets[j] = cpu_to_le32(AR9170_EEPROM_START + +- RB * i + 4 * j); +- +- err = ar->exec_cmd(ar, AR9170_CMD_RREG, +- RB, (u8 *) &offsets, +- RB, eeprom + RB * i); +- if (err) +- return err; +- } +- +-#undef RW +-#undef RB +- +- if (ar->eeprom.length == cpu_to_le16(0xFFFF)) +- return -ENODATA; +- +- if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) { +- ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar9170_band_2GHz; +- bands++; +- } +- if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) { +- ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz; +- bands++; +- } +- +- rx_streams = hweight8(ar->eeprom.rx_mask); +- tx_streams = hweight8(ar->eeprom.tx_mask); +- +- if (rx_streams != tx_streams) +- tx_params = IEEE80211_HT_MCS_TX_RX_DIFF; +- +- if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS) +- tx_params = (tx_streams - 1) << +- IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; +- +- ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params; +- ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params; +- +- /* +- * I measured this, a bandswitch takes roughly +- * 135 ms and a frequency switch about 80. +- * +- * FIXME: measure these values again once EEPROM settings +- * are used, that will influence them! +- */ +- if (bands == 2) +- ar->hw->channel_change_time = 135 * 1000; +- else +- ar->hw->channel_change_time = 80 * 1000; +- +- regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); +- regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); +- +- /* second part of wiphy init */ +- SET_IEEE80211_PERM_ADDR(ar->hw, addr); +- +- return bands ? 0 : -EINVAL; +-} +- +-static int ar9170_reg_notifier(struct wiphy *wiphy, +- struct regulatory_request *request) +-{ +- struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); +- struct ar9170 *ar = hw->priv; +- +- return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory); +-} +- +-int ar9170_register(struct ar9170 *ar, struct device *pdev) +-{ +- struct ath_regulatory *regulatory = &ar->common.regulatory; +- int err; +- +- /* try to read EEPROM, init MAC addr */ +- err = ar9170_read_eeprom(ar); +- if (err) +- goto err_out; +- +- err = ath_regd_init(regulatory, ar->hw->wiphy, +- ar9170_reg_notifier); +- if (err) +- goto err_out; +- +- err = ieee80211_register_hw(ar->hw); +- if (err) +- goto err_out; +- +- if (!ath_is_world_regd(regulatory)) +- regulatory_hint(ar->hw->wiphy, regulatory->alpha2); +- +- err = ar9170_init_leds(ar); +- if (err) +- goto err_unreg; +- +-#ifdef CONFIG_AR9170_LEDS +- err = ar9170_register_leds(ar); +- if (err) +- goto err_unreg; +-#endif /* CONFIG_AR9170_LEDS */ +- +- dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", +- wiphy_name(ar->hw->wiphy)); +- +- ar->registered = true; +- return 0; +- +-err_unreg: +- ieee80211_unregister_hw(ar->hw); +- +-err_out: +- return err; +-} +- +-void ar9170_unregister(struct ar9170 *ar) +-{ +- if (ar->registered) { +-#ifdef CONFIG_AR9170_LEDS +- ar9170_unregister_leds(ar); +-#endif /* CONFIG_AR9170_LEDS */ +- +- ieee80211_unregister_hw(ar->hw); +- } +- +- kfree_skb(ar->rx_failover); +- mutex_destroy(&ar->mutex); +-} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/Makefile linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/Makefile +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/Makefile 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/Makefile 1970-01-01 01:00:00.000000000 +0100 +@@ -1,3 +0,0 @@ +-ar9170usb-objs := usb.o main.o cmd.o mac.o phy.o led.o +- +-obj-$(CONFIG_AR9170_USB) += ar9170usb.o +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/phy.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/phy.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/phy.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/phy.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,1719 +0,0 @@ +-/* +- * Atheros AR9170 driver +- * +- * PHY and RF code +- * +- * Copyright 2008, Johannes Berg +- * +- * 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; see the file COPYING. If not, see +- * http://www.gnu.org/licenses/. +- * +- * This file incorporates work covered by the following copyright and +- * permission notice: +- * Copyright (c) 2007-2008 Atheros Communications, Inc. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-#include +-#include "ar9170.h" +-#include "cmd.h" +- +-static int ar9170_init_power_cal(struct ar9170 *ar) +-{ +- ar9170_regwrite_begin(ar); +- +- ar9170_regwrite(0x1bc000 + 0x993c, 0x7f); +- ar9170_regwrite(0x1bc000 + 0x9934, 0x3f3f3f3f); +- ar9170_regwrite(0x1bc000 + 0x9938, 0x3f3f3f3f); +- ar9170_regwrite(0x1bc000 + 0xa234, 0x3f3f3f3f); +- ar9170_regwrite(0x1bc000 + 0xa238, 0x3f3f3f3f); +- ar9170_regwrite(0x1bc000 + 0xa38c, 0x3f3f3f3f); +- ar9170_regwrite(0x1bc000 + 0xa390, 0x3f3f3f3f); +- ar9170_regwrite(0x1bc000 + 0xa3cc, 0x3f3f3f3f); +- ar9170_regwrite(0x1bc000 + 0xa3d0, 0x3f3f3f3f); +- ar9170_regwrite(0x1bc000 + 0xa3d4, 0x3f3f3f3f); +- +- ar9170_regwrite_finish(); +- return ar9170_regwrite_result(); +-} +- +-struct ar9170_phy_init { +- u32 reg, _5ghz_20, _5ghz_40, _2ghz_40, _2ghz_20; +-}; +- +-static struct ar9170_phy_init ar5416_phy_init[] = { +- { 0x1c5800, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, +- { 0x1c5804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, }, +- { 0x1c5808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c580c, 0xad848e19, 0xad848e19, 0xad848e19, 0xad848e19, }, +- { 0x1c5810, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0x7d14e000, }, +- { 0x1c5814, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, }, +- { 0x1c5818, 0x00000090, 0x00000090, 0x00000090, 0x00000090, }, +- { 0x1c581c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, }, +- { 0x1c5824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, +- { 0x1c5828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, }, +- { 0x1c582c, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, +- { 0x1c5830, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, +- { 0x1c5838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, +- { 0x1c583c, 0x00200400, 0x00200400, 0x00200400, 0x00200400, }, +- { 0x1c5840, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e, }, +- { 0x1c5844, 0x1372161e, 0x13721c1e, 0x13721c24, 0x137216a4, }, +- { 0x1c5848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, }, +- { 0x1c584c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, }, +- { 0x1c5850, 0x6c48b4e4, 0x6c48b4e4, 0x6c48b0e4, 0x6c48b0e4, }, +- { 0x1c5854, 0x00000859, 0x00000859, 0x00000859, 0x00000859, }, +- { 0x1c5858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, }, +- { 0x1c585c, 0x31395c5e, 0x31395c5e, 0x31395c5e, 0x31395c5e, }, +- { 0x1c5860, 0x0004dd10, 0x0004dd10, 0x0004dd20, 0x0004dd20, }, +- { 0x1c5868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, }, +- { 0x1c586c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, }, +- { 0x1c5900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5908, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c590c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, }, +- { 0x1c5918, 0x00000118, 0x00000230, 0x00000268, 0x00000134, }, +- { 0x1c591c, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff, }, +- { 0x1c5920, 0x0510081c, 0x0510081c, 0x0510001c, 0x0510001c, }, +- { 0x1c5924, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0xd0058a15, }, +- { 0x1c5928, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, +- { 0x1c592c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, +- { 0x1c5934, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, +- { 0x1c5938, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, +- { 0x1c593c, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, }, +- { 0x1c5944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, }, +- { 0x1c5948, 0x9280b212, 0x9280b212, 0x9280b212, 0x9280b212, }, +- { 0x1c594c, 0x00020028, 0x00020028, 0x00020028, 0x00020028, }, +- { 0x1c5954, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0x5d50e188, }, +- { 0x1c5958, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, }, +- { 0x1c5960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, +- { 0x1c5964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, }, +- { 0x1c5970, 0x190fb515, 0x190fb515, 0x190fb515, 0x190fb515, }, +- { 0x1c5974, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5978, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, +- { 0x1c597c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5980, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5984, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5988, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c598c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5990, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5994, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5998, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c599c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c59a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c59a4, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, +- { 0x1c59a8, 0x001fff00, 0x001fff00, 0x001fff00, 0x001fff00, }, +- { 0x1c59ac, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0x006f00c4, }, +- { 0x1c59b0, 0x03051000, 0x03051000, 0x03051000, 0x03051000, }, +- { 0x1c59b4, 0x00000820, 0x00000820, 0x00000820, 0x00000820, }, +- { 0x1c59c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, }, +- { 0x1c59c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, }, +- { 0x1c59c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, }, +- { 0x1c59cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, }, +- { 0x1c59d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, }, +- { 0x1c59d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c59d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c59dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c59e0, 0x00000200, 0x00000200, 0x00000200, 0x00000200, }, +- { 0x1c59e4, 0x64646464, 0x64646464, 0x64646464, 0x64646464, }, +- { 0x1c59e8, 0x3c787878, 0x3c787878, 0x3c787878, 0x3c787878, }, +- { 0x1c59ec, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, }, +- { 0x1c59f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c59fc, 0x00001042, 0x00001042, 0x00001042, 0x00001042, }, +- { 0x1c5a00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5a04, 0x00000040, 0x00000040, 0x00000040, 0x00000040, }, +- { 0x1c5a08, 0x00000080, 0x00000080, 0x00000080, 0x00000080, }, +- { 0x1c5a0c, 0x000001a1, 0x000001a1, 0x00000141, 0x00000141, }, +- { 0x1c5a10, 0x000001e1, 0x000001e1, 0x00000181, 0x00000181, }, +- { 0x1c5a14, 0x00000021, 0x00000021, 0x000001c1, 0x000001c1, }, +- { 0x1c5a18, 0x00000061, 0x00000061, 0x00000001, 0x00000001, }, +- { 0x1c5a1c, 0x00000168, 0x00000168, 0x00000041, 0x00000041, }, +- { 0x1c5a20, 0x000001a8, 0x000001a8, 0x000001a8, 0x000001a8, }, +- { 0x1c5a24, 0x000001e8, 0x000001e8, 0x000001e8, 0x000001e8, }, +- { 0x1c5a28, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, +- { 0x1c5a2c, 0x00000068, 0x00000068, 0x00000068, 0x00000068, }, +- { 0x1c5a30, 0x00000189, 0x00000189, 0x000000a8, 0x000000a8, }, +- { 0x1c5a34, 0x000001c9, 0x000001c9, 0x00000169, 0x00000169, }, +- { 0x1c5a38, 0x00000009, 0x00000009, 0x000001a9, 0x000001a9, }, +- { 0x1c5a3c, 0x00000049, 0x00000049, 0x000001e9, 0x000001e9, }, +- { 0x1c5a40, 0x00000089, 0x00000089, 0x00000029, 0x00000029, }, +- { 0x1c5a44, 0x00000170, 0x00000170, 0x00000069, 0x00000069, }, +- { 0x1c5a48, 0x000001b0, 0x000001b0, 0x00000190, 0x00000190, }, +- { 0x1c5a4c, 0x000001f0, 0x000001f0, 0x000001d0, 0x000001d0, }, +- { 0x1c5a50, 0x00000030, 0x00000030, 0x00000010, 0x00000010, }, +- { 0x1c5a54, 0x00000070, 0x00000070, 0x00000050, 0x00000050, }, +- { 0x1c5a58, 0x00000191, 0x00000191, 0x00000090, 0x00000090, }, +- { 0x1c5a5c, 0x000001d1, 0x000001d1, 0x00000151, 0x00000151, }, +- { 0x1c5a60, 0x00000011, 0x00000011, 0x00000191, 0x00000191, }, +- { 0x1c5a64, 0x00000051, 0x00000051, 0x000001d1, 0x000001d1, }, +- { 0x1c5a68, 0x00000091, 0x00000091, 0x00000011, 0x00000011, }, +- { 0x1c5a6c, 0x000001b8, 0x000001b8, 0x00000051, 0x00000051, }, +- { 0x1c5a70, 0x000001f8, 0x000001f8, 0x00000198, 0x00000198, }, +- { 0x1c5a74, 0x00000038, 0x00000038, 0x000001d8, 0x000001d8, }, +- { 0x1c5a78, 0x00000078, 0x00000078, 0x00000018, 0x00000018, }, +- { 0x1c5a7c, 0x00000199, 0x00000199, 0x00000058, 0x00000058, }, +- { 0x1c5a80, 0x000001d9, 0x000001d9, 0x00000098, 0x00000098, }, +- { 0x1c5a84, 0x00000019, 0x00000019, 0x00000159, 0x00000159, }, +- { 0x1c5a88, 0x00000059, 0x00000059, 0x00000199, 0x00000199, }, +- { 0x1c5a8c, 0x00000099, 0x00000099, 0x000001d9, 0x000001d9, }, +- { 0x1c5a90, 0x000000d9, 0x000000d9, 0x00000019, 0x00000019, }, +- { 0x1c5a94, 0x000000f9, 0x000000f9, 0x00000059, 0x00000059, }, +- { 0x1c5a98, 0x000000f9, 0x000000f9, 0x00000099, 0x00000099, }, +- { 0x1c5a9c, 0x000000f9, 0x000000f9, 0x000000d9, 0x000000d9, }, +- { 0x1c5aa0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5aa4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5aa8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5aac, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5ab0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5ab4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5ab8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5abc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5ac0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5ac4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5ac8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5acc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5ad0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5ad4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5ad8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5adc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5ae0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5ae4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5ae8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5aec, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5af0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5af4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5af8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5afc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, +- { 0x1c5b00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5b04, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, +- { 0x1c5b08, 0x00000002, 0x00000002, 0x00000002, 0x00000002, }, +- { 0x1c5b0c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, }, +- { 0x1c5b10, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, +- { 0x1c5b14, 0x00000005, 0x00000005, 0x00000005, 0x00000005, }, +- { 0x1c5b18, 0x00000008, 0x00000008, 0x00000008, 0x00000008, }, +- { 0x1c5b1c, 0x00000009, 0x00000009, 0x00000009, 0x00000009, }, +- { 0x1c5b20, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, }, +- { 0x1c5b24, 0x0000000b, 0x0000000b, 0x0000000b, 0x0000000b, }, +- { 0x1c5b28, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, }, +- { 0x1c5b2c, 0x0000000d, 0x0000000d, 0x0000000d, 0x0000000d, }, +- { 0x1c5b30, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, +- { 0x1c5b34, 0x00000011, 0x00000011, 0x00000011, 0x00000011, }, +- { 0x1c5b38, 0x00000012, 0x00000012, 0x00000012, 0x00000012, }, +- { 0x1c5b3c, 0x00000013, 0x00000013, 0x00000013, 0x00000013, }, +- { 0x1c5b40, 0x00000014, 0x00000014, 0x00000014, 0x00000014, }, +- { 0x1c5b44, 0x00000015, 0x00000015, 0x00000015, 0x00000015, }, +- { 0x1c5b48, 0x00000018, 0x00000018, 0x00000018, 0x00000018, }, +- { 0x1c5b4c, 0x00000019, 0x00000019, 0x00000019, 0x00000019, }, +- { 0x1c5b50, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, +- { 0x1c5b54, 0x0000001b, 0x0000001b, 0x0000001b, 0x0000001b, }, +- { 0x1c5b58, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, }, +- { 0x1c5b5c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, }, +- { 0x1c5b60, 0x00000020, 0x00000020, 0x00000020, 0x00000020, }, +- { 0x1c5b64, 0x00000021, 0x00000021, 0x00000021, 0x00000021, }, +- { 0x1c5b68, 0x00000022, 0x00000022, 0x00000022, 0x00000022, }, +- { 0x1c5b6c, 0x00000023, 0x00000023, 0x00000023, 0x00000023, }, +- { 0x1c5b70, 0x00000024, 0x00000024, 0x00000024, 0x00000024, }, +- { 0x1c5b74, 0x00000025, 0x00000025, 0x00000025, 0x00000025, }, +- { 0x1c5b78, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, +- { 0x1c5b7c, 0x00000029, 0x00000029, 0x00000029, 0x00000029, }, +- { 0x1c5b80, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a, }, +- { 0x1c5b84, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, }, +- { 0x1c5b88, 0x0000002c, 0x0000002c, 0x0000002c, 0x0000002c, }, +- { 0x1c5b8c, 0x0000002d, 0x0000002d, 0x0000002d, 0x0000002d, }, +- { 0x1c5b90, 0x00000030, 0x00000030, 0x00000030, 0x00000030, }, +- { 0x1c5b94, 0x00000031, 0x00000031, 0x00000031, 0x00000031, }, +- { 0x1c5b98, 0x00000032, 0x00000032, 0x00000032, 0x00000032, }, +- { 0x1c5b9c, 0x00000033, 0x00000033, 0x00000033, 0x00000033, }, +- { 0x1c5ba0, 0x00000034, 0x00000034, 0x00000034, 0x00000034, }, +- { 0x1c5ba4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5ba8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bac, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bb0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bb4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bb8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bbc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bc0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bc4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bc8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bcc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bd0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bd4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bd8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bdc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5be0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5be4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5be8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bec, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bf0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bf4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, +- { 0x1c5bf8, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, +- { 0x1c5bfc, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, +- { 0x1c5c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c14, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c1c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c20, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c28, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c2c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c30, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c34, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c38, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5c3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5cf0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5cf4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5cf8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c5cfc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c6200, 0x00000008, 0x00000008, 0x0000000e, 0x0000000e, }, +- { 0x1c6204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, }, +- { 0x1c6208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, }, +- { 0x1c620c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, +- { 0x1c6210, 0x40806333, 0x40806333, 0x40806333, 0x40806333, }, +- { 0x1c6214, 0x00106c10, 0x00106c10, 0x00106c10, 0x00106c10, }, +- { 0x1c6218, 0x009c4060, 0x009c4060, 0x009c4060, 0x009c4060, }, +- { 0x1c621c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, }, +- { 0x1c6220, 0x018830c6, 0x018830c6, 0x018830c6, 0x018830c6, }, +- { 0x1c6224, 0x00000400, 0x00000400, 0x00000400, 0x00000400, }, +- { 0x1c6228, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, }, +- { 0x1c622c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c6230, 0x00000108, 0x00000210, 0x00000210, 0x00000108, }, +- { 0x1c6234, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, +- { 0x1c6238, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, +- { 0x1c623c, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, }, +- { 0x1c6240, 0x38490a20, 0x38490a20, 0x38490a20, 0x38490a20, }, +- { 0x1c6244, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0x00007bb6, }, +- { 0x1c6248, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, }, +- { 0x1c624c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, +- { 0x1c6250, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, +- { 0x1c6254, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c6258, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, }, +- { 0x1c625c, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, }, +- { 0x1c6260, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, }, +- { 0x1c6264, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, }, +- { 0x1c6268, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c626c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, +- { 0x1c6274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, }, +- { 0x1c6278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, +- { 0x1c627c, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, }, +- { 0x1c6300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, }, +- { 0x1c6304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, }, +- { 0x1c6308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, }, +- { 0x1c630c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, }, +- { 0x1c6310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, }, +- { 0x1c6314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, }, +- { 0x1c6318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, }, +- { 0x1c631c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, }, +- { 0x1c6320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, }, +- { 0x1c6324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, }, +- { 0x1c6328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, }, +- { 0x1c632c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c6330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c6334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c6338, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c633c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c6340, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c6344, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c6348, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, +- { 0x1c634c, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, +- { 0x1c6350, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, +- { 0x1c6354, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, }, +- { 0x1c6358, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, }, +- { 0x1c6388, 0x08000000, 0x08000000, 0x08000000, 0x08000000, }, +- { 0x1c638c, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, +- { 0x1c6390, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, +- { 0x1c6394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, +- { 0x1c6398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, }, +- { 0x1c639c, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, +- { 0x1c63a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c63a4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c63a8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c63ac, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c63b0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c63b4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c63b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c63bc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c63c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c63c4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c63c8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c63cc, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, +- { 0x1c63d0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, +- { 0x1c63d4, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, +- { 0x1c63d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, +- { 0x1c63dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, +- { 0x1c63e0, 0x000000c0, 0x000000c0, 0x000000c0, 0x000000c0, }, +- { 0x1c6848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, +- { 0x1c6920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, +- { 0x1c6960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, +- { 0x1c720c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, +- { 0x1c726c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, +- { 0x1c7848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, +- { 0x1c7920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, +- { 0x1c7960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, +- { 0x1c820c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, +- { 0x1c826c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, +-/* { 0x1c8864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, }, */ +- { 0x1c8864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, }, +- { 0x1c895c, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, }, +- { 0x1c8968, 0x000003ce, 0x000003ce, 0x000003ce, 0x000003ce, }, +- { 0x1c89bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, }, +- { 0x1c9270, 0x00820820, 0x00820820, 0x00820820, 0x00820820, }, +- { 0x1c935c, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, }, +- { 0x1c9360, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, }, +- { 0x1c9364, 0x17601685, 0x17601685, 0x17601685, 0x17601685, }, +- { 0x1c9368, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, }, +- { 0x1c936c, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, }, +- { 0x1c9370, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, }, +- { 0x1c9374, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, }, +- { 0x1c9378, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, }, +- { 0x1c937c, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, }, +- { 0x1c9380, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, }, +- { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } +-}; +- +-/* +- * look up a certain register in ar5416_phy_init[] and return the init. value +- * for the band and bandwidth given. Return 0 if register address not found. +- */ +-static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz) +-{ +- unsigned int i; +- for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { +- if (ar5416_phy_init[i].reg != reg) +- continue; +- +- if (is_2ghz) { +- if (is_40mhz) +- return ar5416_phy_init[i]._2ghz_40; +- else +- return ar5416_phy_init[i]._2ghz_20; +- } else { +- if (is_40mhz) +- return ar5416_phy_init[i]._5ghz_40; +- else +- return ar5416_phy_init[i]._5ghz_20; +- } +- } +- return 0; +-} +- +-/* +- * initialize some phy regs from eeprom values in modal_header[] +- * acc. to band and bandwidth +- */ +-static int ar9170_init_phy_from_eeprom(struct ar9170 *ar, +- bool is_2ghz, bool is_40mhz) +-{ +- static const u8 xpd2pd[16] = { +- 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2, +- 0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2 +- }; +- u32 defval, newval; +- /* pointer to the modal_header acc. to band */ +- struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz]; +- +- ar9170_regwrite_begin(ar); +- +- /* ant common control (index 0) */ +- newval = le32_to_cpu(m->antCtrlCommon); +- ar9170_regwrite(0x1c5964, newval); +- +- /* ant control chain 0 (index 1) */ +- newval = le32_to_cpu(m->antCtrlChain[0]); +- ar9170_regwrite(0x1c5960, newval); +- +- /* ant control chain 2 (index 2) */ +- newval = le32_to_cpu(m->antCtrlChain[1]); +- ar9170_regwrite(0x1c7960, newval); +- +- /* SwSettle (index 3) */ +- if (!is_40mhz) { +- defval = ar9170_get_default_phy_reg_val(0x1c5844, +- is_2ghz, is_40mhz); +- newval = (defval & ~0x3f80) | +- ((m->switchSettling & 0x7f) << 7); +- ar9170_regwrite(0x1c5844, newval); +- } +- +- /* adcDesired, pdaDesired (index 4) */ +- defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz); +- newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) | +- ((u8)m->adcDesiredSize); +- ar9170_regwrite(0x1c5850, newval); +- +- /* TxEndToXpaOff, TxFrameToXpaOn (index 5) */ +- defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz); +- newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) | +- (m->txFrameToXpaOn << 8) | m->txFrameToXpaOn; +- ar9170_regwrite(0x1c5834, newval); +- +- /* TxEndToRxOn (index 6) */ +- defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz); +- newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16); +- ar9170_regwrite(0x1c5828, newval); +- +- /* thresh62 (index 7) */ +- defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz); +- newval = (defval & ~0x7f000) | (m->thresh62 << 12); +- ar9170_regwrite(0x1c8864, newval); +- +- /* tx/rx attenuation chain 0 (index 8) */ +- defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz); +- newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12); +- ar9170_regwrite(0x1c5848, newval); +- +- /* tx/rx attenuation chain 2 (index 9) */ +- defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz); +- newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12); +- ar9170_regwrite(0x1c7848, newval); +- +- /* tx/rx margin chain 0 (index 10) */ +- defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz); +- newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18); +- /* bsw margin chain 0 for 5GHz only */ +- if (!is_2ghz) +- newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10); +- ar9170_regwrite(0x1c620c, newval); +- +- /* tx/rx margin chain 2 (index 11) */ +- defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz); +- newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18); +- ar9170_regwrite(0x1c820c, newval); +- +- /* iqCall, iqCallq chain 0 (index 12) */ +- defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz); +- newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) | +- ((u8)m->iqCalQCh[0] & 0x1f); +- ar9170_regwrite(0x1c5920, newval); +- +- /* iqCall, iqCallq chain 2 (index 13) */ +- defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz); +- newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) | +- ((u8)m->iqCalQCh[1] & 0x1f); +- ar9170_regwrite(0x1c7920, newval); +- +- /* xpd gain mask (index 14) */ +- defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz); +- newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16); +- ar9170_regwrite(0x1c6258, newval); +- ar9170_regwrite_finish(); +- +- return ar9170_regwrite_result(); +-} +- +-int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) +-{ +- int i, err; +- u32 val; +- bool is_2ghz = band == IEEE80211_BAND_2GHZ; +- bool is_40mhz = conf_is_ht40(&ar->hw->conf); +- +- ar9170_regwrite_begin(ar); +- +- for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { +- if (is_40mhz) { +- if (is_2ghz) +- val = ar5416_phy_init[i]._2ghz_40; +- else +- val = ar5416_phy_init[i]._5ghz_40; +- } else { +- if (is_2ghz) +- val = ar5416_phy_init[i]._2ghz_20; +- else +- val = ar5416_phy_init[i]._5ghz_20; +- } +- +- ar9170_regwrite(ar5416_phy_init[i].reg, val); +- } +- +- ar9170_regwrite_finish(); +- err = ar9170_regwrite_result(); +- if (err) +- return err; +- +- err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); +- if (err) +- return err; +- +- err = ar9170_init_power_cal(ar); +- if (err) +- return err; +- +- /* XXX: remove magic! */ +- if (is_2ghz) +- err = ar9170_write_reg(ar, 0x1d4014, 0x5163); +- else +- err = ar9170_write_reg(ar, 0x1d4014, 0x5143); +- +- return err; +-} +- +-struct ar9170_rf_init { +- u32 reg, _5ghz, _2ghz; +-}; +- +-static struct ar9170_rf_init ar9170_rf_init[] = { +- /* bank 0 */ +- { 0x1c58b0, 0x1e5795e5, 0x1e5795e5}, +- { 0x1c58e0, 0x02008020, 0x02008020}, +- /* bank 1 */ +- { 0x1c58b0, 0x02108421, 0x02108421}, +- { 0x1c58ec, 0x00000008, 0x00000008}, +- /* bank 2 */ +- { 0x1c58b0, 0x0e73ff17, 0x0e73ff17}, +- { 0x1c58e0, 0x00000420, 0x00000420}, +- /* bank 3 */ +- { 0x1c58f0, 0x01400018, 0x01c00018}, +- /* bank 4 */ +- { 0x1c58b0, 0x000001a1, 0x000001a1}, +- { 0x1c58e8, 0x00000001, 0x00000001}, +- /* bank 5 */ +- { 0x1c58b0, 0x00000013, 0x00000013}, +- { 0x1c58e4, 0x00000002, 0x00000002}, +- /* bank 6 */ +- { 0x1c58b0, 0x00000000, 0x00000000}, +- { 0x1c58b0, 0x00000000, 0x00000000}, +- { 0x1c58b0, 0x00000000, 0x00000000}, +- { 0x1c58b0, 0x00000000, 0x00000000}, +- { 0x1c58b0, 0x00000000, 0x00000000}, +- { 0x1c58b0, 0x00004000, 0x00004000}, +- { 0x1c58b0, 0x00006c00, 0x00006c00}, +- { 0x1c58b0, 0x00002c00, 0x00002c00}, +- { 0x1c58b0, 0x00004800, 0x00004800}, +- { 0x1c58b0, 0x00004000, 0x00004000}, +- { 0x1c58b0, 0x00006000, 0x00006000}, +- { 0x1c58b0, 0x00001000, 0x00001000}, +- { 0x1c58b0, 0x00004000, 0x00004000}, +- { 0x1c58b0, 0x00007c00, 0x00007c00}, +- { 0x1c58b0, 0x00007c00, 0x00007c00}, +- { 0x1c58b0, 0x00007c00, 0x00007c00}, +- { 0x1c58b0, 0x00007c00, 0x00007c00}, +- { 0x1c58b0, 0x00007c00, 0x00007c00}, +- { 0x1c58b0, 0x00087c00, 0x00087c00}, +- { 0x1c58b0, 0x00007c00, 0x00007c00}, +- { 0x1c58b0, 0x00005400, 0x00005400}, +- { 0x1c58b0, 0x00000c00, 0x00000c00}, +- { 0x1c58b0, 0x00001800, 0x00001800}, +- { 0x1c58b0, 0x00007c00, 0x00007c00}, +- { 0x1c58b0, 0x00006c00, 0x00006c00}, +- { 0x1c58b0, 0x00006c00, 0x00006c00}, +- { 0x1c58b0, 0x00007c00, 0x00007c00}, +- { 0x1c58b0, 0x00002c00, 0x00002c00}, +- { 0x1c58b0, 0x00003c00, 0x00003c00}, +- { 0x1c58b0, 0x00003800, 0x00003800}, +- { 0x1c58b0, 0x00001c00, 0x00001c00}, +- { 0x1c58b0, 0x00000800, 0x00000800}, +- { 0x1c58b0, 0x00000408, 0x00000408}, +- { 0x1c58b0, 0x00004c15, 0x00004c15}, +- { 0x1c58b0, 0x00004188, 0x00004188}, +- { 0x1c58b0, 0x0000201e, 0x0000201e}, +- { 0x1c58b0, 0x00010408, 0x00010408}, +- { 0x1c58b0, 0x00000801, 0x00000801}, +- { 0x1c58b0, 0x00000c08, 0x00000c08}, +- { 0x1c58b0, 0x0000181e, 0x0000181e}, +- { 0x1c58b0, 0x00001016, 0x00001016}, +- { 0x1c58b0, 0x00002800, 0x00002800}, +- { 0x1c58b0, 0x00004010, 0x00004010}, +- { 0x1c58b0, 0x0000081c, 0x0000081c}, +- { 0x1c58b0, 0x00000115, 0x00000115}, +- { 0x1c58b0, 0x00000015, 0x00000015}, +- { 0x1c58b0, 0x00000066, 0x00000066}, +- { 0x1c58b0, 0x0000001c, 0x0000001c}, +- { 0x1c58b0, 0x00000000, 0x00000000}, +- { 0x1c58b0, 0x00000004, 0x00000004}, +- { 0x1c58b0, 0x00000015, 0x00000015}, +- { 0x1c58b0, 0x0000001f, 0x0000001f}, +- { 0x1c58e0, 0x00000000, 0x00000400}, +- /* bank 7 */ +- { 0x1c58b0, 0x000000a0, 0x000000a0}, +- { 0x1c58b0, 0x00000000, 0x00000000}, +- { 0x1c58b0, 0x00000040, 0x00000040}, +- { 0x1c58f0, 0x0000001c, 0x0000001c}, +-}; +- +-static int ar9170_init_rf_banks_0_7(struct ar9170 *ar, bool band5ghz) +-{ +- int err, i; +- +- ar9170_regwrite_begin(ar); +- +- for (i = 0; i < ARRAY_SIZE(ar9170_rf_init); i++) +- ar9170_regwrite(ar9170_rf_init[i].reg, +- band5ghz ? ar9170_rf_init[i]._5ghz +- : ar9170_rf_init[i]._2ghz); +- +- ar9170_regwrite_finish(); +- err = ar9170_regwrite_result(); +- if (err) +- wiphy_err(ar->hw->wiphy, "rf init failed\n"); +- return err; +-} +- +-static int ar9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz, +- u32 freq, enum ar9170_bw bw) +-{ +- int err; +- u32 d0, d1, td0, td1, fd0, fd1; +- u8 chansel; +- u8 refsel0 = 1, refsel1 = 0; +- u8 lf_synth = 0; +- +- switch (bw) { +- case AR9170_BW_40_ABOVE: +- freq += 10; +- break; +- case AR9170_BW_40_BELOW: +- freq -= 10; +- break; +- case AR9170_BW_20: +- break; +- case __AR9170_NUM_BW: +- BUG(); +- } +- +- if (band5ghz) { +- if (freq % 10) { +- chansel = (freq - 4800) / 5; +- } else { +- chansel = ((freq - 4800) / 10) * 2; +- refsel0 = 0; +- refsel1 = 1; +- } +- chansel = byte_rev_table[chansel]; +- } else { +- if (freq == 2484) { +- chansel = 10 + (freq - 2274) / 5; +- lf_synth = 1; +- } else +- chansel = 16 + (freq - 2272) / 5; +- chansel *= 4; +- chansel = byte_rev_table[chansel]; +- } +- +- d1 = chansel; +- d0 = 0x21 | +- refsel0 << 3 | +- refsel1 << 2 | +- lf_synth << 1; +- td0 = d0 & 0x1f; +- td1 = d1 & 0x1f; +- fd0 = td1 << 5 | td0; +- +- td0 = (d0 >> 5) & 0x7; +- td1 = (d1 >> 5) & 0x7; +- fd1 = td1 << 5 | td0; +- +- ar9170_regwrite_begin(ar); +- +- ar9170_regwrite(0x1c58b0, fd0); +- ar9170_regwrite(0x1c58e8, fd1); +- +- ar9170_regwrite_finish(); +- err = ar9170_regwrite_result(); +- if (err) +- return err; +- +- msleep(10); +- +- return 0; +-} +- +-struct ar9170_phy_freq_params { +- u8 coeff_exp; +- u16 coeff_man; +- u8 coeff_exp_shgi; +- u16 coeff_man_shgi; +-}; +- +-struct ar9170_phy_freq_entry { +- u16 freq; +- struct ar9170_phy_freq_params params[__AR9170_NUM_BW]; +-}; +- +-/* NB: must be in sync with channel tables in main! */ +-static const struct ar9170_phy_freq_entry ar9170_phy_freq_params[] = { +-/* +- * freq, +- * 20MHz, +- * 40MHz (below), +- * 40Mhz (above), +- */ +- { 2412, { +- { 3, 21737, 3, 19563, }, +- { 3, 21827, 3, 19644, }, +- { 3, 21647, 3, 19482, }, +- } }, +- { 2417, { +- { 3, 21692, 3, 19523, }, +- { 3, 21782, 3, 19604, }, +- { 3, 21602, 3, 19442, }, +- } }, +- { 2422, { +- { 3, 21647, 3, 19482, }, +- { 3, 21737, 3, 19563, }, +- { 3, 21558, 3, 19402, }, +- } }, +- { 2427, { +- { 3, 21602, 3, 19442, }, +- { 3, 21692, 3, 19523, }, +- { 3, 21514, 3, 19362, }, +- } }, +- { 2432, { +- { 3, 21558, 3, 19402, }, +- { 3, 21647, 3, 19482, }, +- { 3, 21470, 3, 19323, }, +- } }, +- { 2437, { +- { 3, 21514, 3, 19362, }, +- { 3, 21602, 3, 19442, }, +- { 3, 21426, 3, 19283, }, +- } }, +- { 2442, { +- { 3, 21470, 3, 19323, }, +- { 3, 21558, 3, 19402, }, +- { 3, 21382, 3, 19244, }, +- } }, +- { 2447, { +- { 3, 21426, 3, 19283, }, +- { 3, 21514, 3, 19362, }, +- { 3, 21339, 3, 19205, }, +- } }, +- { 2452, { +- { 3, 21382, 3, 19244, }, +- { 3, 21470, 3, 19323, }, +- { 3, 21295, 3, 19166, }, +- } }, +- { 2457, { +- { 3, 21339, 3, 19205, }, +- { 3, 21426, 3, 19283, }, +- { 3, 21252, 3, 19127, }, +- } }, +- { 2462, { +- { 3, 21295, 3, 19166, }, +- { 3, 21382, 3, 19244, }, +- { 3, 21209, 3, 19088, }, +- } }, +- { 2467, { +- { 3, 21252, 3, 19127, }, +- { 3, 21339, 3, 19205, }, +- { 3, 21166, 3, 19050, }, +- } }, +- { 2472, { +- { 3, 21209, 3, 19088, }, +- { 3, 21295, 3, 19166, }, +- { 3, 21124, 3, 19011, }, +- } }, +- { 2484, { +- { 3, 21107, 3, 18996, }, +- { 3, 21192, 3, 19073, }, +- { 3, 21022, 3, 18920, }, +- } }, +- { 4920, { +- { 4, 21313, 4, 19181, }, +- { 4, 21356, 4, 19220, }, +- { 4, 21269, 4, 19142, }, +- } }, +- { 4940, { +- { 4, 21226, 4, 19104, }, +- { 4, 21269, 4, 19142, }, +- { 4, 21183, 4, 19065, }, +- } }, +- { 4960, { +- { 4, 21141, 4, 19027, }, +- { 4, 21183, 4, 19065, }, +- { 4, 21098, 4, 18988, }, +- } }, +- { 4980, { +- { 4, 21056, 4, 18950, }, +- { 4, 21098, 4, 18988, }, +- { 4, 21014, 4, 18912, }, +- } }, +- { 5040, { +- { 4, 20805, 4, 18725, }, +- { 4, 20846, 4, 18762, }, +- { 4, 20764, 4, 18687, }, +- } }, +- { 5060, { +- { 4, 20723, 4, 18651, }, +- { 4, 20764, 4, 18687, }, +- { 4, 20682, 4, 18614, }, +- } }, +- { 5080, { +- { 4, 20641, 4, 18577, }, +- { 4, 20682, 4, 18614, }, +- { 4, 20601, 4, 18541, }, +- } }, +- { 5180, { +- { 4, 20243, 4, 18219, }, +- { 4, 20282, 4, 18254, }, +- { 4, 20204, 4, 18183, }, +- } }, +- { 5200, { +- { 4, 20165, 4, 18148, }, +- { 4, 20204, 4, 18183, }, +- { 4, 20126, 4, 18114, }, +- } }, +- { 5220, { +- { 4, 20088, 4, 18079, }, +- { 4, 20126, 4, 18114, }, +- { 4, 20049, 4, 18044, }, +- } }, +- { 5240, { +- { 4, 20011, 4, 18010, }, +- { 4, 20049, 4, 18044, }, +- { 4, 19973, 4, 17976, }, +- } }, +- { 5260, { +- { 4, 19935, 4, 17941, }, +- { 4, 19973, 4, 17976, }, +- { 4, 19897, 4, 17907, }, +- } }, +- { 5280, { +- { 4, 19859, 4, 17873, }, +- { 4, 19897, 4, 17907, }, +- { 4, 19822, 4, 17840, }, +- } }, +- { 5300, { +- { 4, 19784, 4, 17806, }, +- { 4, 19822, 4, 17840, }, +- { 4, 19747, 4, 17772, }, +- } }, +- { 5320, { +- { 4, 19710, 4, 17739, }, +- { 4, 19747, 4, 17772, }, +- { 4, 19673, 4, 17706, }, +- } }, +- { 5500, { +- { 4, 19065, 4, 17159, }, +- { 4, 19100, 4, 17190, }, +- { 4, 19030, 4, 17127, }, +- } }, +- { 5520, { +- { 4, 18996, 4, 17096, }, +- { 4, 19030, 4, 17127, }, +- { 4, 18962, 4, 17065, }, +- } }, +- { 5540, { +- { 4, 18927, 4, 17035, }, +- { 4, 18962, 4, 17065, }, +- { 4, 18893, 4, 17004, }, +- } }, +- { 5560, { +- { 4, 18859, 4, 16973, }, +- { 4, 18893, 4, 17004, }, +- { 4, 18825, 4, 16943, }, +- } }, +- { 5580, { +- { 4, 18792, 4, 16913, }, +- { 4, 18825, 4, 16943, }, +- { 4, 18758, 4, 16882, }, +- } }, +- { 5600, { +- { 4, 18725, 4, 16852, }, +- { 4, 18758, 4, 16882, }, +- { 4, 18691, 4, 16822, }, +- } }, +- { 5620, { +- { 4, 18658, 4, 16792, }, +- { 4, 18691, 4, 16822, }, +- { 4, 18625, 4, 16762, }, +- } }, +- { 5640, { +- { 4, 18592, 4, 16733, }, +- { 4, 18625, 4, 16762, }, +- { 4, 18559, 4, 16703, }, +- } }, +- { 5660, { +- { 4, 18526, 4, 16673, }, +- { 4, 18559, 4, 16703, }, +- { 4, 18493, 4, 16644, }, +- } }, +- { 5680, { +- { 4, 18461, 4, 16615, }, +- { 4, 18493, 4, 16644, }, +- { 4, 18428, 4, 16586, }, +- } }, +- { 5700, { +- { 4, 18396, 4, 16556, }, +- { 4, 18428, 4, 16586, }, +- { 4, 18364, 4, 16527, }, +- } }, +- { 5745, { +- { 4, 18252, 4, 16427, }, +- { 4, 18284, 4, 16455, }, +- { 4, 18220, 4, 16398, }, +- } }, +- { 5765, { +- { 4, 18189, 5, 32740, }, +- { 4, 18220, 4, 16398, }, +- { 4, 18157, 5, 32683, }, +- } }, +- { 5785, { +- { 4, 18126, 5, 32626, }, +- { 4, 18157, 5, 32683, }, +- { 4, 18094, 5, 32570, }, +- } }, +- { 5805, { +- { 4, 18063, 5, 32514, }, +- { 4, 18094, 5, 32570, }, +- { 4, 18032, 5, 32458, }, +- } }, +- { 5825, { +- { 4, 18001, 5, 32402, }, +- { 4, 18032, 5, 32458, }, +- { 4, 17970, 5, 32347, }, +- } }, +- { 5170, { +- { 4, 20282, 4, 18254, }, +- { 4, 20321, 4, 18289, }, +- { 4, 20243, 4, 18219, }, +- } }, +- { 5190, { +- { 4, 20204, 4, 18183, }, +- { 4, 20243, 4, 18219, }, +- { 4, 20165, 4, 18148, }, +- } }, +- { 5210, { +- { 4, 20126, 4, 18114, }, +- { 4, 20165, 4, 18148, }, +- { 4, 20088, 4, 18079, }, +- } }, +- { 5230, { +- { 4, 20049, 4, 18044, }, +- { 4, 20088, 4, 18079, }, +- { 4, 20011, 4, 18010, }, +- } }, +-}; +- +-static const struct ar9170_phy_freq_params * +-ar9170_get_hw_dyn_params(struct ieee80211_channel *channel, +- enum ar9170_bw bw) +-{ +- unsigned int chanidx = 0; +- u16 freq = 2412; +- +- if (channel) { +- chanidx = channel->hw_value; +- freq = channel->center_freq; +- } +- +- BUG_ON(chanidx >= ARRAY_SIZE(ar9170_phy_freq_params)); +- +- BUILD_BUG_ON(__AR9170_NUM_BW != 3); +- +- WARN_ON(ar9170_phy_freq_params[chanidx].freq != freq); +- +- return &ar9170_phy_freq_params[chanidx].params[bw]; +-} +- +- +-int ar9170_init_rf(struct ar9170 *ar) +-{ +- const struct ar9170_phy_freq_params *freqpar; +- __le32 cmd[7]; +- int err; +- +- err = ar9170_init_rf_banks_0_7(ar, false); +- if (err) +- return err; +- +- err = ar9170_init_rf_bank4_pwr(ar, false, 2412, AR9170_BW_20); +- if (err) +- return err; +- +- freqpar = ar9170_get_hw_dyn_params(NULL, AR9170_BW_20); +- +- cmd[0] = cpu_to_le32(2412 * 1000); +- cmd[1] = cpu_to_le32(0); +- cmd[2] = cpu_to_le32(1); +- cmd[3] = cpu_to_le32(freqpar->coeff_exp); +- cmd[4] = cpu_to_le32(freqpar->coeff_man); +- cmd[5] = cpu_to_le32(freqpar->coeff_exp_shgi); +- cmd[6] = cpu_to_le32(freqpar->coeff_man_shgi); +- +- /* RF_INIT echoes the command back to us */ +- err = ar->exec_cmd(ar, AR9170_CMD_RF_INIT, +- sizeof(cmd), (u8 *)cmd, +- sizeof(cmd), (u8 *)cmd); +- if (err) +- return err; +- +- msleep(1000); +- +- return ar9170_echo_test(ar, 0xaabbccdd); +-} +- +-static int ar9170_find_freq_idx(int nfreqs, u8 *freqs, u8 f) +-{ +- int idx = nfreqs - 2; +- +- while (idx >= 0) { +- if (f >= freqs[idx]) +- return idx; +- idx--; +- } +- +- return 0; +-} +- +-static s32 ar9170_interpolate_s32(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) +-{ +- /* nothing to interpolate, it's horizontal */ +- if (y2 == y1) +- return y1; +- +- /* check if we hit one of the edges */ +- if (x == x1) +- return y1; +- if (x == x2) +- return y2; +- +- /* x1 == x2 is bad, hopefully == x */ +- if (x2 == x1) +- return y1; +- +- return y1 + (((y2 - y1) * (x - x1)) / (x2 - x1)); +-} +- +-static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2) +-{ +-#define SHIFT 8 +- s32 y; +- +- y = ar9170_interpolate_s32(x << SHIFT, +- x1 << SHIFT, y1 << SHIFT, +- x2 << SHIFT, y2 << SHIFT); +- +- /* +- * XXX: unwrap this expression +- * Isn't it just DIV_ROUND_UP(y, 1<> SHIFT) + ((y & (1<<(SHIFT-1))) >> (SHIFT - 1)); +-#undef SHIFT +-} +- +-static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array) +-{ +- int i; +- +- for (i = 0; i < 3; i++) +- if (x <= x_array[i + 1]) +- break; +- +- return ar9170_interpolate_u8(x, +- x_array[i], +- y_array[i], +- x_array[i + 1], +- y_array[i + 1]); +-} +- +-static int ar9170_set_freq_cal_data(struct ar9170 *ar, +- struct ieee80211_channel *channel) +-{ +- u8 *cal_freq_pier; +- u8 vpds[2][AR5416_PD_GAIN_ICEPTS]; +- u8 pwrs[2][AR5416_PD_GAIN_ICEPTS]; +- int chain, idx, i; +- u32 phy_data = 0; +- u8 f, tmp; +- +- switch (channel->band) { +- case IEEE80211_BAND_2GHZ: +- f = channel->center_freq - 2300; +- cal_freq_pier = ar->eeprom.cal_freq_pier_2G; +- i = AR5416_NUM_2G_CAL_PIERS - 1; +- break; +- +- case IEEE80211_BAND_5GHZ: +- f = (channel->center_freq - 4800) / 5; +- cal_freq_pier = ar->eeprom.cal_freq_pier_5G; +- i = AR5416_NUM_5G_CAL_PIERS - 1; +- break; +- +- default: +- return -EINVAL; +- break; +- } +- +- for (; i >= 0; i--) { +- if (cal_freq_pier[i] != 0xff) +- break; +- } +- if (i < 0) +- return -EINVAL; +- +- idx = ar9170_find_freq_idx(i, cal_freq_pier, f); +- +- ar9170_regwrite_begin(ar); +- +- for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) { +- for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) { +- struct ar9170_calibration_data_per_freq *cal_pier_data; +- int j; +- +- switch (channel->band) { +- case IEEE80211_BAND_2GHZ: +- cal_pier_data = &ar->eeprom. +- cal_pier_data_2G[chain][idx]; +- break; +- +- case IEEE80211_BAND_5GHZ: +- cal_pier_data = &ar->eeprom. +- cal_pier_data_5G[chain][idx]; +- break; +- +- default: +- return -EINVAL; +- } +- +- for (j = 0; j < 2; j++) { +- vpds[j][i] = ar9170_interpolate_u8(f, +- cal_freq_pier[idx], +- cal_pier_data->vpd_pdg[j][i], +- cal_freq_pier[idx + 1], +- cal_pier_data[1].vpd_pdg[j][i]); +- +- pwrs[j][i] = ar9170_interpolate_u8(f, +- cal_freq_pier[idx], +- cal_pier_data->pwr_pdg[j][i], +- cal_freq_pier[idx + 1], +- cal_pier_data[1].pwr_pdg[j][i]) / 2; +- } +- } +- +- for (i = 0; i < 76; i++) { +- if (i < 25) { +- tmp = ar9170_interpolate_val(i, &pwrs[0][0], +- &vpds[0][0]); +- } else { +- tmp = ar9170_interpolate_val(i - 12, +- &pwrs[1][0], +- &vpds[1][0]); +- } +- +- phy_data |= tmp << ((i & 3) << 3); +- if ((i & 3) == 3) { +- ar9170_regwrite(0x1c6280 + chain * 0x1000 + +- (i & ~3), phy_data); +- phy_data = 0; +- } +- } +- +- for (i = 19; i < 32; i++) +- ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2), +- 0x0); +- } +- +- ar9170_regwrite_finish(); +- return ar9170_regwrite_result(); +-} +- +-static u8 ar9170_get_max_edge_power(struct ar9170 *ar, +- struct ar9170_calctl_edges edges[], +- u32 freq) +-{ +- int i; +- u8 rc = AR5416_MAX_RATE_POWER; +- u8 f; +- if (freq < 3000) +- f = freq - 2300; +- else +- f = (freq - 4800) / 5; +- +- for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { +- if (edges[i].channel == 0xff) +- break; +- if (f == edges[i].channel) { +- /* exact freq match */ +- rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS; +- break; +- } +- if (i > 0 && f < edges[i].channel) { +- if (f > edges[i - 1].channel && +- edges[i - 1].power_flags & +- AR9170_CALCTL_EDGE_FLAGS) { +- /* lower channel has the inband flag set */ +- rc = edges[i - 1].power_flags & +- ~AR9170_CALCTL_EDGE_FLAGS; +- } +- break; +- } +- } +- +- if (i == AR5416_NUM_BAND_EDGES) { +- if (f > edges[i - 1].channel && +- edges[i - 1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { +- /* lower channel has the inband flag set */ +- rc = edges[i - 1].power_flags & +- ~AR9170_CALCTL_EDGE_FLAGS; +- } +- } +- return rc; +-} +- +-static u8 ar9170_get_heavy_clip(struct ar9170 *ar, +- struct ar9170_calctl_edges edges[], +- u32 freq, enum ar9170_bw bw) +-{ +- u8 f; +- int i; +- u8 rc = 0; +- +- if (freq < 3000) +- f = freq - 2300; +- else +- f = (freq - 4800) / 5; +- +- if (bw == AR9170_BW_40_BELOW || bw == AR9170_BW_40_ABOVE) +- rc |= 0xf0; +- +- for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { +- if (edges[i].channel == 0xff) +- break; +- if (f == edges[i].channel) { +- if (!(edges[i].power_flags & AR9170_CALCTL_EDGE_FLAGS)) +- rc |= 0x0f; +- break; +- } +- } +- +- return rc; +-} +- +-/* +- * calculate the conformance test limits and the heavy clip parameter +- * and apply them to ar->power* (derived from otus hal/hpmain.c, line 3706) +- */ +-static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) +-{ +- u8 ctl_grp; /* CTL group */ +- u8 ctl_idx; /* CTL index */ +- int i, j; +- struct ctl_modes { +- u8 ctl_mode; +- u8 max_power; +- u8 *pwr_cal_data; +- int pwr_cal_len; +- } *modes; +- +- /* +- * order is relevant in the mode_list_*: we fall back to the +- * lower indices if any mode is missed in the EEPROM. +- */ +- struct ctl_modes mode_list_2ghz[] = { +- { CTL_11B, 0, ar->power_2G_cck, 4 }, +- { CTL_11G, 0, ar->power_2G_ofdm, 4 }, +- { CTL_2GHT20, 0, ar->power_2G_ht20, 8 }, +- { CTL_2GHT40, 0, ar->power_2G_ht40, 8 }, +- }; +- struct ctl_modes mode_list_5ghz[] = { +- { CTL_11A, 0, ar->power_5G_leg, 4 }, +- { CTL_5GHT20, 0, ar->power_5G_ht20, 8 }, +- { CTL_5GHT40, 0, ar->power_5G_ht40, 8 }, +- }; +- int nr_modes; +- +-#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) +- +- ar->phy_heavy_clip = 0; +- +- /* +- * TODO: investigate the differences between OTUS' +- * hpreg.c::zfHpGetRegulatoryDomain() and +- * ath/regd.c::ath_regd_get_band_ctl() - +- * e.g. for FCC3_WORLD the OTUS procedure +- * always returns CTL_FCC, while the one in ath/ delivers +- * CTL_ETSI for 2GHz and CTL_FCC for 5GHz. +- */ +- ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory, +- ar->hw->conf.channel->band); +- +- /* ctl group not found - either invalid band (NO_CTL) or ww roaming */ +- if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL) +- ctl_grp = CTL_FCC; +- +- if (ctl_grp != CTL_FCC) +- /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */ +- return; +- +- if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) { +- modes = mode_list_2ghz; +- nr_modes = ARRAY_SIZE(mode_list_2ghz); +- } else { +- modes = mode_list_5ghz; +- nr_modes = ARRAY_SIZE(mode_list_5ghz); +- } +- +- for (i = 0; i < nr_modes; i++) { +- u8 c = ctl_grp | modes[i].ctl_mode; +- for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++) +- if (c == ar->eeprom.ctl_index[ctl_idx]) +- break; +- if (ctl_idx < AR5416_NUM_CTLS) { +- int f_off = 0; +- +- /* determine heav clip parameter from +- the 11G edges array */ +- if (modes[i].ctl_mode == CTL_11G) { +- ar->phy_heavy_clip = +- ar9170_get_heavy_clip(ar, +- EDGES(ctl_idx, 1), +- freq, bw); +- } +- +- /* adjust freq for 40MHz */ +- if (modes[i].ctl_mode == CTL_2GHT40 || +- modes[i].ctl_mode == CTL_5GHT40) { +- if (bw == AR9170_BW_40_BELOW) +- f_off = -10; +- else +- f_off = 10; +- } +- +- modes[i].max_power = +- ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1), +- freq+f_off); +- +- /* +- * TODO: check if the regulatory max. power is +- * controlled by cfg80211 for DFS +- * (hpmain applies it to max_power itself for DFS freq) +- */ +- +- } else { +- /* +- * Workaround in otus driver, hpmain.c, line 3906: +- * if no data for 5GHT20 are found, take the +- * legacy 5G value. +- * We extend this here to fallback from any other *HT or +- * 11G, too. +- */ +- int k = i; +- +- modes[i].max_power = AR5416_MAX_RATE_POWER; +- while (k-- > 0) { +- if (modes[k].max_power != +- AR5416_MAX_RATE_POWER) { +- modes[i].max_power = modes[k].max_power; +- break; +- } +- } +- } +- +- /* apply max power to pwr_cal_data (ar->power_*) */ +- for (j = 0; j < modes[i].pwr_cal_len; j++) { +- modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j], +- modes[i].max_power); +- } +- } +- +- if (ar->phy_heavy_clip & 0xf0) { +- ar->power_2G_ht40[0]--; +- ar->power_2G_ht40[1]--; +- ar->power_2G_ht40[2]--; +- } +- if (ar->phy_heavy_clip & 0xf) { +- ar->power_2G_ht20[0]++; +- ar->power_2G_ht20[1]++; +- ar->power_2G_ht20[2]++; +- } +- +- +-#undef EDGES +-} +- +-static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) +-{ +- struct ar9170_calibration_target_power_legacy *ctpl; +- struct ar9170_calibration_target_power_ht *ctph; +- u8 *ctpres; +- int ntargets; +- int idx, i, n; +- u8 ackpower, ackchains, f; +- u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS]; +- +- if (freq < 3000) +- f = freq - 2300; +- else +- f = (freq - 4800)/5; +- +- /* +- * cycle through the various modes +- * +- * legacy modes first: 5G, 2G CCK, 2G OFDM +- */ +- for (i = 0; i < 3; i++) { +- switch (i) { +- case 0: /* 5 GHz legacy */ +- ctpl = &ar->eeprom.cal_tgt_pwr_5G[0]; +- ntargets = AR5416_NUM_5G_TARGET_PWRS; +- ctpres = ar->power_5G_leg; +- break; +- case 1: /* 2.4 GHz CCK */ +- ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0]; +- ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS; +- ctpres = ar->power_2G_cck; +- break; +- case 2: /* 2.4 GHz OFDM */ +- ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0]; +- ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; +- ctpres = ar->power_2G_ofdm; +- break; +- default: +- BUG(); +- } +- +- for (n = 0; n < ntargets; n++) { +- if (ctpl[n].freq == 0xff) +- break; +- pwr_freqs[n] = ctpl[n].freq; +- } +- ntargets = n; +- idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); +- for (n = 0; n < 4; n++) +- ctpres[n] = ar9170_interpolate_u8( +- f, +- ctpl[idx + 0].freq, +- ctpl[idx + 0].power[n], +- ctpl[idx + 1].freq, +- ctpl[idx + 1].power[n]); +- } +- +- /* +- * HT modes now: 5G HT20, 5G HT40, 2G CCK, 2G OFDM, 2G HT20, 2G HT40 +- */ +- for (i = 0; i < 4; i++) { +- switch (i) { +- case 0: /* 5 GHz HT 20 */ +- ctph = &ar->eeprom.cal_tgt_pwr_5G_ht20[0]; +- ntargets = AR5416_NUM_5G_TARGET_PWRS; +- ctpres = ar->power_5G_ht20; +- break; +- case 1: /* 5 GHz HT 40 */ +- ctph = &ar->eeprom.cal_tgt_pwr_5G_ht40[0]; +- ntargets = AR5416_NUM_5G_TARGET_PWRS; +- ctpres = ar->power_5G_ht40; +- break; +- case 2: /* 2.4 GHz HT 20 */ +- ctph = &ar->eeprom.cal_tgt_pwr_2G_ht20[0]; +- ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; +- ctpres = ar->power_2G_ht20; +- break; +- case 3: /* 2.4 GHz HT 40 */ +- ctph = &ar->eeprom.cal_tgt_pwr_2G_ht40[0]; +- ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; +- ctpres = ar->power_2G_ht40; +- break; +- default: +- BUG(); +- } +- +- for (n = 0; n < ntargets; n++) { +- if (ctph[n].freq == 0xff) +- break; +- pwr_freqs[n] = ctph[n].freq; +- } +- ntargets = n; +- idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); +- for (n = 0; n < 8; n++) +- ctpres[n] = ar9170_interpolate_u8( +- f, +- ctph[idx + 0].freq, +- ctph[idx + 0].power[n], +- ctph[idx + 1].freq, +- ctph[idx + 1].power[n]); +- } +- +- +- /* calc. conformance test limits and apply to ar->power*[] */ +- ar9170_calc_ctl(ar, freq, bw); +- +- /* set ACK/CTS TX power */ +- ar9170_regwrite_begin(ar); +- +- if (ar->eeprom.tx_mask != 1) +- ackchains = AR9170_TX_PHY_TXCHAIN_2; +- else +- ackchains = AR9170_TX_PHY_TXCHAIN_1; +- +- if (freq < 3000) +- ackpower = ar->power_2G_ofdm[0] & 0x3f; +- else +- ackpower = ar->power_5G_leg[0] & 0x3f; +- +- ar9170_regwrite(0x1c3694, ackpower << 20 | ackchains << 26); +- ar9170_regwrite(0x1c3bb4, ackpower << 5 | ackchains << 11 | +- ackpower << 21 | ackchains << 27); +- +- ar9170_regwrite_finish(); +- return ar9170_regwrite_result(); +-} +- +-static int ar9170_calc_noise_dbm(u32 raw_noise) +-{ +- if (raw_noise & 0x100) +- return ~((raw_noise & 0x0ff) >> 1); +- else +- return (raw_noise & 0xff) >> 1; +-} +- +-int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, +- enum ar9170_rf_init_mode rfi, enum ar9170_bw bw) +-{ +- const struct ar9170_phy_freq_params *freqpar; +- u32 cmd, tmp, offs; +- __le32 vals[8]; +- int i, err; +- bool bandswitch; +- +- /* clear BB heavy clip enable */ +- err = ar9170_write_reg(ar, 0x1c59e0, 0x200); +- if (err) +- return err; +- +- /* may be NULL at first setup */ +- if (ar->channel) +- bandswitch = ar->channel->band != channel->band; +- else +- bandswitch = true; +- +- /* HW workaround */ +- if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] && +- channel->center_freq <= 2417) +- bandswitch = true; +- +- err = ar->exec_cmd(ar, AR9170_CMD_FREQ_START, 0, NULL, 0, NULL); +- if (err) +- return err; +- +- if (rfi != AR9170_RFI_NONE || bandswitch) { +- u32 val = 0x400; +- +- if (rfi == AR9170_RFI_COLD) +- val = 0x800; +- +- /* warm/cold reset BB/ADDA */ +- err = ar9170_write_reg(ar, 0x1d4004, val); +- if (err) +- return err; +- +- err = ar9170_write_reg(ar, 0x1d4004, 0x0); +- if (err) +- return err; +- +- err = ar9170_init_phy(ar, channel->band); +- if (err) +- return err; +- +- err = ar9170_init_rf_banks_0_7(ar, +- channel->band == IEEE80211_BAND_5GHZ); +- if (err) +- return err; +- +- cmd = AR9170_CMD_RF_INIT; +- } else { +- cmd = AR9170_CMD_FREQUENCY; +- } +- +- err = ar9170_init_rf_bank4_pwr(ar, +- channel->band == IEEE80211_BAND_5GHZ, +- channel->center_freq, bw); +- if (err) +- return err; +- +- switch (bw) { +- case AR9170_BW_20: +- tmp = 0x240; +- offs = 0; +- break; +- case AR9170_BW_40_BELOW: +- tmp = 0x2c4; +- offs = 3; +- break; +- case AR9170_BW_40_ABOVE: +- tmp = 0x2d4; +- offs = 1; +- break; +- default: +- BUG(); +- return -ENOSYS; +- } +- +- if (ar->eeprom.tx_mask != 1) +- tmp |= 0x100; +- +- err = ar9170_write_reg(ar, 0x1c5804, tmp); +- if (err) +- return err; +- +- err = ar9170_set_freq_cal_data(ar, channel); +- if (err) +- return err; +- +- err = ar9170_set_power_cal(ar, channel->center_freq, bw); +- if (err) +- return err; +- +- freqpar = ar9170_get_hw_dyn_params(channel, bw); +- +- vals[0] = cpu_to_le32(channel->center_freq * 1000); +- vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf)); +- vals[2] = cpu_to_le32(offs << 2 | 1); +- vals[3] = cpu_to_le32(freqpar->coeff_exp); +- vals[4] = cpu_to_le32(freqpar->coeff_man); +- vals[5] = cpu_to_le32(freqpar->coeff_exp_shgi); +- vals[6] = cpu_to_le32(freqpar->coeff_man_shgi); +- vals[7] = cpu_to_le32(1000); +- +- err = ar->exec_cmd(ar, cmd, sizeof(vals), (u8 *)vals, +- sizeof(vals), (u8 *)vals); +- if (err) +- return err; +- +- if (ar->phy_heavy_clip) { +- err = ar9170_write_reg(ar, 0x1c59e0, +- 0x200 | ar->phy_heavy_clip); +- if (err) { +- if (ar9170_nag_limiter(ar)) +- wiphy_err(ar->hw->wiphy, +- "failed to set heavy clip\n"); +- } +- } +- +- for (i = 0; i < 2; i++) { +- ar->noise[i] = ar9170_calc_noise_dbm( +- (le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff); +- +- ar->noise[i + 2] = ar9170_calc_noise_dbm( +- (le32_to_cpu(vals[5 + i]) >> 23) & 0x1ff); +- } +- +- ar->channel = channel; +- return 0; +-} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/usb.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/usb.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/usb.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/usb.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,1008 +0,0 @@ +-/* +- * Atheros AR9170 driver +- * +- * USB - frontend +- * +- * Copyright 2008, Johannes Berg +- * Copyright 2009, Christian Lamparter +- * +- * 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; see the file COPYING. If not, see +- * http://www.gnu.org/licenses/. +- * +- * This file incorporates work covered by the following copyright and +- * permission notice: +- * Copyright (c) 2007-2008 Atheros Communications, Inc. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "ar9170.h" +-#include "cmd.h" +-#include "hw.h" +-#include "usb.h" +- +-MODULE_AUTHOR("Johannes Berg "); +-MODULE_AUTHOR("Christian Lamparter "); +-MODULE_LICENSE("GPL"); +-MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); +-MODULE_FIRMWARE("ar9170.fw"); +- +-enum ar9170_requirements { +- AR9170_REQ_FW1_ONLY = 1, +-}; +- +-static struct usb_device_id ar9170_usb_ids[] = { +- /* Atheros 9170 */ +- { USB_DEVICE(0x0cf3, 0x9170) }, +- /* Atheros TG121N */ +- { USB_DEVICE(0x0cf3, 0x1001) }, +- /* TP-Link TL-WN821N v2 */ +- { USB_DEVICE(0x0cf3, 0x1002) }, +- /* 3Com Dual Band 802.11n USB Adapter */ +- { USB_DEVICE(0x0cf3, 0x1010) }, +- /* H3C Dual Band 802.11n USB Adapter */ +- { USB_DEVICE(0x0cf3, 0x1011) }, +- /* Cace Airpcap NX */ +- { USB_DEVICE(0xcace, 0x0300) }, +- /* D-Link DWA 160 A1 */ +- { USB_DEVICE(0x07d1, 0x3c10) }, +- /* D-Link DWA 160 A2 */ +- { USB_DEVICE(0x07d1, 0x3a09) }, +- /* Netgear WNA1000 */ +- { USB_DEVICE(0x0846, 0x9040) }, +- /* Netgear WNDA3100 */ +- { USB_DEVICE(0x0846, 0x9010) }, +- /* Netgear WN111 v2 */ +- { USB_DEVICE(0x0846, 0x9001) }, +- /* Zydas ZD1221 */ +- { USB_DEVICE(0x0ace, 0x1221) }, +- /* Proxim ORiNOCO 802.11n USB */ +- { USB_DEVICE(0x1435, 0x0804) }, +- /* WNC Generic 11n USB Dongle */ +- { USB_DEVICE(0x1435, 0x0326) }, +- /* ZyXEL NWD271N */ +- { USB_DEVICE(0x0586, 0x3417) }, +- /* Z-Com UB81 BG */ +- { USB_DEVICE(0x0cde, 0x0023) }, +- /* Z-Com UB82 ABG */ +- { USB_DEVICE(0x0cde, 0x0026) }, +- /* Sphairon Homelink 1202 */ +- { USB_DEVICE(0x0cde, 0x0027) }, +- /* Arcadyan WN7512 */ +- { USB_DEVICE(0x083a, 0xf522) }, +- /* Planex GWUS300 */ +- { USB_DEVICE(0x2019, 0x5304) }, +- /* IO-Data WNGDNUS2 */ +- { USB_DEVICE(0x04bb, 0x093f) }, +- /* AVM FRITZ!WLAN USB Stick N */ +- { USB_DEVICE(0x057C, 0x8401) }, +- /* NEC WL300NU-G */ +- { USB_DEVICE(0x0409, 0x0249) }, +- /* AVM FRITZ!WLAN USB Stick N 2.4 */ +- { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY }, +- /* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */ +- { USB_DEVICE(0x1668, 0x1200) }, +- +- /* terminate */ +- {} +-}; +-MODULE_DEVICE_TABLE(usb, ar9170_usb_ids); +- +-static void ar9170_usb_submit_urb(struct ar9170_usb *aru) +-{ +- struct urb *urb; +- unsigned long flags; +- int err; +- +- if (unlikely(!IS_STARTED(&aru->common))) +- return ; +- +- spin_lock_irqsave(&aru->tx_urb_lock, flags); +- if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) { +- spin_unlock_irqrestore(&aru->tx_urb_lock, flags); +- return ; +- } +- atomic_inc(&aru->tx_submitted_urbs); +- +- urb = usb_get_from_anchor(&aru->tx_pending); +- if (!urb) { +- atomic_dec(&aru->tx_submitted_urbs); +- spin_unlock_irqrestore(&aru->tx_urb_lock, flags); +- +- return ; +- } +- spin_unlock_irqrestore(&aru->tx_urb_lock, flags); +- +- aru->tx_pending_urbs--; +- usb_anchor_urb(urb, &aru->tx_submitted); +- +- err = usb_submit_urb(urb, GFP_ATOMIC); +- if (unlikely(err)) { +- if (ar9170_nag_limiter(&aru->common)) +- dev_err(&aru->udev->dev, "submit_urb failed (%d).\n", +- err); +- +- usb_unanchor_urb(urb); +- atomic_dec(&aru->tx_submitted_urbs); +- ar9170_tx_callback(&aru->common, urb->context); +- } +- +- usb_free_urb(urb); +-} +- +-static void ar9170_usb_tx_urb_complete_frame(struct urb *urb) +-{ +- struct sk_buff *skb = urb->context; +- struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); +- +- if (unlikely(!aru)) { +- dev_kfree_skb_irq(skb); +- return ; +- } +- +- atomic_dec(&aru->tx_submitted_urbs); +- +- ar9170_tx_callback(&aru->common, skb); +- +- ar9170_usb_submit_urb(aru); +-} +- +-static void ar9170_usb_tx_urb_complete(struct urb *urb) +-{ +-} +- +-static void ar9170_usb_irq_completed(struct urb *urb) +-{ +- struct ar9170_usb *aru = urb->context; +- +- switch (urb->status) { +- /* everything is fine */ +- case 0: +- break; +- +- /* disconnect */ +- case -ENOENT: +- case -ECONNRESET: +- case -ENODEV: +- case -ESHUTDOWN: +- goto free; +- +- default: +- goto resubmit; +- } +- +- ar9170_handle_command_response(&aru->common, urb->transfer_buffer, +- urb->actual_length); +- +-resubmit: +- usb_anchor_urb(urb, &aru->rx_submitted); +- if (usb_submit_urb(urb, GFP_ATOMIC)) { +- usb_unanchor_urb(urb); +- goto free; +- } +- +- return; +- +-free: +- usb_free_coherent(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma); +-} +- +-static void ar9170_usb_rx_completed(struct urb *urb) +-{ +- struct sk_buff *skb = urb->context; +- struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); +- int err; +- +- if (!aru) +- goto free; +- +- switch (urb->status) { +- /* everything is fine */ +- case 0: +- break; +- +- /* disconnect */ +- case -ENOENT: +- case -ECONNRESET: +- case -ENODEV: +- case -ESHUTDOWN: +- goto free; +- +- default: +- goto resubmit; +- } +- +- skb_put(skb, urb->actual_length); +- ar9170_rx(&aru->common, skb); +- +-resubmit: +- skb_reset_tail_pointer(skb); +- skb_trim(skb, 0); +- +- usb_anchor_urb(urb, &aru->rx_submitted); +- err = usb_submit_urb(urb, GFP_ATOMIC); +- if (unlikely(err)) { +- usb_unanchor_urb(urb); +- goto free; +- } +- +- return ; +- +-free: +- dev_kfree_skb_irq(skb); +-} +- +-static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, +- struct urb *urb, gfp_t gfp) +-{ +- struct sk_buff *skb; +- +- skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE + 32, gfp); +- if (!skb) +- return -ENOMEM; +- +- /* reserve some space for mac80211's radiotap */ +- skb_reserve(skb, 32); +- +- usb_fill_bulk_urb(urb, aru->udev, +- usb_rcvbulkpipe(aru->udev, AR9170_EP_RX), +- skb->data, min(skb_tailroom(skb), +- AR9170_MAX_RX_BUFFER_SIZE), +- ar9170_usb_rx_completed, skb); +- +- return 0; +-} +- +-static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru) +-{ +- struct urb *urb = NULL; +- void *ibuf; +- int err = -ENOMEM; +- +- /* initialize interrupt endpoint */ +- urb = usb_alloc_urb(0, GFP_KERNEL); +- if (!urb) +- goto out; +- +- ibuf = usb_alloc_coherent(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma); +- if (!ibuf) +- goto out; +- +- usb_fill_int_urb(urb, aru->udev, +- usb_rcvintpipe(aru->udev, AR9170_EP_IRQ), ibuf, +- 64, ar9170_usb_irq_completed, aru, 1); +- urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +- +- usb_anchor_urb(urb, &aru->rx_submitted); +- err = usb_submit_urb(urb, GFP_KERNEL); +- if (err) { +- usb_unanchor_urb(urb); +- usb_free_coherent(aru->udev, 64, urb->transfer_buffer, +- urb->transfer_dma); +- } +- +-out: +- usb_free_urb(urb); +- return err; +-} +- +-static int ar9170_usb_alloc_rx_bulk_urbs(struct ar9170_usb *aru) +-{ +- struct urb *urb; +- int i; +- int err = -EINVAL; +- +- for (i = 0; i < AR9170_NUM_RX_URBS; i++) { +- err = -ENOMEM; +- urb = usb_alloc_urb(0, GFP_KERNEL); +- if (!urb) +- goto err_out; +- +- err = ar9170_usb_prep_rx_urb(aru, urb, GFP_KERNEL); +- if (err) { +- usb_free_urb(urb); +- goto err_out; +- } +- +- usb_anchor_urb(urb, &aru->rx_submitted); +- err = usb_submit_urb(urb, GFP_KERNEL); +- if (err) { +- usb_unanchor_urb(urb); +- dev_kfree_skb_any((void *) urb->transfer_buffer); +- usb_free_urb(urb); +- goto err_out; +- } +- usb_free_urb(urb); +- } +- +- /* the device now waiting for a firmware. */ +- aru->common.state = AR9170_IDLE; +- return 0; +- +-err_out: +- +- usb_kill_anchored_urbs(&aru->rx_submitted); +- return err; +-} +- +-static int ar9170_usb_flush(struct ar9170 *ar) +-{ +- struct ar9170_usb *aru = (void *) ar; +- struct urb *urb; +- int ret, err = 0; +- +- if (IS_STARTED(ar)) +- aru->common.state = AR9170_IDLE; +- +- usb_wait_anchor_empty_timeout(&aru->tx_pending, +- msecs_to_jiffies(800)); +- while ((urb = usb_get_from_anchor(&aru->tx_pending))) { +- ar9170_tx_callback(&aru->common, (void *) urb->context); +- usb_free_urb(urb); +- } +- +- /* lets wait a while until the tx - queues are dried out */ +- ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, +- msecs_to_jiffies(100)); +- if (ret == 0) +- err = -ETIMEDOUT; +- +- usb_kill_anchored_urbs(&aru->tx_submitted); +- +- if (IS_ACCEPTING_CMD(ar)) +- aru->common.state = AR9170_STARTED; +- +- return err; +-} +- +-static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) +-{ +- int err; +- +- aru->common.state = AR9170_UNKNOWN_STATE; +- +- err = ar9170_usb_flush(&aru->common); +- if (err) +- dev_err(&aru->udev->dev, "stuck tx urbs!\n"); +- +- usb_poison_anchored_urbs(&aru->tx_submitted); +- usb_poison_anchored_urbs(&aru->rx_submitted); +-} +- +-static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, +- unsigned int plen, void *payload, +- unsigned int outlen, void *out) +-{ +- struct ar9170_usb *aru = (void *) ar; +- struct urb *urb = NULL; +- unsigned long flags; +- int err = -ENOMEM; +- +- if (unlikely(!IS_ACCEPTING_CMD(ar))) +- return -EPERM; +- +- if (WARN_ON(plen > AR9170_MAX_CMD_LEN - 4)) +- return -EINVAL; +- +- urb = usb_alloc_urb(0, GFP_ATOMIC); +- if (unlikely(!urb)) +- goto err_free; +- +- ar->cmdbuf[0] = cpu_to_le32(plen); +- ar->cmdbuf[0] |= cpu_to_le32(cmd << 8); +- /* writing multiple regs fills this buffer already */ +- if (plen && payload != (u8 *)(&ar->cmdbuf[1])) +- memcpy(&ar->cmdbuf[1], payload, plen); +- +- spin_lock_irqsave(&aru->common.cmdlock, flags); +- aru->readbuf = (u8 *)out; +- aru->readlen = outlen; +- spin_unlock_irqrestore(&aru->common.cmdlock, flags); +- +- usb_fill_int_urb(urb, aru->udev, +- usb_sndintpipe(aru->udev, AR9170_EP_CMD), +- aru->common.cmdbuf, plen + 4, +- ar9170_usb_tx_urb_complete, NULL, 1); +- +- usb_anchor_urb(urb, &aru->tx_submitted); +- err = usb_submit_urb(urb, GFP_ATOMIC); +- if (unlikely(err)) { +- usb_unanchor_urb(urb); +- usb_free_urb(urb); +- goto err_unbuf; +- } +- usb_free_urb(urb); +- +- err = wait_for_completion_timeout(&aru->cmd_wait, HZ); +- if (err == 0) { +- err = -ETIMEDOUT; +- goto err_unbuf; +- } +- +- if (aru->readlen != outlen) { +- err = -EMSGSIZE; +- goto err_unbuf; +- } +- +- return 0; +- +-err_unbuf: +- /* Maybe the device was removed in the second we were waiting? */ +- if (IS_STARTED(ar)) { +- dev_err(&aru->udev->dev, "no command feedback " +- "received (%d).\n", err); +- +- /* provide some maybe useful debug information */ +- print_hex_dump_bytes("ar9170 cmd: ", DUMP_PREFIX_NONE, +- aru->common.cmdbuf, plen + 4); +- dump_stack(); +- } +- +- /* invalidate to avoid completing the next prematurely */ +- spin_lock_irqsave(&aru->common.cmdlock, flags); +- aru->readbuf = NULL; +- aru->readlen = 0; +- spin_unlock_irqrestore(&aru->common.cmdlock, flags); +- +-err_free: +- +- return err; +-} +- +-static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb) +-{ +- struct ar9170_usb *aru = (struct ar9170_usb *) ar; +- struct urb *urb; +- +- if (unlikely(!IS_STARTED(ar))) { +- /* Seriously, what were you drink... err... thinking!? */ +- return -EPERM; +- } +- +- urb = usb_alloc_urb(0, GFP_ATOMIC); +- if (unlikely(!urb)) +- return -ENOMEM; +- +- usb_fill_bulk_urb(urb, aru->udev, +- usb_sndbulkpipe(aru->udev, AR9170_EP_TX), +- skb->data, skb->len, +- ar9170_usb_tx_urb_complete_frame, skb); +- urb->transfer_flags |= URB_ZERO_PACKET; +- +- usb_anchor_urb(urb, &aru->tx_pending); +- aru->tx_pending_urbs++; +- +- usb_free_urb(urb); +- +- ar9170_usb_submit_urb(aru); +- return 0; +-} +- +-static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) +-{ +- struct ar9170_usb *aru = (void *) ar; +- unsigned long flags; +- u32 in, out; +- +- if (unlikely(!buffer)) +- return ; +- +- in = le32_to_cpup((__le32 *)buffer); +- out = le32_to_cpu(ar->cmdbuf[0]); +- +- /* mask off length byte */ +- out &= ~0xFF; +- +- if (aru->readlen >= 0) { +- /* add expected length */ +- out |= aru->readlen; +- } else { +- /* add obtained length */ +- out |= in & 0xFF; +- } +- +- /* +- * Some commands (e.g: AR9170_CMD_FREQUENCY) have a variable response +- * length and we cannot predict the correct length in advance. +- * So we only check if we provided enough space for the data. +- */ +- if (unlikely(out < in)) { +- dev_warn(&aru->udev->dev, "received invalid command response " +- "got %d bytes, instead of %d bytes " +- "and the resp length is %d bytes\n", +- in, out, len); +- print_hex_dump_bytes("ar9170 invalid resp: ", +- DUMP_PREFIX_OFFSET, buffer, len); +- /* +- * Do not complete, then the command times out, +- * and we get a stack trace from there. +- */ +- return ; +- } +- +- spin_lock_irqsave(&aru->common.cmdlock, flags); +- if (aru->readbuf && len > 0) { +- memcpy(aru->readbuf, buffer + 4, len - 4); +- aru->readbuf = NULL; +- } +- complete(&aru->cmd_wait); +- spin_unlock_irqrestore(&aru->common.cmdlock, flags); +-} +- +-static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data, +- size_t len, u32 addr, bool complete) +-{ +- int transfer, err; +- u8 *buf = kmalloc(4096, GFP_KERNEL); +- +- if (!buf) +- return -ENOMEM; +- +- while (len) { +- transfer = min_t(int, len, 4096); +- memcpy(buf, data, transfer); +- +- err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), +- 0x30 /* FW DL */, 0x40 | USB_DIR_OUT, +- addr >> 8, 0, buf, transfer, 1000); +- +- if (err < 0) { +- kfree(buf); +- return err; +- } +- +- len -= transfer; +- data += transfer; +- addr += transfer; +- } +- kfree(buf); +- +- if (complete) { +- err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), +- 0x31 /* FW DL COMPLETE */, +- 0x40 | USB_DIR_OUT, 0, 0, NULL, 0, 5000); +- } +- +- return 0; +-} +- +-static int ar9170_usb_reset(struct ar9170_usb *aru) +-{ +- int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING); +- +- if (lock) { +- ret = usb_lock_device_for_reset(aru->udev, aru->intf); +- if (ret < 0) { +- dev_err(&aru->udev->dev, "unable to lock device " +- "for reset (%d).\n", ret); +- return ret; +- } +- } +- +- ret = usb_reset_device(aru->udev); +- if (lock) +- usb_unlock_device(aru->udev); +- +- /* let it rest - for a second - */ +- msleep(1000); +- +- return ret; +-} +- +-static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) +-{ +- int err; +- +- if (!aru->init_values) +- goto upload_fw_start; +- +- /* First, upload initial values to device RAM */ +- err = ar9170_usb_upload(aru, aru->init_values->data, +- aru->init_values->size, 0x102800, false); +- if (err) { +- dev_err(&aru->udev->dev, "firmware part 1 " +- "upload failed (%d).\n", err); +- return err; +- } +- +-upload_fw_start: +- +- /* Then, upload the firmware itself and start it */ +- return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, +- 0x200000, true); +-} +- +-static int ar9170_usb_init_transport(struct ar9170_usb *aru) +-{ +- struct ar9170 *ar = (void *) &aru->common; +- int err; +- +- ar9170_regwrite_begin(ar); +- +- /* Set USB Rx stream mode MAX packet number to 2 */ +- ar9170_regwrite(AR9170_USB_REG_MAX_AGG_UPLOAD, 0x4); +- +- /* Set USB Rx stream mode timeout to 10us */ +- ar9170_regwrite(AR9170_USB_REG_UPLOAD_TIME_CTL, 0x80); +- +- ar9170_regwrite_finish(); +- +- err = ar9170_regwrite_result(); +- if (err) +- dev_err(&aru->udev->dev, "USB setup failed (%d).\n", err); +- +- return err; +-} +- +-static void ar9170_usb_stop(struct ar9170 *ar) +-{ +- struct ar9170_usb *aru = (void *) ar; +- int ret; +- +- if (IS_ACCEPTING_CMD(ar)) +- aru->common.state = AR9170_STOPPED; +- +- ret = ar9170_usb_flush(ar); +- if (ret) +- dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); +- +- usb_poison_anchored_urbs(&aru->tx_submitted); +- +- /* +- * Note: +- * So far we freed all tx urbs, but we won't dare to touch any rx urbs. +- * Else we would end up with a unresponsive device... +- */ +-} +- +-static int ar9170_usb_open(struct ar9170 *ar) +-{ +- struct ar9170_usb *aru = (void *) ar; +- int err; +- +- usb_unpoison_anchored_urbs(&aru->tx_submitted); +- err = ar9170_usb_init_transport(aru); +- if (err) { +- usb_poison_anchored_urbs(&aru->tx_submitted); +- return err; +- } +- +- aru->common.state = AR9170_IDLE; +- return 0; +-} +- +-static int ar9170_usb_init_device(struct ar9170_usb *aru) +-{ +- int err; +- +- err = ar9170_usb_alloc_rx_irq_urb(aru); +- if (err) +- goto err_out; +- +- err = ar9170_usb_alloc_rx_bulk_urbs(aru); +- if (err) +- goto err_unrx; +- +- err = ar9170_usb_upload_firmware(aru); +- if (err) { +- err = ar9170_echo_test(&aru->common, 0x60d43110); +- if (err) { +- /* force user invention, by disabling the device */ +- err = usb_driver_set_configuration(aru->udev, -1); +- dev_err(&aru->udev->dev, "device is in a bad state. " +- "please reconnect it!\n"); +- goto err_unrx; +- } +- } +- +- return 0; +- +-err_unrx: +- ar9170_usb_cancel_urbs(aru); +- +-err_out: +- return err; +-} +- +-static void ar9170_usb_firmware_failed(struct ar9170_usb *aru) +-{ +- struct device *parent = aru->udev->dev.parent; +- struct usb_device *udev; +- +- /* +- * Store a copy of the usb_device pointer locally. +- * This is because device_release_driver initiates +- * ar9170_usb_disconnect, which in turn frees our +- * driver context (aru). +- */ +- udev = aru->udev; +- +- complete(&aru->firmware_loading_complete); +- +- /* unbind anything failed */ +- if (parent) +- device_lock(parent); +- +- device_release_driver(&udev->dev); +- if (parent) +- device_unlock(parent); +- +- usb_put_dev(udev); +-} +- +-static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) +-{ +- struct ar9170_usb *aru = context; +- int err; +- +- aru->firmware = fw; +- +- if (!fw) { +- dev_err(&aru->udev->dev, "firmware file not found.\n"); +- goto err_freefw; +- } +- +- err = ar9170_usb_init_device(aru); +- if (err) +- goto err_freefw; +- +- err = ar9170_usb_open(&aru->common); +- if (err) +- goto err_unrx; +- +- err = ar9170_register(&aru->common, &aru->udev->dev); +- +- ar9170_usb_stop(&aru->common); +- if (err) +- goto err_unrx; +- +- complete(&aru->firmware_loading_complete); +- usb_put_dev(aru->udev); +- return; +- +- err_unrx: +- ar9170_usb_cancel_urbs(aru); +- +- err_freefw: +- ar9170_usb_firmware_failed(aru); +-} +- +-static void ar9170_usb_firmware_inits(const struct firmware *fw, +- void *context) +-{ +- struct ar9170_usb *aru = context; +- int err; +- +- if (!fw) { +- dev_err(&aru->udev->dev, "file with init values not found.\n"); +- ar9170_usb_firmware_failed(aru); +- return; +- } +- +- aru->init_values = fw; +- +- /* ok so we have the init values -- get code for two-stage */ +- +- err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw", +- &aru->udev->dev, GFP_KERNEL, aru, +- ar9170_usb_firmware_finish); +- if (err) +- ar9170_usb_firmware_failed(aru); +-} +- +-static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context) +-{ +- struct ar9170_usb *aru = context; +- int err; +- +- if (fw) { +- ar9170_usb_firmware_finish(fw, context); +- return; +- } +- +- if (aru->req_one_stage_fw) { +- dev_err(&aru->udev->dev, "ar9170.fw firmware file " +- "not found and is required for this device\n"); +- ar9170_usb_firmware_failed(aru); +- return; +- } +- +- dev_err(&aru->udev->dev, "ar9170.fw firmware file " +- "not found, trying old firmware...\n"); +- +- err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw", +- &aru->udev->dev, GFP_KERNEL, aru, +- ar9170_usb_firmware_inits); +- if (err) +- ar9170_usb_firmware_failed(aru); +-} +- +-static bool ar9170_requires_one_stage(const struct usb_device_id *id) +-{ +- if (!id->driver_info) +- return false; +- if (id->driver_info == AR9170_REQ_FW1_ONLY) +- return true; +- return false; +-} +- +-static int ar9170_usb_probe(struct usb_interface *intf, +- const struct usb_device_id *id) +-{ +- struct ar9170_usb *aru; +- struct ar9170 *ar; +- struct usb_device *udev; +- int err; +- +- aru = ar9170_alloc(sizeof(*aru)); +- if (IS_ERR(aru)) { +- err = PTR_ERR(aru); +- goto out; +- } +- +- udev = interface_to_usbdev(intf); +- usb_get_dev(udev); +- aru->udev = udev; +- aru->intf = intf; +- ar = &aru->common; +- +- aru->req_one_stage_fw = ar9170_requires_one_stage(id); +- +- usb_set_intfdata(intf, aru); +- SET_IEEE80211_DEV(ar->hw, &intf->dev); +- +- init_usb_anchor(&aru->rx_submitted); +- init_usb_anchor(&aru->tx_pending); +- init_usb_anchor(&aru->tx_submitted); +- init_completion(&aru->cmd_wait); +- init_completion(&aru->firmware_loading_complete); +- spin_lock_init(&aru->tx_urb_lock); +- +- aru->tx_pending_urbs = 0; +- atomic_set(&aru->tx_submitted_urbs, 0); +- +- aru->common.stop = ar9170_usb_stop; +- aru->common.flush = ar9170_usb_flush; +- aru->common.open = ar9170_usb_open; +- aru->common.tx = ar9170_usb_tx; +- aru->common.exec_cmd = ar9170_usb_exec_cmd; +- aru->common.callback_cmd = ar9170_usb_callback_cmd; +- +-#ifdef CONFIG_PM +- udev->reset_resume = 1; +-#endif /* CONFIG_PM */ +- err = ar9170_usb_reset(aru); +- if (err) +- goto err_freehw; +- +- usb_get_dev(aru->udev); +- return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw", +- &aru->udev->dev, GFP_KERNEL, aru, +- ar9170_usb_firmware_step2); +-err_freehw: +- usb_set_intfdata(intf, NULL); +- usb_put_dev(udev); +- ieee80211_free_hw(ar->hw); +-out: +- return err; +-} +- +-static void ar9170_usb_disconnect(struct usb_interface *intf) +-{ +- struct ar9170_usb *aru = usb_get_intfdata(intf); +- +- if (!aru) +- return; +- +- aru->common.state = AR9170_IDLE; +- +- wait_for_completion(&aru->firmware_loading_complete); +- +- ar9170_unregister(&aru->common); +- ar9170_usb_cancel_urbs(aru); +- +- usb_put_dev(aru->udev); +- usb_set_intfdata(intf, NULL); +- ieee80211_free_hw(aru->common.hw); +- +- release_firmware(aru->init_values); +- release_firmware(aru->firmware); +-} +- +-#ifdef CONFIG_PM +-static int ar9170_suspend(struct usb_interface *intf, +- pm_message_t message) +-{ +- struct ar9170_usb *aru = usb_get_intfdata(intf); +- +- if (!aru) +- return -ENODEV; +- +- aru->common.state = AR9170_IDLE; +- ar9170_usb_cancel_urbs(aru); +- +- return 0; +-} +- +-static int ar9170_resume(struct usb_interface *intf) +-{ +- struct ar9170_usb *aru = usb_get_intfdata(intf); +- int err; +- +- if (!aru) +- return -ENODEV; +- +- usb_unpoison_anchored_urbs(&aru->rx_submitted); +- usb_unpoison_anchored_urbs(&aru->tx_submitted); +- +- err = ar9170_usb_init_device(aru); +- if (err) +- goto err_unrx; +- +- err = ar9170_usb_open(&aru->common); +- if (err) +- goto err_unrx; +- +- return 0; +- +-err_unrx: +- aru->common.state = AR9170_IDLE; +- ar9170_usb_cancel_urbs(aru); +- +- return err; +-} +-#endif /* CONFIG_PM */ +- +-static struct usb_driver ar9170_driver = { +- .name = "ar9170usb", +- .probe = ar9170_usb_probe, +- .disconnect = ar9170_usb_disconnect, +- .id_table = ar9170_usb_ids, +- .soft_unbind = 1, +-#ifdef CONFIG_PM +- .suspend = ar9170_suspend, +- .resume = ar9170_resume, +- .reset_resume = ar9170_resume, +-#endif /* CONFIG_PM */ +-}; +- +-static int __init ar9170_init(void) +-{ +- return usb_register(&ar9170_driver); +-} +- +-static void __exit ar9170_exit(void) +-{ +- usb_deregister(&ar9170_driver); +-} +- +-module_init(ar9170_init); +-module_exit(ar9170_exit); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/usb.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/usb.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ar9170/usb.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ar9170/usb.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,82 +0,0 @@ +-/* +- * Atheros AR9170 USB driver +- * +- * Driver specific definitions +- * +- * Copyright 2008, Johannes Berg +- * Copyright 2009, Christian Lamparter +- * +- * 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; see the file COPYING. If not, see +- * http://www.gnu.org/licenses/. +- * +- * This file incorporates work covered by the following copyright and +- * permission notice: +- * Copyright (c) 2007-2008 Atheros Communications, Inc. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +-#ifndef __USB_H +-#define __USB_H +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "eeprom.h" +-#include "hw.h" +-#include "ar9170.h" +- +-#define AR9170_NUM_RX_URBS 16 +-#define AR9170_NUM_TX_URBS 8 +- +-struct firmware; +- +-struct ar9170_usb { +- struct ar9170 common; +- struct usb_device *udev; +- struct usb_interface *intf; +- +- struct usb_anchor rx_submitted; +- struct usb_anchor tx_pending; +- struct usb_anchor tx_submitted; +- +- bool req_one_stage_fw; +- +- spinlock_t tx_urb_lock; +- atomic_t tx_submitted_urbs; +- unsigned int tx_pending_urbs; +- +- struct completion cmd_wait; +- struct completion firmware_loading_complete; +- int readlen; +- u8 *readbuf; +- +- const struct firmware *init_values; +- const struct firmware *firmware; +-}; +- +-#endif /* __USB_H */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/ahb.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/ahb.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/ahb.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/ahb.c 2011-05-05 23:29:49.130485905 +0200 +@@ -18,6 +18,7 @@ + + #include + #include ++#include + #include + #include "ath5k.h" + #include "debug.h" +@@ -62,10 +63,27 @@ + return 0; + } + ++static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) ++{ ++ struct ath5k_softc *sc = ah->ah_sc; ++ struct platform_device *pdev = to_platform_device(sc->dev); ++ struct ar231x_board_config *bcfg = pdev->dev.platform_data; ++ u8 *cfg_mac; ++ ++ if (to_platform_device(sc->dev)->id == 0) ++ cfg_mac = bcfg->config->wlan0_mac; ++ else ++ cfg_mac = bcfg->config->wlan1_mac; ++ ++ memcpy(mac, cfg_mac, ETH_ALEN); ++ return 0; ++} ++ + static const struct ath_bus_ops ath_ahb_bus_ops = { + .ath_bus_type = ATH_AHB, + .read_cachesize = ath5k_ahb_read_cachesize, + .eeprom_read = ath5k_ahb_eeprom_read, ++ .eeprom_read_mac = ath5k_ahb_eeprom_read_mac, + }; + + /*Initialization*/ +@@ -142,6 +160,16 @@ + else + reg |= AR5K_AR5312_ENABLE_WLAN1; + __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE); ++ ++ /* ++ * On a dual-band AR5312, the multiband radio is only ++ * used as pass-through. Disable 2 GHz support in the ++ * driver for it ++ */ ++ if (to_platform_device(sc->dev)->id == 0 && ++ (bcfg->config->flags & (BD_WLAN0|BD_WLAN1)) == ++ (BD_WLAN1|BD_WLAN0)) ++ __set_bit(ATH_STAT_2G_DISABLED, sc->status); + } + + ret = ath5k_init_softc(sc, &ath_ahb_bus_ops); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/ath5k.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/ath5k.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/ath5k.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/ath5k.h 2011-05-05 23:29:49.133485941 +0200 +@@ -224,8 +224,7 @@ + + /* SIFS */ + #define AR5K_INIT_SIFS_TURBO 6 +-/* XXX: 8 from initvals 10 from standard */ +-#define AR5K_INIT_SIFS_DEFAULT_BG 8 ++#define AR5K_INIT_SIFS_DEFAULT_BG 10 + #define AR5K_INIT_SIFS_DEFAULT_A 16 + #define AR5K_INIT_SIFS_HALF_RATE 32 + #define AR5K_INIT_SIFS_QUARTER_RATE 64 +@@ -453,12 +452,10 @@ + u16 ts_seqnum; + u16 ts_tstamp; + u8 ts_status; +- u8 ts_rate[4]; +- u8 ts_retry[4]; + u8 ts_final_idx; ++ u8 ts_final_retry; + s8 ts_rssi; + u8 ts_shortretry; +- u8 ts_longretry; + u8 ts_virtcol; + u8 ts_antenna; + }; +@@ -875,6 +872,19 @@ + AR5K_INT_QTRIG = 0x40000000, /* Non common */ + AR5K_INT_GLOBAL = 0x80000000, + ++ AR5K_INT_TX_ALL = AR5K_INT_TXOK ++ | AR5K_INT_TXDESC ++ | AR5K_INT_TXERR ++ | AR5K_INT_TXEOL ++ | AR5K_INT_TXURN, ++ ++ AR5K_INT_RX_ALL = AR5K_INT_RXOK ++ | AR5K_INT_RXDESC ++ | AR5K_INT_RXERR ++ | AR5K_INT_RXNOFRM ++ | AR5K_INT_RXEOL ++ | AR5K_INT_RXORN, ++ + AR5K_INT_COMMON = AR5K_INT_RXOK + | AR5K_INT_RXDESC + | AR5K_INT_RXERR +@@ -1058,6 +1068,7 @@ + u8 ah_coverage_class; + bool ah_ack_bitrate_high; + u8 ah_bwmode; ++ bool ah_short_slot; + + /* Antenna Control */ + u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; +@@ -1144,6 +1155,13 @@ + struct ath5k_rx_status *); + }; + ++struct ath_bus_ops { ++ enum ath_bus_type ath_bus_type; ++ void (*read_cachesize)(struct ath_common *common, int *csz); ++ bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); ++ int (*eeprom_read_mac)(struct ath5k_hw *ah, u8 *mac); ++}; ++ + /* + * Prototypes + */ +@@ -1227,13 +1245,12 @@ + /* EEPROM access functions */ + int ath5k_eeprom_init(struct ath5k_hw *ah); + void ath5k_eeprom_detach(struct ath5k_hw *ah); +-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); + + + /* Protocol Control Unit Functions */ + /* Helpers */ + int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, +- int len, struct ieee80211_rate *rate); ++ int len, struct ieee80211_rate *rate, bool shortpre); + unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah); + unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah); + extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/attach.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/attach.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/attach.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/attach.c 2011-05-05 23:29:49.133485941 +0200 +@@ -313,12 +313,17 @@ + goto err; + } + ++ if (test_bit(ATH_STAT_2G_DISABLED, sc->status)) { ++ __clear_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode); ++ __clear_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode); ++ } ++ + /* Crypto settings */ + common->keymax = (sc->ah->ah_version == AR5K_AR5210 ? + AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211); + + if (srev >= AR5K_SREV_AR5212_V4 && +- (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 && ++ (ee->ee_version < AR5K_EEPROM_VERSION_5_0 || + !AR5K_EEPROM_AES_DIS(ee->ee_misc5))) + common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/base.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/base.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/base.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/base.c 2011-05-05 23:29:49.123485819 +0200 +@@ -1444,6 +1444,21 @@ + } + + static void ++ath5k_set_current_imask(struct ath5k_softc *sc) ++{ ++ enum ath5k_int imask = sc->imask; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sc->irqlock, flags); ++ if (sc->rx_pending) ++ imask &= ~AR5K_INT_RX_ALL; ++ if (sc->tx_pending) ++ imask &= ~AR5K_INT_TX_ALL; ++ ath5k_hw_set_imr(sc->ah, imask); ++ spin_unlock_irqrestore(&sc->irqlock, flags); ++} ++ ++static void + ath5k_tasklet_rx(unsigned long data) + { + struct ath5k_rx_status rs = {}; +@@ -1506,6 +1521,8 @@ + } while (ath5k_rxbuf_setup(sc, bf) == 0); + unlock: + spin_unlock(&sc->rxbuflock); ++ sc->rx_pending = false; ++ ath5k_set_current_imask(sc); + } + + +@@ -1573,28 +1590,28 @@ + struct ath5k_txq *txq, struct ath5k_tx_status *ts) + { + struct ieee80211_tx_info *info; ++ u8 tries[3]; + int i; + + sc->stats.tx_all_count++; + sc->stats.tx_bytes_count += skb->len; + info = IEEE80211_SKB_CB(skb); + ++ tries[0] = info->status.rates[0].count; ++ tries[1] = info->status.rates[1].count; ++ tries[2] = info->status.rates[2].count; ++ + ieee80211_tx_info_clear_status(info); +- for (i = 0; i < 4; i++) { ++ ++ for (i = 0; i < ts->ts_final_idx; i++) { + struct ieee80211_tx_rate *r = + &info->status.rates[i]; + +- if (ts->ts_rate[i]) { +- r->idx = ath5k_hw_to_driver_rix(sc, ts->ts_rate[i]); +- r->count = ts->ts_retry[i]; +- } else { +- r->idx = -1; +- r->count = 0; +- } ++ r->count = tries[i]; + } + +- /* count the successful attempt as well */ +- info->status.rates[ts->ts_final_idx].count++; ++ info->status.rates[ts->ts_final_idx].count = ts->ts_final_retry; ++ info->status.rates[ts->ts_final_idx + 1].idx = -1; + + if (unlikely(ts->ts_status)) { + sc->stats.ack_fail++; +@@ -1609,6 +1626,9 @@ + } else { + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.ack_signal = ts->ts_rssi; ++ ++ /* count the successful attempt as well */ ++ info->status.rates[ts->ts_final_idx].count++; + } + + /* +@@ -1690,6 +1710,9 @@ + for (i=0; i < AR5K_NUM_TX_QUEUES; i++) + if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i))) + ath5k_tx_processq(sc, &sc->txqs[i]); ++ ++ sc->tx_pending = false; ++ ath5k_set_current_imask(sc); + } + + +@@ -2119,6 +2142,20 @@ + * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ + } + ++static void ++ath5k_schedule_rx(struct ath5k_softc *sc) ++{ ++ sc->rx_pending = true; ++ tasklet_schedule(&sc->rxtq); ++} ++ ++static void ++ath5k_schedule_tx(struct ath5k_softc *sc) ++{ ++ sc->tx_pending = true; ++ tasklet_schedule(&sc->txtq); ++} ++ + irqreturn_t + ath5k_intr(int irq, void *dev_id) + { +@@ -2161,7 +2198,7 @@ + ieee80211_queue_work(sc->hw, &sc->reset_work); + } + else +- tasklet_schedule(&sc->rxtq); ++ ath5k_schedule_rx(sc); + } else { + if (status & AR5K_INT_SWBA) { + tasklet_hi_schedule(&sc->beacontq); +@@ -2179,10 +2216,10 @@ + ath5k_hw_update_tx_triglevel(ah, true); + } + if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) +- tasklet_schedule(&sc->rxtq); ++ ath5k_schedule_rx(sc); + if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC + | AR5K_INT_TXERR | AR5K_INT_TXEOL)) +- tasklet_schedule(&sc->txtq); ++ ath5k_schedule_tx(sc); + if (status & AR5K_INT_BMISS) { + /* TODO */ + } +@@ -2201,6 +2238,9 @@ + + } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); + ++ if (sc->rx_pending || sc->tx_pending) ++ ath5k_set_current_imask(sc); ++ + if (unlikely(!counter)) + ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); + +@@ -2572,6 +2612,8 @@ + + static void stop_tasklets(struct ath5k_softc *sc) + { ++ sc->rx_pending = false; ++ sc->tx_pending = false; + tasklet_kill(&sc->rxtq); + tasklet_kill(&sc->txtq); + tasklet_kill(&sc->calib); +@@ -2838,7 +2880,7 @@ + INIT_WORK(&sc->reset_work, ath5k_reset_work); + INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work); + +- ret = ath5k_eeprom_read_mac(ah, mac); ++ ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac); + if (ret) { + ATH5K_ERR(sc, "unable to read address from EEPROM\n"); + goto err_queues; +@@ -2898,7 +2940,6 @@ + * XXX: ??? detach ath5k_hw ??? + * Other than that, it's straightforward... + */ +- ath5k_debug_finish_device(sc); + ieee80211_unregister_hw(hw); + ath5k_desc_free(sc); + ath5k_txq_release(sc); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/base.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/base.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/base.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/base.h 2011-05-05 23:29:49.117485747 +0200 +@@ -193,12 +193,13 @@ + dma_addr_t desc_daddr; /* DMA (physical) address */ + size_t desc_len; /* size of TX/RX descriptors */ + +- DECLARE_BITMAP(status, 5); ++ DECLARE_BITMAP(status, 6); + #define ATH_STAT_INVALID 0 /* disable hardware accesses */ + #define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ + #define ATH_STAT_PROMISC 2 + #define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ + #define ATH_STAT_STARTED 4 /* opened & irqs enabled */ ++#define ATH_STAT_2G_DISABLED 5 /* multiband radio without 2G */ + + unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ + struct ieee80211_channel *curchan; /* current h/w channel */ +@@ -207,6 +208,10 @@ + + enum ath5k_int imask; /* interrupt mask copy */ + ++ spinlock_t irqlock; ++ bool rx_pending; /* rx tasklet pending */ ++ bool tx_pending; /* tx tasklet pending */ ++ + u8 lladdr[ETH_ALEN]; + u8 bssidmask[ETH_ALEN]; + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/caps.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/caps.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/caps.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/caps.c 2011-05-05 23:29:49.128485881 +0200 +@@ -94,6 +94,9 @@ + } + } + ++ if ((ah->ah_radio_5ghz_revision & 0xf0) == AR5K_SREV_RAD_2112) ++ __clear_bit(AR5K_MODE_11A, caps->cap_mode); ++ + /* Set number of supported TX queues */ + if (ah->ah_version == AR5K_AR5210) + caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/debug.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/debug.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/debug.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/debug.c 2011-05-05 23:29:49.130485905 +0200 +@@ -888,64 +888,37 @@ + void + ath5k_debug_init_device(struct ath5k_softc *sc) + { ++ struct dentry *phydir; ++ + sc->debug.level = ath5k_debug; + +- sc->debug.debugfs_phydir = debugfs_create_dir("ath5k", +- sc->hw->wiphy->debugfsdir); ++ phydir = debugfs_create_dir("ath5k", sc->hw->wiphy->debugfsdir); ++ if (!phydir) ++ return; + +- sc->debug.debugfs_debug = debugfs_create_file("debug", +- S_IWUSR | S_IRUSR, +- sc->debug.debugfs_phydir, sc, &fops_debug); +- +- sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR, +- sc->debug.debugfs_phydir, sc, &fops_registers); +- +- sc->debug.debugfs_beacon = debugfs_create_file("beacon", +- S_IWUSR | S_IRUSR, +- sc->debug.debugfs_phydir, sc, &fops_beacon); +- +- sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, +- sc->debug.debugfs_phydir, sc, &fops_reset); +- +- sc->debug.debugfs_antenna = debugfs_create_file("antenna", +- S_IWUSR | S_IRUSR, +- sc->debug.debugfs_phydir, sc, &fops_antenna); +- +- sc->debug.debugfs_misc = debugfs_create_file("misc", +- S_IRUSR, +- sc->debug.debugfs_phydir, sc, &fops_misc); +- +- sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors", +- S_IWUSR | S_IRUSR, +- sc->debug.debugfs_phydir, sc, +- &fops_frameerrors); +- +- sc->debug.debugfs_ani = debugfs_create_file("ani", +- S_IWUSR | S_IRUSR, +- sc->debug.debugfs_phydir, sc, +- &fops_ani); +- +- sc->debug.debugfs_queue = debugfs_create_file("queue", +- S_IWUSR | S_IRUSR, +- sc->debug.debugfs_phydir, sc, +- &fops_queue); +-} ++ debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, sc, ++ &fops_debug); + +-void +-ath5k_debug_finish_device(struct ath5k_softc *sc) +-{ +- debugfs_remove(sc->debug.debugfs_debug); +- debugfs_remove(sc->debug.debugfs_registers); +- debugfs_remove(sc->debug.debugfs_beacon); +- debugfs_remove(sc->debug.debugfs_reset); +- debugfs_remove(sc->debug.debugfs_antenna); +- debugfs_remove(sc->debug.debugfs_misc); +- debugfs_remove(sc->debug.debugfs_frameerrors); +- debugfs_remove(sc->debug.debugfs_ani); +- debugfs_remove(sc->debug.debugfs_queue); +- debugfs_remove(sc->debug.debugfs_phydir); +-} ++ debugfs_create_file("registers", S_IRUSR, phydir, sc, &fops_registers); ++ ++ debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, sc, ++ &fops_beacon); + ++ debugfs_create_file("reset", S_IWUSR, phydir, sc, &fops_reset); ++ ++ debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, sc, ++ &fops_antenna); ++ ++ debugfs_create_file("misc", S_IRUSR, phydir, sc, &fops_misc); ++ ++ debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, sc, ++ &fops_frameerrors); ++ ++ debugfs_create_file("ani", S_IWUSR | S_IRUSR, phydir, sc, &fops_ani); ++ ++ debugfs_create_file("queue", S_IWUSR | S_IRUSR, phydir, sc, ++ &fops_queue); ++} + + /* functions used in other places */ + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/debug.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/debug.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/debug.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/debug.h 2011-05-05 23:29:49.132485929 +0200 +@@ -68,17 +68,6 @@ + + struct ath5k_dbg_info { + unsigned int level; /* debug level */ +- /* debugfs entries */ +- struct dentry *debugfs_phydir; +- struct dentry *debugfs_debug; +- struct dentry *debugfs_registers; +- struct dentry *debugfs_beacon; +- struct dentry *debugfs_reset; +- struct dentry *debugfs_antenna; +- struct dentry *debugfs_misc; +- struct dentry *debugfs_frameerrors; +- struct dentry *debugfs_ani; +- struct dentry *debugfs_queue; + }; + + /** +@@ -141,9 +130,6 @@ + ath5k_debug_init_device(struct ath5k_softc *sc); + + void +-ath5k_debug_finish_device(struct ath5k_softc *sc); +- +-void + ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah); + + void +@@ -167,9 +153,6 @@ + ath5k_debug_init_device(struct ath5k_softc *sc) {} + + static inline void +-ath5k_debug_finish_device(struct ath5k_softc *sc) {} +- +-static inline void + ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {} + + static inline void +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/desc.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/desc.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/desc.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/desc.c 2011-05-05 23:29:49.126485857 +0200 +@@ -185,6 +185,12 @@ + struct ath5k_hw_4w_tx_ctl *tx_ctl; + unsigned int frame_len; + ++ /* ++ * Use local variables for these to reduce load/store access on ++ * uncached memory ++ */ ++ u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0; ++ + tx_ctl = &desc->ud.ds_tx5212.tx_ctl; + + /* +@@ -208,8 +214,9 @@ + if (tx_power > AR5K_TUNE_MAX_TXPOWER) + tx_power = AR5K_TUNE_MAX_TXPOWER; + +- /* Clear descriptor */ +- memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); ++ /* Clear descriptor status area */ ++ memset(&desc->ud.ds_tx5212.tx_stat, 0, ++ sizeof(desc->ud.ds_tx5212.tx_stat)); + + /* Setup control descriptor */ + +@@ -221,7 +228,7 @@ + if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) + return -EINVAL; + +- tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; ++ txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; + + /* Verify and set buffer length */ + +@@ -232,21 +239,17 @@ + if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) + return -EINVAL; + +- tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; ++ txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; + +- tx_ctl->tx_control_0 |= +- AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | +- AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); +- tx_ctl->tx_control_1 |= AR5K_REG_SM(type, +- AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); +- tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0, +- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); +- tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; ++ txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | ++ AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); ++ txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); ++ txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); ++ txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; + + #define _TX_FLAGS(_c, _flag) \ + if (flags & AR5K_TXDESC_##_flag) { \ +- tx_ctl->tx_control_##_c |= \ +- AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ ++ txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ + } + + _TX_FLAGS(0, CLRDMASK); +@@ -262,8 +265,8 @@ + * WEP crap + */ + if (key_index != AR5K_TXKEYIX_INVALID) { +- tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; +- tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, ++ txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; ++ txctl1 |= AR5K_REG_SM(key_index, + AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX); + } + +@@ -274,12 +277,16 @@ + if ((flags & AR5K_TXDESC_RTSENA) && + (flags & AR5K_TXDESC_CTSENA)) + return -EINVAL; +- tx_ctl->tx_control_2 |= rtscts_duration & +- AR5K_4W_TX_DESC_CTL2_RTS_DURATION; +- tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, ++ txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION; ++ txctl3 |= AR5K_REG_SM(rtscts_rate, + AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); + } + ++ tx_ctl->tx_control_0 = txctl0; ++ tx_ctl->tx_control_1 = txctl1; ++ tx_ctl->tx_control_2 = txctl2; ++ tx_ctl->tx_control_3 = txctl3; ++ + return 0; + } + +@@ -364,7 +371,7 @@ + AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); + ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); +- ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, ++ ts->ts_final_retry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); + /*TODO: ts->ts_virtcol + test*/ + ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, +@@ -373,9 +380,6 @@ + AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); + ts->ts_antenna = 1; + ts->ts_status = 0; +- ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0, +- AR5K_2W_TX_DESC_CTL0_XMIT_RATE); +- ts->ts_retry[0] = ts->ts_longretry; + ts->ts_final_idx = 0; + + if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { +@@ -401,81 +405,48 @@ + { + struct ath5k_hw_4w_tx_ctl *tx_ctl; + struct ath5k_hw_tx_status *tx_status; ++ u32 txstat0, txstat1; + + tx_ctl = &desc->ud.ds_tx5212.tx_ctl; + tx_status = &desc->ud.ds_tx5212.tx_stat; + ++ txstat1 = ACCESS_ONCE(tx_status->tx_status_1); ++ + /* No frame has been send or error */ +- if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE))) ++ if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE))) + return -EINPROGRESS; + ++ txstat0 = ACCESS_ONCE(tx_status->tx_status_0); ++ + /* + * Get descriptor status + */ +- ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, ++ ts->ts_tstamp = AR5K_REG_MS(txstat0, + AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); +- ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, ++ ts->ts_shortretry = AR5K_REG_MS(txstat0, + AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); +- ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, ++ ts->ts_final_retry = AR5K_REG_MS(txstat0, + AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); +- ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, ++ ts->ts_seqnum = AR5K_REG_MS(txstat1, + AR5K_DESC_TX_STATUS1_SEQ_NUM); +- ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, ++ ts->ts_rssi = AR5K_REG_MS(txstat1, + AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); +- ts->ts_antenna = (tx_status->tx_status_1 & ++ ts->ts_antenna = (txstat1 & + AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1; + ts->ts_status = 0; + +- ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1, ++ ts->ts_final_idx = AR5K_REG_MS(txstat1, + AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212); + +- /* The longretry counter has the number of un-acked retries +- * for the final rate. To get the total number of retries +- * we have to add the retry counters for the other rates +- * as well +- */ +- ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; +- switch (ts->ts_final_idx) { +- case 3: +- ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3, +- AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); +- +- ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2, +- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); +- ts->ts_longretry += ts->ts_retry[2]; +- /* fall through */ +- case 2: +- ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3, +- AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); +- +- ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2, +- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); +- ts->ts_longretry += ts->ts_retry[1]; +- /* fall through */ +- case 1: +- ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3, +- AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); +- +- ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2, +- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); +- ts->ts_longretry += ts->ts_retry[0]; +- /* fall through */ +- case 0: +- ts->ts_rate[0] = tx_ctl->tx_control_3 & +- AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; +- break; +- } +- + /* TX error */ +- if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { +- if (tx_status->tx_status_0 & +- AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) ++ if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { ++ if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) + ts->ts_status |= AR5K_TXERR_XRETRY; + +- if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) ++ if (txstat0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) + ts->ts_status |= AR5K_TXERR_FIFO; + +- if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) ++ if (txstat0 & AR5K_DESC_TX_STATUS0_FILTERED) + ts->ts_status |= AR5K_TXERR_FILT; + } + +@@ -609,37 +580,37 @@ + struct ath5k_rx_status *rs) + { + struct ath5k_hw_rx_status *rx_status; ++ u32 rxstat0, rxstat1; + + rx_status = &desc->ud.ds_rx.rx_stat; ++ rxstat1 = ACCESS_ONCE(rx_status->rx_status_1); + + /* No frame received / not ready */ +- if (unlikely(!(rx_status->rx_status_1 & +- AR5K_5212_RX_DESC_STATUS1_DONE))) ++ if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE))) + return -EINPROGRESS; + + memset(rs, 0, sizeof(struct ath5k_rx_status)); ++ rxstat0 = ACCESS_ONCE(rx_status->rx_status_0); + + /* + * Frame receive status + */ +- rs->rs_datalen = rx_status->rx_status_0 & +- AR5K_5212_RX_DESC_STATUS0_DATA_LEN; +- rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, ++ rs->rs_datalen = rxstat0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN; ++ rs->rs_rssi = AR5K_REG_MS(rxstat0, + AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); +- rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, ++ rs->rs_rate = AR5K_REG_MS(rxstat0, + AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); +- rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0, ++ rs->rs_antenna = AR5K_REG_MS(rxstat0, + AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA); +- rs->rs_more = !!(rx_status->rx_status_0 & +- AR5K_5212_RX_DESC_STATUS0_MORE); +- rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, ++ rs->rs_more = !!(rxstat0 & AR5K_5212_RX_DESC_STATUS0_MORE); ++ rs->rs_tstamp = AR5K_REG_MS(rxstat1, + AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); + + /* + * Key table status + */ +- if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) +- rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, ++ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) ++ rs->rs_keyix = AR5K_REG_MS(rxstat1, + AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); + else + rs->rs_keyix = AR5K_RXKEYIX_INVALID; +@@ -647,27 +618,22 @@ + /* + * Receive/descriptor errors + */ +- if (!(rx_status->rx_status_1 & +- AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { +- if (rx_status->rx_status_1 & +- AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) ++ if (!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { ++ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_CRC; + +- if (rx_status->rx_status_1 & +- AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { ++ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { + rs->rs_status |= AR5K_RXERR_PHY; +- rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, ++ rs->rs_phyerr = AR5K_REG_MS(rxstat1, + AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE); + if (!ah->ah_capabilities.cap_has_phyerr_counters) + ath5k_ani_phy_error_report(ah, rs->rs_phyerr); + } + +- if (rx_status->rx_status_1 & +- AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) ++ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_DECRYPT; + +- if (rx_status->rx_status_1 & +- AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) ++ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) + rs->rs_status |= AR5K_RXERR_MIC; + } + return 0; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/eeprom.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/eeprom.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/eeprom.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/eeprom.c 2011-05-05 23:29:49.125485844 +0200 +@@ -660,6 +660,53 @@ + vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100; + } + ++static int ++ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) ++{ ++ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; ++ struct ath5k_chan_pcal_info *chinfo; ++ u8 pier, pdg; ++ ++ switch (mode) { ++ case AR5K_EEPROM_MODE_11A: ++ if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) ++ return 0; ++ chinfo = ee->ee_pwr_cal_a; ++ break; ++ case AR5K_EEPROM_MODE_11B: ++ if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) ++ return 0; ++ chinfo = ee->ee_pwr_cal_b; ++ break; ++ case AR5K_EEPROM_MODE_11G: ++ if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) ++ return 0; ++ chinfo = ee->ee_pwr_cal_g; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { ++ if (!chinfo[pier].pd_curves) ++ continue; ++ ++ for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { ++ struct ath5k_pdgain_info *pd = ++ &chinfo[pier].pd_curves[pdg]; ++ ++ if (pd != NULL) { ++ kfree(pd->pd_step); ++ kfree(pd->pd_pwr); ++ } ++ } ++ ++ kfree(chinfo[pier].pd_curves); ++ } ++ ++ return 0; ++} ++ + /* Convert RF5111 specific data to generic raw data + * used by interpolation code */ + static int +@@ -684,7 +731,7 @@ + GFP_KERNEL); + + if (!chinfo[pier].pd_curves) +- return -ENOMEM; ++ goto err_out; + + /* Only one curve for RF5111 + * find out which one and place +@@ -708,12 +755,12 @@ + pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, + sizeof(u8), GFP_KERNEL); + if (!pd->pd_step) +- return -ENOMEM; ++ goto err_out; + + pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, + sizeof(s16), GFP_KERNEL); + if (!pd->pd_pwr) +- return -ENOMEM; ++ goto err_out; + + /* Fill raw dataset + * (convert power to 0.25dB units +@@ -734,6 +781,10 @@ + } + + return 0; ++ ++err_out: ++ ath5k_eeprom_free_pcal_info(ah, mode); ++ return -ENOMEM; + } + + /* Parse EEPROM data */ +@@ -867,7 +918,7 @@ + GFP_KERNEL); + + if (!chinfo[pier].pd_curves) +- return -ENOMEM; ++ goto err_out; + + /* Fill pd_curves */ + for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { +@@ -886,14 +937,13 @@ + sizeof(u8), GFP_KERNEL); + + if (!pd->pd_step) +- return -ENOMEM; ++ goto err_out; + + pd->pd_pwr = kcalloc(pd->pd_points, + sizeof(s16), GFP_KERNEL); + + if (!pd->pd_pwr) +- return -ENOMEM; +- ++ goto err_out; + + /* Fill raw dataset + * (all power levels are in 0.25dB units) */ +@@ -925,13 +975,13 @@ + sizeof(u8), GFP_KERNEL); + + if (!pd->pd_step) +- return -ENOMEM; ++ goto err_out; + + pd->pd_pwr = kcalloc(pd->pd_points, + sizeof(s16), GFP_KERNEL); + + if (!pd->pd_pwr) +- return -ENOMEM; ++ goto err_out; + + /* Fill raw dataset + * (all power levels are in 0.25dB units) */ +@@ -954,6 +1004,10 @@ + } + + return 0; ++ ++err_out: ++ ath5k_eeprom_free_pcal_info(ah, mode); ++ return -ENOMEM; + } + + /* Parse EEPROM data */ +@@ -1156,7 +1210,7 @@ + GFP_KERNEL); + + if (!chinfo[pier].pd_curves) +- return -ENOMEM; ++ goto err_out; + + /* Fill pd_curves */ + for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { +@@ -1177,13 +1231,13 @@ + sizeof(u8), GFP_KERNEL); + + if (!pd->pd_step) +- return -ENOMEM; ++ goto err_out; + + pd->pd_pwr = kcalloc(pd->pd_points, + sizeof(s16), GFP_KERNEL); + + if (!pd->pd_pwr) +- return -ENOMEM; ++ goto err_out; + + /* Fill raw dataset + * convert all pwr levels to +@@ -1213,6 +1267,10 @@ + } + + return 0; ++ ++err_out: ++ ath5k_eeprom_free_pcal_info(ah, mode); ++ return -ENOMEM; + } + + /* Parse EEPROM data */ +@@ -1534,53 +1592,6 @@ + return 0; + } + +-static int +-ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) +-{ +- struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; +- struct ath5k_chan_pcal_info *chinfo; +- u8 pier, pdg; +- +- switch (mode) { +- case AR5K_EEPROM_MODE_11A: +- if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) +- return 0; +- chinfo = ee->ee_pwr_cal_a; +- break; +- case AR5K_EEPROM_MODE_11B: +- if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) +- return 0; +- chinfo = ee->ee_pwr_cal_b; +- break; +- case AR5K_EEPROM_MODE_11G: +- if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) +- return 0; +- chinfo = ee->ee_pwr_cal_g; +- break; +- default: +- return -EINVAL; +- } +- +- for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { +- if (!chinfo[pier].pd_curves) +- continue; +- +- for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { +- struct ath5k_pdgain_info *pd = +- &chinfo[pier].pd_curves[pdg]; +- +- if (pd != NULL) { +- kfree(pd->pd_step); +- kfree(pd->pd_pwr); +- } +- } +- +- kfree(chinfo[pier].pd_curves); +- } +- +- return 0; +-} +- + /* Read conformance test limits used for regulatory control */ + static int + ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) +@@ -1721,35 +1732,6 @@ + return ret; + } + +-/* +- * Read the MAC address from eeprom +- */ +-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) +-{ +- u8 mac_d[ETH_ALEN] = {}; +- u32 total, offset; +- u16 data; +- int octet; +- +- AR5K_EEPROM_READ(0x20, data); +- +- for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { +- AR5K_EEPROM_READ(offset, data); +- +- total += data; +- mac_d[octet + 1] = data & 0xff; +- mac_d[octet] = data >> 8; +- octet += 2; +- } +- +- if (!total || total == 3 * 0xffff) +- return -EINVAL; +- +- memcpy(mac, mac_d, ETH_ALEN); +- +- return 0; +-} +- + + /***********************\ + * Init/Detach functions * +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/mac80211-ops.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/mac80211-ops.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/mac80211-ops.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/mac80211-ops.c 2011-05-05 23:29:49.126485857 +0200 +@@ -282,6 +282,15 @@ + if (changes & BSS_CHANGED_BEACON_INT) + sc->bintval = bss_conf->beacon_int; + ++ if (changes & BSS_CHANGED_ERP_SLOT) { ++ int slot_time; ++ ++ ah->ah_short_slot = bss_conf->use_short_slot; ++ slot_time = ath5k_hw_get_default_slottime(ah) + ++ 3 * ah->ah_coverage_class; ++ ath5k_hw_set_ifs_intervals(ah, slot_time); ++ } ++ + if (changes & BSS_CHANGED_ASSOC) { + avf->assoc = bss_conf->assoc; + if (bss_conf->assoc) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/pci.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/pci.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/pci.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/pci.c 2011-05-05 23:29:49.131485917 +0200 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include "../ath.h" + #include "ath5k.h" + #include "debug.h" +@@ -108,11 +109,42 @@ + return 0; + } + ++/* ++ * Read the MAC address from eeprom or platform_data ++ */ ++static int ath5k_pci_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) ++{ ++ u8 mac_d[ETH_ALEN] = {}; ++ u32 total, offset; ++ u16 data; ++ int octet; ++ ++ AR5K_EEPROM_READ(0x20, data); ++ ++ for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { ++ AR5K_EEPROM_READ(offset, data); ++ ++ total += data; ++ mac_d[octet + 1] = data & 0xff; ++ mac_d[octet] = data >> 8; ++ octet += 2; ++ } ++ ++ if (!total || total == 3 * 0xffff) ++ return -EINVAL; ++ ++ memcpy(mac, mac_d, ETH_ALEN); ++ ++ return 0; ++} ++ ++ + /* Common ath_bus_opts structure */ + static const struct ath_bus_ops ath_pci_bus_ops = { + .ath_bus_type = ATH_PCI, + .read_cachesize = ath5k_pci_read_cachesize, + .eeprom_read = ath5k_pci_eeprom_read, ++ .eeprom_read_mac = ath5k_pci_eeprom_read_mac, + }; + + /********************\ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/pcu.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/pcu.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/pcu.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/pcu.c 2011-05-05 23:29:49.133485941 +0200 +@@ -75,7 +75,7 @@ + * bwmodes. + */ + int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, +- int len, struct ieee80211_rate *rate) ++ int len, struct ieee80211_rate *rate, bool shortpre) + { + struct ath5k_softc *sc = ah->ah_sc; + int sifs, preamble, plcp_bits, sym_time; +@@ -84,9 +84,15 @@ + + /* Fallback */ + if (!ah->ah_bwmode) { +- dur = ieee80211_generic_frame_duration(sc->hw, +- NULL, len, rate); +- return le16_to_cpu(dur); ++ __le16 raw_dur = ieee80211_generic_frame_duration(sc->hw, ++ NULL, len, rate); ++ ++ /* subtract difference between long and short preamble */ ++ dur = le16_to_cpu(raw_dur); ++ if (shortpre) ++ dur -= 96; ++ ++ return dur; + } + + bitrate = rate->bitrate; +@@ -145,9 +151,9 @@ + slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE; + break; + case AR5K_BWMODE_DEFAULT: +- slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; + default: +- if (channel->hw_value & CHANNEL_CCK) ++ slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; ++ if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot) + slot_time = AR5K_INIT_SLOT_TIME_B; + break; + } +@@ -263,27 +269,14 @@ + * actual rate for this rate. See mac80211 tx.c + * ieee80211_duration() for a brief description of + * what rate we should choose to TX ACKs. */ +- tx_time = ath5k_hw_get_frame_duration(ah, 10, rate); ++ tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); + + ath5k_hw_reg_write(ah, tx_time, reg); + + if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) + continue; + +- /* +- * We're not distinguishing short preamble here, +- * This is true, all we'll get is a longer value here +- * which is not necessarilly bad. We could use +- * export ieee80211_frame_duration() but that needs to be +- * fixed first to be properly used by mac802111 drivers: +- * +- * - remove erp stuff and let the routine figure ofdm +- * erp rates +- * - remove passing argument ieee80211_local as +- * drivers don't have access to it +- * - move drivers using ieee80211_generic_frame_duration() +- * to this +- */ ++ tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true); + ath5k_hw_reg_write(ah, tx_time, + reg + (AR5K_SET_SHORT_PREAMBLE << 2)); + } +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/qcu.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/qcu.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/qcu.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/qcu.c 2011-05-05 23:29:49.129485893 +0200 +@@ -519,7 +519,7 @@ + return -EINVAL; + + sifs = ath5k_hw_get_default_sifs(ah); +- sifs_clock = ath5k_hw_htoclock(ah, sifs); ++ sifs_clock = ath5k_hw_htoclock(ah, sifs - 2); + + /* EIFS + * Txtime of ack at lowest rate + SIFS + DIFS +@@ -550,7 +550,7 @@ + else + rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0]; + +- ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate); ++ ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); + + /* ack_tx_time includes an SIFS already */ + eifs = ack_tx_time + sifs + 2 * slot_time; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/reset.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/reset.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath5k/reset.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath5k/reset.c 2011-05-05 23:29:49.132485929 +0200 +@@ -159,6 +159,11 @@ + rxlat = AR5K_REG_MS(usec_reg, AR5K_USEC_RX_LATENCY_5211); + + /* ++ * Set default Tx frame to Tx data start delay ++ */ ++ txf2txs = AR5K_INIT_TXF2TXD_START_DEFAULT; ++ ++ /* + * 5210 initvals don't include usec settings + * so we need to use magic values here for + * tx/rx latencies +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ahb.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ahb.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ahb.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ahb.c 2011-05-05 23:29:49.081485313 +0200 +@@ -21,6 +21,18 @@ + #include + #include "ath9k.h" + ++static const struct platform_device_id ath9k_platform_id_table[] = { ++ { ++ .name = "ath9k", ++ .driver_data = AR5416_AR9100_DEVID, ++ }, ++ { ++ .name = "ar934x_wmac", ++ .driver_data = AR9300_DEVID_AR9340, ++ }, ++ {}, ++}; ++ + /* return bus cachesize in 4B word units */ + static void ath_ahb_read_cachesize(struct ath_common *common, int *csz) + { +@@ -57,6 +69,7 @@ + struct ath_softc *sc; + struct ieee80211_hw *hw; + struct resource *res; ++ const struct platform_device_id *id = platform_get_device_id(pdev); + int irq; + int ret = 0; + struct ath_hw *ah; +@@ -116,7 +129,7 @@ + goto err_free_hw; + } + +- ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops); ++ ret = ath9k_init_device(id->driver_data, sc, 0x0, &ath_ahb_bus_ops); + if (ret) { + dev_err(&pdev->dev, "failed to initialize device\n"); + goto err_irq; +@@ -165,8 +178,11 @@ + .name = "ath9k", + .owner = THIS_MODULE, + }, ++ .id_table = ath9k_platform_id_table, + }; + ++MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table); ++ + int ath_ahb_init(void) + { + return platform_driver_register(&ath_ahb_driver); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ani.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ani.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ani.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ani.c 2011-05-05 23:29:49.073485215 +0200 +@@ -899,12 +899,6 @@ + * check here default level should not modify INI setting. + */ + if (use_new_ani(ah)) { +- const struct ani_ofdm_level_entry *entry_ofdm; +- const struct ani_cck_level_entry *entry_cck; +- +- entry_ofdm = &ofdm_level_table[ATH9K_ANI_OFDM_DEF_LEVEL]; +- entry_cck = &cck_level_table[ATH9K_ANI_CCK_DEF_LEVEL]; +- + ah->aniperiod = ATH9K_ANI_PERIOD_NEW; + ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW; + } else { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar5008_phy.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar5008_phy.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar5008_phy.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar5008_phy.c 2011-05-05 23:29:49.110485663 +0200 +@@ -44,6 +44,34 @@ + static const int m2ThreshExt_off = 127; + + ++static void ar5008_rf_bank_setup(u32 *bank, struct ar5416IniArray *array, ++ int col) ++{ ++ int i; ++ ++ for (i = 0; i < array->ia_rows; i++) ++ bank[i] = INI_RA(array, i, col); ++} ++ ++ ++#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) \ ++ ar5008_write_rf_array(ah, iniarray, regData, &(regWr)) ++ ++static void ar5008_write_rf_array(struct ath_hw *ah, struct ar5416IniArray *array, ++ u32 *data, unsigned int *writecnt) ++{ ++ int r; ++ ++ ENABLE_REGWRITE_BUFFER(ah); ++ ++ for (r = 0; r < array->ia_rows; r++) { ++ REG_WRITE(ah, INI_RA(array, r, 0), data[r]); ++ DO_DELAY(*writecnt); ++ } ++ ++ REGWRITE_BUFFER_FLUSH(ah); ++} ++ + /** + * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters + * @rfbuf: +@@ -530,16 +558,16 @@ + eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); + + /* Setup Bank 0 Write */ +- RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); ++ ar5008_rf_bank_setup(ah->analogBank0Data, &ah->iniBank0, 1); + + /* Setup Bank 1 Write */ +- RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); ++ ar5008_rf_bank_setup(ah->analogBank1Data, &ah->iniBank1, 1); + + /* Setup Bank 2 Write */ +- RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); ++ ar5008_rf_bank_setup(ah->analogBank2Data, &ah->iniBank2, 1); + + /* Setup Bank 6 Write */ +- RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, ++ ar5008_rf_bank_setup(ah->analogBank3Data, &ah->iniBank3, + modesIndex); + { + int i; +@@ -569,7 +597,7 @@ + } + + /* Setup Bank 7 Setup */ +- RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); ++ ar5008_rf_bank_setup(ah->analogBank7Data, &ah->iniBank7, 1); + + /* Write Analog registers */ + REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, +@@ -729,6 +757,7 @@ + struct ath9k_channel *chan) + { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); ++ struct ath_common *common = ath9k_hw_common(ah); + int i, regWrites = 0; + struct ieee80211_channel *channel = chan->chan; + u32 modesIndex, freqIndex; +@@ -805,7 +834,8 @@ + REG_WRITE(ah, reg, val); + + if (reg >= 0x7800 && reg < 0x78a0 +- && ah->config.analog_shiftreg) { ++ && ah->config.analog_shiftreg ++ && (common->bus_ops->ath_bus_type != ATH_USB)) { + udelay(100); + } + +@@ -835,7 +865,8 @@ + REG_WRITE(ah, reg, val); + + if (reg >= 0x7800 && reg < 0x78a0 +- && ah->config.analog_shiftreg) { ++ && ah->config.analog_shiftreg ++ && (common->bus_ops->ath_bus_type != ATH_USB)) { + udelay(100); + } + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9002_calib.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9002_calib.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9002_calib.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9002_calib.c 2011-05-05 23:29:49.076485252 +0200 +@@ -26,6 +26,27 @@ + IQ_MISMATCH_CAL = BIT(2), + }; + ++static bool ar9002_hw_is_cal_supported(struct ath_hw *ah, ++ struct ath9k_channel *chan, ++ enum ar9002_cal_types cal_type) ++{ ++ bool supported = false; ++ switch (ah->supp_cals & cal_type) { ++ case IQ_MISMATCH_CAL: ++ /* Run IQ Mismatch for non-CCK only */ ++ if (!IS_CHAN_B(chan)) ++ supported = true; ++ break; ++ case ADC_GAIN_CAL: ++ case ADC_DC_CAL: ++ /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ ++ if (!IS_CHAN_B(chan) && ++ !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) ++ supported = true; ++ break; ++ } ++ return supported; ++} + + static void ar9002_hw_setup_calibration(struct ath_hw *ah, + struct ath9k_cal_list *currCal) +@@ -858,26 +879,32 @@ + if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { + ah->supp_cals = IQ_MISMATCH_CAL; + +- if (AR_SREV_9160_10_OR_LATER(ah) && +- !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) { ++ if (AR_SREV_9160_10_OR_LATER(ah)) + ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL; + ++ if (AR_SREV_9287(ah)) ++ ah->supp_cals &= ~ADC_GAIN_CAL; + ++ if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) { + INIT_CAL(&ah->adcgain_caldata); + INSERT_CAL(ah, &ah->adcgain_caldata); + ath_dbg(common, ATH_DBG_CALIBRATE, +- "enabling ADC Gain Calibration.\n"); ++ "enabling ADC Gain Calibration.\n"); ++ } + ++ if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) { + INIT_CAL(&ah->adcdc_caldata); + INSERT_CAL(ah, &ah->adcdc_caldata); + ath_dbg(common, ATH_DBG_CALIBRATE, +- "enabling ADC DC Calibration.\n"); ++ "enabling ADC DC Calibration.\n"); + } + +- INIT_CAL(&ah->iq_caldata); +- INSERT_CAL(ah, &ah->iq_caldata); +- ath_dbg(common, ATH_DBG_CALIBRATE, +- "enabling IQ Calibration.\n"); ++ if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) { ++ INIT_CAL(&ah->iq_caldata); ++ INSERT_CAL(ah, &ah->iq_caldata); ++ ath_dbg(common, ATH_DBG_CALIBRATE, ++ "enabling IQ Calibration.\n"); ++ } + + ah->cal_list_curr = ah->cal_list; + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9002_mac.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9002_mac.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9002_mac.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9002_mac.c 2011-05-05 23:29:49.089485409 +0200 +@@ -290,7 +290,6 @@ + | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) + | SM(txPower, AR_XmitPower) + | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) +- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) + | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) + | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); + +@@ -311,6 +310,16 @@ + } + } + ++static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) ++{ ++ struct ar5416_desc *ads = AR5416DESC(ds); ++ ++ if (val) ++ ads->ds_ctl0 |= AR_ClrDestMask; ++ else ++ ads->ds_ctl0 &= ~AR_ClrDestMask; ++} ++ + static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, + void *lastds, + u32 durUpdateEn, u32 rtsctsRate, +@@ -415,17 +424,6 @@ + ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); + } + +-static void ar9002_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, +- u32 vmf) +-{ +- struct ar5416_desc *ads = AR5416DESC(ds); +- +- if (vmf) +- ads->ds_ctl0 |= AR_VirtMoreFrag; +- else +- ads->ds_ctl0 &= ~AR_VirtMoreFrag; +-} +- + void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 size, u32 flags) + { +@@ -459,5 +457,5 @@ + ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; + ops->clr11n_aggr = ar9002_hw_clr11n_aggr; + ops->set11n_burstduration = ar9002_hw_set11n_burstduration; +- ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag; ++ ops->set_clrdmask = ar9002_hw_set_clrdmask; + } +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9002_phy.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9002_phy.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9002_phy.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9002_phy.h 2011-05-05 23:29:49.007484419 +0200 +@@ -483,7 +483,11 @@ + #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000 + #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19 + ++#define AR_PHY_TX_PWRCTRL8 0xa278 ++ + #define AR_PHY_TX_PWRCTRL9 0xa27C ++ ++#define AR_PHY_TX_PWRCTRL10 0xa394 + #define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 + #define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 + #define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000 +@@ -495,6 +499,8 @@ + + #define AR_PHY_CH0_TX_PWRCTRL11 0xa398 + #define AR_PHY_CH1_TX_PWRCTRL11 0xb398 ++#define AR_PHY_CH0_TX_PWRCTRL12 0xa3dc ++#define AR_PHY_CH0_TX_PWRCTRL13 0xa3e0 + #define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00 + #define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10 + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h 2011-05-05 23:29:49.075485239 +0200 +@@ -34,10 +34,10 @@ + + static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ +- {0x0000a2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800}, +- {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000}, +- {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000}, +- {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, ++ {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, ++ {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, ++ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, +@@ -119,14 +119,14 @@ + {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, +- {0x0000b2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800}, +- {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000}, +- {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000}, +- {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +- {0x0000c2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800}, +- {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000}, +- {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000}, +- {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, ++ {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, ++ {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, ++ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, ++ {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, ++ {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, ++ {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, ++ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +@@ -835,10 +835,10 @@ + + static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ +- {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, +- {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, +- {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, +- {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, ++ {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, ++ {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, ++ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, +@@ -920,14 +920,14 @@ + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, +- {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, +- {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, +- {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, +- {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +- {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, +- {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, +- {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, +- {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, ++ {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, ++ {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, ++ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, ++ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, ++ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, ++ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, ++ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, + {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, + {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, +@@ -941,10 +941,10 @@ + + static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ +- {0x0000a2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, +- {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, +- {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, +- {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, ++ {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, ++ {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, ++ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, +@@ -1026,14 +1026,14 @@ + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, +- {0x0000b2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, +- {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, +- {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, +- {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +- {0x0000c2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, +- {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, +- {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, +- {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, ++ {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, ++ {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, ++ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, ++ {0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, ++ {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, ++ {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, ++ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, + {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +@@ -1307,10 +1307,10 @@ + + static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ +- {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, +- {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, +- {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, +- {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, ++ {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, ++ {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, ++ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, +@@ -1329,21 +1329,21 @@ + {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, +- {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, +- {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, +- {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83}, +- {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84}, +- {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3}, +- {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5}, +- {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9}, +- {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb}, +- {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, +- {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, +- {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, +- {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, +- {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, +- {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, +- {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861}, ++ {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81}, ++ {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83}, ++ {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84}, ++ {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3}, ++ {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5}, ++ {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9}, ++ {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb}, ++ {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, ++ {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, ++ {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, ++ {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, ++ {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, ++ {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, ++ {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, +@@ -1361,45 +1361,45 @@ + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, +- {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, +- {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, +- {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83}, +- {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84}, +- {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3}, +- {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5}, +- {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9}, +- {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb}, +- {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, +- {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, +- {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, +- {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, +- {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, +- {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, +- {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861}, ++ {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81}, ++ {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83}, ++ {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84}, ++ {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3}, ++ {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5}, ++ {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9}, ++ {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb}, ++ {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +- {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, +- {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, +- {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, +- {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, +- {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, +- {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, +- {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, +- {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, +- {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, +- {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, +- {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, +- {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, +- {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, +- {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, +- {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +- {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, +- {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, +- {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, +- {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000}, ++ {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501}, ++ {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501}, ++ {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03}, ++ {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04}, ++ {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04}, ++ {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, ++ {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, ++ {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, ++ {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, ++ {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, ++ {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, ++ {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, ++ {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, ++ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, ++ {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, ++ {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, ++ {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, ++ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_calib.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_calib.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_calib.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_calib.c 2011-05-05 23:29:49.064485107 +0200 +@@ -18,13 +18,13 @@ + #include "hw-ops.h" + #include "ar9003_phy.h" + +-#define MPASS 3 + #define MAX_MEASUREMENT 8 +-#define MAX_DIFFERENCE 10 ++#define MAX_MAG_DELTA 11 ++#define MAX_PHS_DELTA 10 + + struct coeff { +- int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS]; +- int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS]; ++ int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; ++ int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; + int iqc_coeff[2]; + }; + +@@ -185,17 +185,19 @@ + + /* Accumulate IQ cal measures for active chains */ + for (i = 0; i < AR5416_MAX_CHAINS; i++) { +- ah->totalPowerMeasI[i] += +- REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); +- ah->totalPowerMeasQ[i] += +- REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); +- ah->totalIqCorrMeas[i] += +- (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); +- ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, +- "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", +- ah->cal_samples, i, ah->totalPowerMeasI[i], +- ah->totalPowerMeasQ[i], +- ah->totalIqCorrMeas[i]); ++ if (ah->txchainmask & BIT(i)) { ++ ah->totalPowerMeasI[i] += ++ REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); ++ ah->totalPowerMeasQ[i] += ++ REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); ++ ah->totalIqCorrMeas[i] += ++ (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); ++ ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, ++ "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", ++ ah->cal_samples, i, ah->totalPowerMeasI[i], ++ ah->totalPowerMeasQ[i], ++ ah->totalIqCorrMeas[i]); ++ } + } + } + +@@ -608,36 +610,48 @@ + return true; + } + +-static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg) ++static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, ++ int max_delta) + { +- int diff[MPASS]; +- +- diff[0] = abs(mp_coeff[0] - mp_coeff[1]); +- diff[1] = abs(mp_coeff[1] - mp_coeff[2]); +- diff[2] = abs(mp_coeff[2] - mp_coeff[0]); +- +- if (diff[0] > MAX_DIFFERENCE && +- diff[1] > MAX_DIFFERENCE && +- diff[2] > MAX_DIFFERENCE) +- return false; +- +- if (diff[0] <= diff[1] && diff[0] <= diff[2]) +- *mp_avg = (mp_coeff[0] + mp_coeff[1]) / 2; +- else if (diff[1] <= diff[2]) +- *mp_avg = (mp_coeff[1] + mp_coeff[2]) / 2; +- else +- *mp_avg = (mp_coeff[2] + mp_coeff[0]) / 2; ++ int mp_max = -64, max_idx = 0; ++ int mp_min = 63, min_idx = 0; ++ int mp_avg = 0, i, outlier_idx = 0; ++ ++ /* find min/max mismatch across all calibrated gains */ ++ for (i = 0; i < nmeasurement; i++) { ++ mp_avg += mp_coeff[i]; ++ if (mp_coeff[i] > mp_max) { ++ mp_max = mp_coeff[i]; ++ max_idx = i; ++ } else if (mp_coeff[i] < mp_min) { ++ mp_min = mp_coeff[i]; ++ min_idx = i; ++ } ++ } + +- return true; ++ /* find average (exclude max abs value) */ ++ for (i = 0; i < nmeasurement; i++) { ++ if ((abs(mp_coeff[i]) < abs(mp_max)) || ++ (abs(mp_coeff[i]) < abs(mp_min))) ++ mp_avg += mp_coeff[i]; ++ } ++ mp_avg /= (nmeasurement - 1); ++ ++ /* detect outlier */ ++ if (abs(mp_max - mp_min) > max_delta) { ++ if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg)) ++ outlier_idx = max_idx; ++ else ++ outlier_idx = min_idx; ++ } ++ mp_coeff[outlier_idx] = mp_avg; + } + + static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, + u8 num_chains, + struct coeff *coeff) + { +- struct ath_common *common = ath9k_hw_common(ah); + int i, im, nmeasurement; +- int magnitude, phase; + u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; + + memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff)); +@@ -657,37 +671,28 @@ + + /* Load the average of 2 passes */ + for (i = 0; i < num_chains; i++) { +- if (AR_SREV_9485(ah)) +- nmeasurement = REG_READ_FIELD(ah, +- AR_PHY_TX_IQCAL_STATUS_B0_9485, +- AR_PHY_CALIBRATED_GAINS_0); +- else +- nmeasurement = REG_READ_FIELD(ah, +- AR_PHY_TX_IQCAL_STATUS_B0, +- AR_PHY_CALIBRATED_GAINS_0); ++ nmeasurement = REG_READ_FIELD(ah, ++ AR_PHY_TX_IQCAL_STATUS_B0, ++ AR_PHY_CALIBRATED_GAINS_0); + + if (nmeasurement > MAX_MEASUREMENT) + nmeasurement = MAX_MEASUREMENT; + +- for (im = 0; im < nmeasurement; im++) { +- /* +- * Determine which 2 passes are closest and compute avg +- * magnitude +- */ +- if (!ar9003_hw_compute_closest_pass_and_avg(coeff->mag_coeff[i][im], +- &magnitude)) +- goto disable_txiqcal; ++ /* detect outlier only if nmeasurement > 1 */ ++ if (nmeasurement > 1) { ++ /* Detect magnitude outlier */ ++ ar9003_hw_detect_outlier(coeff->mag_coeff[i], ++ nmeasurement, MAX_MAG_DELTA); ++ ++ /* Detect phase outlier */ ++ ar9003_hw_detect_outlier(coeff->phs_coeff[i], ++ nmeasurement, MAX_PHS_DELTA); ++ } + +- /* +- * Determine which 2 passes are closest and compute avg +- * phase +- */ +- if (!ar9003_hw_compute_closest_pass_and_avg(coeff->phs_coeff[i][im], +- &phase)) +- goto disable_txiqcal; ++ for (im = 0; im < nmeasurement; im++) { + +- coeff->iqc_coeff[0] = (magnitude & 0x7f) | +- ((phase & 0x7f) << 7); ++ coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) | ++ ((coeff->phs_coeff[i][im] & 0x7f) << 7); + + if ((im % 2) == 0) + REG_RMW_FIELD(ah, tx_corr_coeff[im][i], +@@ -707,141 +712,37 @@ + + return; + +-disable_txiqcal: +- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, +- AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x0); +- REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, +- AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x0); +- +- ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n"); + } + +-static void ar9003_hw_tx_iq_cal(struct ath_hw *ah) ++static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) + { + struct ath_common *common = ath9k_hw_common(ah); +- static const u32 txiqcal_status[AR9300_MAX_CHAINS] = { +- AR_PHY_TX_IQCAL_STATUS_B0, +- AR_PHY_TX_IQCAL_STATUS_B1, +- AR_PHY_TX_IQCAL_STATUS_B2, +- }; +- static const u32 chan_info_tab[] = { +- AR_PHY_CHAN_INFO_TAB_0, +- AR_PHY_CHAN_INFO_TAB_1, +- AR_PHY_CHAN_INFO_TAB_2, +- }; +- struct coeff coeff; +- s32 iq_res[6]; +- s32 i, j, ip, im, nmeasurement; +- u8 nchains = get_streams(common->tx_chainmask); +- +- for (ip = 0; ip < MPASS; ip++) { +- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, +- AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, +- DELPT); +- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, +- AR_PHY_TX_IQCAL_START_DO_CAL, +- AR_PHY_TX_IQCAL_START_DO_CAL); +- +- if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, +- AR_PHY_TX_IQCAL_START_DO_CAL, +- 0, AH_WAIT_TIMEOUT)) { +- ath_dbg(common, ATH_DBG_CALIBRATE, +- "Tx IQ Cal not complete.\n"); +- goto TX_IQ_CAL_FAILED; +- } +- +- nmeasurement = REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0, +- AR_PHY_CALIBRATED_GAINS_0); +- if (nmeasurement > MAX_MEASUREMENT) +- nmeasurement = MAX_MEASUREMENT; +- +- for (i = 0; i < nchains; i++) { +- ath_dbg(common, ATH_DBG_CALIBRATE, +- "Doing Tx IQ Cal for chain %d.\n", i); +- for (im = 0; im < nmeasurement; im++) { +- if (REG_READ(ah, txiqcal_status[i]) & +- AR_PHY_TX_IQCAL_STATUS_FAILED) { +- ath_dbg(common, ATH_DBG_CALIBRATE, +- "Tx IQ Cal failed for chain %d.\n", i); +- goto TX_IQ_CAL_FAILED; +- } +- +- for (j = 0; j < 3; j++) { +- u8 idx = 2 * j, +- offset = 4 * (3 * im + j); +- +- REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, +- AR_PHY_CHAN_INFO_TAB_S2_READ, +- 0); +- +- /* 32 bits */ +- iq_res[idx] = REG_READ(ah, +- chan_info_tab[i] + +- offset); +- +- REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, +- AR_PHY_CHAN_INFO_TAB_S2_READ, +- 1); +- +- /* 16 bits */ +- iq_res[idx+1] = 0xffff & REG_READ(ah, +- chan_info_tab[i] + +- offset); +- +- ath_dbg(common, ATH_DBG_CALIBRATE, +- "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n", +- idx, iq_res[idx], idx+1, iq_res[idx+1]); +- } +- +- if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, +- coeff.iqc_coeff)) { +- ath_dbg(common, ATH_DBG_CALIBRATE, +- "Failed in calculation of IQ correction.\n"); +- goto TX_IQ_CAL_FAILED; +- } +- coeff.mag_coeff[i][im][ip] = +- coeff.iqc_coeff[0] & 0x7f; +- coeff.phs_coeff[i][im][ip] = +- (coeff.iqc_coeff[0] >> 7) & 0x7f; +- +- if (coeff.mag_coeff[i][im][ip] > 63) +- coeff.mag_coeff[i][im][ip] -= 128; +- if (coeff.phs_coeff[i][im][ip] > 63) +- coeff.phs_coeff[i][im][ip] -= 128; +- +- } +- } +- } +- +- ar9003_hw_tx_iqcal_load_avg_2_passes(ah, nchains, &coeff); +- +- return; +- +-TX_IQ_CAL_FAILED: +- ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n"); +-} +- +-static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) +-{ + u8 tx_gain_forced; + +- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1_9485, +- AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT); + tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN, + AR_PHY_TXGAIN_FORCE); + if (tx_gain_forced) + REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, + AR_PHY_TXGAIN_FORCE, 0); + +- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START_9485, +- AR_PHY_TX_IQCAL_START_DO_CAL_9485, 1); ++ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, ++ AR_PHY_TX_IQCAL_START_DO_CAL, 1); ++ ++ if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, ++ AR_PHY_TX_IQCAL_START_DO_CAL, 0, ++ AH_WAIT_TIMEOUT)) { ++ ath_dbg(common, ATH_DBG_CALIBRATE, ++ "Tx IQ Cal is not completed.\n"); ++ return false; ++ } ++ return true; + } + + static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) + { + struct ath_common *common = ath9k_hw_common(ah); + const u32 txiqcal_status[AR9300_MAX_CHAINS] = { +- AR_PHY_TX_IQCAL_STATUS_B0_9485, ++ AR_PHY_TX_IQCAL_STATUS_B0, + AR_PHY_TX_IQCAL_STATUS_B1, + AR_PHY_TX_IQCAL_STATUS_B2, + }; +@@ -853,7 +754,7 @@ + struct coeff coeff; + s32 iq_res[6]; + u8 num_chains = 0; +- int i, ip, im, j; ++ int i, im, j; + int nmeasurement; + + for (i = 0; i < AR9300_MAX_CHAINS; i++) { +@@ -861,71 +762,69 @@ + num_chains++; + } + +- for (ip = 0; ip < MPASS; ip++) { +- for (i = 0; i < num_chains; i++) { +- nmeasurement = REG_READ_FIELD(ah, +- AR_PHY_TX_IQCAL_STATUS_B0_9485, +- AR_PHY_CALIBRATED_GAINS_0); +- if (nmeasurement > MAX_MEASUREMENT) +- nmeasurement = MAX_MEASUREMENT; ++ for (i = 0; i < num_chains; i++) { ++ nmeasurement = REG_READ_FIELD(ah, ++ AR_PHY_TX_IQCAL_STATUS_B0, ++ AR_PHY_CALIBRATED_GAINS_0); ++ if (nmeasurement > MAX_MEASUREMENT) ++ nmeasurement = MAX_MEASUREMENT; ++ ++ for (im = 0; im < nmeasurement; im++) { ++ ath_dbg(common, ATH_DBG_CALIBRATE, ++ "Doing Tx IQ Cal for chain %d.\n", i); + +- for (im = 0; im < nmeasurement; im++) { ++ if (REG_READ(ah, txiqcal_status[i]) & ++ AR_PHY_TX_IQCAL_STATUS_FAILED) { + ath_dbg(common, ATH_DBG_CALIBRATE, +- "Doing Tx IQ Cal for chain %d.\n", i); +- +- if (REG_READ(ah, txiqcal_status[i]) & +- AR_PHY_TX_IQCAL_STATUS_FAILED) { +- ath_dbg(common, ATH_DBG_CALIBRATE, + "Tx IQ Cal failed for chain %d.\n", i); +- goto tx_iqcal_fail; +- } ++ goto tx_iqcal_fail; ++ } + +- for (j = 0; j < 3; j++) { +- u32 idx = 2 * j, offset = 4 * (3 * im + j); ++ for (j = 0; j < 3; j++) { ++ u32 idx = 2 * j, offset = 4 * (3 * im + j); + +- REG_RMW_FIELD(ah, ++ REG_RMW_FIELD(ah, + AR_PHY_CHAN_INFO_MEMORY, + AR_PHY_CHAN_INFO_TAB_S2_READ, + 0); + +- /* 32 bits */ +- iq_res[idx] = REG_READ(ah, +- chan_info_tab[i] + +- offset); ++ /* 32 bits */ ++ iq_res[idx] = REG_READ(ah, ++ chan_info_tab[i] + ++ offset); + +- REG_RMW_FIELD(ah, ++ REG_RMW_FIELD(ah, + AR_PHY_CHAN_INFO_MEMORY, + AR_PHY_CHAN_INFO_TAB_S2_READ, + 1); + +- /* 16 bits */ +- iq_res[idx + 1] = 0xffff & REG_READ(ah, +- chan_info_tab[i] + offset); +- +- ath_dbg(common, ATH_DBG_CALIBRATE, +- "IQ RES[%d]=0x%x" +- "IQ_RES[%d]=0x%x\n", +- idx, iq_res[idx], idx + 1, +- iq_res[idx + 1]); +- } ++ /* 16 bits */ ++ iq_res[idx + 1] = 0xffff & REG_READ(ah, ++ chan_info_tab[i] + offset); + +- if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, +- coeff.iqc_coeff)) { +- ath_dbg(common, ATH_DBG_CALIBRATE, +- "Failed in calculation of IQ correction.\n"); +- goto tx_iqcal_fail; +- } ++ ath_dbg(common, ATH_DBG_CALIBRATE, ++ "IQ RES[%d]=0x%x" ++ "IQ_RES[%d]=0x%x\n", ++ idx, iq_res[idx], idx + 1, ++ iq_res[idx + 1]); ++ } + +- coeff.mag_coeff[i][im][ip] = +- coeff.iqc_coeff[0] & 0x7f; +- coeff.phs_coeff[i][im][ip] = +- (coeff.iqc_coeff[0] >> 7) & 0x7f; +- +- if (coeff.mag_coeff[i][im][ip] > 63) +- coeff.mag_coeff[i][im][ip] -= 128; +- if (coeff.phs_coeff[i][im][ip] > 63) +- coeff.phs_coeff[i][im][ip] -= 128; ++ if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, ++ coeff.iqc_coeff)) { ++ ath_dbg(common, ATH_DBG_CALIBRATE, ++ "Failed in calculation of \ ++ IQ correction.\n"); ++ goto tx_iqcal_fail; + } ++ ++ coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f; ++ coeff.phs_coeff[i][im] = ++ (coeff.iqc_coeff[0] >> 7) & 0x7f; ++ ++ if (coeff.mag_coeff[i][im] > 63) ++ coeff.mag_coeff[i][im] -= 128; ++ if (coeff.phs_coeff[i][im] > 63) ++ coeff.phs_coeff[i][im] -= 128; + } + } + ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff); +@@ -940,31 +839,37 @@ + struct ath9k_channel *chan) + { + struct ath_common *common = ath9k_hw_common(ah); ++ struct ath9k_hw_capabilities *pCap = &ah->caps; + int val; ++ bool txiqcal_done = false; + + val = REG_READ(ah, AR_ENT_OTP); + ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val); + +- if (AR_SREV_9485(ah)) +- ar9003_hw_set_chain_masks(ah, 0x1, 0x1); +- else if (val & AR_ENT_OTP_CHAIN2_DISABLE) ++ /* Configure rx/tx chains before running AGC/TxiQ cals */ ++ if (val & AR_ENT_OTP_CHAIN2_DISABLE) + ar9003_hw_set_chain_masks(ah, 0x3, 0x3); + else +- /* +- * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain +- * mode before running AGC/TxIQ cals +- */ +- ar9003_hw_set_chain_masks(ah, 0x7, 0x7); ++ ar9003_hw_set_chain_masks(ah, pCap->rx_chainmask, ++ pCap->tx_chainmask); + + /* Do Tx IQ Calibration */ +- if (AR_SREV_9485(ah)) +- ar9003_hw_tx_iq_cal_run(ah); +- else +- ar9003_hw_tx_iq_cal(ah); ++ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, ++ AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, ++ DELPT); + +- REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); +- udelay(5); +- REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); ++ /* ++ * For AR9485 or later chips, TxIQ cal runs as part of ++ * AGC calibration ++ */ ++ if (AR_SREV_9485_OR_LATER(ah)) ++ txiqcal_done = true; ++ else { ++ txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); ++ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); ++ udelay(5); ++ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); ++ } + + /* Calibrate the AGC */ + REG_WRITE(ah, AR_PHY_AGC_CONTROL, +@@ -979,7 +884,7 @@ + return false; + } + +- if (AR_SREV_9485(ah)) ++ if (txiqcal_done) + ar9003_hw_tx_iq_cal_post_proc(ah); + + /* Revert chainmasks to their original values before NF cal */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c 2011-05-05 23:29:49.096485493 +0200 +@@ -3217,7 +3217,6 @@ + u8 *word, int length, int mdata_size) + { + struct ath_common *common = ath9k_hw_common(ah); +- u8 *dptr; + const struct ar9300_eeprom *eep = NULL; + + switch (code) { +@@ -3235,7 +3234,6 @@ + break; + case _CompressBlock: + if (reference == 0) { +- dptr = mptr; + } else { + eep = ar9003_eeprom_struct_find_by_id(reference); + if (eep == NULL) { +@@ -3448,9 +3446,13 @@ + REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); + else { + REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); +- REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPABIASLVL_MSB, +- bias >> 2); +- REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPASHORT2GND, 1); ++ if (!AR_SREV_9340(ah)) { ++ REG_RMW_FIELD(ah, AR_CH0_THERM, ++ AR_CH0_THERM_XPABIASLVL_MSB, ++ bias >> 2); ++ REG_RMW_FIELD(ah, AR_CH0_THERM, ++ AR_CH0_THERM_XPASHORT2GND, 1); ++ } + } + } + +@@ -3497,23 +3499,28 @@ + + static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) + { ++ int chain; ++ static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = { ++ AR_PHY_SWITCH_CHAIN_0, ++ AR_PHY_SWITCH_CHAIN_1, ++ AR_PHY_SWITCH_CHAIN_2, ++ }; ++ + u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz); ++ + REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_ALL, value); + + value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz); + REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); + +- value = ar9003_hw_ant_ctrl_chain_get(ah, 0, is2ghz); +- REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value); +- +- if (!AR_SREV_9485(ah)) { +- value = ar9003_hw_ant_ctrl_chain_get(ah, 1, is2ghz); +- REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL, +- value); +- +- value = ar9003_hw_ant_ctrl_chain_get(ah, 2, is2ghz); +- REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL, +- value); ++ for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { ++ if ((ah->rxchainmask & BIT(chain)) || ++ (ah->txchainmask & BIT(chain))) { ++ value = ar9003_hw_ant_ctrl_chain_get(ah, chain, ++ is2ghz); ++ REG_RMW_FIELD(ah, switch_chain_reg[chain], ++ AR_SWITCH_TABLE_ALL, value); ++ } + } + + if (AR_SREV_9485(ah)) { +@@ -3634,13 +3641,16 @@ + + /* Test value. if 0 then attenuation is unused. Don't load anything. */ + for (i = 0; i < 3; i++) { +- value = ar9003_hw_atten_chain_get(ah, i, chan); +- REG_RMW_FIELD(ah, ext_atten_reg[i], +- AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); +- +- value = ar9003_hw_atten_chain_get_margin(ah, i, chan); +- REG_RMW_FIELD(ah, ext_atten_reg[i], +- AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value); ++ if (ah->txchainmask & BIT(i)) { ++ value = ar9003_hw_atten_chain_get(ah, i, chan); ++ REG_RMW_FIELD(ah, ext_atten_reg[i], ++ AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); ++ ++ value = ar9003_hw_atten_chain_get_margin(ah, i, chan); ++ REG_RMW_FIELD(ah, ext_atten_reg[i], ++ AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, ++ value); ++ } + } + } + +@@ -3749,8 +3759,9 @@ + ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan)); + ar9003_hw_drive_strength_apply(ah); + ar9003_hw_atten_apply(ah, chan); +- ar9003_hw_internal_regulator_apply(ah); +- if (AR_SREV_9485(ah)) ++ if (!AR_SREV_9340(ah)) ++ ar9003_hw_internal_regulator_apply(ah); ++ if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) + ar9003_hw_apply_tuning_caps(ah); + } + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_hw.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_hw.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_hw.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_hw.c 2011-05-05 23:29:49.044484865 +0200 +@@ -18,6 +18,7 @@ + #include "ar9003_mac.h" + #include "ar9003_2p2_initvals.h" + #include "ar9485_initvals.h" ++#include "ar9340_initvals.h" + + /* General hardware code for the AR9003 hadware family */ + +@@ -28,109 +29,105 @@ + */ + static void ar9003_hw_init_mode_regs(struct ath_hw *ah) + { +- if (AR_SREV_9485_11(ah)) { ++ if (AR_SREV_9340(ah)) { + /* mac */ + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], +- ar9485_1_1_mac_core, +- ARRAY_SIZE(ar9485_1_1_mac_core), 2); ++ ar9340_1p0_mac_core, ++ ARRAY_SIZE(ar9340_1p0_mac_core), 2); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], +- ar9485_1_1_mac_postamble, +- ARRAY_SIZE(ar9485_1_1_mac_postamble), 5); ++ ar9340_1p0_mac_postamble, ++ ARRAY_SIZE(ar9340_1p0_mac_postamble), 5); + + /* bb */ +- INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_1, +- ARRAY_SIZE(ar9485_1_1), 2); ++ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], +- ar9485_1_1_baseband_core, +- ARRAY_SIZE(ar9485_1_1_baseband_core), 2); ++ ar9340_1p0_baseband_core, ++ ARRAY_SIZE(ar9340_1p0_baseband_core), 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], +- ar9485_1_1_baseband_postamble, +- ARRAY_SIZE(ar9485_1_1_baseband_postamble), 5); ++ ar9340_1p0_baseband_postamble, ++ ARRAY_SIZE(ar9340_1p0_baseband_postamble), 5); + + /* radio */ + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], +- ar9485_1_1_radio_core, +- ARRAY_SIZE(ar9485_1_1_radio_core), 2); ++ ar9340_1p0_radio_core, ++ ARRAY_SIZE(ar9340_1p0_radio_core), 2); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], +- ar9485_1_1_radio_postamble, +- ARRAY_SIZE(ar9485_1_1_radio_postamble), 2); ++ ar9340_1p0_radio_postamble, ++ ARRAY_SIZE(ar9340_1p0_radio_postamble), 5); + + /* soc */ + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], +- ar9485_1_1_soc_preamble, +- ARRAY_SIZE(ar9485_1_1_soc_preamble), 2); ++ ar9340_1p0_soc_preamble, ++ ARRAY_SIZE(ar9340_1p0_soc_preamble), 2); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); +- INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0); ++ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], ++ ar9340_1p0_soc_postamble, ++ ARRAY_SIZE(ar9340_1p0_soc_postamble), 5); + + /* rx/tx gain */ + INIT_INI_ARRAY(&ah->iniModesRxGain, +- ar9485_common_rx_gain_1_1, +- ARRAY_SIZE(ar9485_common_rx_gain_1_1), 2); ++ ar9340Common_wo_xlna_rx_gain_table_1p0, ++ ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0), ++ 5); + INIT_INI_ARRAY(&ah->iniModesTxGain, +- ar9485_modes_lowest_ob_db_tx_gain_1_1, +- ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), ++ ar9340Modes_high_ob_db_tx_gain_table_1p0, ++ ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0), + 5); + +- /* Load PCIE SERDES settings from INI */ +- +- /* Awake Setting */ +- +- INIT_INI_ARRAY(&ah->iniPcieSerdes, +- ar9485_1_1_pcie_phy_clkreq_disable_L1, +- ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), +- 2); +- +- /* Sleep Setting */ ++ INIT_INI_ARRAY(&ah->iniModesAdditional, ++ ar9340Modes_fast_clock_1p0, ++ ARRAY_SIZE(ar9340Modes_fast_clock_1p0), ++ 3); + +- INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, +- ar9485_1_1_pcie_phy_clkreq_disable_L1, +- ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), ++ INIT_INI_ARRAY(&ah->iniModesAdditional_40M, ++ ar9340_1p0_radio_core_40M, ++ ARRAY_SIZE(ar9340_1p0_radio_core_40M), + 2); +- } else if (AR_SREV_9485(ah)) { ++ } else if (AR_SREV_9485_11(ah)) { + /* mac */ + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], +- ar9485_1_0_mac_core, +- ARRAY_SIZE(ar9485_1_0_mac_core), 2); ++ ar9485_1_1_mac_core, ++ ARRAY_SIZE(ar9485_1_1_mac_core), 2); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], +- ar9485_1_0_mac_postamble, +- ARRAY_SIZE(ar9485_1_0_mac_postamble), 5); ++ ar9485_1_1_mac_postamble, ++ ARRAY_SIZE(ar9485_1_1_mac_postamble), 5); + + /* bb */ +- INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_0, +- ARRAY_SIZE(ar9485_1_0), 2); ++ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_1, ++ ARRAY_SIZE(ar9485_1_1), 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], +- ar9485_1_0_baseband_core, +- ARRAY_SIZE(ar9485_1_0_baseband_core), 2); ++ ar9485_1_1_baseband_core, ++ ARRAY_SIZE(ar9485_1_1_baseband_core), 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], +- ar9485_1_0_baseband_postamble, +- ARRAY_SIZE(ar9485_1_0_baseband_postamble), 5); ++ ar9485_1_1_baseband_postamble, ++ ARRAY_SIZE(ar9485_1_1_baseband_postamble), 5); + + /* radio */ + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], +- ar9485_1_0_radio_core, +- ARRAY_SIZE(ar9485_1_0_radio_core), 2); ++ ar9485_1_1_radio_core, ++ ARRAY_SIZE(ar9485_1_1_radio_core), 2); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], +- ar9485_1_0_radio_postamble, +- ARRAY_SIZE(ar9485_1_0_radio_postamble), 2); ++ ar9485_1_1_radio_postamble, ++ ARRAY_SIZE(ar9485_1_1_radio_postamble), 2); + + /* soc */ + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], +- ar9485_1_0_soc_preamble, +- ARRAY_SIZE(ar9485_1_0_soc_preamble), 2); ++ ar9485_1_1_soc_preamble, ++ ARRAY_SIZE(ar9485_1_1_soc_preamble), 2); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0); + + /* rx/tx gain */ + INIT_INI_ARRAY(&ah->iniModesRxGain, +- ar9485Common_rx_gain_1_0, +- ARRAY_SIZE(ar9485Common_rx_gain_1_0), 2); ++ ar9485Common_wo_xlna_rx_gain_1_1, ++ ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); + INIT_INI_ARRAY(&ah->iniModesTxGain, +- ar9485Modes_lowest_ob_db_tx_gain_1_0, +- ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0), ++ ar9485_modes_lowest_ob_db_tx_gain_1_1, ++ ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), + 5); + + /* Load PCIE SERDES settings from INI */ +@@ -138,15 +135,15 @@ + /* Awake Setting */ + + INIT_INI_ARRAY(&ah->iniPcieSerdes, +- ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1, +- ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1), ++ ar9485_1_1_pcie_phy_clkreq_disable_L1, ++ ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), + 2); + + /* Sleep Setting */ + + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, +- ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1, +- ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1), ++ ar9485_1_1_pcie_phy_clkreq_disable_L1, ++ ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), + 2); + } else { + /* mac */ +@@ -223,15 +220,15 @@ + switch (ar9003_hw_get_tx_gain_idx(ah)) { + case 0: + default: +- if (AR_SREV_9485_11(ah)) ++ if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, +- ar9485_modes_lowest_ob_db_tx_gain_1_1, +- ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), ++ ar9340Modes_lowest_ob_db_tx_gain_table_1p0, ++ ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); +- else if (AR_SREV_9485(ah)) ++ else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, +- ar9485Modes_lowest_ob_db_tx_gain_1_0, +- ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0), ++ ar9485_modes_lowest_ob_db_tx_gain_1_1, ++ ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), + 5); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, +@@ -240,15 +237,15 @@ + 5); + break; + case 1: +- if (AR_SREV_9485_11(ah)) ++ if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, +- ar9485Modes_high_ob_db_tx_gain_1_1, +- ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1), ++ ar9340Modes_lowest_ob_db_tx_gain_table_1p0, ++ ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); +- else if (AR_SREV_9485(ah)) ++ else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, +- ar9485Modes_high_ob_db_tx_gain_1_0, +- ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_0), ++ ar9485Modes_high_ob_db_tx_gain_1_1, ++ ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1), + 5); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, +@@ -257,15 +254,15 @@ + 5); + break; + case 2: +- if (AR_SREV_9485_11(ah)) ++ if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, +- ar9485Modes_low_ob_db_tx_gain_1_1, +- ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1), ++ ar9340Modes_lowest_ob_db_tx_gain_table_1p0, ++ ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); +- else if (AR_SREV_9485(ah)) ++ else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, +- ar9485Modes_low_ob_db_tx_gain_1_0, +- ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_0), ++ ar9485Modes_low_ob_db_tx_gain_1_1, ++ ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1), + 5); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, +@@ -274,15 +271,15 @@ + 5); + break; + case 3: +- if (AR_SREV_9485_11(ah)) ++ if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, +- ar9485Modes_high_power_tx_gain_1_1, +- ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1), ++ ar9340Modes_lowest_ob_db_tx_gain_table_1p0, ++ ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); +- else if (AR_SREV_9485(ah)) ++ else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, +- ar9485Modes_high_power_tx_gain_1_0, +- ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_0), ++ ar9485Modes_high_power_tx_gain_1_1, ++ ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1), + 5); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, +@@ -298,15 +295,15 @@ + switch (ar9003_hw_get_rx_gain_idx(ah)) { + case 0: + default: +- if (AR_SREV_9485_11(ah)) ++ if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, +- ar9485_common_rx_gain_1_1, +- ARRAY_SIZE(ar9485_common_rx_gain_1_1), ++ ar9340Common_rx_gain_table_1p0, ++ ARRAY_SIZE(ar9340Common_rx_gain_table_1p0), + 2); +- else if (AR_SREV_9485(ah)) ++ else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, +- ar9485Common_rx_gain_1_0, +- ARRAY_SIZE(ar9485Common_rx_gain_1_0), ++ ar9485Common_wo_xlna_rx_gain_1_1, ++ ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), + 2); + else + INIT_INI_ARRAY(&ah->iniModesRxGain, +@@ -315,15 +312,15 @@ + 2); + break; + case 1: +- if (AR_SREV_9485_11(ah)) ++ if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, +- ar9485Common_wo_xlna_rx_gain_1_1, +- ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), ++ ar9340Common_wo_xlna_rx_gain_table_1p0, ++ ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0), + 2); +- else if (AR_SREV_9485(ah)) ++ else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, +- ar9485Common_wo_xlna_rx_gain_1_0, +- ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_0), ++ ar9485Common_wo_xlna_rx_gain_1_1, ++ ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), + 2); + else + INIT_INI_ARRAY(&ah->iniModesRxGain, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_mac.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_mac.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_mac.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_mac.c 2011-05-05 23:29:49.081485313 +0200 +@@ -329,7 +329,6 @@ + | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) + | SM(txpower, AR_XmitPower) + | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) +- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) + | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) + | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0); + +@@ -350,6 +349,16 @@ + ads->ctl22 = 0; + } + ++static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) ++{ ++ struct ar9003_txc *ads = (struct ar9003_txc *) ds; ++ ++ if (val) ++ ads->ctl11 |= AR_ClrDestMask; ++ else ++ ads->ctl11 &= ~AR_ClrDestMask; ++} ++ + static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, + void *lastds, + u32 durUpdateEn, u32 rtsctsRate, +@@ -485,17 +494,6 @@ + + } + +-static void ar9003_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, +- u32 vmf) +-{ +- struct ar9003_txc *ads = (struct ar9003_txc *) ds; +- +- if (vmf) +- ads->ctl11 |= AR_VirtMoreFrag; +- else +- ads->ctl11 &= ~AR_VirtMoreFrag; +-} +- + void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains) + { + struct ar9003_txc *ads = ds; +@@ -521,7 +519,7 @@ + ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; + ops->clr11n_aggr = ar9003_hw_clr11n_aggr; + ops->set11n_burstduration = ar9003_hw_set11n_burstduration; +- ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag; ++ ops->set_clrdmask = ar9003_hw_set_clrdmask; + } + + void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_phy.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_phy.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_phy.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_phy.c 2011-05-05 23:29:49.076485252 +0200 +@@ -75,16 +75,42 @@ + freq = centers.synth_center; + + if (freq < 4800) { /* 2 GHz, fractional mode */ +- if (AR_SREV_9485(ah)) +- channelSel = CHANSEL_2G_9485(freq); +- else ++ if (AR_SREV_9485(ah)) { ++ u32 chan_frac; ++ ++ /* ++ * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0 ++ * ndiv = ((chan_mhz * 4) / 3) / freq_ref; ++ * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 ++ */ ++ channelSel = (freq * 4) / 120; ++ chan_frac = (((freq * 4) % 120) * 0x20000) / 120; ++ channelSel = (channelSel << 17) | chan_frac; ++ } else if (AR_SREV_9340(ah)) { ++ if (ah->is_clk_25mhz) { ++ u32 chan_frac; ++ ++ channelSel = (freq * 2) / 75; ++ chan_frac = (((freq * 2) % 75) * 0x20000) / 75; ++ channelSel = (channelSel << 17) | chan_frac; ++ } else ++ channelSel = CHANSEL_2G(freq) >> 1; ++ } else + channelSel = CHANSEL_2G(freq); + /* Set to 2G mode */ + bMode = 1; + } else { +- channelSel = CHANSEL_5G(freq); +- /* Doubler is ON, so, divide channelSel by 2. */ +- channelSel >>= 1; ++ if (AR_SREV_9340(ah) && ah->is_clk_25mhz) { ++ u32 chan_frac; ++ ++ channelSel = (freq * 2) / 75; ++ chan_frac = ((freq % 75) * 0x20000) / 75; ++ channelSel = (channelSel << 17) | chan_frac; ++ } else { ++ channelSel = CHANSEL_5G(freq); ++ /* Doubler is ON, so, divide channelSel by 2. */ ++ channelSel >>= 1; ++ } + /* Set to 5G mode */ + bMode = 0; + } +@@ -142,7 +168,7 @@ + * is out-of-band and can be ignored. + */ + +- if (AR_SREV_9485(ah)) { ++ if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) { + spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah, + IS_CHAN_2GHZ(chan)); + if (spur_fbin_ptr[0] == 0) /* No spur */ +@@ -167,7 +193,7 @@ + + for (i = 0; i < max_spur_cnts; i++) { + negative = 0; +- if (AR_SREV_9485(ah)) ++ if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) + cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i], + IS_CHAN_2GHZ(chan)) - synth_freq; + else +@@ -401,7 +427,7 @@ + + ar9003_hw_spur_ofdm_clear(ah); + +- for (i = 0; spurChansPtr[i] && i < 5; i++) { ++ for (i = 0; i < AR_EEPROM_MODAL_SPURS && spurChansPtr[i]; i++) { + freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq; + if (abs(freq_offset) < range) { + ar9003_hw_spur_ofdm_work(ah, chan, freq_offset); +@@ -590,29 +616,25 @@ + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + unsigned int regWrites = 0, i; + struct ieee80211_channel *channel = chan->chan; +- u32 modesIndex, freqIndex; ++ u32 modesIndex; + + switch (chan->chanmode) { + case CHANNEL_A: + case CHANNEL_A_HT20: + modesIndex = 1; +- freqIndex = 1; + break; + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + modesIndex = 2; +- freqIndex = 1; + break; + case CHANNEL_G: + case CHANNEL_G_HT20: + case CHANNEL_B: + modesIndex = 4; +- freqIndex = 2; + break; + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + modesIndex = 3; +- freqIndex = 2; + break; + + default: +@@ -637,6 +659,9 @@ + REG_WRITE_ARRAY(&ah->iniModesAdditional, + modesIndex, regWrites); + ++ if (AR_SREV_9340(ah) && !ah->is_clk_25mhz) ++ REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites); ++ + ar9003_hw_override_ini(ah); + ar9003_hw_set_channel_regs(ah, chan); + ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_phy.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_phy.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9003_phy.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9003_phy.h 2011-05-05 23:29:49.097485505 +0200 +@@ -548,15 +548,12 @@ + + #define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300) + +-#define AR_PHY_TX_IQCAL_START_9485 (AR_SM_BASE + 0x3c4) +-#define AR_PHY_TX_IQCAL_START_DO_CAL_9485 0x80000000 +-#define AR_PHY_TX_IQCAL_START_DO_CAL_9485_S 31 +-#define AR_PHY_TX_IQCAL_CONTROL_1_9485 (AR_SM_BASE + 0x3c8) +-#define AR_PHY_TX_IQCAL_STATUS_B0_9485 (AR_SM_BASE + 0x3f0) +- +-#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + 0x448) +-#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + 0x440) +-#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + 0x48c) ++#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + AR_SREV_9485(ah) ? \ ++ 0x3c8 : 0x448) ++#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + AR_SREV_9485(ah) ? \ ++ 0x3c4 : 0x440) ++#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + AR_SREV_9485(ah) ? \ ++ 0x3f0 : 0x48c) + #define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i) (AR_SM_BASE + \ + (AR_SREV_9485(ah) ? \ + 0x3d0 : 0x450) + ((_i) << 2)) +@@ -588,7 +585,7 @@ + #define AR_PHY_65NM_CH0_BIAS2 0x160c4 + #define AR_PHY_65NM_CH0_BIAS4 0x160cc + #define AR_PHY_65NM_CH0_RXTX4 0x1610c +-#define AR_PHY_65NM_CH0_THERM (AR_SREV_9485(ah) ? 0x1628c : 0x16290) ++#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : 0x1628c) + + #define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000 + #define AR_PHY_65NM_CH0_THERM_LOCAL_S 31 +@@ -758,10 +755,10 @@ + #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 + #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 + #define AR_PHY_CHANNEL_STATUS_RX_CLEAR 0x00000004 +-#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000 +-#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18 +-#define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001 +-#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0 ++#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000 ++#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18 ++#define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001 ++#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0 + + #define AR_PHY_TX_IQCAL_STATUS_FAILED 0x00000001 + #define AR_PHY_CALIBRATED_GAINS_0 0x3e +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9340_initvals.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9340_initvals.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9340_initvals.h 2011-05-05 23:29:49.092485445 +0200 +@@ -0,0 +1,1525 @@ ++/* ++ * Copyright (c) 2011 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef INITVALS_9340_H ++#define INITVALS_9340_H ++ ++static const u32 ar9340_1p0_radio_postamble[][5] = { ++ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ ++ {0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800}, ++ {0x0001610c, 0x08000000, 0x08000000, 0x00000000, 0x00000000}, ++ {0x00016140, 0x10804000, 0x10804000, 0x50804000, 0x50804000}, ++ {0x0001650c, 0x08000000, 0x08000000, 0x00000000, 0x00000000}, ++ {0x00016540, 0x10804000, 0x10804000, 0x50804000, 0x50804000}, ++}; ++ ++static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = { ++ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ ++ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, ++ {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, ++ {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, ++ {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, ++ {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, ++ {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, ++ {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, ++ {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, ++ {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, ++ {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, ++ {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, ++ {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, ++ {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, ++ {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, ++ {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, ++ {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, ++ {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, ++ {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, ++ {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, ++ {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, ++ {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, ++ {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, ++ {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, ++ {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, ++ {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, ++ {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, ++ {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, ++ {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, ++ {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, ++ {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, ++ {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, ++ {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402}, ++ {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, ++ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, ++ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, ++ {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, ++ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, ++ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, ++ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, ++ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, ++ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, ++ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, ++ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, ++ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, ++ {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83}, ++ {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84}, ++ {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3}, ++ {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5}, ++ {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9}, ++ {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb}, ++ {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, ++ {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, ++ {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, ++ {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, ++}; ++ ++static const u32 ar9340Modes_fast_clock_1p0[][3] = { ++ /* Addr 5G_HT20 5G_HT40 */ ++ {0x00001030, 0x00000268, 0x000004d0}, ++ {0x00001070, 0x0000018c, 0x00000318}, ++ {0x000010b0, 0x00000fd0, 0x00001fa0}, ++ {0x00008014, 0x044c044c, 0x08980898}, ++ {0x0000801c, 0x148ec02b, 0x148ec057}, ++ {0x00008318, 0x000044c0, 0x00008980}, ++ {0x00009e00, 0x03721821, 0x03721821}, ++ {0x0000a230, 0x0000000b, 0x00000016}, ++ {0x0000a254, 0x00000898, 0x00001130}, ++}; ++ ++static const u32 ar9340_1p0_radio_core[][2] = { ++ /* Addr allmodes */ ++ {0x00016000, 0x36db6db6}, ++ {0x00016004, 0x6db6db40}, ++ {0x00016008, 0x73f00000}, ++ {0x0001600c, 0x00000000}, ++ {0x00016040, 0x7f80fff8}, ++ {0x00016044, 0x03b6d2db}, ++ {0x00016048, 0x24925266}, ++ {0x0001604c, 0x000f0278}, ++ {0x00016050, 0x6db6db6c}, ++ {0x00016054, 0x6db60000}, ++ {0x00016080, 0x00080000}, ++ {0x00016084, 0x0e48048c}, ++ {0x00016088, 0x14214514}, ++ {0x0001608c, 0x119f081c}, ++ {0x00016090, 0x24926490}, ++ {0x00016094, 0x00000000}, ++ {0x00016098, 0xd411eb84}, ++ {0x0001609c, 0x03e47f32}, ++ {0x000160a0, 0xc2108ffe}, ++ {0x000160a4, 0x812fc370}, ++ {0x000160a8, 0x423c8000}, ++ {0x000160ac, 0xa4646800}, ++ {0x000160b0, 0x00fe7f46}, ++ {0x000160b4, 0x92480000}, ++ {0x000160c0, 0x006db6db}, ++ {0x000160c4, 0x6db6db60}, ++ {0x000160c8, 0x6db6db6c}, ++ {0x000160cc, 0x6de6db6c}, ++ {0x000160d0, 0xb6da4924}, ++ {0x00016100, 0x04cb0001}, ++ {0x00016104, 0xfff80000}, ++ {0x00016108, 0x00080010}, ++ {0x0001610c, 0x00000000}, ++ {0x00016140, 0x50804008}, ++ {0x00016144, 0x01884080}, ++ {0x00016148, 0x000080c0}, ++ {0x00016280, 0x01000015}, ++ {0x00016284, 0x05530000}, ++ {0x00016288, 0x00318000}, ++ {0x0001628c, 0x50000000}, ++ {0x00016290, 0x4080294f}, ++ {0x00016380, 0x00000000}, ++ {0x00016384, 0x00000000}, ++ {0x00016388, 0x00800700}, ++ {0x0001638c, 0x00800700}, ++ {0x00016390, 0x00800700}, ++ {0x00016394, 0x00000000}, ++ {0x00016398, 0x00000000}, ++ {0x0001639c, 0x00000000}, ++ {0x000163a0, 0x00000001}, ++ {0x000163a4, 0x00000001}, ++ {0x000163a8, 0x00000000}, ++ {0x000163ac, 0x00000000}, ++ {0x000163b0, 0x00000000}, ++ {0x000163b4, 0x00000000}, ++ {0x000163b8, 0x00000000}, ++ {0x000163bc, 0x00000000}, ++ {0x000163c0, 0x000000a0}, ++ {0x000163c4, 0x000c0000}, ++ {0x000163c8, 0x14021402}, ++ {0x000163cc, 0x00001402}, ++ {0x000163d0, 0x00000000}, ++ {0x000163d4, 0x00000000}, ++ {0x00016400, 0x36db6db6}, ++ {0x00016404, 0x6db6db40}, ++ {0x00016408, 0x73f00000}, ++ {0x0001640c, 0x00000000}, ++ {0x00016440, 0x7f80fff8}, ++ {0x00016444, 0x03b6d2db}, ++ {0x00016448, 0x24927266}, ++ {0x0001644c, 0x000f0278}, ++ {0x00016450, 0x6db6db6c}, ++ {0x00016454, 0x6db60000}, ++ {0x00016500, 0x04cb0001}, ++ {0x00016504, 0xfff80000}, ++ {0x00016508, 0x00080010}, ++ {0x0001650c, 0x00000000}, ++ {0x00016540, 0x50804008}, ++ {0x00016544, 0x01884080}, ++ {0x00016548, 0x000080c0}, ++ {0x00016780, 0x00000000}, ++ {0x00016784, 0x00000000}, ++ {0x00016788, 0x00800700}, ++ {0x0001678c, 0x00800700}, ++ {0x00016790, 0x00800700}, ++ {0x00016794, 0x00000000}, ++ {0x00016798, 0x00000000}, ++ {0x0001679c, 0x00000000}, ++ {0x000167a0, 0x00000001}, ++ {0x000167a4, 0x00000001}, ++ {0x000167a8, 0x00000000}, ++ {0x000167ac, 0x00000000}, ++ {0x000167b0, 0x00000000}, ++ {0x000167b4, 0x00000000}, ++ {0x000167b8, 0x00000000}, ++ {0x000167bc, 0x00000000}, ++ {0x000167c0, 0x000000a0}, ++ {0x000167c4, 0x000c0000}, ++ {0x000167c8, 0x14021402}, ++ {0x000167cc, 0x00001402}, ++ {0x000167d0, 0x00000000}, ++ {0x000167d4, 0x00000000}, ++}; ++ ++static const u32 ar9340_1p0_radio_core_40M[][2] = { ++ {0x0001609c, 0x02566f3a}, ++ {0x000160ac, 0xa4647c00}, ++ {0x000160b0, 0x01885f5a}, ++}; ++ ++static const u32 ar9340_1p0_mac_postamble[][5] = { ++ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ ++ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, ++ {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, ++ {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, ++ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, ++ {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, ++ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, ++ {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, ++ {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, ++}; ++ ++static const u32 ar9340_1p0_soc_postamble[][5] = { ++ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ ++ {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, ++}; ++ ++static const u32 ar9340_1p0_baseband_postamble[][5] = { ++ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ ++ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, ++ {0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e}, ++ {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, ++ {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, ++ {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, ++ {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, ++ {0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044}, ++ {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, ++ {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, ++ {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, ++ {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e}, ++ {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, ++ {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, ++ {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, ++ {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, ++ {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, ++ {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, ++ {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, ++ {0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0}, ++ {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, ++ {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, ++ {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, ++ {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, ++ {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, ++ {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, ++ {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, ++ {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, ++ {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, ++ {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, ++ {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, ++ {0x0000a288, 0x00000220, 0x00000220, 0x00000110, 0x00000110}, ++ {0x0000a28c, 0x00011111, 0x00011111, 0x00022222, 0x00022222}, ++ {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, ++ {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, ++ {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, ++ {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, ++ {0x0000ae04, 0x00180000, 0x00180000, 0x00180000, 0x00180000}, ++ {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, ++ {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, ++ {0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, ++}; ++ ++static const u32 ar9340_1p0_baseband_core[][2] = { ++ /* Addr allmodes */ ++ {0x00009800, 0xafe68e30}, ++ {0x00009804, 0xfd14e000}, ++ {0x00009808, 0x9c0a9f6b}, ++ {0x0000980c, 0x04900000}, ++ {0x00009814, 0xb280c00a}, ++ {0x00009818, 0x00000000}, ++ {0x0000981c, 0x00020028}, ++ {0x00009834, 0x5f3ca3de}, ++ {0x00009838, 0x0108ecff}, ++ {0x0000983c, 0x14750600}, ++ {0x00009880, 0x201fff00}, ++ {0x00009884, 0x00001042}, ++ {0x000098a4, 0x00200400}, ++ {0x000098b0, 0x52440bbe}, ++ {0x000098d0, 0x004b6a8e}, ++ {0x000098d4, 0x00000820}, ++ {0x000098dc, 0x00000000}, ++ {0x000098f0, 0x00000000}, ++ {0x000098f4, 0x00000000}, ++ {0x00009c04, 0xff55ff55}, ++ {0x00009c08, 0x0320ff55}, ++ {0x00009c0c, 0x00000000}, ++ {0x00009c10, 0x00000000}, ++ {0x00009c14, 0x00046384}, ++ {0x00009c18, 0x05b6b440}, ++ {0x00009c1c, 0x00b6b440}, ++ {0x00009d00, 0xc080a333}, ++ {0x00009d04, 0x40206c10}, ++ {0x00009d08, 0x009c4060}, ++ {0x00009d0c, 0x9883800a}, ++ {0x00009d10, 0x01834061}, ++ {0x00009d14, 0x00c0040b}, ++ {0x00009d18, 0x00000000}, ++ {0x00009e08, 0x0038230c}, ++ {0x00009e24, 0x990bb515}, ++ {0x00009e28, 0x0c6f0000}, ++ {0x00009e30, 0x06336f77}, ++ {0x00009e34, 0x6af6532f}, ++ {0x00009e38, 0x0cc80c00}, ++ {0x00009e3c, 0xcf946222}, ++ {0x00009e40, 0x0d261820}, ++ {0x00009e4c, 0x00001004}, ++ {0x00009e50, 0x00ff03f1}, ++ {0x00009e54, 0x00000000}, ++ {0x00009fc0, 0x803e4788}, ++ {0x00009fc4, 0x0001efb5}, ++ {0x00009fcc, 0x40000014}, ++ {0x00009fd0, 0x01193b93}, ++ {0x0000a20c, 0x00000000}, ++ {0x0000a220, 0x00000000}, ++ {0x0000a224, 0x00000000}, ++ {0x0000a228, 0x10002310}, ++ {0x0000a22c, 0x01036a1e}, ++ {0x0000a234, 0x10000fff}, ++ {0x0000a23c, 0x00000000}, ++ {0x0000a244, 0x0c000000}, ++ {0x0000a2a0, 0x00000001}, ++ {0x0000a2c0, 0x00000001}, ++ {0x0000a2c8, 0x00000000}, ++ {0x0000a2cc, 0x18c43433}, ++ {0x0000a2d4, 0x00000000}, ++ {0x0000a2dc, 0x00000000}, ++ {0x0000a2e0, 0x00000000}, ++ {0x0000a2e4, 0x00000000}, ++ {0x0000a2e8, 0x00000000}, ++ {0x0000a2ec, 0x00000000}, ++ {0x0000a2f0, 0x00000000}, ++ {0x0000a2f4, 0x00000000}, ++ {0x0000a2f8, 0x00000000}, ++ {0x0000a344, 0x00000000}, ++ {0x0000a34c, 0x00000000}, ++ {0x0000a350, 0x0000a000}, ++ {0x0000a364, 0x00000000}, ++ {0x0000a370, 0x00000000}, ++ {0x0000a390, 0x00000001}, ++ {0x0000a394, 0x00000444}, ++ {0x0000a398, 0x001f0e0f}, ++ {0x0000a39c, 0x0075393f}, ++ {0x0000a3a0, 0xb79f6427}, ++ {0x0000a3a4, 0x00000000}, ++ {0x0000a3a8, 0xaaaaaaaa}, ++ {0x0000a3ac, 0x3c466478}, ++ {0x0000a3c0, 0x20202020}, ++ {0x0000a3c4, 0x22222220}, ++ {0x0000a3c8, 0x20200020}, ++ {0x0000a3cc, 0x20202020}, ++ {0x0000a3d0, 0x20202020}, ++ {0x0000a3d4, 0x20202020}, ++ {0x0000a3d8, 0x20202020}, ++ {0x0000a3dc, 0x20202020}, ++ {0x0000a3e0, 0x20202020}, ++ {0x0000a3e4, 0x20202020}, ++ {0x0000a3e8, 0x20202020}, ++ {0x0000a3ec, 0x20202020}, ++ {0x0000a3f0, 0x00000000}, ++ {0x0000a3f4, 0x00000246}, ++ {0x0000a3f8, 0x0cdbd380}, ++ {0x0000a3fc, 0x000f0f01}, ++ {0x0000a400, 0x8fa91f01}, ++ {0x0000a404, 0x00000000}, ++ {0x0000a408, 0x0e79e5c6}, ++ {0x0000a40c, 0x00820820}, ++ {0x0000a414, 0x1ce739ce}, ++ {0x0000a418, 0x2d001dce}, ++ {0x0000a41c, 0x1ce739ce}, ++ {0x0000a420, 0x000001ce}, ++ {0x0000a424, 0x1ce739ce}, ++ {0x0000a428, 0x000001ce}, ++ {0x0000a42c, 0x1ce739ce}, ++ {0x0000a430, 0x1ce739ce}, ++ {0x0000a434, 0x00000000}, ++ {0x0000a438, 0x00001801}, ++ {0x0000a43c, 0x00000000}, ++ {0x0000a440, 0x00000000}, ++ {0x0000a444, 0x00000000}, ++ {0x0000a448, 0x04000080}, ++ {0x0000a44c, 0x00000001}, ++ {0x0000a450, 0x00010000}, ++ {0x0000a458, 0x00000000}, ++ {0x0000a600, 0x00000000}, ++ {0x0000a604, 0x00000000}, ++ {0x0000a608, 0x00000000}, ++ {0x0000a60c, 0x00000000}, ++ {0x0000a610, 0x00000000}, ++ {0x0000a614, 0x00000000}, ++ {0x0000a618, 0x00000000}, ++ {0x0000a61c, 0x00000000}, ++ {0x0000a620, 0x00000000}, ++ {0x0000a624, 0x00000000}, ++ {0x0000a628, 0x00000000}, ++ {0x0000a62c, 0x00000000}, ++ {0x0000a630, 0x00000000}, ++ {0x0000a634, 0x00000000}, ++ {0x0000a638, 0x00000000}, ++ {0x0000a63c, 0x00000000}, ++ {0x0000a640, 0x00000000}, ++ {0x0000a644, 0x3fad9d74}, ++ {0x0000a648, 0x0048060a}, ++ {0x0000a64c, 0x00000637}, ++ {0x0000a670, 0x03020100}, ++ {0x0000a674, 0x09080504}, ++ {0x0000a678, 0x0d0c0b0a}, ++ {0x0000a67c, 0x13121110}, ++ {0x0000a680, 0x31301514}, ++ {0x0000a684, 0x35343332}, ++ {0x0000a688, 0x00000036}, ++ {0x0000a690, 0x00000838}, ++ {0x0000a7c0, 0x00000000}, ++ {0x0000a7c4, 0xfffffffc}, ++ {0x0000a7c8, 0x00000000}, ++ {0x0000a7cc, 0x00000000}, ++ {0x0000a7d0, 0x00000000}, ++ {0x0000a7d4, 0x00000004}, ++ {0x0000a7dc, 0x00000000}, ++ {0x0000a8d0, 0x004b6a8e}, ++ {0x0000a8d4, 0x00000820}, ++ {0x0000a8dc, 0x00000000}, ++ {0x0000a8f0, 0x00000000}, ++ {0x0000a8f4, 0x00000000}, ++ {0x0000b2d0, 0x00000080}, ++ {0x0000b2d4, 0x00000000}, ++ {0x0000b2dc, 0x00000000}, ++ {0x0000b2e0, 0x00000000}, ++ {0x0000b2e4, 0x00000000}, ++ {0x0000b2e8, 0x00000000}, ++ {0x0000b2ec, 0x00000000}, ++ {0x0000b2f0, 0x00000000}, ++ {0x0000b2f4, 0x00000000}, ++ {0x0000b2f8, 0x00000000}, ++ {0x0000b408, 0x0e79e5c0}, ++ {0x0000b40c, 0x00820820}, ++ {0x0000b420, 0x00000000}, ++}; ++ ++static const u32 ar9340Modes_high_power_tx_gain_table_1p0[][5] = { ++ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ ++ {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, ++ {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, ++ {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, ++ {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, ++ {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, ++ {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, ++ {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, ++ {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, ++ {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, ++ {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, ++ {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, ++ {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, ++ {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, ++ {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, ++ {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, ++ {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, ++ {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, ++ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, ++ {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, ++ {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, ++ {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, ++ {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, ++ {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, ++ {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, ++ {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, ++ {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, ++ {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, ++ {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, ++ {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, ++ {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, ++ {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, ++ {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, ++ {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, ++ {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, ++ {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, ++ {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, ++ {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, ++ {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, ++ {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, ++ {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, ++ {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, ++ {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, ++ {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, ++ {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, ++ {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, ++ {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, ++ {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, ++ {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, ++ {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, ++ {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, ++ {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, ++ {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, ++ {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, ++ {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, ++ {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, ++}; ++ ++static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = { ++ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ ++ {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, ++ {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, ++ {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, ++ {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, ++ {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, ++ {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, ++ {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, ++ {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, ++ {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, ++ {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, ++ {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, ++ {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, ++ {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, ++ {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, ++ {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, ++ {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, ++ {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, ++ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, ++ {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, ++ {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, ++ {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, ++ {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, ++ {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, ++ {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, ++ {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, ++ {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, ++ {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, ++ {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, ++ {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, ++ {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, ++ {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, ++ {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, ++ {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, ++ {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, ++ {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, ++ {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, ++ {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, ++ {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, ++ {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, ++ {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, ++ {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, ++ {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, ++ {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, ++ {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, ++ {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, ++ {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, ++ {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, ++ {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, ++ {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, ++ {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, ++ {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, ++ {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x00016044, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, ++ {0x00016048, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266}, ++ {0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, ++ {0x00016448, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266}, ++}; ++static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = { ++ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ ++ {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, ++ {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, ++ {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, ++ {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, ++ {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, ++ {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, ++ {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, ++ {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, ++ {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, ++ {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, ++ {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, ++ {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, ++ {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, ++ {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, ++ {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, ++ {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, ++ {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, ++ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, ++ {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, ++ {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, ++ {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, ++ {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, ++ {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, ++ {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, ++ {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, ++ {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, ++ {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, ++ {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, ++ {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, ++ {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, ++ {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, ++ {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, ++ {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, ++ {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, ++ {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, ++ {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, ++ {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, ++ {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, ++ {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, ++ {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, ++ {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, ++ {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, ++ {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, ++ {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, ++ {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, ++ {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, ++ {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, ++ {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, ++ {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, ++ {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, ++ {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, ++ {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, ++ {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, ++ {0x00016044, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db}, ++ {0x00016048, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266}, ++ {0x00016444, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db}, ++ {0x00016448, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266}, ++}; ++ ++ ++static const u32 ar9340Common_rx_gain_table_1p0[][2] = { ++ /* Addr allmodes */ ++ {0x0000a000, 0x00010000}, ++ {0x0000a004, 0x00030002}, ++ {0x0000a008, 0x00050004}, ++ {0x0000a00c, 0x00810080}, ++ {0x0000a010, 0x00830082}, ++ {0x0000a014, 0x01810180}, ++ {0x0000a018, 0x01830182}, ++ {0x0000a01c, 0x01850184}, ++ {0x0000a020, 0x01890188}, ++ {0x0000a024, 0x018b018a}, ++ {0x0000a028, 0x018d018c}, ++ {0x0000a02c, 0x01910190}, ++ {0x0000a030, 0x01930192}, ++ {0x0000a034, 0x01950194}, ++ {0x0000a038, 0x038a0196}, ++ {0x0000a03c, 0x038c038b}, ++ {0x0000a040, 0x0390038d}, ++ {0x0000a044, 0x03920391}, ++ {0x0000a048, 0x03940393}, ++ {0x0000a04c, 0x03960395}, ++ {0x0000a050, 0x00000000}, ++ {0x0000a054, 0x00000000}, ++ {0x0000a058, 0x00000000}, ++ {0x0000a05c, 0x00000000}, ++ {0x0000a060, 0x00000000}, ++ {0x0000a064, 0x00000000}, ++ {0x0000a068, 0x00000000}, ++ {0x0000a06c, 0x00000000}, ++ {0x0000a070, 0x00000000}, ++ {0x0000a074, 0x00000000}, ++ {0x0000a078, 0x00000000}, ++ {0x0000a07c, 0x00000000}, ++ {0x0000a080, 0x22222229}, ++ {0x0000a084, 0x1d1d1d1d}, ++ {0x0000a088, 0x1d1d1d1d}, ++ {0x0000a08c, 0x1d1d1d1d}, ++ {0x0000a090, 0x171d1d1d}, ++ {0x0000a094, 0x11111717}, ++ {0x0000a098, 0x00030311}, ++ {0x0000a09c, 0x00000000}, ++ {0x0000a0a0, 0x00000000}, ++ {0x0000a0a4, 0x00000000}, ++ {0x0000a0a8, 0x00000000}, ++ {0x0000a0ac, 0x00000000}, ++ {0x0000a0b0, 0x00000000}, ++ {0x0000a0b4, 0x00000000}, ++ {0x0000a0b8, 0x00000000}, ++ {0x0000a0bc, 0x00000000}, ++ {0x0000a0c0, 0x001f0000}, ++ {0x0000a0c4, 0x01000101}, ++ {0x0000a0c8, 0x011e011f}, ++ {0x0000a0cc, 0x011c011d}, ++ {0x0000a0d0, 0x02030204}, ++ {0x0000a0d4, 0x02010202}, ++ {0x0000a0d8, 0x021f0200}, ++ {0x0000a0dc, 0x0302021e}, ++ {0x0000a0e0, 0x03000301}, ++ {0x0000a0e4, 0x031e031f}, ++ {0x0000a0e8, 0x0402031d}, ++ {0x0000a0ec, 0x04000401}, ++ {0x0000a0f0, 0x041e041f}, ++ {0x0000a0f4, 0x0502041d}, ++ {0x0000a0f8, 0x05000501}, ++ {0x0000a0fc, 0x051e051f}, ++ {0x0000a100, 0x06010602}, ++ {0x0000a104, 0x061f0600}, ++ {0x0000a108, 0x061d061e}, ++ {0x0000a10c, 0x07020703}, ++ {0x0000a110, 0x07000701}, ++ {0x0000a114, 0x00000000}, ++ {0x0000a118, 0x00000000}, ++ {0x0000a11c, 0x00000000}, ++ {0x0000a120, 0x00000000}, ++ {0x0000a124, 0x00000000}, ++ {0x0000a128, 0x00000000}, ++ {0x0000a12c, 0x00000000}, ++ {0x0000a130, 0x00000000}, ++ {0x0000a134, 0x00000000}, ++ {0x0000a138, 0x00000000}, ++ {0x0000a13c, 0x00000000}, ++ {0x0000a140, 0x001f0000}, ++ {0x0000a144, 0x01000101}, ++ {0x0000a148, 0x011e011f}, ++ {0x0000a14c, 0x011c011d}, ++ {0x0000a150, 0x02030204}, ++ {0x0000a154, 0x02010202}, ++ {0x0000a158, 0x021f0200}, ++ {0x0000a15c, 0x0302021e}, ++ {0x0000a160, 0x03000301}, ++ {0x0000a164, 0x031e031f}, ++ {0x0000a168, 0x0402031d}, ++ {0x0000a16c, 0x04000401}, ++ {0x0000a170, 0x041e041f}, ++ {0x0000a174, 0x0502041d}, ++ {0x0000a178, 0x05000501}, ++ {0x0000a17c, 0x051e051f}, ++ {0x0000a180, 0x06010602}, ++ {0x0000a184, 0x061f0600}, ++ {0x0000a188, 0x061d061e}, ++ {0x0000a18c, 0x07020703}, ++ {0x0000a190, 0x07000701}, ++ {0x0000a194, 0x00000000}, ++ {0x0000a198, 0x00000000}, ++ {0x0000a19c, 0x00000000}, ++ {0x0000a1a0, 0x00000000}, ++ {0x0000a1a4, 0x00000000}, ++ {0x0000a1a8, 0x00000000}, ++ {0x0000a1ac, 0x00000000}, ++ {0x0000a1b0, 0x00000000}, ++ {0x0000a1b4, 0x00000000}, ++ {0x0000a1b8, 0x00000000}, ++ {0x0000a1bc, 0x00000000}, ++ {0x0000a1c0, 0x00000000}, ++ {0x0000a1c4, 0x00000000}, ++ {0x0000a1c8, 0x00000000}, ++ {0x0000a1cc, 0x00000000}, ++ {0x0000a1d0, 0x00000000}, ++ {0x0000a1d4, 0x00000000}, ++ {0x0000a1d8, 0x00000000}, ++ {0x0000a1dc, 0x00000000}, ++ {0x0000a1e0, 0x00000000}, ++ {0x0000a1e4, 0x00000000}, ++ {0x0000a1e8, 0x00000000}, ++ {0x0000a1ec, 0x00000000}, ++ {0x0000a1f0, 0x00000396}, ++ {0x0000a1f4, 0x00000396}, ++ {0x0000a1f8, 0x00000396}, ++ {0x0000a1fc, 0x00000196}, ++ {0x0000b000, 0x00010000}, ++ {0x0000b004, 0x00030002}, ++ {0x0000b008, 0x00050004}, ++ {0x0000b00c, 0x00810080}, ++ {0x0000b010, 0x00830082}, ++ {0x0000b014, 0x01810180}, ++ {0x0000b018, 0x01830182}, ++ {0x0000b01c, 0x01850184}, ++ {0x0000b020, 0x02810280}, ++ {0x0000b024, 0x02830282}, ++ {0x0000b028, 0x02850284}, ++ {0x0000b02c, 0x02890288}, ++ {0x0000b030, 0x028b028a}, ++ {0x0000b034, 0x0388028c}, ++ {0x0000b038, 0x038a0389}, ++ {0x0000b03c, 0x038c038b}, ++ {0x0000b040, 0x0390038d}, ++ {0x0000b044, 0x03920391}, ++ {0x0000b048, 0x03940393}, ++ {0x0000b04c, 0x03960395}, ++ {0x0000b050, 0x00000000}, ++ {0x0000b054, 0x00000000}, ++ {0x0000b058, 0x00000000}, ++ {0x0000b05c, 0x00000000}, ++ {0x0000b060, 0x00000000}, ++ {0x0000b064, 0x00000000}, ++ {0x0000b068, 0x00000000}, ++ {0x0000b06c, 0x00000000}, ++ {0x0000b070, 0x00000000}, ++ {0x0000b074, 0x00000000}, ++ {0x0000b078, 0x00000000}, ++ {0x0000b07c, 0x00000000}, ++ {0x0000b080, 0x32323232}, ++ {0x0000b084, 0x2f2f3232}, ++ {0x0000b088, 0x23282a2d}, ++ {0x0000b08c, 0x1c1e2123}, ++ {0x0000b090, 0x14171919}, ++ {0x0000b094, 0x0e0e1214}, ++ {0x0000b098, 0x03050707}, ++ {0x0000b09c, 0x00030303}, ++ {0x0000b0a0, 0x00000000}, ++ {0x0000b0a4, 0x00000000}, ++ {0x0000b0a8, 0x00000000}, ++ {0x0000b0ac, 0x00000000}, ++ {0x0000b0b0, 0x00000000}, ++ {0x0000b0b4, 0x00000000}, ++ {0x0000b0b8, 0x00000000}, ++ {0x0000b0bc, 0x00000000}, ++ {0x0000b0c0, 0x003f0020}, ++ {0x0000b0c4, 0x00400041}, ++ {0x0000b0c8, 0x0140005f}, ++ {0x0000b0cc, 0x0160015f}, ++ {0x0000b0d0, 0x017e017f}, ++ {0x0000b0d4, 0x02410242}, ++ {0x0000b0d8, 0x025f0240}, ++ {0x0000b0dc, 0x027f0260}, ++ {0x0000b0e0, 0x0341027e}, ++ {0x0000b0e4, 0x035f0340}, ++ {0x0000b0e8, 0x037f0360}, ++ {0x0000b0ec, 0x04400441}, ++ {0x0000b0f0, 0x0460045f}, ++ {0x0000b0f4, 0x0541047f}, ++ {0x0000b0f8, 0x055f0540}, ++ {0x0000b0fc, 0x057f0560}, ++ {0x0000b100, 0x06400641}, ++ {0x0000b104, 0x0660065f}, ++ {0x0000b108, 0x067e067f}, ++ {0x0000b10c, 0x07410742}, ++ {0x0000b110, 0x075f0740}, ++ {0x0000b114, 0x077f0760}, ++ {0x0000b118, 0x07800781}, ++ {0x0000b11c, 0x07a0079f}, ++ {0x0000b120, 0x07c107bf}, ++ {0x0000b124, 0x000007c0}, ++ {0x0000b128, 0x00000000}, ++ {0x0000b12c, 0x00000000}, ++ {0x0000b130, 0x00000000}, ++ {0x0000b134, 0x00000000}, ++ {0x0000b138, 0x00000000}, ++ {0x0000b13c, 0x00000000}, ++ {0x0000b140, 0x003f0020}, ++ {0x0000b144, 0x00400041}, ++ {0x0000b148, 0x0140005f}, ++ {0x0000b14c, 0x0160015f}, ++ {0x0000b150, 0x017e017f}, ++ {0x0000b154, 0x02410242}, ++ {0x0000b158, 0x025f0240}, ++ {0x0000b15c, 0x027f0260}, ++ {0x0000b160, 0x0341027e}, ++ {0x0000b164, 0x035f0340}, ++ {0x0000b168, 0x037f0360}, ++ {0x0000b16c, 0x04400441}, ++ {0x0000b170, 0x0460045f}, ++ {0x0000b174, 0x0541047f}, ++ {0x0000b178, 0x055f0540}, ++ {0x0000b17c, 0x057f0560}, ++ {0x0000b180, 0x06400641}, ++ {0x0000b184, 0x0660065f}, ++ {0x0000b188, 0x067e067f}, ++ {0x0000b18c, 0x07410742}, ++ {0x0000b190, 0x075f0740}, ++ {0x0000b194, 0x077f0760}, ++ {0x0000b198, 0x07800781}, ++ {0x0000b19c, 0x07a0079f}, ++ {0x0000b1a0, 0x07c107bf}, ++ {0x0000b1a4, 0x000007c0}, ++ {0x0000b1a8, 0x00000000}, ++ {0x0000b1ac, 0x00000000}, ++ {0x0000b1b0, 0x00000000}, ++ {0x0000b1b4, 0x00000000}, ++ {0x0000b1b8, 0x00000000}, ++ {0x0000b1bc, 0x00000000}, ++ {0x0000b1c0, 0x00000000}, ++ {0x0000b1c4, 0x00000000}, ++ {0x0000b1c8, 0x00000000}, ++ {0x0000b1cc, 0x00000000}, ++ {0x0000b1d0, 0x00000000}, ++ {0x0000b1d4, 0x00000000}, ++ {0x0000b1d8, 0x00000000}, ++ {0x0000b1dc, 0x00000000}, ++ {0x0000b1e0, 0x00000000}, ++ {0x0000b1e4, 0x00000000}, ++ {0x0000b1e8, 0x00000000}, ++ {0x0000b1ec, 0x00000000}, ++ {0x0000b1f0, 0x00000396}, ++ {0x0000b1f4, 0x00000396}, ++ {0x0000b1f8, 0x00000396}, ++ {0x0000b1fc, 0x00000196}, ++}; ++ ++static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = { ++ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ ++ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, ++ {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, ++ {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, ++ {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, ++ {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, ++ {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, ++ {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, ++ {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, ++ {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, ++ {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, ++ {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, ++ {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, ++ {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, ++ {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, ++ {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, ++ {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, ++ {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, ++ {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, ++ {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, ++ {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, ++ {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, ++ {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, ++ {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, ++ {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, ++ {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, ++ {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, ++ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, ++ {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, ++ {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, ++ {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, ++ {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, ++ {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, ++ {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402}, ++ {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, ++ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, ++ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, ++ {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, ++ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, ++ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, ++ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, ++ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, ++ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, ++ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, ++ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, ++ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, ++ {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83}, ++ {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84}, ++ {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3}, ++ {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5}, ++ {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9}, ++ {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb}, ++ {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, ++ {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, ++ {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, ++ {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, ++ {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, ++}; ++ ++static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = { ++ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ ++ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, ++ {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, ++ {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, ++ {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, ++ {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, ++ {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, ++ {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400}, ++ {0x0000a518, 0x21020220, 0x21020220, 0x15000402, 0x15000402}, ++ {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, ++ {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603}, ++ {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02}, ++ {0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04}, ++ {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20}, ++ {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20}, ++ {0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22}, ++ {0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24}, ++ {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640}, ++ {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660}, ++ {0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861}, ++ {0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81}, ++ {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x42001a83, 0x42001a83}, ++ {0x0000a550, 0x61042a6c, 0x61042a6c, 0x44001c84, 0x44001c84}, ++ {0x0000a554, 0x66062a6c, 0x66062a6c, 0x48001ce3, 0x48001ce3}, ++ {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x4c001ce5, 0x4c001ce5}, ++ {0x0000a55c, 0x7006308c, 0x7006308c, 0x50001ce9, 0x50001ce9}, ++ {0x0000a560, 0x730a308a, 0x730a308a, 0x54001ceb, 0x54001ceb}, ++ {0x0000a564, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, ++ {0x0000a568, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, ++ {0x0000a56c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, ++ {0x0000a570, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, ++ {0x0000a574, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, ++ {0x0000a578, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, ++ {0x0000a57c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, ++ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, ++ {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, ++ {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, ++ {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, ++ {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, ++ {0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400}, ++ {0x0000a598, 0x21820220, 0x21820220, 0x15800402, 0x15800402}, ++ {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, ++ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603}, ++ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02}, ++ {0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04}, ++ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20}, ++ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20}, ++ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22}, ++ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24}, ++ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640}, ++ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660}, ++ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861}, ++ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81}, ++ {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42801a83, 0x42801a83}, ++ {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x44801c84, 0x44801c84}, ++ {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x48801ce3, 0x48801ce3}, ++ {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c801ce5, 0x4c801ce5}, ++ {0x0000a5dc, 0x7086308c, 0x7086308c, 0x50801ce9, 0x50801ce9}, ++ {0x0000a5e0, 0x738a308a, 0x738a308a, 0x54801ceb, 0x54801ceb}, ++ {0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, ++ {0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, ++ {0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, ++ {0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, ++ {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, ++ {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, ++ {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, ++ {0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, ++ {0x00016048, 0x24927266, 0x24927266, 0x8e483266, 0x8e483266}, ++ {0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, ++ {0x00016448, 0x24927266, 0x24927266, 0x8e482266, 0x8e482266}, ++}; ++ ++static const u32 ar9340_1p0_mac_core[][2] = { ++ /* Addr allmodes */ ++ {0x00000008, 0x00000000}, ++ {0x00000030, 0x00020085}, ++ {0x00000034, 0x00000005}, ++ {0x00000040, 0x00000000}, ++ {0x00000044, 0x00000000}, ++ {0x00000048, 0x00000008}, ++ {0x0000004c, 0x00000010}, ++ {0x00000050, 0x00000000}, ++ {0x00001040, 0x002ffc0f}, ++ {0x00001044, 0x002ffc0f}, ++ {0x00001048, 0x002ffc0f}, ++ {0x0000104c, 0x002ffc0f}, ++ {0x00001050, 0x002ffc0f}, ++ {0x00001054, 0x002ffc0f}, ++ {0x00001058, 0x002ffc0f}, ++ {0x0000105c, 0x002ffc0f}, ++ {0x00001060, 0x002ffc0f}, ++ {0x00001064, 0x002ffc0f}, ++ {0x000010f0, 0x00000100}, ++ {0x00001270, 0x00000000}, ++ {0x000012b0, 0x00000000}, ++ {0x000012f0, 0x00000000}, ++ {0x0000143c, 0x00000000}, ++ {0x0000147c, 0x00000000}, ++ {0x00008000, 0x00000000}, ++ {0x00008004, 0x00000000}, ++ {0x00008008, 0x00000000}, ++ {0x0000800c, 0x00000000}, ++ {0x00008018, 0x00000000}, ++ {0x00008020, 0x00000000}, ++ {0x00008038, 0x00000000}, ++ {0x0000803c, 0x00000000}, ++ {0x00008040, 0x00000000}, ++ {0x00008044, 0x00000000}, ++ {0x00008048, 0x00000000}, ++ {0x0000804c, 0xffffffff}, ++ {0x00008054, 0x00000000}, ++ {0x00008058, 0x00000000}, ++ {0x0000805c, 0x000fc78f}, ++ {0x00008060, 0x0000000f}, ++ {0x00008064, 0x00000000}, ++ {0x00008070, 0x00000310}, ++ {0x00008074, 0x00000020}, ++ {0x00008078, 0x00000000}, ++ {0x0000809c, 0x0000000f}, ++ {0x000080a0, 0x00000000}, ++ {0x000080a4, 0x02ff0000}, ++ {0x000080a8, 0x0e070605}, ++ {0x000080ac, 0x0000000d}, ++ {0x000080b0, 0x00000000}, ++ {0x000080b4, 0x00000000}, ++ {0x000080b8, 0x00000000}, ++ {0x000080bc, 0x00000000}, ++ {0x000080c0, 0x2a800000}, ++ {0x000080c4, 0x06900168}, ++ {0x000080c8, 0x13881c20}, ++ {0x000080cc, 0x01f40000}, ++ {0x000080d0, 0x00252500}, ++ {0x000080d4, 0x00a00000}, ++ {0x000080d8, 0x00400000}, ++ {0x000080dc, 0x00000000}, ++ {0x000080e0, 0xffffffff}, ++ {0x000080e4, 0x0000ffff}, ++ {0x000080e8, 0x3f3f3f3f}, ++ {0x000080ec, 0x00000000}, ++ {0x000080f0, 0x00000000}, ++ {0x000080f4, 0x00000000}, ++ {0x000080fc, 0x00020000}, ++ {0x00008100, 0x00000000}, ++ {0x00008108, 0x00000052}, ++ {0x0000810c, 0x00000000}, ++ {0x00008110, 0x00000000}, ++ {0x00008114, 0x000007ff}, ++ {0x00008118, 0x000000aa}, ++ {0x0000811c, 0x00003210}, ++ {0x00008124, 0x00000000}, ++ {0x00008128, 0x00000000}, ++ {0x0000812c, 0x00000000}, ++ {0x00008130, 0x00000000}, ++ {0x00008134, 0x00000000}, ++ {0x00008138, 0x00000000}, ++ {0x0000813c, 0x0000ffff}, ++ {0x00008144, 0xffffffff}, ++ {0x00008168, 0x00000000}, ++ {0x0000816c, 0x00000000}, ++ {0x00008170, 0x18486200}, ++ {0x00008174, 0x33332210}, ++ {0x00008178, 0x00000000}, ++ {0x0000817c, 0x00020000}, ++ {0x000081c0, 0x00000000}, ++ {0x000081c4, 0x33332210}, ++ {0x000081c8, 0x00000000}, ++ {0x000081cc, 0x00000000}, ++ {0x000081d4, 0x00000000}, ++ {0x000081ec, 0x00000000}, ++ {0x000081f0, 0x00000000}, ++ {0x000081f4, 0x00000000}, ++ {0x000081f8, 0x00000000}, ++ {0x000081fc, 0x00000000}, ++ {0x00008240, 0x00100000}, ++ {0x00008244, 0x0010f424}, ++ {0x00008248, 0x00000800}, ++ {0x0000824c, 0x0001e848}, ++ {0x00008250, 0x00000000}, ++ {0x00008254, 0x00000000}, ++ {0x00008258, 0x00000000}, ++ {0x0000825c, 0x40000000}, ++ {0x00008260, 0x00080922}, ++ {0x00008264, 0x9d400010}, ++ {0x00008268, 0xffffffff}, ++ {0x0000826c, 0x0000ffff}, ++ {0x00008270, 0x00000000}, ++ {0x00008274, 0x40000000}, ++ {0x00008278, 0x003e4180}, ++ {0x0000827c, 0x00000004}, ++ {0x00008284, 0x0000002c}, ++ {0x00008288, 0x0000002c}, ++ {0x0000828c, 0x000000ff}, ++ {0x00008294, 0x00000000}, ++ {0x00008298, 0x00000000}, ++ {0x0000829c, 0x00000000}, ++ {0x00008300, 0x00000140}, ++ {0x00008314, 0x00000000}, ++ {0x0000831c, 0x0000010d}, ++ {0x00008328, 0x00000000}, ++ {0x0000832c, 0x00000007}, ++ {0x00008330, 0x00000302}, ++ {0x00008334, 0x00000700}, ++ {0x00008338, 0x00ff0000}, ++ {0x0000833c, 0x02400000}, ++ {0x00008340, 0x000107ff}, ++ {0x00008344, 0xaa48105b}, ++ {0x00008348, 0x008f0000}, ++ {0x0000835c, 0x00000000}, ++ {0x00008360, 0xffffffff}, ++ {0x00008364, 0xffffffff}, ++ {0x00008368, 0x00000000}, ++ {0x00008370, 0x00000000}, ++ {0x00008374, 0x000000ff}, ++ {0x00008378, 0x00000000}, ++ {0x0000837c, 0x00000000}, ++ {0x00008380, 0xffffffff}, ++ {0x00008384, 0xffffffff}, ++ {0x00008390, 0xffffffff}, ++ {0x00008394, 0xffffffff}, ++ {0x00008398, 0x00000000}, ++ {0x0000839c, 0x00000000}, ++ {0x000083a0, 0x00000000}, ++ {0x000083a4, 0x0000fa14}, ++ {0x000083a8, 0x000f0c00}, ++ {0x000083ac, 0x33332210}, ++ {0x000083b0, 0x33332210}, ++ {0x000083b4, 0x33332210}, ++ {0x000083b8, 0x33332210}, ++ {0x000083bc, 0x00000000}, ++ {0x000083c0, 0x00000000}, ++ {0x000083c4, 0x00000000}, ++ {0x000083c8, 0x00000000}, ++ {0x000083cc, 0x00000200}, ++ {0x000083d0, 0x000301ff}, ++}; ++ ++static const u32 ar9340Common_wo_xlna_rx_gain_table_1p0[][2] = { ++ /* Addr allmodes */ ++ {0x0000a000, 0x00010000}, ++ {0x0000a004, 0x00030002}, ++ {0x0000a008, 0x00050004}, ++ {0x0000a00c, 0x00810080}, ++ {0x0000a010, 0x00830082}, ++ {0x0000a014, 0x01810180}, ++ {0x0000a018, 0x01830182}, ++ {0x0000a01c, 0x01850184}, ++ {0x0000a020, 0x01890188}, ++ {0x0000a024, 0x018b018a}, ++ {0x0000a028, 0x018d018c}, ++ {0x0000a02c, 0x03820190}, ++ {0x0000a030, 0x03840383}, ++ {0x0000a034, 0x03880385}, ++ {0x0000a038, 0x038a0389}, ++ {0x0000a03c, 0x038c038b}, ++ {0x0000a040, 0x0390038d}, ++ {0x0000a044, 0x03920391}, ++ {0x0000a048, 0x03940393}, ++ {0x0000a04c, 0x03960395}, ++ {0x0000a050, 0x00000000}, ++ {0x0000a054, 0x00000000}, ++ {0x0000a058, 0x00000000}, ++ {0x0000a05c, 0x00000000}, ++ {0x0000a060, 0x00000000}, ++ {0x0000a064, 0x00000000}, ++ {0x0000a068, 0x00000000}, ++ {0x0000a06c, 0x00000000}, ++ {0x0000a070, 0x00000000}, ++ {0x0000a074, 0x00000000}, ++ {0x0000a078, 0x00000000}, ++ {0x0000a07c, 0x00000000}, ++ {0x0000a080, 0x29292929}, ++ {0x0000a084, 0x29292929}, ++ {0x0000a088, 0x29292929}, ++ {0x0000a08c, 0x29292929}, ++ {0x0000a090, 0x22292929}, ++ {0x0000a094, 0x1d1d2222}, ++ {0x0000a098, 0x0c111117}, ++ {0x0000a09c, 0x00030303}, ++ {0x0000a0a0, 0x00000000}, ++ {0x0000a0a4, 0x00000000}, ++ {0x0000a0a8, 0x00000000}, ++ {0x0000a0ac, 0x00000000}, ++ {0x0000a0b0, 0x00000000}, ++ {0x0000a0b4, 0x00000000}, ++ {0x0000a0b8, 0x00000000}, ++ {0x0000a0bc, 0x00000000}, ++ {0x0000a0c0, 0x001f0000}, ++ {0x0000a0c4, 0x01000101}, ++ {0x0000a0c8, 0x011e011f}, ++ {0x0000a0cc, 0x011c011d}, ++ {0x0000a0d0, 0x02030204}, ++ {0x0000a0d4, 0x02010202}, ++ {0x0000a0d8, 0x021f0200}, ++ {0x0000a0dc, 0x0302021e}, ++ {0x0000a0e0, 0x03000301}, ++ {0x0000a0e4, 0x031e031f}, ++ {0x0000a0e8, 0x0402031d}, ++ {0x0000a0ec, 0x04000401}, ++ {0x0000a0f0, 0x041e041f}, ++ {0x0000a0f4, 0x0502041d}, ++ {0x0000a0f8, 0x05000501}, ++ {0x0000a0fc, 0x051e051f}, ++ {0x0000a100, 0x06010602}, ++ {0x0000a104, 0x061f0600}, ++ {0x0000a108, 0x061d061e}, ++ {0x0000a10c, 0x07020703}, ++ {0x0000a110, 0x07000701}, ++ {0x0000a114, 0x00000000}, ++ {0x0000a118, 0x00000000}, ++ {0x0000a11c, 0x00000000}, ++ {0x0000a120, 0x00000000}, ++ {0x0000a124, 0x00000000}, ++ {0x0000a128, 0x00000000}, ++ {0x0000a12c, 0x00000000}, ++ {0x0000a130, 0x00000000}, ++ {0x0000a134, 0x00000000}, ++ {0x0000a138, 0x00000000}, ++ {0x0000a13c, 0x00000000}, ++ {0x0000a140, 0x001f0000}, ++ {0x0000a144, 0x01000101}, ++ {0x0000a148, 0x011e011f}, ++ {0x0000a14c, 0x011c011d}, ++ {0x0000a150, 0x02030204}, ++ {0x0000a154, 0x02010202}, ++ {0x0000a158, 0x021f0200}, ++ {0x0000a15c, 0x0302021e}, ++ {0x0000a160, 0x03000301}, ++ {0x0000a164, 0x031e031f}, ++ {0x0000a168, 0x0402031d}, ++ {0x0000a16c, 0x04000401}, ++ {0x0000a170, 0x041e041f}, ++ {0x0000a174, 0x0502041d}, ++ {0x0000a178, 0x05000501}, ++ {0x0000a17c, 0x051e051f}, ++ {0x0000a180, 0x06010602}, ++ {0x0000a184, 0x061f0600}, ++ {0x0000a188, 0x061d061e}, ++ {0x0000a18c, 0x07020703}, ++ {0x0000a190, 0x07000701}, ++ {0x0000a194, 0x00000000}, ++ {0x0000a198, 0x00000000}, ++ {0x0000a19c, 0x00000000}, ++ {0x0000a1a0, 0x00000000}, ++ {0x0000a1a4, 0x00000000}, ++ {0x0000a1a8, 0x00000000}, ++ {0x0000a1ac, 0x00000000}, ++ {0x0000a1b0, 0x00000000}, ++ {0x0000a1b4, 0x00000000}, ++ {0x0000a1b8, 0x00000000}, ++ {0x0000a1bc, 0x00000000}, ++ {0x0000a1c0, 0x00000000}, ++ {0x0000a1c4, 0x00000000}, ++ {0x0000a1c8, 0x00000000}, ++ {0x0000a1cc, 0x00000000}, ++ {0x0000a1d0, 0x00000000}, ++ {0x0000a1d4, 0x00000000}, ++ {0x0000a1d8, 0x00000000}, ++ {0x0000a1dc, 0x00000000}, ++ {0x0000a1e0, 0x00000000}, ++ {0x0000a1e4, 0x00000000}, ++ {0x0000a1e8, 0x00000000}, ++ {0x0000a1ec, 0x00000000}, ++ {0x0000a1f0, 0x00000396}, ++ {0x0000a1f4, 0x00000396}, ++ {0x0000a1f8, 0x00000396}, ++ {0x0000a1fc, 0x00000196}, ++ {0x0000b000, 0x00010000}, ++ {0x0000b004, 0x00030002}, ++ {0x0000b008, 0x00050004}, ++ {0x0000b00c, 0x00810080}, ++ {0x0000b010, 0x00830082}, ++ {0x0000b014, 0x01810180}, ++ {0x0000b018, 0x01830182}, ++ {0x0000b01c, 0x01850184}, ++ {0x0000b020, 0x02810280}, ++ {0x0000b024, 0x02830282}, ++ {0x0000b028, 0x02850284}, ++ {0x0000b02c, 0x02890288}, ++ {0x0000b030, 0x028b028a}, ++ {0x0000b034, 0x0388028c}, ++ {0x0000b038, 0x038a0389}, ++ {0x0000b03c, 0x038c038b}, ++ {0x0000b040, 0x0390038d}, ++ {0x0000b044, 0x03920391}, ++ {0x0000b048, 0x03940393}, ++ {0x0000b04c, 0x03960395}, ++ {0x0000b050, 0x00000000}, ++ {0x0000b054, 0x00000000}, ++ {0x0000b058, 0x00000000}, ++ {0x0000b05c, 0x00000000}, ++ {0x0000b060, 0x00000000}, ++ {0x0000b064, 0x00000000}, ++ {0x0000b068, 0x00000000}, ++ {0x0000b06c, 0x00000000}, ++ {0x0000b070, 0x00000000}, ++ {0x0000b074, 0x00000000}, ++ {0x0000b078, 0x00000000}, ++ {0x0000b07c, 0x00000000}, ++ {0x0000b080, 0x32323232}, ++ {0x0000b084, 0x2f2f3232}, ++ {0x0000b088, 0x23282a2d}, ++ {0x0000b08c, 0x1c1e2123}, ++ {0x0000b090, 0x14171919}, ++ {0x0000b094, 0x0e0e1214}, ++ {0x0000b098, 0x03050707}, ++ {0x0000b09c, 0x00030303}, ++ {0x0000b0a0, 0x00000000}, ++ {0x0000b0a4, 0x00000000}, ++ {0x0000b0a8, 0x00000000}, ++ {0x0000b0ac, 0x00000000}, ++ {0x0000b0b0, 0x00000000}, ++ {0x0000b0b4, 0x00000000}, ++ {0x0000b0b8, 0x00000000}, ++ {0x0000b0bc, 0x00000000}, ++ {0x0000b0c0, 0x003f0020}, ++ {0x0000b0c4, 0x00400041}, ++ {0x0000b0c8, 0x0140005f}, ++ {0x0000b0cc, 0x0160015f}, ++ {0x0000b0d0, 0x017e017f}, ++ {0x0000b0d4, 0x02410242}, ++ {0x0000b0d8, 0x025f0240}, ++ {0x0000b0dc, 0x027f0260}, ++ {0x0000b0e0, 0x0341027e}, ++ {0x0000b0e4, 0x035f0340}, ++ {0x0000b0e8, 0x037f0360}, ++ {0x0000b0ec, 0x04400441}, ++ {0x0000b0f0, 0x0460045f}, ++ {0x0000b0f4, 0x0541047f}, ++ {0x0000b0f8, 0x055f0540}, ++ {0x0000b0fc, 0x057f0560}, ++ {0x0000b100, 0x06400641}, ++ {0x0000b104, 0x0660065f}, ++ {0x0000b108, 0x067e067f}, ++ {0x0000b10c, 0x07410742}, ++ {0x0000b110, 0x075f0740}, ++ {0x0000b114, 0x077f0760}, ++ {0x0000b118, 0x07800781}, ++ {0x0000b11c, 0x07a0079f}, ++ {0x0000b120, 0x07c107bf}, ++ {0x0000b124, 0x000007c0}, ++ {0x0000b128, 0x00000000}, ++ {0x0000b12c, 0x00000000}, ++ {0x0000b130, 0x00000000}, ++ {0x0000b134, 0x00000000}, ++ {0x0000b138, 0x00000000}, ++ {0x0000b13c, 0x00000000}, ++ {0x0000b140, 0x003f0020}, ++ {0x0000b144, 0x00400041}, ++ {0x0000b148, 0x0140005f}, ++ {0x0000b14c, 0x0160015f}, ++ {0x0000b150, 0x017e017f}, ++ {0x0000b154, 0x02410242}, ++ {0x0000b158, 0x025f0240}, ++ {0x0000b15c, 0x027f0260}, ++ {0x0000b160, 0x0341027e}, ++ {0x0000b164, 0x035f0340}, ++ {0x0000b168, 0x037f0360}, ++ {0x0000b16c, 0x04400441}, ++ {0x0000b170, 0x0460045f}, ++ {0x0000b174, 0x0541047f}, ++ {0x0000b178, 0x055f0540}, ++ {0x0000b17c, 0x057f0560}, ++ {0x0000b180, 0x06400641}, ++ {0x0000b184, 0x0660065f}, ++ {0x0000b188, 0x067e067f}, ++ {0x0000b18c, 0x07410742}, ++ {0x0000b190, 0x075f0740}, ++ {0x0000b194, 0x077f0760}, ++ {0x0000b198, 0x07800781}, ++ {0x0000b19c, 0x07a0079f}, ++ {0x0000b1a0, 0x07c107bf}, ++ {0x0000b1a4, 0x000007c0}, ++ {0x0000b1a8, 0x00000000}, ++ {0x0000b1ac, 0x00000000}, ++ {0x0000b1b0, 0x00000000}, ++ {0x0000b1b4, 0x00000000}, ++ {0x0000b1b8, 0x00000000}, ++ {0x0000b1bc, 0x00000000}, ++ {0x0000b1c0, 0x00000000}, ++ {0x0000b1c4, 0x00000000}, ++ {0x0000b1c8, 0x00000000}, ++ {0x0000b1cc, 0x00000000}, ++ {0x0000b1d0, 0x00000000}, ++ {0x0000b1d4, 0x00000000}, ++ {0x0000b1d8, 0x00000000}, ++ {0x0000b1dc, 0x00000000}, ++ {0x0000b1e0, 0x00000000}, ++ {0x0000b1e4, 0x00000000}, ++ {0x0000b1e8, 0x00000000}, ++ {0x0000b1ec, 0x00000000}, ++ {0x0000b1f0, 0x00000396}, ++ {0x0000b1f4, 0x00000396}, ++ {0x0000b1f8, 0x00000396}, ++ {0x0000b1fc, 0x00000196}, ++}; ++ ++static const u32 ar9340_1p0_soc_preamble[][2] = { ++ /* Addr allmodes */ ++ {0x000040a4, 0x00a0c1c9}, ++ {0x00007008, 0x00000000}, ++ {0x00007020, 0x00000000}, ++ {0x00007034, 0x00000002}, ++ {0x00007038, 0x000004c2}, ++}; ++ ++#endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9485_initvals.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ar9485_initvals.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ar9485_initvals.h 2011-05-05 23:29:49.080485301 +0200 +@@ -17,931 +17,6 @@ + #ifndef INITVALS_9485_H + #define INITVALS_9485_H + +-static const u32 ar9485Common_1_0[][2] = { +- /* Addr allmodes */ +- {0x00007010, 0x00000022}, +- {0x00007020, 0x00000000}, +- {0x00007034, 0x00000002}, +- {0x00007038, 0x000004c2}, +-}; +- +-static const u32 ar9485_1_0_mac_postamble[][5] = { +- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ +- {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, +- {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, +- {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, +- {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, +- {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, +- {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, +- {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, +- {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, +-}; +- +-static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1[][2] = { +- /* Addr allmodes */ +- {0x00018c00, 0x10212e5e}, +- {0x00018c04, 0x000801d8}, +- {0x00018c08, 0x0000580c}, +-}; +- +-static const u32 ar9485Common_wo_xlna_rx_gain_1_0[][2] = { +- /* Addr allmodes */ +- {0x0000a000, 0x00010000}, +- {0x0000a004, 0x00030002}, +- {0x0000a008, 0x00050004}, +- {0x0000a00c, 0x00810080}, +- {0x0000a010, 0x01800082}, +- {0x0000a014, 0x01820181}, +- {0x0000a018, 0x01840183}, +- {0x0000a01c, 0x01880185}, +- {0x0000a020, 0x018a0189}, +- {0x0000a024, 0x02850284}, +- {0x0000a028, 0x02890288}, +- {0x0000a02c, 0x03850384}, +- {0x0000a030, 0x03890388}, +- {0x0000a034, 0x038b038a}, +- {0x0000a038, 0x038d038c}, +- {0x0000a03c, 0x03910390}, +- {0x0000a040, 0x03930392}, +- {0x0000a044, 0x03950394}, +- {0x0000a048, 0x00000396}, +- {0x0000a04c, 0x00000000}, +- {0x0000a050, 0x00000000}, +- {0x0000a054, 0x00000000}, +- {0x0000a058, 0x00000000}, +- {0x0000a05c, 0x00000000}, +- {0x0000a060, 0x00000000}, +- {0x0000a064, 0x00000000}, +- {0x0000a068, 0x00000000}, +- {0x0000a06c, 0x00000000}, +- {0x0000a070, 0x00000000}, +- {0x0000a074, 0x00000000}, +- {0x0000a078, 0x00000000}, +- {0x0000a07c, 0x00000000}, +- {0x0000a080, 0x28282828}, +- {0x0000a084, 0x28282828}, +- {0x0000a088, 0x28282828}, +- {0x0000a08c, 0x28282828}, +- {0x0000a090, 0x28282828}, +- {0x0000a094, 0x21212128}, +- {0x0000a098, 0x171c1c1c}, +- {0x0000a09c, 0x02020212}, +- {0x0000a0a0, 0x00000202}, +- {0x0000a0a4, 0x00000000}, +- {0x0000a0a8, 0x00000000}, +- {0x0000a0ac, 0x00000000}, +- {0x0000a0b0, 0x00000000}, +- {0x0000a0b4, 0x00000000}, +- {0x0000a0b8, 0x00000000}, +- {0x0000a0bc, 0x00000000}, +- {0x0000a0c0, 0x001f0000}, +- {0x0000a0c4, 0x111f1100}, +- {0x0000a0c8, 0x111d111e}, +- {0x0000a0cc, 0x111b111c}, +- {0x0000a0d0, 0x22032204}, +- {0x0000a0d4, 0x22012202}, +- {0x0000a0d8, 0x221f2200}, +- {0x0000a0dc, 0x221d221e}, +- {0x0000a0e0, 0x33013302}, +- {0x0000a0e4, 0x331f3300}, +- {0x0000a0e8, 0x4402331e}, +- {0x0000a0ec, 0x44004401}, +- {0x0000a0f0, 0x441e441f}, +- {0x0000a0f4, 0x55015502}, +- {0x0000a0f8, 0x551f5500}, +- {0x0000a0fc, 0x6602551e}, +- {0x0000a100, 0x66006601}, +- {0x0000a104, 0x661e661f}, +- {0x0000a108, 0x7703661d}, +- {0x0000a10c, 0x77017702}, +- {0x0000a110, 0x00007700}, +- {0x0000a114, 0x00000000}, +- {0x0000a118, 0x00000000}, +- {0x0000a11c, 0x00000000}, +- {0x0000a120, 0x00000000}, +- {0x0000a124, 0x00000000}, +- {0x0000a128, 0x00000000}, +- {0x0000a12c, 0x00000000}, +- {0x0000a130, 0x00000000}, +- {0x0000a134, 0x00000000}, +- {0x0000a138, 0x00000000}, +- {0x0000a13c, 0x00000000}, +- {0x0000a140, 0x001f0000}, +- {0x0000a144, 0x111f1100}, +- {0x0000a148, 0x111d111e}, +- {0x0000a14c, 0x111b111c}, +- {0x0000a150, 0x22032204}, +- {0x0000a154, 0x22012202}, +- {0x0000a158, 0x221f2200}, +- {0x0000a15c, 0x221d221e}, +- {0x0000a160, 0x33013302}, +- {0x0000a164, 0x331f3300}, +- {0x0000a168, 0x4402331e}, +- {0x0000a16c, 0x44004401}, +- {0x0000a170, 0x441e441f}, +- {0x0000a174, 0x55015502}, +- {0x0000a178, 0x551f5500}, +- {0x0000a17c, 0x6602551e}, +- {0x0000a180, 0x66006601}, +- {0x0000a184, 0x661e661f}, +- {0x0000a188, 0x7703661d}, +- {0x0000a18c, 0x77017702}, +- {0x0000a190, 0x00007700}, +- {0x0000a194, 0x00000000}, +- {0x0000a198, 0x00000000}, +- {0x0000a19c, 0x00000000}, +- {0x0000a1a0, 0x00000000}, +- {0x0000a1a4, 0x00000000}, +- {0x0000a1a8, 0x00000000}, +- {0x0000a1ac, 0x00000000}, +- {0x0000a1b0, 0x00000000}, +- {0x0000a1b4, 0x00000000}, +- {0x0000a1b8, 0x00000000}, +- {0x0000a1bc, 0x00000000}, +- {0x0000a1c0, 0x00000000}, +- {0x0000a1c4, 0x00000000}, +- {0x0000a1c8, 0x00000000}, +- {0x0000a1cc, 0x00000000}, +- {0x0000a1d0, 0x00000000}, +- {0x0000a1d4, 0x00000000}, +- {0x0000a1d8, 0x00000000}, +- {0x0000a1dc, 0x00000000}, +- {0x0000a1e0, 0x00000000}, +- {0x0000a1e4, 0x00000000}, +- {0x0000a1e8, 0x00000000}, +- {0x0000a1ec, 0x00000000}, +- {0x0000a1f0, 0x00000396}, +- {0x0000a1f4, 0x00000396}, +- {0x0000a1f8, 0x00000396}, +- {0x0000a1fc, 0x00000296}, +-}; +- +-static const u32 ar9485Modes_high_power_tx_gain_1_0[][5] = { +- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ +- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, +- {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, +- {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, +- {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, +- {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, +- {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, +- {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, +- {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, +- {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, +- {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, +- {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, +- {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, +- {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, +- {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, +- {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, +- {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, +- {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, +- {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, +- {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, +- {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, +- {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, +- {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, +- {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, +- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, +- {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, +- {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, +- {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, +- {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, +-}; +- +-static const u32 ar9485_1_0[][2] = { +- /* Addr allmodes */ +- {0x0000a580, 0x00000000}, +- {0x0000a584, 0x00000000}, +- {0x0000a588, 0x00000000}, +- {0x0000a58c, 0x00000000}, +- {0x0000a590, 0x00000000}, +- {0x0000a594, 0x00000000}, +- {0x0000a598, 0x00000000}, +- {0x0000a59c, 0x00000000}, +- {0x0000a5a0, 0x00000000}, +- {0x0000a5a4, 0x00000000}, +- {0x0000a5a8, 0x00000000}, +- {0x0000a5ac, 0x00000000}, +- {0x0000a5b0, 0x00000000}, +- {0x0000a5b4, 0x00000000}, +- {0x0000a5b8, 0x00000000}, +- {0x0000a5bc, 0x00000000}, +-}; +- +-static const u32 ar9485_1_0_radio_core[][2] = { +- /* Addr allmodes */ +- {0x00016000, 0x36db6db6}, +- {0x00016004, 0x6db6db40}, +- {0x00016008, 0x73800000}, +- {0x0001600c, 0x00000000}, +- {0x00016040, 0x7f80fff8}, +- {0x00016048, 0x6c92426e}, +- {0x0001604c, 0x000f0278}, +- {0x00016050, 0x6db6db6c}, +- {0x00016054, 0x6db60000}, +- {0x00016080, 0x00080000}, +- {0x00016084, 0x0e48048c}, +- {0x00016088, 0x14214514}, +- {0x0001608c, 0x119f081e}, +- {0x00016090, 0x24926490}, +- {0x00016098, 0xd28b3330}, +- {0x000160a0, 0xc2108ffe}, +- {0x000160a4, 0x812fc370}, +- {0x000160a8, 0x423c8000}, +- {0x000160b4, 0x92480040}, +- {0x000160c0, 0x006db6db}, +- {0x000160c4, 0x0186db60}, +- {0x000160c8, 0x6db6db6c}, +- {0x000160cc, 0x6de6fbe0}, +- {0x000160d0, 0xf7dfcf3c}, +- {0x00016100, 0x04cb0001}, +- {0x00016104, 0xfff80015}, +- {0x00016108, 0x00080010}, +- {0x00016144, 0x01884080}, +- {0x00016148, 0x00008040}, +- {0x00016180, 0x08453333}, +- {0x00016184, 0x18e82f01}, +- {0x00016188, 0x00000000}, +- {0x0001618c, 0x00000000}, +- {0x00016240, 0x08400000}, +- {0x00016244, 0x1bf90f00}, +- {0x00016248, 0x00000000}, +- {0x0001624c, 0x00000000}, +- {0x00016280, 0x01000015}, +- {0x00016284, 0x00d30000}, +- {0x00016288, 0x00318000}, +- {0x0001628c, 0x50000000}, +- {0x00016290, 0x4b96210f}, +- {0x00016380, 0x00000000}, +- {0x00016384, 0x00000000}, +- {0x00016388, 0x00800700}, +- {0x0001638c, 0x00800700}, +- {0x00016390, 0x00800700}, +- {0x00016394, 0x00000000}, +- {0x00016398, 0x00000000}, +- {0x0001639c, 0x00000000}, +- {0x000163a0, 0x00000001}, +- {0x000163a4, 0x00000001}, +- {0x000163a8, 0x00000000}, +- {0x000163ac, 0x00000000}, +- {0x000163b0, 0x00000000}, +- {0x000163b4, 0x00000000}, +- {0x000163b8, 0x00000000}, +- {0x000163bc, 0x00000000}, +- {0x000163c0, 0x000000a0}, +- {0x000163c4, 0x000c0000}, +- {0x000163c8, 0x14021402}, +- {0x000163cc, 0x00001402}, +- {0x000163d0, 0x00000000}, +- {0x000163d4, 0x00000000}, +- {0x00016c40, 0x1319c178}, +- {0x00016c44, 0x10000000}, +-}; +- +-static const u32 ar9485Modes_lowest_ob_db_tx_gain_1_0[][5] = { +- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ +- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, +- {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, +- {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, +- {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, +- {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, +- {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, +- {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, +- {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, +- {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, +- {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, +- {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, +- {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, +- {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, +- {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, +- {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, +- {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, +- {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, +- {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, +- {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, +- {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, +- {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, +- {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, +- {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, +- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, +- {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, +- {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, +- {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, +- {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, +-}; +- +-static const u32 ar9485_1_0_baseband_core[][2] = { +- /* Addr allmodes */ +- {0x00009800, 0xafe68e30}, +- {0x00009804, 0xfd14e000}, +- {0x00009808, 0x9c0a8f6b}, +- {0x0000980c, 0x04800000}, +- {0x00009814, 0x9280c00a}, +- {0x00009818, 0x00000000}, +- {0x0000981c, 0x00020028}, +- {0x00009834, 0x5f3ca3de}, +- {0x00009838, 0x0108ecff}, +- {0x0000983c, 0x14750600}, +- {0x00009880, 0x201fff00}, +- {0x00009884, 0x00001042}, +- {0x000098a4, 0x00200400}, +- {0x000098b0, 0x52440bbe}, +- {0x000098bc, 0x00000002}, +- {0x000098d0, 0x004b6a8e}, +- {0x000098d4, 0x00000820}, +- {0x000098dc, 0x00000000}, +- {0x000098f0, 0x00000000}, +- {0x000098f4, 0x00000000}, +- {0x00009c04, 0x00000000}, +- {0x00009c08, 0x03200000}, +- {0x00009c0c, 0x00000000}, +- {0x00009c10, 0x00000000}, +- {0x00009c14, 0x00046384}, +- {0x00009c18, 0x05b6b440}, +- {0x00009c1c, 0x00b6b440}, +- {0x00009d00, 0xc080a333}, +- {0x00009d04, 0x40206c10}, +- {0x00009d08, 0x009c4060}, +- {0x00009d0c, 0x1883800a}, +- {0x00009d10, 0x01834061}, +- {0x00009d14, 0x00c00400}, +- {0x00009d18, 0x00000000}, +- {0x00009d1c, 0x00000000}, +- {0x00009e08, 0x0038233c}, +- {0x00009e24, 0x990bb515}, +- {0x00009e28, 0x0a6f0000}, +- {0x00009e30, 0x06336f77}, +- {0x00009e34, 0x6af6532f}, +- {0x00009e38, 0x0cc80c00}, +- {0x00009e40, 0x0d261820}, +- {0x00009e4c, 0x00001004}, +- {0x00009e50, 0x00ff03f1}, +- {0x00009fc0, 0x80be4788}, +- {0x00009fc4, 0x0001efb5}, +- {0x00009fcc, 0x40000014}, +- {0x0000a20c, 0x00000000}, +- {0x0000a210, 0x00000000}, +- {0x0000a220, 0x00000000}, +- {0x0000a224, 0x00000000}, +- {0x0000a228, 0x10002310}, +- {0x0000a23c, 0x00000000}, +- {0x0000a244, 0x0c000000}, +- {0x0000a2a0, 0x00000001}, +- {0x0000a2c0, 0x00000001}, +- {0x0000a2c8, 0x00000000}, +- {0x0000a2cc, 0x18c43433}, +- {0x0000a2d4, 0x00000000}, +- {0x0000a2dc, 0x00000000}, +- {0x0000a2e0, 0x00000000}, +- {0x0000a2e4, 0x00000000}, +- {0x0000a2e8, 0x00000000}, +- {0x0000a2ec, 0x00000000}, +- {0x0000a2f0, 0x00000000}, +- {0x0000a2f4, 0x00000000}, +- {0x0000a2f8, 0x00000000}, +- {0x0000a344, 0x00000000}, +- {0x0000a34c, 0x00000000}, +- {0x0000a350, 0x0000a000}, +- {0x0000a364, 0x00000000}, +- {0x0000a370, 0x00000000}, +- {0x0000a390, 0x00000001}, +- {0x0000a394, 0x00000444}, +- {0x0000a398, 0x001f0e0f}, +- {0x0000a39c, 0x0075393f}, +- {0x0000a3a0, 0xb79f6427}, +- {0x0000a3a4, 0x00000000}, +- {0x0000a3a8, 0xaaaaaaaa}, +- {0x0000a3ac, 0x3c466478}, +- {0x0000a3c0, 0x20202020}, +- {0x0000a3c4, 0x22222220}, +- {0x0000a3c8, 0x20200020}, +- {0x0000a3cc, 0x20202020}, +- {0x0000a3d0, 0x20202020}, +- {0x0000a3d4, 0x20202020}, +- {0x0000a3d8, 0x20202020}, +- {0x0000a3dc, 0x20202020}, +- {0x0000a3e0, 0x20202020}, +- {0x0000a3e4, 0x20202020}, +- {0x0000a3e8, 0x20202020}, +- {0x0000a3ec, 0x20202020}, +- {0x0000a3f0, 0x00000000}, +- {0x0000a3f4, 0x00000006}, +- {0x0000a3f8, 0x0cdbd380}, +- {0x0000a3fc, 0x000f0f01}, +- {0x0000a400, 0x8fa91f01}, +- {0x0000a404, 0x00000000}, +- {0x0000a408, 0x0e79e5c6}, +- {0x0000a40c, 0x00820820}, +- {0x0000a414, 0x1ce739ce}, +- {0x0000a418, 0x2d0011ce}, +- {0x0000a41c, 0x1ce739ce}, +- {0x0000a420, 0x000001ce}, +- {0x0000a424, 0x1ce739ce}, +- {0x0000a428, 0x000001ce}, +- {0x0000a42c, 0x1ce739ce}, +- {0x0000a430, 0x1ce739ce}, +- {0x0000a434, 0x00000000}, +- {0x0000a438, 0x00001801}, +- {0x0000a43c, 0x00000000}, +- {0x0000a440, 0x00000000}, +- {0x0000a444, 0x00000000}, +- {0x0000a448, 0x04000000}, +- {0x0000a44c, 0x00000001}, +- {0x0000a450, 0x00010000}, +- {0x0000a458, 0x00000000}, +- {0x0000a5c4, 0x3fad9d74}, +- {0x0000a5c8, 0x0048060a}, +- {0x0000a5cc, 0x00000637}, +- {0x0000a760, 0x03020100}, +- {0x0000a764, 0x09080504}, +- {0x0000a768, 0x0d0c0b0a}, +- {0x0000a76c, 0x13121110}, +- {0x0000a770, 0x31301514}, +- {0x0000a774, 0x35343332}, +- {0x0000a778, 0x00000036}, +- {0x0000a780, 0x00000838}, +- {0x0000a7c0, 0x00000000}, +- {0x0000a7c4, 0xfffffffc}, +- {0x0000a7c8, 0x00000000}, +- {0x0000a7cc, 0x00000000}, +- {0x0000a7d0, 0x00000000}, +- {0x0000a7d4, 0x00000004}, +- {0x0000a7dc, 0x00000001}, +-}; +- +-static const u32 ar9485Modes_high_ob_db_tx_gain_1_0[][5] = { +- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ +- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, +- {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, +- {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, +- {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, +- {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, +- {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, +- {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, +- {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, +- {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, +- {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, +- {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, +- {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, +- {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, +- {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, +- {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, +- {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, +- {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, +- {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, +- {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, +- {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, +- {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, +- {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, +- {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, +- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, +- {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, +- {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, +- {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, +- {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, +-}; +- +-static const u32 ar9485Common_rx_gain_1_0[][2] = { +- /* Addr allmodes */ +- {0x0000a000, 0x00010000}, +- {0x0000a004, 0x00030002}, +- {0x0000a008, 0x00050004}, +- {0x0000a00c, 0x00810080}, +- {0x0000a010, 0x01800082}, +- {0x0000a014, 0x01820181}, +- {0x0000a018, 0x01840183}, +- {0x0000a01c, 0x01880185}, +- {0x0000a020, 0x018a0189}, +- {0x0000a024, 0x02850284}, +- {0x0000a028, 0x02890288}, +- {0x0000a02c, 0x03850384}, +- {0x0000a030, 0x03890388}, +- {0x0000a034, 0x038b038a}, +- {0x0000a038, 0x038d038c}, +- {0x0000a03c, 0x03910390}, +- {0x0000a040, 0x03930392}, +- {0x0000a044, 0x03950394}, +- {0x0000a048, 0x00000396}, +- {0x0000a04c, 0x00000000}, +- {0x0000a050, 0x00000000}, +- {0x0000a054, 0x00000000}, +- {0x0000a058, 0x00000000}, +- {0x0000a05c, 0x00000000}, +- {0x0000a060, 0x00000000}, +- {0x0000a064, 0x00000000}, +- {0x0000a068, 0x00000000}, +- {0x0000a06c, 0x00000000}, +- {0x0000a070, 0x00000000}, +- {0x0000a074, 0x00000000}, +- {0x0000a078, 0x00000000}, +- {0x0000a07c, 0x00000000}, +- {0x0000a080, 0x28282828}, +- {0x0000a084, 0x28282828}, +- {0x0000a088, 0x28282828}, +- {0x0000a08c, 0x28282828}, +- {0x0000a090, 0x28282828}, +- {0x0000a094, 0x21212128}, +- {0x0000a098, 0x171c1c1c}, +- {0x0000a09c, 0x02020212}, +- {0x0000a0a0, 0x00000202}, +- {0x0000a0a4, 0x00000000}, +- {0x0000a0a8, 0x00000000}, +- {0x0000a0ac, 0x00000000}, +- {0x0000a0b0, 0x00000000}, +- {0x0000a0b4, 0x00000000}, +- {0x0000a0b8, 0x00000000}, +- {0x0000a0bc, 0x00000000}, +- {0x0000a0c0, 0x001f0000}, +- {0x0000a0c4, 0x111f1100}, +- {0x0000a0c8, 0x111d111e}, +- {0x0000a0cc, 0x111b111c}, +- {0x0000a0d0, 0x22032204}, +- {0x0000a0d4, 0x22012202}, +- {0x0000a0d8, 0x221f2200}, +- {0x0000a0dc, 0x221d221e}, +- {0x0000a0e0, 0x33013302}, +- {0x0000a0e4, 0x331f3300}, +- {0x0000a0e8, 0x4402331e}, +- {0x0000a0ec, 0x44004401}, +- {0x0000a0f0, 0x441e441f}, +- {0x0000a0f4, 0x55015502}, +- {0x0000a0f8, 0x551f5500}, +- {0x0000a0fc, 0x6602551e}, +- {0x0000a100, 0x66006601}, +- {0x0000a104, 0x661e661f}, +- {0x0000a108, 0x7703661d}, +- {0x0000a10c, 0x77017702}, +- {0x0000a110, 0x00007700}, +- {0x0000a114, 0x00000000}, +- {0x0000a118, 0x00000000}, +- {0x0000a11c, 0x00000000}, +- {0x0000a120, 0x00000000}, +- {0x0000a124, 0x00000000}, +- {0x0000a128, 0x00000000}, +- {0x0000a12c, 0x00000000}, +- {0x0000a130, 0x00000000}, +- {0x0000a134, 0x00000000}, +- {0x0000a138, 0x00000000}, +- {0x0000a13c, 0x00000000}, +- {0x0000a140, 0x001f0000}, +- {0x0000a144, 0x111f1100}, +- {0x0000a148, 0x111d111e}, +- {0x0000a14c, 0x111b111c}, +- {0x0000a150, 0x22032204}, +- {0x0000a154, 0x22012202}, +- {0x0000a158, 0x221f2200}, +- {0x0000a15c, 0x221d221e}, +- {0x0000a160, 0x33013302}, +- {0x0000a164, 0x331f3300}, +- {0x0000a168, 0x4402331e}, +- {0x0000a16c, 0x44004401}, +- {0x0000a170, 0x441e441f}, +- {0x0000a174, 0x55015502}, +- {0x0000a178, 0x551f5500}, +- {0x0000a17c, 0x6602551e}, +- {0x0000a180, 0x66006601}, +- {0x0000a184, 0x661e661f}, +- {0x0000a188, 0x7703661d}, +- {0x0000a18c, 0x77017702}, +- {0x0000a190, 0x00007700}, +- {0x0000a194, 0x00000000}, +- {0x0000a198, 0x00000000}, +- {0x0000a19c, 0x00000000}, +- {0x0000a1a0, 0x00000000}, +- {0x0000a1a4, 0x00000000}, +- {0x0000a1a8, 0x00000000}, +- {0x0000a1ac, 0x00000000}, +- {0x0000a1b0, 0x00000000}, +- {0x0000a1b4, 0x00000000}, +- {0x0000a1b8, 0x00000000}, +- {0x0000a1bc, 0x00000000}, +- {0x0000a1c0, 0x00000000}, +- {0x0000a1c4, 0x00000000}, +- {0x0000a1c8, 0x00000000}, +- {0x0000a1cc, 0x00000000}, +- {0x0000a1d0, 0x00000000}, +- {0x0000a1d4, 0x00000000}, +- {0x0000a1d8, 0x00000000}, +- {0x0000a1dc, 0x00000000}, +- {0x0000a1e0, 0x00000000}, +- {0x0000a1e4, 0x00000000}, +- {0x0000a1e8, 0x00000000}, +- {0x0000a1ec, 0x00000000}, +- {0x0000a1f0, 0x00000396}, +- {0x0000a1f4, 0x00000396}, +- {0x0000a1f8, 0x00000396}, +- {0x0000a1fc, 0x00000296}, +-}; +- +-static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_enable_L1[][2] = { +- /* Addr allmodes */ +- {0x00018c00, 0x10252e5e}, +- {0x00018c04, 0x000801d8}, +- {0x00018c08, 0x0000580c}, +-}; +- +-static const u32 ar9485_1_0_pcie_phy_clkreq_enable_L1[][2] = { +- /* Addr allmodes */ +- {0x00018c00, 0x10253e5e}, +- {0x00018c04, 0x000801d8}, +- {0x00018c08, 0x0000580c}, +-}; +- +-static const u32 ar9485_1_0_soc_preamble[][2] = { +- /* Addr allmodes */ +- {0x00004090, 0x00aa10aa}, +- {0x000040a4, 0x00a0c9c9}, +- {0x00007048, 0x00000004}, +-}; +- +-static const u32 ar9485_fast_clock_1_0_baseband_postamble[][3] = { +- /* Addr 5G_HT20 5G_HT40 */ +- {0x00009e00, 0x03721821, 0x03721821}, +- {0x0000a230, 0x0000400b, 0x00004016}, +- {0x0000a254, 0x00000898, 0x00001130}, +-}; +- +-static const u32 ar9485_1_0_baseband_postamble[][5] = { +- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ +- {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, +- {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, +- {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, +- {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, +- {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, +- {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, +- {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, +- {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, +- {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, +- {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, +- {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e}, +- {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, +- {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +- {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, +- {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, +- {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, +- {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, +- {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, +- {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, +- {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, +- {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0}, +- {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, +- {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, +- {0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff}, +- {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, +- {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, +- {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, +- {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, +- {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, +- {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, +- {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, +- {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, +- {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0}, +- {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +- {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +- {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, +- {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, +- {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, +- {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +- {0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, +- {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +-}; +- +-static const u32 ar9485Modes_low_ob_db_tx_gain_1_0[][5] = { +- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ +- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, +- {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, +- {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, +- {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, +- {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, +- {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, +- {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, +- {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, +- {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, +- {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, +- {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, +- {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, +- {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, +- {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, +- {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, +- {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, +- {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, +- {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, +- {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, +- {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, +- {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, +- {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, +- {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, +- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, +- {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, +- {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, +- {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, +- {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, +- {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, +-}; +- +-static const u32 ar9485_1_0_pcie_phy_clkreq_disable_L1[][2] = { +- /* Addr allmodes */ +- {0x00018c00, 0x10213e5e}, +- {0x00018c04, 0x000801d8}, +- {0x00018c08, 0x0000580c}, +-}; +- +-static const u32 ar9485_1_0_radio_postamble[][2] = { +- /* Addr allmodes */ +- {0x0001609c, 0x0b283f31}, +- {0x000160ac, 0x24611800}, +- {0x000160b0, 0x03284f3e}, +- {0x0001610c, 0x00170000}, +- {0x00016140, 0x10804008}, +-}; +- +-static const u32 ar9485_1_0_mac_core[][2] = { +- /* Addr allmodes */ +- {0x00000008, 0x00000000}, +- {0x00000030, 0x00020085}, +- {0x00000034, 0x00000005}, +- {0x00000040, 0x00000000}, +- {0x00000044, 0x00000000}, +- {0x00000048, 0x00000008}, +- {0x0000004c, 0x00000010}, +- {0x00000050, 0x00000000}, +- {0x00001040, 0x002ffc0f}, +- {0x00001044, 0x002ffc0f}, +- {0x00001048, 0x002ffc0f}, +- {0x0000104c, 0x002ffc0f}, +- {0x00001050, 0x002ffc0f}, +- {0x00001054, 0x002ffc0f}, +- {0x00001058, 0x002ffc0f}, +- {0x0000105c, 0x002ffc0f}, +- {0x00001060, 0x002ffc0f}, +- {0x00001064, 0x002ffc0f}, +- {0x000010f0, 0x00000100}, +- {0x00001270, 0x00000000}, +- {0x000012b0, 0x00000000}, +- {0x000012f0, 0x00000000}, +- {0x0000143c, 0x00000000}, +- {0x0000147c, 0x00000000}, +- {0x00008000, 0x00000000}, +- {0x00008004, 0x00000000}, +- {0x00008008, 0x00000000}, +- {0x0000800c, 0x00000000}, +- {0x00008018, 0x00000000}, +- {0x00008020, 0x00000000}, +- {0x00008038, 0x00000000}, +- {0x0000803c, 0x00000000}, +- {0x00008040, 0x00000000}, +- {0x00008044, 0x00000000}, +- {0x00008048, 0x00000000}, +- {0x0000804c, 0xffffffff}, +- {0x00008054, 0x00000000}, +- {0x00008058, 0x00000000}, +- {0x0000805c, 0x000fc78f}, +- {0x00008060, 0x0000000f}, +- {0x00008064, 0x00000000}, +- {0x00008070, 0x00000310}, +- {0x00008074, 0x00000020}, +- {0x00008078, 0x00000000}, +- {0x0000809c, 0x0000000f}, +- {0x000080a0, 0x00000000}, +- {0x000080a4, 0x02ff0000}, +- {0x000080a8, 0x0e070605}, +- {0x000080ac, 0x0000000d}, +- {0x000080b0, 0x00000000}, +- {0x000080b4, 0x00000000}, +- {0x000080b8, 0x00000000}, +- {0x000080bc, 0x00000000}, +- {0x000080c0, 0x2a800000}, +- {0x000080c4, 0x06900168}, +- {0x000080c8, 0x13881c20}, +- {0x000080cc, 0x01f40000}, +- {0x000080d0, 0x00252500}, +- {0x000080d4, 0x00a00000}, +- {0x000080d8, 0x00400000}, +- {0x000080dc, 0x00000000}, +- {0x000080e0, 0xffffffff}, +- {0x000080e4, 0x0000ffff}, +- {0x000080e8, 0x3f3f3f3f}, +- {0x000080ec, 0x00000000}, +- {0x000080f0, 0x00000000}, +- {0x000080f4, 0x00000000}, +- {0x000080fc, 0x00020000}, +- {0x00008100, 0x00000000}, +- {0x00008108, 0x00000052}, +- {0x0000810c, 0x00000000}, +- {0x00008110, 0x00000000}, +- {0x00008114, 0x000007ff}, +- {0x00008118, 0x000000aa}, +- {0x0000811c, 0x00003210}, +- {0x00008124, 0x00000000}, +- {0x00008128, 0x00000000}, +- {0x0000812c, 0x00000000}, +- {0x00008130, 0x00000000}, +- {0x00008134, 0x00000000}, +- {0x00008138, 0x00000000}, +- {0x0000813c, 0x0000ffff}, +- {0x00008144, 0xffffffff}, +- {0x00008168, 0x00000000}, +- {0x0000816c, 0x00000000}, +- {0x00008170, 0x18486200}, +- {0x00008174, 0x33332210}, +- {0x00008178, 0x00000000}, +- {0x0000817c, 0x00020000}, +- {0x000081c0, 0x00000000}, +- {0x000081c4, 0x33332210}, +- {0x000081c8, 0x00000000}, +- {0x000081cc, 0x00000000}, +- {0x000081d4, 0x00000000}, +- {0x000081ec, 0x00000000}, +- {0x000081f0, 0x00000000}, +- {0x000081f4, 0x00000000}, +- {0x000081f8, 0x00000000}, +- {0x000081fc, 0x00000000}, +- {0x00008240, 0x00100000}, +- {0x00008244, 0x0010f400}, +- {0x00008248, 0x00000800}, +- {0x0000824c, 0x0001e800}, +- {0x00008250, 0x00000000}, +- {0x00008254, 0x00000000}, +- {0x00008258, 0x00000000}, +- {0x0000825c, 0x40000000}, +- {0x00008260, 0x00080922}, +- {0x00008264, 0x9ca00010}, +- {0x00008268, 0xffffffff}, +- {0x0000826c, 0x0000ffff}, +- {0x00008270, 0x00000000}, +- {0x00008274, 0x40000000}, +- {0x00008278, 0x003e4180}, +- {0x0000827c, 0x00000004}, +- {0x00008284, 0x0000002c}, +- {0x00008288, 0x0000002c}, +- {0x0000828c, 0x000000ff}, +- {0x00008294, 0x00000000}, +- {0x00008298, 0x00000000}, +- {0x0000829c, 0x00000000}, +- {0x00008300, 0x00000140}, +- {0x00008314, 0x00000000}, +- {0x0000831c, 0x0000010d}, +- {0x00008328, 0x00000000}, +- {0x0000832c, 0x00000007}, +- {0x00008330, 0x00000302}, +- {0x00008334, 0x00000700}, +- {0x00008338, 0x00ff0000}, +- {0x0000833c, 0x02400000}, +- {0x00008340, 0x000107ff}, +- {0x00008344, 0xa248105b}, +- {0x00008348, 0x008f0000}, +- {0x0000835c, 0x00000000}, +- {0x00008360, 0xffffffff}, +- {0x00008364, 0xffffffff}, +- {0x00008368, 0x00000000}, +- {0x00008370, 0x00000000}, +- {0x00008374, 0x000000ff}, +- {0x00008378, 0x00000000}, +- {0x0000837c, 0x00000000}, +- {0x00008380, 0xffffffff}, +- {0x00008384, 0xffffffff}, +- {0x00008390, 0xffffffff}, +- {0x00008394, 0xffffffff}, +- {0x00008398, 0x00000000}, +- {0x0000839c, 0x00000000}, +- {0x000083a0, 0x00000000}, +- {0x000083a4, 0x0000fa14}, +- {0x000083a8, 0x000f0c00}, +- {0x000083ac, 0x33332210}, +- {0x000083b0, 0x33332210}, +- {0x000083b4, 0x33332210}, +- {0x000083b8, 0x33332210}, +- {0x000083bc, 0x00000000}, +- {0x000083c0, 0x00000000}, +- {0x000083c4, 0x00000000}, +- {0x000083c8, 0x00000000}, +- {0x000083cc, 0x00000200}, +- {0x000083d0, 0x000301ff}, +-}; +- + static const u32 ar9485_1_1_mac_core[][2] = { + /* Addr allmodes */ + {0x00000008, 0x00000000}, +@@ -1321,7 +396,7 @@ + {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, +- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, ++ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, +@@ -1394,7 +469,7 @@ + {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, +- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, ++ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, +@@ -1560,7 +635,7 @@ + {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, +- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, ++ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, +@@ -1653,7 +728,7 @@ + {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, +- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, ++ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, +@@ -1752,7 +827,7 @@ + {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, +- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, ++ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ath9k.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ath9k.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/ath9k.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/ath9k.h 2011-05-05 23:29:49.077485265 +0200 +@@ -120,13 +120,11 @@ + /* RX / TX */ + /***********/ + +-#define ATH_MAX_ANTENNA 3 + #define ATH_RXBUF 512 + #define ATH_TXBUF 512 + #define ATH_TXBUF_RESERVE 5 + #define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE) + #define ATH_TXMAXTRY 13 +-#define ATH_MGT_TXMAXTRY 4 + + #define TID_TO_WME_AC(_tid) \ + ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ +@@ -202,6 +200,7 @@ + int sched; + struct list_head list; + struct list_head tid_q; ++ bool clear_ps_filter; + }; + + struct ath_frame_info { +@@ -257,8 +256,12 @@ + #endif + struct ath_atx_tid tid[WME_NUM_TID]; + struct ath_atx_ac ac[WME_NUM_AC]; ++ int ps_key; ++ + u16 maxampdu; + u8 mpdudensity; ++ ++ bool sleeping; + }; + + #define AGGR_CLEANUP BIT(1) +@@ -340,17 +343,18 @@ + void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); + void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); + ++void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); ++bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an); ++ + /********/ + /* VIFs */ + /********/ + + struct ath_vif { + int av_bslot; +- bool is_bslot_active; ++ bool is_bslot_active, primary_sta_vif; + __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ +- enum nl80211_iftype av_opmode; + struct ath_buf *av_bcbuf; +- u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */ + }; + + /*******************/ +@@ -362,7 +366,7 @@ + * number of BSSIDs) if a given beacon does not go out even after waiting this + * number of beacon intervals, the game's up. + */ +-#define BSTUCK_THRESH (9 * ATH_BCBUF) ++#define BSTUCK_THRESH 9 + #define ATH_BCBUF 4 + #define ATH_DEFAULT_BINTVAL 100 /* TU */ + #define ATH_DEFAULT_BMISS_LIMIT 10 +@@ -386,7 +390,7 @@ + u32 beaconq; + u32 bmisscnt; + u32 ast_be_xmit; +- u64 bc_tstamp; ++ u32 bc_tstamp; + struct ieee80211_vif *bslot[ATH_BCBUF]; + int slottime; + int slotupdate; +@@ -401,6 +405,7 @@ + int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif); + void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); + int ath_beaconq_config(struct ath_softc *sc); ++void ath_set_beacon(struct ath_softc *sc); + void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); + + /*******/ +@@ -418,6 +423,7 @@ + #define ATH_PAPRD_TIMEOUT 100 /* msecs */ + + void ath_hw_check(struct work_struct *work); ++void ath_hw_pll_work(struct work_struct *work); + void ath_paprd_calibrate(struct work_struct *work); + void ath_ani_calibrate(unsigned long data); + +@@ -448,6 +454,7 @@ + + #define ATH_LED_PIN_DEF 1 + #define ATH_LED_PIN_9287 8 ++#define ATH_LED_PIN_9300 10 + #define ATH_LED_PIN_9485 6 + + #ifdef CONFIG_MAC80211_LEDS +@@ -550,6 +557,7 @@ + #define SC_OP_BT_SCAN BIT(13) + #define SC_OP_ANI_RUN BIT(14) + #define SC_OP_ENABLE_APM BIT(15) ++#define SC_OP_PRIM_STA_VIF BIT(16) + + /* Powersave flags */ + #define PS_WAIT_FOR_BEACON BIT(0) +@@ -667,7 +675,7 @@ + bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode); + bool ath9k_uses_beacons(int type); + +-#ifdef CONFIG_PCI ++#ifdef CONFIG_ATH9K_PCI + int ath_pci_init(void); + void ath_pci_exit(void); + #else +@@ -675,7 +683,7 @@ + static inline void ath_pci_exit(void) {}; + #endif + +-#ifdef CONFIG_ATHEROS_AR71XX ++#ifdef CONFIG_ATH9K_AHB + int ath_ahb_init(void); + void ath_ahb_exit(void); + #else +@@ -688,8 +696,6 @@ + + u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate); + +-void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +- + void ath_start_rfkill_poll(struct ath_softc *sc); + extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); + void ath9k_calculate_iter_data(struct ieee80211_hw *hw, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/beacon.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/beacon.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/beacon.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/beacon.c 2011-05-05 23:29:49.082485325 +0200 +@@ -57,8 +57,8 @@ + + /* + * Associates the beacon frame buffer with a transmit descriptor. Will set +- * up all required antenna switch parameters, rate codes, and channel flags. +- * Beacons are always sent out at the lowest rate, and are not retried. ++ * up rate codes, and channel flags. Beacons are always sent out at the ++ * lowest rate, and are not retried. + */ + static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, + struct ath_buf *bf, int rateidx) +@@ -68,7 +68,7 @@ + struct ath_common *common = ath9k_hw_common(ah); + struct ath_desc *ds; + struct ath9k_11n_rate_series series[4]; +- int flags, antenna, ctsrate = 0, ctsduration = 0; ++ int flags, ctsrate = 0, ctsduration = 0; + struct ieee80211_supported_band *sband; + u8 rate = 0; + +@@ -76,12 +76,6 @@ + flags = ATH9K_TXDESC_NOACK; + + ds->ds_link = 0; +- /* +- * Switch antenna every beacon. +- * Should only switch every beacon period, not for every SWBA +- * XXX assumes two antennae +- */ +- antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); + + sband = &sc->sbands[common->hw->conf.channel->band]; + rate = sband->bitrates[rateidx].hw_value; +@@ -278,7 +272,7 @@ + return -ENOMEM; + + tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; +- sc->beacon.bc_tstamp = le64_to_cpu(tstamp); ++ sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp); + /* Calculate a TSF adjustment factor required for staggered beacons. */ + if (avp->av_bslot > 0) { + u64 tsfadjust; +@@ -294,8 +288,8 @@ + * adjustment. Other slots are adjusted to get the timestamp + * close to the TBTT for the BSS. + */ +- tsfadjust = intval * avp->av_bslot / ATH_BCBUF; +- avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); ++ tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF; ++ avp->tsf_adjust = cpu_to_le64(tsfadjust); + + ath_dbg(common, ATH_DBG_BEACON, + "stagger beacons, bslot %d intval %u tsfadjust %llu\n", +@@ -326,9 +320,11 @@ + if (avp->av_bcbuf != NULL) { + struct ath_buf *bf; + ++ avp->is_bslot_active = false; + if (avp->av_bslot != -1) { + sc->beacon.bslot[avp->av_bslot] = NULL; + sc->nbcnvifs--; ++ avp->av_bslot = -1; + } + + bf = avp->av_bcbuf; +@@ -369,12 +365,13 @@ + if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { + sc->beacon.bmisscnt++; + +- if (sc->beacon.bmisscnt < BSTUCK_THRESH) { ++ if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) { + ath_dbg(common, ATH_DBG_BSTUCK, + "missed %u consecutive beacons\n", + sc->beacon.bmisscnt); + ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); +- ath9k_hw_bstuck_nfcal(ah); ++ if (sc->beacon.bmisscnt > 3) ++ ath9k_hw_bstuck_nfcal(ah); + } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { + ath_dbg(common, ATH_DBG_BSTUCK, + "beacon is officially stuck\n"); +@@ -385,13 +382,6 @@ + return; + } + +- if (sc->beacon.bmisscnt != 0) { +- ath_dbg(common, ATH_DBG_BSTUCK, +- "resume beacon xmit after %u misses\n", +- sc->beacon.bmisscnt); +- sc->beacon.bmisscnt = 0; +- } +- + /* + * Generate beacon frames. we are sending frames + * staggered so calculate the slot for this frame based +@@ -401,21 +391,14 @@ + intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; + + tsf = ath9k_hw_gettsf64(ah); +- tsftu = TSF_TO_TU(tsf>>32, tsf); +- slot = ((tsftu % intval) * ATH_BCBUF) / intval; +- /* +- * Reverse the slot order to get slot 0 on the TBTT offset that does +- * not require TSF adjustment and other slots adding +- * slot/ATH_BCBUF * beacon_int to timestamp. For example, with +- * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 .. +- * and slot 0 is at correct offset to TBTT. +- */ +- slot = ATH_BCBUF - slot - 1; ++ tsf += TU_TO_USEC(ah->config.sw_beacon_response_time); ++ tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF); ++ slot = (tsftu % (intval * ATH_BCBUF)) / intval; + vif = sc->beacon.bslot[slot]; + + ath_dbg(common, ATH_DBG_BEACON, + "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", +- slot, tsf, tsftu, intval, vif); ++ slot, tsf, tsftu / ATH_BCBUF, intval, vif); + + bfaddr = 0; + if (vif) { +@@ -424,6 +407,13 @@ + bfaddr = bf->bf_daddr; + bc = 1; + } ++ ++ if (sc->beacon.bmisscnt != 0) { ++ ath_dbg(common, ATH_DBG_BSTUCK, ++ "resume beacon xmit after %u misses\n", ++ sc->beacon.bmisscnt); ++ sc->beacon.bmisscnt = 0; ++ } + } + + /* +@@ -463,13 +453,17 @@ + u32 next_beacon, + u32 beacon_period) + { +- if (beacon_period & ATH9K_BEACON_RESET_TSF) ++ if (sc->sc_flags & SC_OP_TSF_RESET) { + ath9k_ps_wakeup(sc); ++ ath9k_hw_reset_tsf(sc->sc_ah); ++ } + + ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); + +- if (beacon_period & ATH9K_BEACON_RESET_TSF) ++ if (sc->sc_flags & SC_OP_TSF_RESET) { + ath9k_ps_restore(sc); ++ sc->sc_flags &= ~SC_OP_TSF_RESET; ++ } + } + + /* +@@ -484,18 +478,14 @@ + u32 nexttbtt, intval; + + /* NB: the beacon interval is kept internally in TU's */ +- intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; ++ intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); + intval /= ATH_BCBUF; /* for staggered beacons */ + nexttbtt = intval; + +- if (sc->sc_flags & SC_OP_TSF_RESET) +- intval |= ATH9K_BEACON_RESET_TSF; +- + /* + * In AP mode we enable the beacon timers and SWBA interrupts to + * prepare beacon frames. + */ +- intval |= ATH9K_BEACON_ENA; + ah->imask |= ATH9K_INT_SWBA; + ath_beaconq_config(sc); + +@@ -505,11 +495,6 @@ + ath9k_beacon_init(sc, nexttbtt, intval); + sc->beacon.bmisscnt = 0; + ath9k_hw_set_interrupts(ah, ah->imask); +- +- /* Clear the reset TSF flag, so that subsequent beacon updation +- will not reset the HW TSF. */ +- +- sc->sc_flags &= ~SC_OP_TSF_RESET; + } + + /* +@@ -643,25 +628,20 @@ + { + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); +- u64 tsf; +- u32 tsftu, intval, nexttbtt; +- +- intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; ++ u32 tsf, delta, intval, nexttbtt; + ++ tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE); ++ intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); + +- /* Pull nexttbtt forward to reflect the current TSF */ +- +- nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); +- if (nexttbtt == 0) +- nexttbtt = intval; +- else if (intval) +- nexttbtt = roundup(nexttbtt, intval); +- +- tsf = ath9k_hw_gettsf64(ah); +- tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; +- do { +- nexttbtt += intval; +- } while (nexttbtt < tsftu); ++ if (!sc->beacon.bc_tstamp) ++ nexttbtt = tsf + intval; ++ else { ++ if (tsf > sc->beacon.bc_tstamp) ++ delta = (tsf - sc->beacon.bc_tstamp); ++ else ++ delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp)); ++ nexttbtt = tsf + roundup(delta, intval); ++ } + + ath_dbg(common, ATH_DBG_BEACON, + "IBSS nexttbtt %u intval %u (%u)\n", +@@ -672,7 +652,6 @@ + * if we need to manually prepare beacon frames. Otherwise we use a + * self-linked tx descriptor and let the hardware deal with things. + */ +- intval |= ATH9K_BEACON_ENA; + ah->imask |= ATH9K_INT_SWBA; + + ath_beaconq_config(sc); +@@ -685,22 +664,63 @@ + ath9k_hw_set_interrupts(ah, ah->imask); + } + +-void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) ++static bool ath9k_allow_beacon_config(struct ath_softc *sc, ++ struct ieee80211_vif *vif) + { + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); +- enum nl80211_iftype iftype; ++ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; ++ struct ath_vif *avp = (void *)vif->drv_priv; + +- /* Setup the beacon configuration parameters */ +- if (vif) { +- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; +- iftype = vif->type; +- cur_conf->beacon_interval = bss_conf->beacon_int; +- cur_conf->dtim_period = bss_conf->dtim_period; +- } else { +- iftype = sc->sc_ah->opmode; ++ /* ++ * Can not have different beacon interval on multiple ++ * AP interface case ++ */ ++ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && ++ (sc->nbcnvifs > 1) && ++ (vif->type == NL80211_IFTYPE_AP) && ++ (cur_conf->beacon_interval != bss_conf->beacon_int)) { ++ ath_dbg(common, ATH_DBG_CONFIG, ++ "Changing beacon interval of multiple \ ++ AP interfaces !\n"); ++ return false; ++ } ++ /* ++ * Can not configure station vif's beacon config ++ * while on AP opmode ++ */ ++ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && ++ (vif->type != NL80211_IFTYPE_AP)) { ++ ath_dbg(common, ATH_DBG_CONFIG, ++ "STA vif's beacon not allowed on AP mode\n"); ++ return false; ++ } ++ /* ++ * Do not allow beacon config if HW was already configured ++ * with another STA vif ++ */ ++ if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && ++ (vif->type == NL80211_IFTYPE_STATION) && ++ (sc->sc_flags & SC_OP_BEACONS) && ++ !avp->primary_sta_vif) { ++ ath_dbg(common, ATH_DBG_CONFIG, ++ "Beacon already configured for a station interface\n"); ++ return false; + } ++ return true; ++} ++ ++void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) ++{ ++ struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; ++ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + ++ if (!ath9k_allow_beacon_config(sc, vif)) ++ return; ++ ++ /* Setup the beacon configuration parameters */ ++ cur_conf->beacon_interval = bss_conf->beacon_int; ++ cur_conf->dtim_period = bss_conf->dtim_period; + cur_conf->listen_interval = 1; + cur_conf->dtim_count = 1; + cur_conf->bmiss_timeout = +@@ -723,9 +743,37 @@ + if (cur_conf->dtim_period == 0) + cur_conf->dtim_period = 1; + +- switch (iftype) { ++ ath_set_beacon(sc); ++} ++ ++static bool ath_has_valid_bslot(struct ath_softc *sc) ++{ ++ struct ath_vif *avp; ++ int slot; ++ bool found = false; ++ ++ for (slot = 0; slot < ATH_BCBUF; slot++) { ++ if (sc->beacon.bslot[slot]) { ++ avp = (void *)sc->beacon.bslot[slot]->drv_priv; ++ if (avp->is_bslot_active) { ++ found = true; ++ break; ++ } ++ } ++ } ++ return found; ++} ++ ++ ++void ath_set_beacon(struct ath_softc *sc) ++{ ++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); ++ struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; ++ ++ switch (sc->sc_ah->opmode) { + case NL80211_IFTYPE_AP: +- ath_beacon_config_ap(sc, cur_conf); ++ if (ath_has_valid_bslot(sc)) ++ ath_beacon_config_ap(sc, cur_conf); + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: +@@ -746,26 +794,15 @@ + void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) + { + struct ath_hw *ah = sc->sc_ah; +- struct ath_vif *avp; +- int slot; +- bool found = false; ++ ++ if (!ath_has_valid_bslot(sc)) ++ return; + + ath9k_ps_wakeup(sc); + if (status) { +- for (slot = 0; slot < ATH_BCBUF; slot++) { +- if (sc->beacon.bslot[slot]) { +- avp = (void *)sc->beacon.bslot[slot]->drv_priv; +- if (avp->is_bslot_active) { +- found = true; +- break; +- } +- } +- } +- if (found) { +- /* Re-enable beaconing */ +- ah->imask |= ATH9K_INT_SWBA; +- ath9k_hw_set_interrupts(ah, ah->imask); +- } ++ /* Re-enable beaconing */ ++ ah->imask |= ATH9K_INT_SWBA; ++ ath9k_hw_set_interrupts(ah, ah->imask); + } else { + /* Disable SWBA interrupt */ + ah->imask &= ~ATH9K_INT_SWBA; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/btcoex.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/btcoex.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/btcoex.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/btcoex.c 2011-05-05 23:29:49.071485191 +0200 +@@ -51,6 +51,10 @@ + .bt_hold_rx_clear = true, + }; + u32 i; ++ bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity; ++ ++ if (AR_SREV_9300_20_OR_LATER(ah)) ++ rxclear_polarity = !ath_bt_config.bt_rxclear_polarity; + + btcoex_hw->bt_coex_mode = + (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) | +@@ -59,7 +63,7 @@ + SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | + SM(ath_bt_config.bt_mode, AR_BT_MODE) | + SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) | +- SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | ++ SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | + SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) | + SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | + SM(qnum, AR_BT_QCU_THRESH); +@@ -142,6 +146,7 @@ + } + EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); + ++ + static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) + { + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; +@@ -152,9 +157,22 @@ + * enable coex 3-wire + */ + REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_hw->bt_coex_mode); +- REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); + REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2); + ++ ++ if (AR_SREV_9300_20_OR_LATER(ah)) { ++ REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, ah->bt_coex_wlan_weight[0]); ++ REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, ah->bt_coex_wlan_weight[1]); ++ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, ah->bt_coex_bt_weight[0]); ++ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, ah->bt_coex_bt_weight[1]); ++ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, ah->bt_coex_bt_weight[2]); ++ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, ah->bt_coex_bt_weight[3]); ++ ++ } else ++ REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); ++ ++ ++ + if (AR_SREV_9271(ah)) { + val = REG_READ(ah, 0x50040); + val &= 0xFFFFFEFF; +@@ -202,10 +220,86 @@ + + if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) { + REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); +- REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); + REG_WRITE(ah, AR_BT_COEX_MODE2, 0); ++ ++ if (AR_SREV_9300_20_OR_LATER(ah)) { ++ REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, 0); ++ REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, 0); ++ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, 0); ++ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, 0); ++ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, 0); ++ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, 0); ++ } else ++ REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); ++ + } + + ah->btcoex_hw.enabled = false; + } + EXPORT_SYMBOL(ath9k_hw_btcoex_disable); ++ ++static void ar9003_btcoex_bt_stomp(struct ath_hw *ah, ++ enum ath_stomp_type stomp_type) ++{ ++ ah->bt_coex_bt_weight[0] = AR9300_BT_WGHT; ++ ah->bt_coex_bt_weight[1] = AR9300_BT_WGHT; ++ ah->bt_coex_bt_weight[2] = AR9300_BT_WGHT; ++ ah->bt_coex_bt_weight[3] = AR9300_BT_WGHT; ++ ++ ++ switch (stomp_type) { ++ case ATH_BTCOEX_STOMP_ALL: ++ ah->bt_coex_wlan_weight[0] = AR9300_STOMP_ALL_WLAN_WGHT0; ++ ah->bt_coex_wlan_weight[1] = AR9300_STOMP_ALL_WLAN_WGHT1; ++ break; ++ case ATH_BTCOEX_STOMP_LOW: ++ ah->bt_coex_wlan_weight[0] = AR9300_STOMP_LOW_WLAN_WGHT0; ++ ah->bt_coex_wlan_weight[1] = AR9300_STOMP_LOW_WLAN_WGHT1; ++ break; ++ case ATH_BTCOEX_STOMP_NONE: ++ ah->bt_coex_wlan_weight[0] = AR9300_STOMP_NONE_WLAN_WGHT0; ++ ah->bt_coex_wlan_weight[1] = AR9300_STOMP_NONE_WLAN_WGHT1; ++ break; ++ ++ default: ++ ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, ++ "Invalid Stomptype\n"); ++ break; ++ } ++ ++ ath9k_hw_btcoex_enable(ah); ++} ++ ++/* ++ * Configures appropriate weight based on stomp type. ++ */ ++void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, ++ enum ath_stomp_type stomp_type) ++{ ++ if (AR_SREV_9300_20_OR_LATER(ah)) { ++ ar9003_btcoex_bt_stomp(ah, stomp_type); ++ return; ++ } ++ ++ switch (stomp_type) { ++ case ATH_BTCOEX_STOMP_ALL: ++ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, ++ AR_STOMP_ALL_WLAN_WGHT); ++ break; ++ case ATH_BTCOEX_STOMP_LOW: ++ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, ++ AR_STOMP_LOW_WLAN_WGHT); ++ break; ++ case ATH_BTCOEX_STOMP_NONE: ++ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, ++ AR_STOMP_NONE_WLAN_WGHT); ++ break; ++ default: ++ ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, ++ "Invalid Stomptype\n"); ++ break; ++ } ++ ++ ath9k_hw_btcoex_enable(ah); ++} ++EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/btcoex.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/btcoex.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/btcoex.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/btcoex.h 2011-05-05 23:29:49.078485277 +0200 +@@ -19,9 +19,13 @@ + + #include "hw.h" + +-#define ATH_WLANACTIVE_GPIO 5 +-#define ATH_BTACTIVE_GPIO 6 +-#define ATH_BTPRIORITY_GPIO 7 ++#define ATH_WLANACTIVE_GPIO_9280 5 ++#define ATH_BTACTIVE_GPIO_9280 6 ++#define ATH_BTPRIORITY_GPIO_9285 7 ++ ++#define ATH_WLANACTIVE_GPIO_9300 5 ++#define ATH_BTACTIVE_GPIO_9300 4 ++#define ATH_BTPRIORITY_GPIO_9300 8 + + #define ATH_BTCOEX_DEF_BT_PERIOD 45 + #define ATH_BTCOEX_DEF_DUTY_CYCLE 55 +@@ -32,6 +36,14 @@ + #define ATH_BT_CNT_THRESHOLD 3 + #define ATH_BT_CNT_SCAN_THRESHOLD 15 + ++/* Defines the BT AR_BT_COEX_WGHT used */ ++enum ath_stomp_type { ++ ATH_BTCOEX_NO_STOMP, ++ ATH_BTCOEX_STOMP_ALL, ++ ATH_BTCOEX_STOMP_LOW, ++ ATH_BTCOEX_STOMP_NONE ++}; ++ + enum ath_btcoex_scheme { + ATH_BTCOEX_CFG_NONE, + ATH_BTCOEX_CFG_2WIRE, +@@ -57,5 +69,7 @@ + u32 wlan_weight); + void ath9k_hw_btcoex_enable(struct ath_hw *ah); + void ath9k_hw_btcoex_disable(struct ath_hw *ah); ++void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, ++ enum ath_stomp_type stomp_type); + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/common.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/common.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/common.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/common.c 2011-05-05 23:29:49.070485179 +0200 +@@ -116,7 +116,7 @@ + + if (chan->band == IEEE80211_BAND_2GHZ) { + ichan->chanmode = CHANNEL_G; +- ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; ++ ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; + } else { + ichan->chanmode = CHANNEL_A; + ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; +@@ -158,37 +158,6 @@ + } + EXPORT_SYMBOL(ath9k_cmn_count_streams); + +-/* +- * Configures appropriate weight based on stomp type. +- */ +-void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common, +- enum ath_stomp_type stomp_type) +-{ +- struct ath_hw *ah = common->ah; +- +- switch (stomp_type) { +- case ATH_BTCOEX_STOMP_ALL: +- ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, +- AR_STOMP_ALL_WLAN_WGHT); +- break; +- case ATH_BTCOEX_STOMP_LOW: +- ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, +- AR_STOMP_LOW_WLAN_WGHT); +- break; +- case ATH_BTCOEX_STOMP_NONE: +- ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, +- AR_STOMP_NONE_WLAN_WGHT); +- break; +- default: +- ath_dbg(common, ATH_DBG_BTCOEX, +- "Invalid Stomptype\n"); +- break; +- } +- +- ath9k_hw_btcoex_enable(ah); +-} +-EXPORT_SYMBOL(ath9k_cmn_btcoex_bt_stomp); +- + void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, + u16 new_txpow, u16 *txpower) + { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/common.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/common.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/common.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/common.h 2011-05-05 23:29:49.079485289 +0200 +@@ -50,14 +50,6 @@ + #define ATH_EP_RND(x, mul) \ + ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) + +-/* Defines the BT AR_BT_COEX_WGHT used */ +-enum ath_stomp_type { +- ATH_BTCOEX_NO_STOMP, +- ATH_BTCOEX_STOMP_ALL, +- ATH_BTCOEX_STOMP_LOW, +- ATH_BTCOEX_STOMP_NONE +-}; +- + int ath9k_cmn_padpos(__le16 frame_control); + int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); + void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/debug.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/debug.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/debug.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/debug.c 2011-05-05 23:29:49.081485313 +0200 +@@ -326,6 +326,8 @@ + sc->debug.stats.istats.dtimsync++; + if (status & ATH9K_INT_DTIM) + sc->debug.stats.istats.dtim++; ++ if (status & ATH9K_INT_TSFOOR) ++ sc->debug.stats.istats.tsfoor++; + } + + static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, +@@ -380,8 +382,11 @@ + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim); + len += snprintf(buf + len, sizeof(buf) - len, ++ "%8s: %10u\n", "TSFOOR", sc->debug.stats.istats.tsfoor); ++ len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total); + ++ + if (len > sizeof(buf)) + len = sizeof(buf); + +@@ -845,7 +850,7 @@ + + struct ath_softc *sc = file->private_data; + char *buf; +- unsigned int len = 0, size = 1152; ++ unsigned int len = 0, size = 1400; + ssize_t retval = 0; + + buf = kzalloc(size, GFP_KERNEL); +@@ -874,6 +879,34 @@ + "%18s : %10u\n", "DECRYPT BUSY ERR", + sc->debug.stats.rxstats.decrypt_busy_err); + ++ len += snprintf(buf + len, size - len, ++ "%18s : %10d\n", "RSSI-CTL0", ++ sc->debug.stats.rxstats.rs_rssi_ctl0); ++ ++ len += snprintf(buf + len, size - len, ++ "%18s : %10d\n", "RSSI-CTL1", ++ sc->debug.stats.rxstats.rs_rssi_ctl1); ++ ++ len += snprintf(buf + len, size - len, ++ "%18s : %10d\n", "RSSI-CTL2", ++ sc->debug.stats.rxstats.rs_rssi_ctl2); ++ ++ len += snprintf(buf + len, size - len, ++ "%18s : %10d\n", "RSSI-EXT0", ++ sc->debug.stats.rxstats.rs_rssi_ext0); ++ ++ len += snprintf(buf + len, size - len, ++ "%18s : %10d\n", "RSSI-EXT1", ++ sc->debug.stats.rxstats.rs_rssi_ext1); ++ ++ len += snprintf(buf + len, size - len, ++ "%18s : %10d\n", "RSSI-EXT2", ++ sc->debug.stats.rxstats.rs_rssi_ext2); ++ ++ len += snprintf(buf + len, size - len, ++ "%18s : %10d\n", "Rx Antenna", ++ sc->debug.stats.rxstats.rs_antenna); ++ + PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); + PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); + PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); +@@ -948,6 +981,16 @@ + RX_PHY_ERR_INC(phyerr); + } + ++ sc->debug.stats.rxstats.rs_rssi_ctl0 = rs->rs_rssi_ctl0; ++ sc->debug.stats.rxstats.rs_rssi_ctl1 = rs->rs_rssi_ctl1; ++ sc->debug.stats.rxstats.rs_rssi_ctl2 = rs->rs_rssi_ctl2; ++ ++ sc->debug.stats.rxstats.rs_rssi_ext0 = rs->rs_rssi_ext0; ++ sc->debug.stats.rxstats.rs_rssi_ext1 = rs->rs_rssi_ext1; ++ sc->debug.stats.rxstats.rs_rssi_ext2 = rs->rs_rssi_ext2; ++ ++ sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna; ++ + #undef RX_STAT_INC + #undef RX_PHY_ERR_INC + } +@@ -1088,67 +1131,43 @@ + return -ENOMEM; + + #ifdef CONFIG_ATH_DEBUG +- if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR, +- sc->debug.debugfs_phy, sc, &fops_debug)) +- goto err; ++ debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, ++ sc, &fops_debug); + #endif ++ debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, ++ &fops_dma); ++ debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc, ++ &fops_interrupt); ++ debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, ++ sc, &fops_wiphy); ++ debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, ++ &fops_xmit); ++ debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc, ++ &fops_stations); ++ debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, ++ &fops_misc); ++ debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, ++ &fops_recv); ++ debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, ++ sc->debug.debugfs_phy, sc, &fops_rx_chainmask); ++ debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, ++ sc->debug.debugfs_phy, sc, &fops_tx_chainmask); ++ debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, ++ sc, &fops_regidx); ++ debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, ++ sc, &fops_regval); ++ debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, ++ sc->debug.debugfs_phy, ++ &ah->config.cwm_ignore_extcca); ++ debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc, ++ &fops_regdump); ++ ++ debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, ++ sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); + +- if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, +- sc, &fops_dma)) +- goto err; +- +- if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, +- sc, &fops_interrupt)) +- goto err; +- +- if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, +- sc->debug.debugfs_phy, sc, &fops_wiphy)) +- goto err; +- +- if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, +- sc, &fops_xmit)) +- goto err; +- +- if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, +- sc, &fops_stations)) +- goto err; +- +- if (!debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, +- sc, &fops_misc)) +- goto err; +- +- if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, +- sc, &fops_recv)) +- goto err; +- +- if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, +- sc->debug.debugfs_phy, sc, &fops_rx_chainmask)) +- goto err; +- +- if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, +- sc->debug.debugfs_phy, sc, &fops_tx_chainmask)) +- goto err; +- +- if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR, +- sc->debug.debugfs_phy, sc, &fops_regidx)) +- goto err; +- +- if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR, +- sc->debug.debugfs_phy, sc, &fops_regval)) +- goto err; +- +- if (!debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, +- sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca)) +- goto err; +- +- if (!debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, +- sc, &fops_regdump)) +- goto err; ++ debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, ++ sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); + + sc->debug.regidx = 0; + return 0; +-err: +- debugfs_remove_recursive(sc->debug.debugfs_phy); +- sc->debug.debugfs_phy = NULL; +- return -ENOMEM; + } +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/debug.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/debug.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/debug.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/debug.h 2011-05-05 23:29:49.086485373 +0200 +@@ -54,6 +54,9 @@ + * @dtimsync: DTIM sync lossage + * @dtim: RX Beacon with DTIM + * @bb_watchdog: Baseband watchdog ++ * @tsfoor: TSF out of range, indicates that the corrected TSF received ++ * from a beacon differs from the PCU's internal TSF by more than a ++ * (programmable) threshold + */ + struct ath_interrupt_stats { + u32 total; +@@ -78,6 +81,7 @@ + u32 dtimsync; + u32 dtim; + u32 bb_watchdog; ++ u32 tsfoor; + }; + + /** +@@ -157,6 +161,13 @@ + u32 post_delim_crc_err; + u32 decrypt_busy_err; + u32 phy_err_stats[ATH9K_PHYERR_MAX]; ++ int8_t rs_rssi_ctl0; ++ int8_t rs_rssi_ctl1; ++ int8_t rs_rssi_ctl2; ++ int8_t rs_rssi_ext0; ++ int8_t rs_rssi_ext1; ++ int8_t rs_rssi_ext2; ++ u8 rs_antenna; + }; + + struct ath_stats { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/eeprom_4k.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/eeprom_4k.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/eeprom_4k.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/eeprom_4k.c 2011-05-05 23:29:49.064485107 +0200 +@@ -781,6 +781,7 @@ + { + struct modal_eep_4k_header *pModal; + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; ++ struct base_eep_header_4k *pBase = &eep->baseEepHeader; + u8 txRxAttenLocal; + u8 ob[5], db1[5], db2[5]; + u8 ant_div_control1, ant_div_control2; +@@ -1003,6 +1004,31 @@ + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } ++ if (AR_SREV_9271(ah) || AR_SREV_9285(ah)) { ++ u8 bb_desired_scale = (pModal->bb_scale_smrt_antenna & ++ EEP_4K_BB_DESIRED_SCALE_MASK); ++ if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) { ++ u32 pwrctrl, mask, clr; ++ ++ mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25); ++ pwrctrl = mask * bb_desired_scale; ++ clr = mask * 0x1f; ++ REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr); ++ REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr); ++ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr); ++ ++ mask = BIT(0)|BIT(5)|BIT(15); ++ pwrctrl = mask * bb_desired_scale; ++ clr = mask * 0x1f; ++ REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr); ++ ++ mask = BIT(0)|BIT(5); ++ pwrctrl = mask * bb_desired_scale; ++ clr = mask * 0x1f; ++ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr); ++ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr); ++ } ++ } + } + + static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/eeprom_9287.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/eeprom_9287.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/eeprom_9287.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/eeprom_9287.c 2011-05-05 23:29:49.043484853 +0200 +@@ -319,10 +319,9 @@ + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0}; + u32 reg32, regOffset, regChainOffset, regval; +- int16_t modalIdx, diff = 0; ++ int16_t diff = 0; + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; + +- modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader.xpdGain; + + if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= +@@ -392,6 +391,8 @@ + numXpdGain); + } + ++ ENABLE_REGWRITE_BUFFER(ah); ++ + if (i == 0) { + if (!ath9k_hw_ar9287_get_eeprom(ah, + EEP_OL_PWRCTRL)) { +@@ -442,6 +443,7 @@ + regOffset += 4; + } + } ++ REGWRITE_BUFFER_FLUSH(ah); + } + } + +@@ -757,6 +759,8 @@ + ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; + } + ++ ENABLE_REGWRITE_BUFFER(ah); ++ + /* OFDM power per rate */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) +@@ -840,6 +844,7 @@ + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } ++ REGWRITE_BUFFER_FLUSH(ah); + } + + static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah, +@@ -852,35 +857,12 @@ + { + struct ar9287_eeprom *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; +- u16 antWrites[AR9287_ANT_16S]; + u32 regChainOffset, regval; + u8 txRxAttenLocal; +- int i, j, offset_num; ++ int i; + + pModal = &eep->modalHeader; + +- antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF); +- antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF); +- antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF); +- antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF); +- antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF); +- antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF); +- antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF); +- antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF); +- +- offset_num = 8; +- +- for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { +- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf); +- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3); +- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3); +- antWrites[j++] = 0; +- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3); +- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3); +- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3); +- antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); +- } +- + REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/eeprom_def.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/eeprom_def.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/eeprom_def.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/eeprom_def.c 2011-05-05 23:29:49.074485227 +0200 +@@ -231,6 +231,10 @@ + integer = swab32(pModal->antCtrlChain[i]); + pModal->antCtrlChain[i] = integer; + } ++ for (i = 0; i < 3; i++) { ++ word = swab16(pModal->xpaBiasLvlFreq[i]); ++ pModal->xpaBiasLvlFreq[i] = word; ++ } + + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + word = swab16(pModal->spurChans[i].spurChan); +@@ -799,6 +803,8 @@ + pwr_table_offset, + &diff); + ++ ENABLE_REGWRITE_BUFFER(ah); ++ + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { + if (OLC_FOR_AR9280_20_LATER) { + REG_WRITE(ah, +@@ -847,6 +853,7 @@ + + regOffset += 4; + } ++ REGWRITE_BUFFER_FLUSH(ah); + } + } + +@@ -1205,6 +1212,8 @@ + } + } + ++ ENABLE_REGWRITE_BUFFER(ah); ++ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) +@@ -1291,6 +1300,8 @@ + REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) + | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); ++ ++ REGWRITE_BUFFER_FLUSH(ah); + } + + static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/eeprom.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/eeprom.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/eeprom.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/eeprom.h 2011-05-05 23:29:49.075485239 +0200 +@@ -436,7 +436,11 @@ + u8 db2_2:4, db2_3:4; + u8 db2_4:4, reserved:4; + #endif +- u8 futureModal[4]; ++ u8 tx_diversity; ++ u8 flc_pwr_thresh; ++ u8 bb_scale_smrt_antenna; ++#define EEP_4K_BB_DESIRED_SCALE_MASK 0x1f ++ u8 futureModal[1]; + struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS]; + } __packed; + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/gpio.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/gpio.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/gpio.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/gpio.c 2011-05-05 23:29:49.080485301 +0200 +@@ -41,12 +41,16 @@ + { + int ret; + +- if (AR_SREV_9287(sc->sc_ah)) +- sc->sc_ah->led_pin = ATH_LED_PIN_9287; +- else if (AR_SREV_9485(sc->sc_ah)) +- sc->sc_ah->led_pin = ATH_LED_PIN_9485; +- else +- sc->sc_ah->led_pin = ATH_LED_PIN_DEF; ++ if (sc->sc_ah->led_pin < 0) { ++ if (AR_SREV_9287(sc->sc_ah)) ++ sc->sc_ah->led_pin = ATH_LED_PIN_9287; ++ else if (AR_SREV_9485(sc->sc_ah)) ++ sc->sc_ah->led_pin = ATH_LED_PIN_9485; ++ else if (AR_SREV_9300(sc->sc_ah)) ++ sc->sc_ah->led_pin = ATH_LED_PIN_9300; ++ else ++ sc->sc_ah->led_pin = ATH_LED_PIN_DEF; ++ } + + /* Configure gpio 1 for output */ + ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, +@@ -136,10 +140,10 @@ + + static void ath9k_gen_timer_start(struct ath_hw *ah, + struct ath_gen_timer *timer, +- u32 timer_next, ++ u32 trig_timeout, + u32 timer_period) + { +- ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); ++ ath9k_hw_gen_timer_start(ah, timer, trig_timeout, timer_period); + + if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { + ath9k_hw_disable_interrupts(ah); +@@ -172,17 +176,17 @@ + struct ath_softc *sc = (struct ath_softc *) data; + struct ath_hw *ah = sc->sc_ah; + struct ath_btcoex *btcoex = &sc->btcoex; +- struct ath_common *common = ath9k_hw_common(ah); + u32 timer_period; + bool is_btscan; + ++ ath9k_ps_wakeup(sc); + ath_detect_bt_priority(sc); + + is_btscan = sc->sc_flags & SC_OP_BT_SCAN; + + spin_lock_bh(&btcoex->btcoex_lock); + +- ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL : ++ ath9k_hw_btcoex_bt_stomp(ah, is_btscan ? ATH_BTCOEX_STOMP_ALL : + btcoex->bt_stomp_type); + + spin_unlock_bh(&btcoex->btcoex_lock); +@@ -193,11 +197,12 @@ + + timer_period = is_btscan ? btcoex->btscan_no_stomp : + btcoex->btcoex_no_stomp; +- ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, 0, ++ ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period, + timer_period * 10); + btcoex->hw_timer_enabled = true; + } + ++ ath9k_ps_restore(sc); + mod_timer(&btcoex->period_timer, jiffies + + msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); + } +@@ -217,14 +222,16 @@ + ath_dbg(common, ATH_DBG_BTCOEX, + "no stomp timer running\n"); + ++ ath9k_ps_wakeup(sc); + spin_lock_bh(&btcoex->btcoex_lock); + + if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) +- ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE); ++ ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); + else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) +- ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW); ++ ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); + + spin_unlock_bh(&btcoex->btcoex_lock); ++ ath9k_ps_restore(sc); + } + + int ath_init_btcoex_timer(struct ath_softc *sc) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/hif_usb.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/hif_usb.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/hif_usb.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/hif_usb.c 2011-05-05 23:29:49.091485433 +0200 +@@ -17,11 +17,9 @@ + #include "htc.h" + + /* identify firmware images */ +-#define FIRMWARE_AR7010 "ar7010.fw" +-#define FIRMWARE_AR7010_1_1 "ar7010_1_1.fw" +-#define FIRMWARE_AR9271 "ar9271.fw" ++#define FIRMWARE_AR7010_1_1 "htc_7010.fw" ++#define FIRMWARE_AR9271 "htc_9271.fw" + +-MODULE_FIRMWARE(FIRMWARE_AR7010); + MODULE_FIRMWARE(FIRMWARE_AR7010_1_1); + MODULE_FIRMWARE(FIRMWARE_AR9271); + +@@ -80,7 +78,7 @@ + + if (cmd) { + ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle, +- cmd->skb, 1); ++ cmd->skb, true); + kfree(cmd); + } + +@@ -126,6 +124,90 @@ + return ret; + } + ++static void hif_usb_mgmt_cb(struct urb *urb) ++{ ++ struct cmd_buf *cmd = (struct cmd_buf *)urb->context; ++ struct hif_device_usb *hif_dev = cmd->hif_dev; ++ bool txok = true; ++ ++ if (!cmd || !cmd->skb || !cmd->hif_dev) ++ return; ++ ++ switch (urb->status) { ++ case 0: ++ break; ++ case -ENOENT: ++ case -ECONNRESET: ++ case -ENODEV: ++ case -ESHUTDOWN: ++ txok = false; ++ ++ /* ++ * If the URBs are being flushed, no need to complete ++ * this packet. ++ */ ++ spin_lock(&hif_dev->tx.tx_lock); ++ if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) { ++ spin_unlock(&hif_dev->tx.tx_lock); ++ dev_kfree_skb_any(cmd->skb); ++ kfree(cmd); ++ return; ++ } ++ spin_unlock(&hif_dev->tx.tx_lock); ++ ++ break; ++ default: ++ txok = false; ++ break; ++ } ++ ++ skb_pull(cmd->skb, 4); ++ ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle, ++ cmd->skb, txok); ++ kfree(cmd); ++} ++ ++static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev, ++ struct sk_buff *skb) ++{ ++ struct urb *urb; ++ struct cmd_buf *cmd; ++ int ret = 0; ++ __le16 *hdr; ++ ++ urb = usb_alloc_urb(0, GFP_ATOMIC); ++ if (urb == NULL) ++ return -ENOMEM; ++ ++ cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); ++ if (cmd == NULL) { ++ usb_free_urb(urb); ++ return -ENOMEM; ++ } ++ ++ cmd->skb = skb; ++ cmd->hif_dev = hif_dev; ++ ++ hdr = (__le16 *) skb_push(skb, 4); ++ *hdr++ = cpu_to_le16(skb->len - 4); ++ *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG); ++ ++ usb_fill_bulk_urb(urb, hif_dev->udev, ++ usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE), ++ skb->data, skb->len, ++ hif_usb_mgmt_cb, cmd); ++ ++ usb_anchor_urb(urb, &hif_dev->mgmt_submitted); ++ ret = usb_submit_urb(urb, GFP_ATOMIC); ++ if (ret) { ++ usb_unanchor_urb(urb); ++ kfree(cmd); ++ } ++ usb_free_urb(urb); ++ ++ return ret; ++} ++ + static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, + struct sk_buff_head *list) + { +@@ -133,7 +215,22 @@ + + while ((skb = __skb_dequeue(list)) != NULL) { + dev_kfree_skb_any(skb); +- TX_STAT_INC(skb_dropped); ++ } ++} ++ ++static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev, ++ struct sk_buff_head *queue, ++ bool txok) ++{ ++ struct sk_buff *skb; ++ ++ while ((skb = __skb_dequeue(queue)) != NULL) { ++ ath9k_htc_txcompletion_cb(hif_dev->htc_handle, ++ skb, txok); ++ if (txok) ++ TX_STAT_INC(skb_success); ++ else ++ TX_STAT_INC(skb_failed); + } + } + +@@ -141,7 +238,7 @@ + { + struct tx_buf *tx_buf = (struct tx_buf *) urb->context; + struct hif_device_usb *hif_dev; +- struct sk_buff *skb; ++ bool txok = true; + + if (!tx_buf || !tx_buf->hif_dev) + return; +@@ -155,10 +252,7 @@ + case -ECONNRESET: + case -ENODEV: + case -ESHUTDOWN: +- /* +- * The URB has been killed, free the SKBs. +- */ +- ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); ++ txok = false; + + /* + * If the URBs are being flushed, no need to add this +@@ -167,41 +261,19 @@ + spin_lock(&hif_dev->tx.tx_lock); + if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) { + spin_unlock(&hif_dev->tx.tx_lock); ++ ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); + return; + } + spin_unlock(&hif_dev->tx.tx_lock); + +- /* +- * In the stop() case, this URB has to be added to +- * the free list. +- */ +- goto add_free; ++ break; + default: ++ txok = false; + break; + } + +- /* +- * Check if TX has been stopped, this is needed because +- * this CB could have been invoked just after the TX lock +- * was released in hif_stop() and kill_urb() hasn't been +- * called yet. +- */ +- spin_lock(&hif_dev->tx.tx_lock); +- if (hif_dev->tx.flags & HIF_USB_TX_STOP) { +- spin_unlock(&hif_dev->tx.tx_lock); +- ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); +- goto add_free; +- } +- spin_unlock(&hif_dev->tx.tx_lock); +- +- /* Complete the queued SKBs. */ +- while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) { +- ath9k_htc_txcompletion_cb(hif_dev->htc_handle, +- skb, 1); +- TX_STAT_INC(skb_completed); +- } ++ ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, txok); + +-add_free: + /* Re-initialize the SKB queue */ + tx_buf->len = tx_buf->offset = 0; + __skb_queue_head_init(&tx_buf->skb_queue); +@@ -274,7 +346,7 @@ + ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC); + if (ret) { + tx_buf->len = tx_buf->offset = 0; +- ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); ++ ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, false); + __skb_queue_head_init(&tx_buf->skb_queue); + list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf); + hif_dev->tx.tx_buf_cnt++; +@@ -286,10 +358,11 @@ + return ret; + } + +-static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb, +- struct ath9k_htc_tx_ctl *tx_ctl) ++static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb) + { ++ struct ath9k_htc_tx_ctl *tx_ctl; + unsigned long flags; ++ int ret = 0; + + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); + +@@ -304,26 +377,36 @@ + return -ENOMEM; + } + +- __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb); +- hif_dev->tx.tx_skb_cnt++; ++ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); + +- /* Send normal frames immediately */ +- if (!tx_ctl || (tx_ctl && (tx_ctl->type == ATH9K_HTC_NORMAL))) +- __hif_usb_tx(hif_dev); ++ tx_ctl = HTC_SKB_CB(skb); ++ ++ /* Mgmt/Beacon frames don't use the TX buffer pool */ ++ if ((tx_ctl->type == ATH9K_HTC_MGMT) || ++ (tx_ctl->type == ATH9K_HTC_BEACON)) { ++ ret = hif_usb_send_mgmt(hif_dev, skb); ++ } ++ ++ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); ++ ++ if ((tx_ctl->type == ATH9K_HTC_NORMAL) || ++ (tx_ctl->type == ATH9K_HTC_AMPDU)) { ++ __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb); ++ hif_dev->tx.tx_skb_cnt++; ++ } + + /* Check if AMPDUs have to be sent immediately */ +- if (tx_ctl && (tx_ctl->type == ATH9K_HTC_AMPDU) && +- (hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) && ++ if ((hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) && + (hif_dev->tx.tx_skb_cnt < 2)) { + __hif_usb_tx(hif_dev); + } + + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); + +- return 0; ++ return ret; + } + +-static void hif_usb_start(void *hif_handle, u8 pipe_id) ++static void hif_usb_start(void *hif_handle) + { + struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + unsigned long flags; +@@ -335,14 +418,14 @@ + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); + } + +-static void hif_usb_stop(void *hif_handle, u8 pipe_id) ++static void hif_usb_stop(void *hif_handle) + { + struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; + unsigned long flags; + + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); +- ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue); ++ ath9k_skb_queue_complete(hif_dev, &hif_dev->tx.tx_skb_queue, false); + hif_dev->tx.tx_skb_cnt = 0; + hif_dev->tx.flags |= HIF_USB_TX_STOP; + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); +@@ -352,17 +435,18 @@ + &hif_dev->tx.tx_pending, list) { + usb_kill_urb(tx_buf->urb); + } ++ ++ usb_kill_anchored_urbs(&hif_dev->mgmt_submitted); + } + +-static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, +- struct ath9k_htc_tx_ctl *tx_ctl) ++static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb) + { + struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + int ret = 0; + + switch (pipe_id) { + case USB_WLAN_TX_PIPE: +- ret = hif_usb_send_tx(hif_dev, skb, tx_ctl); ++ ret = hif_usb_send_tx(hif_dev, skb); + break; + case USB_REG_OUT_PIPE: + ret = hif_usb_send_regout(hif_dev, skb); +@@ -377,6 +461,40 @@ + return ret; + } + ++static inline bool check_index(struct sk_buff *skb, u8 idx) ++{ ++ struct ath9k_htc_tx_ctl *tx_ctl; ++ ++ tx_ctl = HTC_SKB_CB(skb); ++ ++ if ((tx_ctl->type == ATH9K_HTC_AMPDU) && ++ (tx_ctl->sta_idx == idx)) ++ return true; ++ ++ return false; ++} ++ ++static void hif_usb_sta_drain(void *hif_handle, u8 idx) ++{ ++ struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; ++ struct sk_buff *skb, *tmp; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); ++ ++ skb_queue_walk_safe(&hif_dev->tx.tx_skb_queue, skb, tmp) { ++ if (check_index(skb, idx)) { ++ __skb_unlink(skb, &hif_dev->tx.tx_skb_queue); ++ ath9k_htc_txcompletion_cb(hif_dev->htc_handle, ++ skb, false); ++ hif_dev->tx.tx_skb_cnt--; ++ TX_STAT_INC(skb_failed); ++ } ++ } ++ ++ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); ++} ++ + static struct ath9k_htc_hif hif_usb = { + .transport = ATH9K_HIF_USB, + .name = "ath9k_hif_usb", +@@ -386,6 +504,7 @@ + + .start = hif_usb_start, + .stop = hif_usb_stop, ++ .sta_drain = hif_usb_sta_drain, + .send = hif_usb_send, + }; + +@@ -567,6 +686,9 @@ + case -ESHUTDOWN: + goto free; + default: ++ skb_reset_tail_pointer(skb); ++ skb_trim(skb, 0); ++ + goto resubmit; + } + +@@ -591,23 +713,15 @@ + USB_REG_IN_PIPE), + nskb->data, MAX_REG_IN_BUF_SIZE, + ath9k_hif_usb_reg_in_cb, nskb); +- +- ret = usb_submit_urb(urb, GFP_ATOMIC); +- if (ret) { +- kfree_skb(nskb); +- urb->context = NULL; +- } +- +- return; + } + + resubmit: +- skb_reset_tail_pointer(skb); +- skb_trim(skb, 0); +- ++ usb_anchor_urb(urb, &hif_dev->reg_in_submitted); + ret = usb_submit_urb(urb, GFP_ATOMIC); +- if (ret) ++ if (ret) { ++ usb_unanchor_urb(urb); + goto free; ++ } + + return; + free: +@@ -641,6 +755,8 @@ + kfree(tx_buf->buf); + kfree(tx_buf); + } ++ ++ usb_kill_anchored_urbs(&hif_dev->mgmt_submitted); + } + + static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) +@@ -652,6 +768,7 @@ + INIT_LIST_HEAD(&hif_dev->tx.tx_pending); + spin_lock_init(&hif_dev->tx.tx_lock); + __skb_queue_head_init(&hif_dev->tx.tx_skb_queue); ++ init_usb_anchor(&hif_dev->mgmt_submitted); + + for (i = 0; i < MAX_TX_URB_NUM; i++) { + tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL); +@@ -748,43 +865,67 @@ + return ret; + } + +-static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev) ++static void ath9k_hif_usb_dealloc_reg_in_urbs(struct hif_device_usb *hif_dev) + { +- if (hif_dev->reg_in_urb) { +- usb_kill_urb(hif_dev->reg_in_urb); +- if (hif_dev->reg_in_urb->context) +- kfree_skb((void *)hif_dev->reg_in_urb->context); +- usb_free_urb(hif_dev->reg_in_urb); +- hif_dev->reg_in_urb = NULL; +- } ++ usb_kill_anchored_urbs(&hif_dev->reg_in_submitted); + } + +-static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev) ++static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev) + { +- struct sk_buff *skb; ++ struct urb *urb = NULL; ++ struct sk_buff *skb = NULL; ++ int i, ret; + +- hif_dev->reg_in_urb = usb_alloc_urb(0, GFP_KERNEL); +- if (hif_dev->reg_in_urb == NULL) +- return -ENOMEM; ++ init_usb_anchor(&hif_dev->reg_in_submitted); + +- skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL); +- if (!skb) +- goto err; ++ for (i = 0; i < MAX_REG_IN_URB_NUM; i++) { + +- usb_fill_bulk_urb(hif_dev->reg_in_urb, hif_dev->udev, +- usb_rcvbulkpipe(hif_dev->udev, +- USB_REG_IN_PIPE), +- skb->data, MAX_REG_IN_BUF_SIZE, +- ath9k_hif_usb_reg_in_cb, skb); ++ /* Allocate URB */ ++ urb = usb_alloc_urb(0, GFP_KERNEL); ++ if (urb == NULL) { ++ ret = -ENOMEM; ++ goto err_urb; ++ } + +- if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0) +- goto err; ++ /* Allocate buffer */ ++ skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL); ++ if (!skb) { ++ ret = -ENOMEM; ++ goto err_skb; ++ } ++ ++ usb_fill_bulk_urb(urb, hif_dev->udev, ++ usb_rcvbulkpipe(hif_dev->udev, ++ USB_REG_IN_PIPE), ++ skb->data, MAX_REG_IN_BUF_SIZE, ++ ath9k_hif_usb_reg_in_cb, skb); ++ ++ /* Anchor URB */ ++ usb_anchor_urb(urb, &hif_dev->reg_in_submitted); ++ ++ /* Submit URB */ ++ ret = usb_submit_urb(urb, GFP_KERNEL); ++ if (ret) { ++ usb_unanchor_urb(urb); ++ goto err_submit; ++ } ++ ++ /* ++ * Drop reference count. ++ * This ensures that the URB is freed when killing them. ++ */ ++ usb_free_urb(urb); ++ } + + return 0; + +-err: +- ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); +- return -ENOMEM; ++err_submit: ++ kfree_skb(skb); ++err_skb: ++ usb_free_urb(urb); ++err_urb: ++ ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev); ++ return ret; + } + + static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev) +@@ -801,7 +942,7 @@ + goto err_rx; + + /* Register Read */ +- if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0) ++ if (ath9k_hif_usb_alloc_reg_in_urbs(hif_dev) < 0) + goto err_reg; + + return 0; +@@ -816,7 +957,7 @@ + static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev) + { + usb_kill_anchored_urbs(&hif_dev->regout_submitted); +- ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); ++ ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev); + ath9k_hif_usb_dealloc_tx_urbs(hif_dev); + ath9k_hif_usb_dealloc_rx_urbs(hif_dev); + } +@@ -1026,10 +1167,7 @@ + /* Find out which firmware to load */ + + if (IS_AR7010_DEVICE(id->driver_info)) +- if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202) +- hif_dev->fw_name = FIRMWARE_AR7010_1_1; +- else +- hif_dev->fw_name = FIRMWARE_AR7010; ++ hif_dev->fw_name = FIRMWARE_AR7010_1_1; + else + hif_dev->fw_name = FIRMWARE_AR9271; + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/hif_usb.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/hif_usb.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/hif_usb.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/hif_usb.h 2011-05-05 23:29:49.085485361 +0200 +@@ -17,6 +17,9 @@ + #ifndef HTC_USB_H + #define HTC_USB_H + ++#define MAJOR_VERSION_REQ 1 ++#define MINOR_VERSION_REQ 2 ++ + #define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB)) + + #define AR9271_FIRMWARE 0x501000 +@@ -31,7 +34,7 @@ + + /* FIXME: Verify these numbers (with Windows) */ + #define MAX_TX_URB_NUM 8 +-#define MAX_TX_BUF_NUM 1024 ++#define MAX_TX_BUF_NUM 256 + #define MAX_TX_BUF_SIZE 32768 + #define MAX_TX_AGGR_NUM 20 + +@@ -40,7 +43,7 @@ + #define MAX_PKT_NUM_IN_TRANSFER 10 + + #define MAX_REG_OUT_URB_NUM 1 +-#define MAX_REG_OUT_BUF_NUM 8 ++#define MAX_REG_IN_URB_NUM 64 + + #define MAX_REG_IN_BUF_SIZE 64 + +@@ -90,9 +93,10 @@ + const struct firmware *firmware; + struct htc_target *htc_handle; + struct hif_usb_tx tx; +- struct urb *reg_in_urb; + struct usb_anchor regout_submitted; + struct usb_anchor rx_submitted; ++ struct usb_anchor reg_in_submitted; ++ struct usb_anchor mgmt_submitted; + struct sk_buff *remain_skb; + const char *fw_name; + int rx_remain_len; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c 2011-05-05 23:29:49.072485203 +0200 +@@ -18,6 +18,50 @@ + + #define FUDGE 2 + ++void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) ++{ ++ struct ath_hw *ah = priv->ah; ++ struct ath9k_tx_queue_info qi, qi_be; ++ ++ memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); ++ memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); ++ ++ ath9k_hw_get_txq_props(ah, priv->beaconq, &qi); ++ ++ if (priv->ah->opmode == NL80211_IFTYPE_AP) { ++ qi.tqi_aifs = 1; ++ qi.tqi_cwmin = 0; ++ qi.tqi_cwmax = 0; ++ } else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) { ++ int qnum = priv->hwq_map[WME_AC_BE]; ++ ++ ath9k_hw_get_txq_props(ah, qnum, &qi_be); ++ ++ qi.tqi_aifs = qi_be.tqi_aifs; ++ ++ /* ++ * For WIFI Beacon Distribution ++ * Long slot time : 2x cwmin ++ * Short slot time : 4x cwmin ++ */ ++ if (ah->slottime == ATH9K_SLOT_TIME_20) ++ qi.tqi_cwmin = 2*qi_be.tqi_cwmin; ++ else ++ qi.tqi_cwmin = 4*qi_be.tqi_cwmin; ++ ++ qi.tqi_cwmax = qi_be.tqi_cwmax; ++ ++ } ++ ++ if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { ++ ath_err(ath9k_hw_common(ah), ++ "Unable to update beacon queue %u!\n", priv->beaconq); ++ } else { ++ ath9k_hw_resettxqueue(ah, priv->beaconq); ++ } ++} ++ ++ + static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, + struct htc_beacon_config *bss_conf) + { +@@ -30,7 +74,7 @@ + __be32 htc_imask = 0; + u64 tsf; + int num_beacons, offset, dtim_dec_count, cfp_dec_count; +- int ret; ++ int ret __attribute__ ((unused)); + u8 cmd_rsp; + + memset(&bs, 0, sizeof(bs)); +@@ -146,7 +190,7 @@ + enum ath9k_int imask = 0; + u32 nexttbtt, intval, tsftu; + __be32 htc_imask = 0; +- int ret; ++ int ret __attribute__ ((unused)); + u8 cmd_rsp; + u64 tsf; + +@@ -154,8 +198,17 @@ + intval /= ATH9K_HTC_MAX_BCN_VIF; + nexttbtt = intval; + ++ /* ++ * To reduce beacon misses under heavy TX load, ++ * set the beacon response time to a larger value. ++ */ ++ if (intval > DEFAULT_SWBA_RESPONSE) ++ priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; ++ else ++ priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; ++ + if (priv->op_flags & OP_TSF_RESET) { +- intval |= ATH9K_BEACON_RESET_TSF; ++ ath9k_hw_reset_tsf(priv->ah); + priv->op_flags &= ~OP_TSF_RESET; + } else { + /* +@@ -168,18 +221,20 @@ + } while (nexttbtt < tsftu); + } + +- intval |= ATH9K_BEACON_ENA; +- + if (priv->op_flags & OP_ENABLE_BEACON) + imask |= ATH9K_INT_SWBA; + + ath_dbg(common, ATH_DBG_CONFIG, +- "AP Beacon config, intval: %d, nexttbtt: %u imask: 0x%x\n", +- bss_conf->beacon_interval, nexttbtt, imask); ++ "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d " ++ "imask: 0x%x\n", ++ bss_conf->beacon_interval, nexttbtt, ++ priv->ah->config.sw_beacon_response_time, imask); ++ ++ ath9k_htc_beaconq_config(priv); + + WMI_CMD(WMI_DISABLE_INTR_CMDID); +- ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); +- priv->bmiss_cnt = 0; ++ ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); ++ priv->cur_beacon_conf.bmiss_cnt = 0; + htc_imask = cpu_to_be32(imask); + WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); + } +@@ -191,7 +246,7 @@ + enum ath9k_int imask = 0; + u32 nexttbtt, intval, tsftu; + __be32 htc_imask = 0; +- int ret; ++ int ret __attribute__ ((unused)); + u8 cmd_rsp; + u64 tsf; + +@@ -207,17 +262,26 @@ + nexttbtt += intval; + } while (nexttbtt < tsftu); + +- intval |= ATH9K_BEACON_ENA; ++ /* ++ * Only one IBSS interfce is allowed. ++ */ ++ if (intval > DEFAULT_SWBA_RESPONSE) ++ priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; ++ else ++ priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; ++ + if (priv->op_flags & OP_ENABLE_BEACON) + imask |= ATH9K_INT_SWBA; + + ath_dbg(common, ATH_DBG_CONFIG, +- "IBSS Beacon config, intval: %d, nexttbtt: %u, imask: 0x%x\n", +- bss_conf->beacon_interval, nexttbtt, imask); ++ "IBSS Beacon config, intval: %d, nexttbtt: %u, " ++ "resp_time: %d, imask: 0x%x\n", ++ bss_conf->beacon_interval, nexttbtt, ++ priv->ah->config.sw_beacon_response_time, imask); + + WMI_CMD(WMI_DISABLE_INTR_CMDID); +- ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); +- priv->bmiss_cnt = 0; ++ ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); ++ priv->cur_beacon_conf.bmiss_cnt = 0; + htc_imask = cpu_to_be32(imask); + WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); + } +@@ -228,38 +292,101 @@ + dev_kfree_skb_any(skb); + } + +-void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) ++static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, ++ int slot) ++{ ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ struct ieee80211_vif *vif; ++ struct sk_buff *skb; ++ struct ieee80211_hdr *hdr; ++ int padpos, padsize, ret, tx_slot; ++ ++ spin_lock_bh(&priv->beacon_lock); ++ ++ vif = priv->cur_beacon_conf.bslot[slot]; ++ ++ skb = ieee80211_get_buffered_bc(priv->hw, vif); ++ ++ while(skb) { ++ hdr = (struct ieee80211_hdr *) skb->data; ++ ++ padpos = ath9k_cmn_padpos(hdr->frame_control); ++ padsize = padpos & 3; ++ if (padsize && skb->len > padpos) { ++ if (skb_headroom(skb) < padsize) { ++ dev_kfree_skb_any(skb); ++ goto next; ++ } ++ skb_push(skb, padsize); ++ memmove(skb->data, skb->data + padsize, padpos); ++ } ++ ++ tx_slot = ath9k_htc_tx_get_slot(priv); ++ if (tx_slot < 0) { ++ ath_dbg(common, ATH_DBG_XMIT, "No free CAB slot\n"); ++ dev_kfree_skb_any(skb); ++ goto next; ++ } ++ ++ ret = ath9k_htc_tx_start(priv, skb, tx_slot, true); ++ if (ret != 0) { ++ ath9k_htc_tx_clear_slot(priv, tx_slot); ++ dev_kfree_skb_any(skb); ++ ++ ath_dbg(common, ATH_DBG_XMIT, ++ "Failed to send CAB frame\n"); ++ } else { ++ spin_lock_bh(&priv->tx.tx_lock); ++ priv->tx.queued_cnt++; ++ spin_unlock_bh(&priv->tx.tx_lock); ++ } ++ next: ++ skb = ieee80211_get_buffered_bc(priv->hw, vif); ++ } ++ ++ spin_unlock_bh(&priv->beacon_lock); ++} ++ ++static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, ++ int slot) + { +- struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv; ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ struct ieee80211_vif *vif; ++ struct ath9k_htc_vif *avp; + struct tx_beacon_header beacon_hdr; +- struct ath9k_htc_tx_ctl tx_ctl; ++ struct ath9k_htc_tx_ctl *tx_ctl; + struct ieee80211_tx_info *info; ++ struct ieee80211_mgmt *mgmt; + struct sk_buff *beacon; + u8 *tx_fhdr; ++ int ret; + + memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header)); +- memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); +- +- /* FIXME: Handle BMISS */ +- if (beacon_pending != 0) { +- priv->bmiss_cnt++; +- return; +- } + + spin_lock_bh(&priv->beacon_lock); + ++ vif = priv->cur_beacon_conf.bslot[slot]; ++ avp = (struct ath9k_htc_vif *)vif->drv_priv; ++ + if (unlikely(priv->op_flags & OP_SCANNING)) { + spin_unlock_bh(&priv->beacon_lock); + return; + } + + /* Get a new beacon */ +- beacon = ieee80211_beacon_get(priv->hw, priv->vif); ++ beacon = ieee80211_beacon_get(priv->hw, vif); + if (!beacon) { + spin_unlock_bh(&priv->beacon_lock); + return; + } + ++ /* ++ * Update the TSF adjust value here, the HW will ++ * add this value for every beacon. ++ */ ++ mgmt = (struct ieee80211_mgmt *)beacon->data; ++ mgmt->u.beacon.timestamp = avp->tsfadjust; ++ + info = IEEE80211_SKB_CB(beacon); + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + struct ieee80211_hdr *hdr = +@@ -269,45 +396,149 @@ + hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); + } + +- tx_ctl.type = ATH9K_HTC_NORMAL; ++ tx_ctl = HTC_SKB_CB(beacon); ++ memset(tx_ctl, 0, sizeof(*tx_ctl)); ++ ++ tx_ctl->type = ATH9K_HTC_BEACON; ++ tx_ctl->epid = priv->beacon_ep; ++ + beacon_hdr.vif_index = avp->index; + tx_fhdr = skb_push(beacon, sizeof(beacon_hdr)); + memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr)); + +- htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl); ++ ret = htc_send(priv->htc, beacon); ++ if (ret != 0) { ++ if (ret == -ENOMEM) { ++ ath_dbg(common, ATH_DBG_BSTUCK, ++ "Failed to send beacon, no free TX buffer\n"); ++ } ++ dev_kfree_skb_any(beacon); ++ } + + spin_unlock_bh(&priv->beacon_lock); + } + +-/* Currently, only for IBSS */ +-void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) ++static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv, ++ struct wmi_event_swba *swba) + { +- struct ath_hw *ah = priv->ah; +- struct ath9k_tx_queue_info qi, qi_be; +- int qnum = priv->hwq_map[WME_AC_BE]; ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ u64 tsf; ++ u32 tsftu; ++ u16 intval; ++ int slot; ++ ++ intval = priv->cur_beacon_conf.beacon_interval & ATH9K_BEACON_PERIOD; ++ ++ tsf = be64_to_cpu(swba->tsf); ++ tsftu = TSF_TO_TU(tsf >> 32, tsf); ++ slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval; ++ slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1; ++ ++ ath_dbg(common, ATH_DBG_BEACON, ++ "Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n", ++ slot, tsf, tsftu, intval); + +- memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); +- memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); ++ return slot; ++} + +- ath9k_hw_get_txq_props(ah, qnum, &qi_be); ++void ath9k_htc_swba(struct ath9k_htc_priv *priv, ++ struct wmi_event_swba *swba) ++{ ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ int slot; + +- qi.tqi_aifs = qi_be.tqi_aifs; +- /* For WIFI Beacon Distribution +- * Long slot time : 2x cwmin +- * Short slot time : 4x cwmin +- */ +- if (ah->slottime == ATH9K_SLOT_TIME_20) +- qi.tqi_cwmin = 2*qi_be.tqi_cwmin; +- else +- qi.tqi_cwmin = 4*qi_be.tqi_cwmin; +- qi.tqi_cwmax = qi_be.tqi_cwmax; ++ if (swba->beacon_pending != 0) { ++ priv->cur_beacon_conf.bmiss_cnt++; ++ if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) { ++ ath_dbg(common, ATH_DBG_BSTUCK, ++ "Beacon stuck, HW reset\n"); ++ ieee80211_queue_work(priv->hw, ++ &priv->fatal_work); ++ } ++ return; ++ } + +- if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { +- ath_err(ath9k_hw_common(ah), +- "Unable to update beacon queue %u!\n", qnum); +- } else { +- ath9k_hw_resettxqueue(ah, priv->beaconq); ++ if (priv->cur_beacon_conf.bmiss_cnt) { ++ ath_dbg(common, ATH_DBG_BSTUCK, ++ "Resuming beacon xmit after %u misses\n", ++ priv->cur_beacon_conf.bmiss_cnt); ++ priv->cur_beacon_conf.bmiss_cnt = 0; ++ } ++ ++ slot = ath9k_htc_choose_bslot(priv, swba); ++ spin_lock_bh(&priv->beacon_lock); ++ if (priv->cur_beacon_conf.bslot[slot] == NULL) { ++ spin_unlock_bh(&priv->beacon_lock); ++ return; + } ++ spin_unlock_bh(&priv->beacon_lock); ++ ++ ath9k_htc_send_buffered(priv, slot); ++ ath9k_htc_send_beacon(priv, slot); ++} ++ ++void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, ++ struct ieee80211_vif *vif) ++{ ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; ++ int i = 0; ++ ++ spin_lock_bh(&priv->beacon_lock); ++ for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) { ++ if (priv->cur_beacon_conf.bslot[i] == NULL) { ++ avp->bslot = i; ++ break; ++ } ++ } ++ ++ priv->cur_beacon_conf.bslot[avp->bslot] = vif; ++ spin_unlock_bh(&priv->beacon_lock); ++ ++ ath_dbg(common, ATH_DBG_CONFIG, ++ "Added interface at beacon slot: %d\n", avp->bslot); ++} ++ ++void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, ++ struct ieee80211_vif *vif) ++{ ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; ++ ++ spin_lock_bh(&priv->beacon_lock); ++ priv->cur_beacon_conf.bslot[avp->bslot] = NULL; ++ spin_unlock_bh(&priv->beacon_lock); ++ ++ ath_dbg(common, ATH_DBG_CONFIG, ++ "Removed interface at beacon slot: %d\n", avp->bslot); ++} ++ ++/* ++ * Calculate the TSF adjustment value for all slots ++ * other than zero. ++ */ ++void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, ++ struct ieee80211_vif *vif) ++{ ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; ++ struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; ++ u64 tsfadjust; ++ ++ if (avp->bslot == 0) ++ return; ++ ++ /* ++ * The beacon interval cannot be different for multi-AP mode, ++ * and we reach here only for VIF slots greater than zero, ++ * so beacon_interval is guaranteed to be set in cur_conf. ++ */ ++ tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF; ++ avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); ++ ++ ath_dbg(common, ATH_DBG_CONFIG, ++ "tsfadjust is: %llu for bslot: %d\n", ++ (unsigned long long)tsfadjust, avp->bslot); + } + + static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_drv_debug.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_drv_debug.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_drv_debug.c 2011-05-05 23:29:49.025484635 +0200 +@@ -0,0 +1,960 @@ ++/* ++ * Copyright (c) 2010-2011 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include "htc.h" ++ ++static int ath9k_debugfs_open(struct inode *inode, struct file *file) ++{ ++ file->private_data = inode->i_private; ++ return 0; ++} ++ ++static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath9k_htc_priv *priv = file->private_data; ++ struct ath9k_htc_target_int_stats cmd_rsp; ++ char buf[512]; ++ unsigned int len = 0; ++ int ret = 0; ++ ++ memset(&cmd_rsp, 0, sizeof(cmd_rsp)); ++ ++ ath9k_htc_ps_wakeup(priv); ++ ++ WMI_CMD(WMI_INT_STATS_CMDID); ++ if (ret) { ++ ath9k_htc_ps_restore(priv); ++ return -EINVAL; ++ } ++ ++ ath9k_htc_ps_restore(priv); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "RX", ++ be32_to_cpu(cmd_rsp.rx)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "RXORN", ++ be32_to_cpu(cmd_rsp.rxorn)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "RXEOL", ++ be32_to_cpu(cmd_rsp.rxeol)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "TXURN", ++ be32_to_cpu(cmd_rsp.txurn)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "TXTO", ++ be32_to_cpu(cmd_rsp.txto)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "CST", ++ be32_to_cpu(cmd_rsp.cst)); ++ ++ if (len > sizeof(buf)) ++ len = sizeof(buf); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static const struct file_operations fops_tgt_int_stats = { ++ .read = read_file_tgt_int_stats, ++ .open = ath9k_debugfs_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath9k_htc_priv *priv = file->private_data; ++ struct ath9k_htc_target_tx_stats cmd_rsp; ++ char buf[512]; ++ unsigned int len = 0; ++ int ret = 0; ++ ++ memset(&cmd_rsp, 0, sizeof(cmd_rsp)); ++ ++ ath9k_htc_ps_wakeup(priv); ++ ++ WMI_CMD(WMI_TX_STATS_CMDID); ++ if (ret) { ++ ath9k_htc_ps_restore(priv); ++ return -EINVAL; ++ } ++ ++ ath9k_htc_ps_restore(priv); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "Xretries", ++ be32_to_cpu(cmd_rsp.xretries)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "FifoErr", ++ be32_to_cpu(cmd_rsp.fifoerr)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "Filtered", ++ be32_to_cpu(cmd_rsp.filtered)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "TimerExp", ++ be32_to_cpu(cmd_rsp.timer_exp)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "ShortRetries", ++ be32_to_cpu(cmd_rsp.shortretries)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "LongRetries", ++ be32_to_cpu(cmd_rsp.longretries)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "QueueNull", ++ be32_to_cpu(cmd_rsp.qnull)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "EncapFail", ++ be32_to_cpu(cmd_rsp.encap_fail)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "NoBuf", ++ be32_to_cpu(cmd_rsp.nobuf)); ++ ++ if (len > sizeof(buf)) ++ len = sizeof(buf); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static const struct file_operations fops_tgt_tx_stats = { ++ .read = read_file_tgt_tx_stats, ++ .open = ath9k_debugfs_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath9k_htc_priv *priv = file->private_data; ++ struct ath9k_htc_target_rx_stats cmd_rsp; ++ char buf[512]; ++ unsigned int len = 0; ++ int ret = 0; ++ ++ memset(&cmd_rsp, 0, sizeof(cmd_rsp)); ++ ++ ath9k_htc_ps_wakeup(priv); ++ ++ WMI_CMD(WMI_RX_STATS_CMDID); ++ if (ret) { ++ ath9k_htc_ps_restore(priv); ++ return -EINVAL; ++ } ++ ++ ath9k_htc_ps_restore(priv); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "NoBuf", ++ be32_to_cpu(cmd_rsp.nobuf)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "HostSend", ++ be32_to_cpu(cmd_rsp.host_send)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "HostDone", ++ be32_to_cpu(cmd_rsp.host_done)); ++ ++ if (len > sizeof(buf)) ++ len = sizeof(buf); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static const struct file_operations fops_tgt_rx_stats = { ++ .read = read_file_tgt_rx_stats, ++ .open = ath9k_debugfs_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++static ssize_t read_file_xmit(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath9k_htc_priv *priv = file->private_data; ++ char buf[512]; ++ unsigned int len = 0; ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "Buffers queued", ++ priv->debug.tx_stats.buf_queued); ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "Buffers completed", ++ priv->debug.tx_stats.buf_completed); ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "SKBs queued", ++ priv->debug.tx_stats.skb_queued); ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "SKBs success", ++ priv->debug.tx_stats.skb_success); ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "SKBs failed", ++ priv->debug.tx_stats.skb_failed); ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "CAB queued", ++ priv->debug.tx_stats.cab_queued); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "BE queued", ++ priv->debug.tx_stats.queue_stats[WME_AC_BE]); ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "BK queued", ++ priv->debug.tx_stats.queue_stats[WME_AC_BK]); ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "VI queued", ++ priv->debug.tx_stats.queue_stats[WME_AC_VI]); ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%20s : %10u\n", "VO queued", ++ priv->debug.tx_stats.queue_stats[WME_AC_VO]); ++ ++ if (len > sizeof(buf)) ++ len = sizeof(buf); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static const struct file_operations fops_xmit = { ++ .read = read_file_xmit, ++ .open = ath9k_debugfs_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, ++ struct ath_htc_rx_status *rxs) ++{ ++#define RX_PHY_ERR_INC(c) priv->debug.rx_stats.err_phy_stats[c]++ ++ ++ if (rxs->rs_status & ATH9K_RXERR_CRC) ++ priv->debug.rx_stats.err_crc++; ++ if (rxs->rs_status & ATH9K_RXERR_DECRYPT) ++ priv->debug.rx_stats.err_decrypt_crc++; ++ if (rxs->rs_status & ATH9K_RXERR_MIC) ++ priv->debug.rx_stats.err_mic++; ++ if (rxs->rs_status & ATH9K_RX_DELIM_CRC_PRE) ++ priv->debug.rx_stats.err_pre_delim++; ++ if (rxs->rs_status & ATH9K_RX_DELIM_CRC_POST) ++ priv->debug.rx_stats.err_post_delim++; ++ if (rxs->rs_status & ATH9K_RX_DECRYPT_BUSY) ++ priv->debug.rx_stats.err_decrypt_busy++; ++ ++ if (rxs->rs_status & ATH9K_RXERR_PHY) { ++ priv->debug.rx_stats.err_phy++; ++ if (rxs->rs_phyerr < ATH9K_PHYERR_MAX) ++ RX_PHY_ERR_INC(rxs->rs_phyerr); ++ } ++ ++#undef RX_PHY_ERR_INC ++} ++ ++static ssize_t read_file_recv(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++#define PHY_ERR(s, p) \ ++ len += snprintf(buf + len, size - len, "%20s : %10u\n", s, \ ++ priv->debug.rx_stats.err_phy_stats[p]); ++ ++ struct ath9k_htc_priv *priv = file->private_data; ++ char *buf; ++ unsigned int len = 0, size = 1500; ++ ssize_t retval = 0; ++ ++ buf = kzalloc(size, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ ++ len += snprintf(buf + len, size - len, ++ "%20s : %10u\n", "SKBs allocated", ++ priv->debug.rx_stats.skb_allocated); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10u\n", "SKBs completed", ++ priv->debug.rx_stats.skb_completed); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10u\n", "SKBs Dropped", ++ priv->debug.rx_stats.skb_dropped); ++ ++ len += snprintf(buf + len, size - len, ++ "%20s : %10u\n", "CRC ERR", ++ priv->debug.rx_stats.err_crc); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10u\n", "DECRYPT CRC ERR", ++ priv->debug.rx_stats.err_decrypt_crc); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10u\n", "MIC ERR", ++ priv->debug.rx_stats.err_mic); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10u\n", "PRE-DELIM CRC ERR", ++ priv->debug.rx_stats.err_pre_delim); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10u\n", "POST-DELIM CRC ERR", ++ priv->debug.rx_stats.err_post_delim); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10u\n", "DECRYPT BUSY ERR", ++ priv->debug.rx_stats.err_decrypt_busy); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10u\n", "TOTAL PHY ERR", ++ priv->debug.rx_stats.err_phy); ++ ++ ++ PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); ++ PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); ++ PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); ++ PHY_ERR("RATE", ATH9K_PHYERR_RATE); ++ PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH); ++ PHY_ERR("RADAR", ATH9K_PHYERR_RADAR); ++ PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE); ++ PHY_ERR("TOR", ATH9K_PHYERR_TOR); ++ PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING); ++ PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); ++ PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); ++ PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); ++ PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP); ++ PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE); ++ PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART); ++ PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT); ++ PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING); ++ PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC); ++ PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL); ++ PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE); ++ PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART); ++ PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); ++ PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP); ++ PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR); ++ PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); ++ PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL); ++ ++ if (len > size) ++ len = size; ++ ++ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ kfree(buf); ++ ++ return retval; ++ ++#undef PHY_ERR ++} ++ ++static const struct file_operations fops_recv = { ++ .read = read_file_recv, ++ .open = ath9k_debugfs_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++static ssize_t read_file_slot(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath9k_htc_priv *priv = file->private_data; ++ char buf[512]; ++ unsigned int len = 0; ++ ++ spin_lock_bh(&priv->tx.tx_lock); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : "); ++ ++ len += bitmap_scnprintf(buf + len, sizeof(buf) - len, ++ priv->tx.tx_slot, MAX_TX_BUF_NUM); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, "\n"); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "Used slots : %d\n", ++ bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM)); ++ ++ spin_unlock_bh(&priv->tx.tx_lock); ++ ++ if (len > sizeof(buf)) ++ len = sizeof(buf); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static const struct file_operations fops_slot = { ++ .read = read_file_slot, ++ .open = ath9k_debugfs_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++static ssize_t read_file_queue(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath9k_htc_priv *priv = file->private_data; ++ char buf[512]; ++ unsigned int len = 0; ++ ++ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", ++ "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", ++ "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", ++ "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", ++ "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", ++ "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", ++ "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue)); ++ ++ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", ++ "Failed queue", skb_queue_len(&priv->tx.tx_failed)); ++ ++ spin_lock_bh(&priv->tx.tx_lock); ++ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", ++ "Queued count", priv->tx.queued_cnt); ++ spin_unlock_bh(&priv->tx.tx_lock); ++ ++ if (len > sizeof(buf)) ++ len = sizeof(buf); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++} ++ ++static const struct file_operations fops_queue = { ++ .read = read_file_queue, ++ .open = ath9k_debugfs_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++static ssize_t read_file_debug(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath9k_htc_priv *priv = file->private_data; ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ char buf[32]; ++ unsigned int len; ++ ++ len = sprintf(buf, "0x%08x\n", common->debug_mask); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t write_file_debug(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath9k_htc_priv *priv = file->private_data; ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ unsigned long mask; ++ char buf[32]; ++ ssize_t len; ++ ++ len = min(count, sizeof(buf) - 1); ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ if (strict_strtoul(buf, 0, &mask)) ++ return -EINVAL; ++ ++ common->debug_mask = mask; ++ return count; ++} ++ ++static const struct file_operations fops_debug = { ++ .read = read_file_debug, ++ .write = write_file_debug, ++ .open = ath9k_debugfs_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath9k_htc_priv *priv = file->private_data; ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ struct base_eep_header *pBase = NULL; ++ unsigned int len = 0, size = 1500; ++ ssize_t retval = 0; ++ char *buf; ++ ++ /* ++ * This can be done since all the 3 EEPROM families have the ++ * same base header upto a certain point, and we are interested in ++ * the data only upto that point. ++ */ ++ ++ if (AR_SREV_9271(priv->ah)) ++ pBase = (struct base_eep_header *) ++ &priv->ah->eeprom.map4k.baseEepHeader; ++ else if (priv->ah->hw_version.usbdev == AR9280_USB) ++ pBase = (struct base_eep_header *) ++ &priv->ah->eeprom.def.baseEepHeader; ++ else if (priv->ah->hw_version.usbdev == AR9287_USB) ++ pBase = (struct base_eep_header *) ++ &priv->ah->eeprom.map9287.baseEepHeader; ++ ++ if (pBase == NULL) { ++ ath_err(common, "Unknown EEPROM type\n"); ++ return 0; ++ } ++ ++ buf = kzalloc(size, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", "Major Version", ++ pBase->version >> 12); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", "Minor Version", ++ pBase->version & 0xFFF); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", "Checksum", ++ pBase->checksum); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", "Length", ++ pBase->length); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", "RegDomain1", ++ pBase->regDmn[0]); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", "RegDomain2", ++ pBase->regDmn[1]); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "TX Mask", pBase->txMask); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "RX Mask", pBase->rxMask); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "Allow 5GHz", ++ !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "Allow 2GHz", ++ !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "Disable 2GHz HT20", ++ !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT20)); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "Disable 2GHz HT40", ++ !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT40)); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "Disable 5Ghz HT20", ++ !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT20)); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "Disable 5Ghz HT40", ++ !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40)); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "Big Endian", ++ !!(pBase->eepMisc & 0x01)); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "Cal Bin Major Ver", ++ (pBase->binBuildNumber >> 24) & 0xFF); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "Cal Bin Minor Ver", ++ (pBase->binBuildNumber >> 16) & 0xFF); ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "Cal Bin Build", ++ (pBase->binBuildNumber >> 8) & 0xFF); ++ ++ /* ++ * UB91 specific data. ++ */ ++ if (AR_SREV_9271(priv->ah)) { ++ struct base_eep_header_4k *pBase4k = ++ &priv->ah->eeprom.map4k.baseEepHeader; ++ ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "TX Gain type", ++ pBase4k->txGainType); ++ } ++ ++ /* ++ * UB95 specific data. ++ */ ++ if (priv->ah->hw_version.usbdev == AR9287_USB) { ++ struct base_eep_ar9287_header *pBase9287 = ++ &priv->ah->eeprom.map9287.baseEepHeader; ++ ++ len += snprintf(buf + len, size - len, ++ "%20s : %10ddB\n", ++ "Power Table Offset", ++ pBase9287->pwrTableOffset); ++ ++ len += snprintf(buf + len, size - len, ++ "%20s : %10d\n", ++ "OpenLoop Power Ctrl", ++ pBase9287->openLoopPwrCntl); ++ } ++ ++ len += snprintf(buf + len, size - len, ++ "%20s : %02X:%02X:%02X:%02X:%02X:%02X\n", ++ "MacAddress", ++ pBase->macAddr[0], pBase->macAddr[1], pBase->macAddr[2], ++ pBase->macAddr[3], pBase->macAddr[4], pBase->macAddr[5]); ++ if (len > size) ++ len = size; ++ ++ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ kfree(buf); ++ ++ return retval; ++} ++ ++static const struct file_operations fops_base_eeprom = { ++ .read = read_file_base_eeprom, ++ .open = ath9k_debugfs_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++static ssize_t read_4k_modal_eeprom(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++#define PR_EEP(_s, _val) \ ++ do { \ ++ len += snprintf(buf + len, size - len, "%20s : %10d\n", \ ++ _s, (_val)); \ ++ } while (0) ++ ++ struct ath9k_htc_priv *priv = file->private_data; ++ struct modal_eep_4k_header *pModal = &priv->ah->eeprom.map4k.modalHeader; ++ unsigned int len = 0, size = 2048; ++ ssize_t retval = 0; ++ char *buf; ++ ++ buf = kzalloc(size, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ ++ PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); ++ PR_EEP("Ant. Common Control", pModal->antCtrlCommon); ++ PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); ++ PR_EEP("Switch Settle", pModal->switchSettling); ++ PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); ++ PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); ++ PR_EEP("ADC Desired size", pModal->adcDesiredSize); ++ PR_EEP("PGA Desired size", pModal->pgaDesiredSize); ++ PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); ++ PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); ++ PR_EEP("txEndToRxOn", pModal->txEndToRxOn); ++ PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); ++ PR_EEP("CCA Threshold)", pModal->thresh62); ++ PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); ++ PR_EEP("xpdGain", pModal->xpdGain); ++ PR_EEP("External PD", pModal->xpd); ++ PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); ++ PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); ++ PR_EEP("pdGainOverlap", pModal->pdGainOverlap); ++ PR_EEP("O/D Bias Version", pModal->version); ++ PR_EEP("CCK OutputBias", pModal->ob_0); ++ PR_EEP("BPSK OutputBias", pModal->ob_1); ++ PR_EEP("QPSK OutputBias", pModal->ob_2); ++ PR_EEP("16QAM OutputBias", pModal->ob_3); ++ PR_EEP("64QAM OutputBias", pModal->ob_4); ++ PR_EEP("CCK Driver1_Bias", pModal->db1_0); ++ PR_EEP("BPSK Driver1_Bias", pModal->db1_1); ++ PR_EEP("QPSK Driver1_Bias", pModal->db1_2); ++ PR_EEP("16QAM Driver1_Bias", pModal->db1_3); ++ PR_EEP("64QAM Driver1_Bias", pModal->db1_4); ++ PR_EEP("CCK Driver2_Bias", pModal->db2_0); ++ PR_EEP("BPSK Driver2_Bias", pModal->db2_1); ++ PR_EEP("QPSK Driver2_Bias", pModal->db2_2); ++ PR_EEP("16QAM Driver2_Bias", pModal->db2_3); ++ PR_EEP("64QAM Driver2_Bias", pModal->db2_4); ++ PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); ++ PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); ++ PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); ++ PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); ++ PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); ++ PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); ++ PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); ++ PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); ++ PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); ++ PR_EEP("Ant. Diversity ctl1", pModal->antdiv_ctl1); ++ PR_EEP("Ant. Diversity ctl2", pModal->antdiv_ctl2); ++ PR_EEP("TX Diversity", pModal->tx_diversity); ++ ++ if (len > size) ++ len = size; ++ ++ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ kfree(buf); ++ ++ return retval; ++ ++#undef PR_EEP ++} ++ ++static ssize_t read_def_modal_eeprom(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++#define PR_EEP(_s, _val) \ ++ do { \ ++ if (pBase->opCapFlags & AR5416_OPFLAGS_11G) { \ ++ pModal = &priv->ah->eeprom.def.modalHeader[1]; \ ++ len += snprintf(buf + len, size - len, "%20s : %8d%7s", \ ++ _s, (_val), "|"); \ ++ } \ ++ if (pBase->opCapFlags & AR5416_OPFLAGS_11A) { \ ++ pModal = &priv->ah->eeprom.def.modalHeader[0]; \ ++ len += snprintf(buf + len, size - len, "%9d\n", \ ++ (_val)); \ ++ } \ ++ } while (0) ++ ++ struct ath9k_htc_priv *priv = file->private_data; ++ struct base_eep_header *pBase = &priv->ah->eeprom.def.baseEepHeader; ++ struct modal_eep_header *pModal = NULL; ++ unsigned int len = 0, size = 3500; ++ ssize_t retval = 0; ++ char *buf; ++ ++ buf = kzalloc(size, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ ++ len += snprintf(buf + len, size - len, ++ "%31s %15s\n", "2G", "5G"); ++ len += snprintf(buf + len, size - len, ++ "%32s %16s\n", "====", "====\n"); ++ ++ PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); ++ PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); ++ PR_EEP("Chain2 Ant. Control", pModal->antCtrlChain[2]); ++ PR_EEP("Ant. Common Control", pModal->antCtrlCommon); ++ PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); ++ PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); ++ PR_EEP("Chain2 Ant. Gain", pModal->antennaGainCh[2]); ++ PR_EEP("Switch Settle", pModal->switchSettling); ++ PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); ++ PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); ++ PR_EEP("Chain2 TxRxAtten", pModal->txRxAttenCh[2]); ++ PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); ++ PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); ++ PR_EEP("Chain2 RxTxMargin", pModal->rxTxMarginCh[2]); ++ PR_EEP("ADC Desired size", pModal->adcDesiredSize); ++ PR_EEP("PGA Desired size", pModal->pgaDesiredSize); ++ PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); ++ PR_EEP("Chain1 xlna Gain", pModal->xlnaGainCh[1]); ++ PR_EEP("Chain2 xlna Gain", pModal->xlnaGainCh[2]); ++ PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); ++ PR_EEP("txEndToRxOn", pModal->txEndToRxOn); ++ PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); ++ PR_EEP("CCA Threshold)", pModal->thresh62); ++ PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); ++ PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); ++ PR_EEP("Chain2 NF Threshold", pModal->noiseFloorThreshCh[2]); ++ PR_EEP("xpdGain", pModal->xpdGain); ++ PR_EEP("External PD", pModal->xpd); ++ PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); ++ PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); ++ PR_EEP("Chain2 I Coefficient", pModal->iqCalICh[2]); ++ PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); ++ PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); ++ PR_EEP("Chain2 Q Coefficient", pModal->iqCalQCh[2]); ++ PR_EEP("pdGainOverlap", pModal->pdGainOverlap); ++ PR_EEP("Chain0 OutputBias", pModal->ob); ++ PR_EEP("Chain0 DriverBias", pModal->db); ++ PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); ++ PR_EEP("2chain pwr decrease", pModal->pwrDecreaseFor2Chain); ++ PR_EEP("3chain pwr decrease", pModal->pwrDecreaseFor3Chain); ++ PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); ++ PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); ++ PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); ++ PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); ++ PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); ++ PR_EEP("Chain2 bswAtten", pModal->bswAtten[2]); ++ PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); ++ PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); ++ PR_EEP("Chain2 bswMargin", pModal->bswMargin[2]); ++ PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); ++ PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); ++ PR_EEP("Chain1 xatten2Db", pModal->xatten2Db[1]); ++ PR_EEP("Chain2 xatten2Db", pModal->xatten2Db[2]); ++ PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); ++ PR_EEP("Chain1 xatten2Margin", pModal->xatten2Margin[1]); ++ PR_EEP("Chain2 xatten2Margin", pModal->xatten2Margin[2]); ++ PR_EEP("Chain1 OutputBias", pModal->ob_ch1); ++ PR_EEP("Chain1 DriverBias", pModal->db_ch1); ++ PR_EEP("LNA Control", pModal->lna_ctl); ++ PR_EEP("XPA Bias Freq0", pModal->xpaBiasLvlFreq[0]); ++ PR_EEP("XPA Bias Freq1", pModal->xpaBiasLvlFreq[1]); ++ PR_EEP("XPA Bias Freq2", pModal->xpaBiasLvlFreq[2]); ++ ++ if (len > size) ++ len = size; ++ ++ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ kfree(buf); ++ ++ return retval; ++ ++#undef PR_EEP ++} ++ ++static ssize_t read_9287_modal_eeprom(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++#define PR_EEP(_s, _val) \ ++ do { \ ++ len += snprintf(buf + len, size - len, "%20s : %10d\n", \ ++ _s, (_val)); \ ++ } while (0) ++ ++ struct ath9k_htc_priv *priv = file->private_data; ++ struct modal_eep_ar9287_header *pModal = &priv->ah->eeprom.map9287.modalHeader; ++ unsigned int len = 0, size = 3000; ++ ssize_t retval = 0; ++ char *buf; ++ ++ buf = kzalloc(size, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ ++ PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); ++ PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); ++ PR_EEP("Ant. Common Control", pModal->antCtrlCommon); ++ PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); ++ PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); ++ PR_EEP("Switch Settle", pModal->switchSettling); ++ PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); ++ PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); ++ PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); ++ PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); ++ PR_EEP("ADC Desired size", pModal->adcDesiredSize); ++ PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); ++ PR_EEP("txEndToRxOn", pModal->txEndToRxOn); ++ PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); ++ PR_EEP("CCA Threshold)", pModal->thresh62); ++ PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); ++ PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); ++ PR_EEP("xpdGain", pModal->xpdGain); ++ PR_EEP("External PD", pModal->xpd); ++ PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); ++ PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); ++ PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); ++ PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); ++ PR_EEP("pdGainOverlap", pModal->pdGainOverlap); ++ PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); ++ PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); ++ PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); ++ PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); ++ PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); ++ PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); ++ PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); ++ PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); ++ PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); ++ PR_EEP("AR92x7 Version", pModal->version); ++ PR_EEP("DriverBias1", pModal->db1); ++ PR_EEP("DriverBias2", pModal->db1); ++ PR_EEP("CCK OutputBias", pModal->ob_cck); ++ PR_EEP("PSK OutputBias", pModal->ob_psk); ++ PR_EEP("QAM OutputBias", pModal->ob_qam); ++ PR_EEP("PAL_OFF OutputBias", pModal->ob_pal_off); ++ ++ if (len > size) ++ len = size; ++ ++ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ kfree(buf); ++ ++ return retval; ++ ++#undef PR_EEP ++} ++ ++static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath9k_htc_priv *priv = file->private_data; ++ ++ if (AR_SREV_9271(priv->ah)) ++ return read_4k_modal_eeprom(file, user_buf, count, ppos); ++ else if (priv->ah->hw_version.usbdev == AR9280_USB) ++ return read_def_modal_eeprom(file, user_buf, count, ppos); ++ else if (priv->ah->hw_version.usbdev == AR9287_USB) ++ return read_9287_modal_eeprom(file, user_buf, count, ppos); ++ ++ return 0; ++} ++ ++static const struct file_operations fops_modal_eeprom = { ++ .read = read_file_modal_eeprom, ++ .open = ath9k_debugfs_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++int ath9k_htc_init_debug(struct ath_hw *ah) ++{ ++ struct ath_common *common = ath9k_hw_common(ah); ++ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; ++ ++ priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME, ++ priv->hw->wiphy->debugfsdir); ++ if (!priv->debug.debugfs_phy) ++ return -ENOMEM; ++ ++ debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy, ++ priv, &fops_tgt_int_stats); ++ debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy, ++ priv, &fops_tgt_tx_stats); ++ debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy, ++ priv, &fops_tgt_rx_stats); ++ debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy, ++ priv, &fops_xmit); ++ debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy, ++ priv, &fops_recv); ++ debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy, ++ priv, &fops_slot); ++ debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy, ++ priv, &fops_queue); ++ debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, ++ priv, &fops_debug); ++ debugfs_create_file("base_eeprom", S_IRUSR, priv->debug.debugfs_phy, ++ priv, &fops_base_eeprom); ++ debugfs_create_file("modal_eeprom", S_IRUSR, priv->debug.debugfs_phy, ++ priv, &fops_modal_eeprom); ++ ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c 2011-05-05 23:29:49.089485409 +0200 +@@ -65,17 +65,19 @@ + u32 timer_period; + bool is_btscan; + int ret; +- u8 cmd_rsp, aggr; + + ath_detect_bt_priority(priv); + + is_btscan = !!(priv->op_flags & OP_BT_SCAN); + +- aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED; +- +- WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr); ++ ret = ath9k_htc_update_cap_target(priv, ++ !!(priv->op_flags & OP_BT_PRIORITY_DETECTED)); ++ if (ret) { ++ ath_err(common, "Unable to set BTCOEX parameters\n"); ++ return; ++ } + +- ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL : ++ ath9k_hw_btcoex_bt_stomp(priv->ah, is_btscan ? ATH_BTCOEX_STOMP_ALL : + btcoex->bt_stomp_type); + + timer_period = is_btscan ? btcoex->btscan_no_stomp : +@@ -103,9 +105,9 @@ + "time slice work for bt and wlan\n"); + + if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) +- ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE); ++ ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); + else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) +- ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW); ++ ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); + } + + void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv) +@@ -152,140 +154,41 @@ + /* LED */ + /*******/ + +-static void ath9k_led_blink_work(struct work_struct *work) ++#ifdef CONFIG_MAC80211_LEDS ++void ath9k_led_work(struct work_struct *work) + { +- struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv, +- ath9k_led_blink_work.work); +- +- if (!(priv->op_flags & OP_LED_ASSOCIATED)) +- return; +- +- if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) || +- (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) +- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); +- else +- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, +- (priv->op_flags & OP_LED_ON) ? 1 : 0); ++ struct ath9k_htc_priv *priv = container_of(work, ++ struct ath9k_htc_priv, ++ led_work); + +- ieee80211_queue_delayed_work(priv->hw, +- &priv->ath9k_led_blink_work, +- (priv->op_flags & OP_LED_ON) ? +- msecs_to_jiffies(priv->led_off_duration) : +- msecs_to_jiffies(priv->led_on_duration)); +- +- priv->led_on_duration = priv->led_on_cnt ? +- max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) : +- ATH_LED_ON_DURATION_IDLE; +- priv->led_off_duration = priv->led_off_cnt ? +- max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) : +- ATH_LED_OFF_DURATION_IDLE; +- priv->led_on_cnt = priv->led_off_cnt = 0; +- +- if (priv->op_flags & OP_LED_ON) +- priv->op_flags &= ~OP_LED_ON; +- else +- priv->op_flags |= OP_LED_ON; +-} +- +-static void ath9k_led_brightness_work(struct work_struct *work) +-{ +- struct ath_led *led = container_of(work, struct ath_led, +- brightness_work.work); +- struct ath9k_htc_priv *priv = led->priv; +- +- switch (led->brightness) { +- case LED_OFF: +- if (led->led_type == ATH_LED_ASSOC || +- led->led_type == ATH_LED_RADIO) { +- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, +- (led->led_type == ATH_LED_RADIO)); +- priv->op_flags &= ~OP_LED_ASSOCIATED; +- if (led->led_type == ATH_LED_RADIO) +- priv->op_flags &= ~OP_LED_ON; +- } else { +- priv->led_off_cnt++; +- } +- break; +- case LED_FULL: +- if (led->led_type == ATH_LED_ASSOC) { +- priv->op_flags |= OP_LED_ASSOCIATED; +- ieee80211_queue_delayed_work(priv->hw, +- &priv->ath9k_led_blink_work, 0); +- } else if (led->led_type == ATH_LED_RADIO) { +- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); +- priv->op_flags |= OP_LED_ON; +- } else { +- priv->led_on_cnt++; +- } +- break; +- default: +- break; +- } ++ ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, ++ (priv->brightness == LED_OFF)); + } + + static void ath9k_led_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) + { +- struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); +- struct ath9k_htc_priv *priv = led->priv; +- +- led->brightness = brightness; +- if (!(priv->op_flags & OP_LED_DEINIT)) +- ieee80211_queue_delayed_work(priv->hw, +- &led->brightness_work, 0); +-} +- +-void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv) +-{ +- cancel_delayed_work_sync(&priv->radio_led.brightness_work); +- cancel_delayed_work_sync(&priv->assoc_led.brightness_work); +- cancel_delayed_work_sync(&priv->tx_led.brightness_work); +- cancel_delayed_work_sync(&priv->rx_led.brightness_work); +-} +- +-static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led, +- char *trigger) +-{ +- int ret; +- +- led->priv = priv; +- led->led_cdev.name = led->name; +- led->led_cdev.default_trigger = trigger; +- led->led_cdev.brightness_set = ath9k_led_brightness; +- +- ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev); +- if (ret) +- ath_err(ath9k_hw_common(priv->ah), +- "Failed to register led:%s", led->name); +- else +- led->registered = 1; +- +- INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work); +- +- return ret; +-} +- +-static void ath9k_unregister_led(struct ath_led *led) +-{ +- if (led->registered) { +- led_classdev_unregister(&led->led_cdev); +- led->registered = 0; +- } ++ struct ath9k_htc_priv *priv = container_of(led_cdev, ++ struct ath9k_htc_priv, ++ led_cdev); ++ ++ /* Not locked, but it's just a tiny green light..*/ ++ priv->brightness = brightness; ++ ieee80211_queue_work(priv->hw, &priv->led_work); + } + + void ath9k_deinit_leds(struct ath9k_htc_priv *priv) + { +- priv->op_flags |= OP_LED_DEINIT; +- ath9k_unregister_led(&priv->assoc_led); +- priv->op_flags &= ~OP_LED_ASSOCIATED; +- ath9k_unregister_led(&priv->tx_led); +- ath9k_unregister_led(&priv->rx_led); +- ath9k_unregister_led(&priv->radio_led); ++ if (!priv->led_registered) ++ return; ++ ++ ath9k_led_brightness(&priv->led_cdev, LED_OFF); ++ led_classdev_unregister(&priv->led_cdev); ++ cancel_work_sync(&priv->led_work); + } + + void ath9k_init_leds(struct ath9k_htc_priv *priv) + { +- char *trigger; + int ret; + + if (AR_SREV_9287(priv->ah)) +@@ -303,48 +206,21 @@ + /* LED off, active low */ + ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); + +- INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work); ++ snprintf(priv->led_name, sizeof(priv->led_name), ++ "ath9k_htc-%s", wiphy_name(priv->hw->wiphy)); ++ priv->led_cdev.name = priv->led_name; ++ priv->led_cdev.brightness_set = ath9k_led_brightness; + +- trigger = ieee80211_get_radio_led_name(priv->hw); +- snprintf(priv->radio_led.name, sizeof(priv->radio_led.name), +- "ath9k-%s::radio", wiphy_name(priv->hw->wiphy)); +- ret = ath9k_register_led(priv, &priv->radio_led, trigger); +- priv->radio_led.led_type = ATH_LED_RADIO; +- if (ret) +- goto fail; +- +- trigger = ieee80211_get_assoc_led_name(priv->hw); +- snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name), +- "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy)); +- ret = ath9k_register_led(priv, &priv->assoc_led, trigger); +- priv->assoc_led.led_type = ATH_LED_ASSOC; +- if (ret) +- goto fail; +- +- trigger = ieee80211_get_tx_led_name(priv->hw); +- snprintf(priv->tx_led.name, sizeof(priv->tx_led.name), +- "ath9k-%s::tx", wiphy_name(priv->hw->wiphy)); +- ret = ath9k_register_led(priv, &priv->tx_led, trigger); +- priv->tx_led.led_type = ATH_LED_TX; +- if (ret) +- goto fail; +- +- trigger = ieee80211_get_rx_led_name(priv->hw); +- snprintf(priv->rx_led.name, sizeof(priv->rx_led.name), +- "ath9k-%s::rx", wiphy_name(priv->hw->wiphy)); +- ret = ath9k_register_led(priv, &priv->rx_led, trigger); +- priv->rx_led.led_type = ATH_LED_RX; +- if (ret) +- goto fail; ++ ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &priv->led_cdev); ++ if (ret < 0) ++ return; + +- priv->op_flags &= ~OP_LED_DEINIT; ++ INIT_WORK(&priv->led_work, ath9k_led_work); ++ priv->led_registered = true; + + return; +- +-fail: +- cancel_delayed_work_sync(&priv->ath9k_led_blink_work); +- ath9k_deinit_leds(priv); + } ++#endif + + /*******************/ + /* Rfkill */ +@@ -398,9 +274,9 @@ + + /* Start TX */ + htc_start(priv->htc); +- spin_lock_bh(&priv->tx_lock); +- priv->tx_queues_stop = false; +- spin_unlock_bh(&priv->tx_lock); ++ spin_lock_bh(&priv->tx.tx_lock); ++ priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP; ++ spin_unlock_bh(&priv->tx.tx_lock); + ieee80211_wake_queues(hw); + + WMI_CMD(WMI_ENABLE_INTR_CMDID); +@@ -429,13 +305,15 @@ + + /* Stop TX */ + ieee80211_stop_queues(hw); +- htc_stop(priv->htc); ++ ath9k_htc_tx_drain(priv); + WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); +- skb_queue_purge(&priv->tx_queue); + + /* Stop RX */ + WMI_CMD(WMI_STOP_RECV_CMDID); + ++ /* Clear the WMI event queue */ ++ ath9k_wmi_event_drain(priv); ++ + /* + * The MIB counters have to be disabled here, + * since the target doesn't do it. +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_drv_init.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_drv_init.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_drv_init.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_drv_init.c 2011-05-05 23:29:49.094485469 +0200 +@@ -117,6 +117,21 @@ + RATE(540, 0x0c, 0), + }; + ++#ifdef CONFIG_MAC80211_LEDS ++static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { ++ { .throughput = 0 * 1024, .blink_time = 334 }, ++ { .throughput = 1 * 1024, .blink_time = 260 }, ++ { .throughput = 5 * 1024, .blink_time = 220 }, ++ { .throughput = 10 * 1024, .blink_time = 190 }, ++ { .throughput = 20 * 1024, .blink_time = 170 }, ++ { .throughput = 50 * 1024, .blink_time = 150 }, ++ { .throughput = 70 * 1024, .blink_time = 130 }, ++ { .throughput = 100 * 1024, .blink_time = 110 }, ++ { .throughput = 200 * 1024, .blink_time = 80 }, ++ { .throughput = 300 * 1024, .blink_time = 50 }, ++}; ++#endif ++ + static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) + { + int time_left; +@@ -140,7 +155,6 @@ + + static void ath9k_deinit_priv(struct ath9k_htc_priv *priv) + { +- ath9k_htc_exit_debug(priv->ah); + ath9k_hw_deinit(priv->ah); + kfree(priv->ah); + priv->ah = NULL; +@@ -244,7 +258,7 @@ + */ + + if (IS_AR7010_DEVICE(drv_info)) +- priv->htc->credits = 45; ++ priv->htc->credits = 48; + else + priv->htc->credits = 33; + +@@ -430,13 +444,16 @@ + mutex_unlock(&priv->wmi->multi_write_mutex); + } + +-static const struct ath_ops ath9k_common_ops = { +- .read = ath9k_regread, +- .multi_read = ath9k_multi_regread, +- .write = ath9k_regwrite, +- .enable_write_buffer = ath9k_enable_regwrite_buffer, +- .write_flush = ath9k_regwrite_flush, +-}; ++static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) ++{ ++ u32 val; ++ ++ val = ath9k_regread(hw_priv, reg_offset); ++ val &= ~clr; ++ val |= set; ++ ath9k_regwrite(hw_priv, val, reg_offset); ++ return val; ++} + + static void ath_usb_read_cachesize(struct ath_common *common, int *csz) + { +@@ -561,13 +578,7 @@ + int i = 0; + + /* Get the hardware key cache size. */ +- common->keymax = priv->ah->caps.keycache_size; +- if (common->keymax > ATH_KEYMAX) { +- ath_dbg(common, ATH_DBG_ANY, +- "Warning, using only %u entries in %u key cache\n", +- ATH_KEYMAX, common->keymax); +- common->keymax = ATH_KEYMAX; +- } ++ common->keymax = AR_KEYTABLE_SIZE; + + if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) + common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; +@@ -646,7 +657,7 @@ + { + struct ath_hw *ah = NULL; + struct ath_common *common; +- int ret = 0, csz = 0; ++ int i, ret = 0, csz = 0; + + priv->op_flags |= OP_INVALID; + +@@ -658,30 +669,35 @@ + ah->hw_version.subsysid = 0; /* FIXME */ + ah->hw_version.usbdev = drv_info; + ah->ah_flags |= AH_USE_EEPROM; ++ ah->reg_ops.read = ath9k_regread; ++ ah->reg_ops.multi_read = ath9k_multi_regread; ++ ah->reg_ops.write = ath9k_regwrite; ++ ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer; ++ ah->reg_ops.write_flush = ath9k_regwrite_flush; ++ ah->reg_ops.rmw = ath9k_reg_rmw; + priv->ah = ah; + + common = ath9k_hw_common(ah); +- common->ops = &ath9k_common_ops; ++ common->ops = &ah->reg_ops; + common->bus_ops = &ath9k_usb_bus_ops; + common->ah = ah; + common->hw = priv->hw; + common->priv = priv; + common->debug_mask = ath9k_debug; + +- spin_lock_init(&priv->wmi->wmi_lock); + spin_lock_init(&priv->beacon_lock); +- spin_lock_init(&priv->tx_lock); ++ spin_lock_init(&priv->tx.tx_lock); + mutex_init(&priv->mutex); + mutex_init(&priv->htc_pm_lock); +- tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet, +- (unsigned long)priv); + tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, + (unsigned long)priv); +- tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, ++ tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet, + (unsigned long)priv); + INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work); + INIT_WORK(&priv->ps_work, ath9k_ps_work); + INIT_WORK(&priv->fatal_work, ath9k_fatal_work); ++ setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer, ++ (unsigned long)priv); + + /* + * Cache line size is used to size and align various +@@ -698,16 +714,13 @@ + goto err_hw; + } + +- ret = ath9k_htc_init_debug(ah); +- if (ret) { +- ath_err(common, "Unable to create debugfs files\n"); +- goto err_debug; +- } +- + ret = ath9k_init_queues(priv); + if (ret) + goto err_queues; + ++ for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) ++ priv->cur_beacon_conf.bslot[i] = NULL; ++ + ath9k_init_crypto(priv); + ath9k_init_channels_rates(priv); + ath9k_init_misc(priv); +@@ -720,8 +733,6 @@ + return 0; + + err_queues: +- ath9k_htc_exit_debug(ah); +-err_debug: + ath9k_hw_deinit(ah); + err_hw: + +@@ -742,17 +753,27 @@ + IEEE80211_HW_HAS_RATE_CONTROL | + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SUPPORTS_PS | +- IEEE80211_HW_PS_NULLFUNC_STACK; ++ IEEE80211_HW_PS_NULLFUNC_STACK | ++ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | +- BIT(NL80211_IFTYPE_ADHOC); ++ BIT(NL80211_IFTYPE_ADHOC) | ++ BIT(NL80211_IFTYPE_AP) | ++ BIT(NL80211_IFTYPE_P2P_GO) | ++ BIT(NL80211_IFTYPE_P2P_CLIENT); + + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + + hw->queues = 4; + hw->channel_change_time = 5000; + hw->max_listen_interval = 10; ++ ++ if (AR_SREV_9271(priv->ah)) ++ hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_9271; ++ else ++ hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_7010; ++ + hw->vif_data_size = sizeof(struct ath9k_htc_vif); + hw->sta_data_size = sizeof(struct ath9k_htc_sta); + +@@ -779,6 +800,43 @@ + SET_IEEE80211_PERM_ADDR(hw, common->macaddr); + } + ++static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv) ++{ ++ struct ieee80211_hw *hw = priv->hw; ++ struct wmi_fw_version cmd_rsp; ++ int ret; ++ ++ memset(&cmd_rsp, 0, sizeof(cmd_rsp)); ++ ++ WMI_CMD(WMI_GET_FW_VERSION); ++ if (ret) ++ return -EINVAL; ++ ++ priv->fw_version_major = be16_to_cpu(cmd_rsp.major); ++ priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor); ++ ++ snprintf(hw->wiphy->fw_version, ETHTOOL_BUSINFO_LEN, "%d.%d", ++ priv->fw_version_major, ++ priv->fw_version_minor); ++ ++ dev_info(priv->dev, "ath9k_htc: FW Version: %d.%d\n", ++ priv->fw_version_major, ++ priv->fw_version_minor); ++ ++ /* ++ * Check if the available FW matches the driver's ++ * required version. ++ */ ++ if (priv->fw_version_major != MAJOR_VERSION_REQ || ++ priv->fw_version_minor != MINOR_VERSION_REQ) { ++ dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n", ++ MAJOR_VERSION_REQ, MINOR_VERSION_REQ); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ + static int ath9k_init_device(struct ath9k_htc_priv *priv, + u16 devid, char *product, u32 drv_info) + { +@@ -798,6 +856,10 @@ + common = ath9k_hw_common(ah); + ath9k_set_hw_capab(priv, hw); + ++ error = ath9k_init_firmware_version(priv); ++ if (error != 0) ++ goto err_fw; ++ + /* Initialize regulatory */ + error = ath_regd_init(&common->regulatory, priv->hw->wiphy, + ath9k_reg_notifier); +@@ -816,6 +878,13 @@ + if (error != 0) + goto err_rx; + ++#ifdef CONFIG_MAC80211_LEDS ++ /* must be initialized before ieee80211_register_hw */ ++ priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw, ++ IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_htc_tpt_blink, ++ ARRAY_SIZE(ath9k_htc_tpt_blink)); ++#endif ++ + /* Register with mac80211 */ + error = ieee80211_register_hw(hw); + if (error) +@@ -828,6 +897,12 @@ + goto err_world; + } + ++ error = ath9k_htc_init_debug(priv->ah); ++ if (error) { ++ ath_err(common, "Unable to create debugfs files\n"); ++ goto err_world; ++ } ++ + ath_dbg(common, ATH_DBG_CONFIG, + "WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, " + "BE:%d, BK:%d, VI:%d, VO:%d\n", +@@ -858,6 +933,8 @@ + err_tx: + /* Nothing */ + err_regd: ++ /* Nothing */ ++err_fw: + ath9k_deinit_priv(priv); + err_init: + return error; +@@ -946,38 +1023,20 @@ + + static int __init ath9k_htc_init(void) + { +- int error; +- +- error = ath9k_htc_debug_create_root(); +- if (error < 0) { +- printk(KERN_ERR +- "ath9k_htc: Unable to create debugfs root: %d\n", +- error); +- goto err_dbg; +- } +- +- error = ath9k_hif_usb_init(); +- if (error < 0) { ++ if (ath9k_hif_usb_init() < 0) { + printk(KERN_ERR + "ath9k_htc: No USB devices found," + " driver not installed.\n"); +- error = -ENODEV; +- goto err_usb; ++ return -ENODEV; + } + + return 0; +- +-err_usb: +- ath9k_htc_debug_remove_root(); +-err_dbg: +- return error; + } + module_init(ath9k_htc_init); + + static void __exit ath9k_htc_exit(void) + { + ath9k_hif_usb_exit(); +- ath9k_htc_debug_remove_root(); + printk(KERN_INFO "ath9k_htc: Driver unloaded\n"); + } + module_exit(ath9k_htc_exit); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_drv_main.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_drv_main.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_drv_main.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_drv_main.c 2011-05-05 23:29:49.095485481 +0200 +@@ -16,10 +16,6 @@ + + #include "htc.h" + +-#ifdef CONFIG_ATH9K_HTC_DEBUGFS +-static struct dentry *ath9k_debugfs_root; +-#endif +- + /*************/ + /* Utilities */ + /*************/ +@@ -197,11 +193,16 @@ + + ath9k_htc_stop_ani(priv); + ieee80211_stop_queues(priv->hw); +- htc_stop(priv->htc); ++ ++ del_timer_sync(&priv->tx.cleanup_timer); ++ ath9k_htc_tx_drain(priv); ++ + WMI_CMD(WMI_DISABLE_INTR_CMDID); + WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); + WMI_CMD(WMI_STOP_RECV_CMDID); + ++ ath9k_wmi_event_drain(priv); ++ + caldata = &priv->caldata; + ret = ath9k_hw_reset(ah, ah->curchan, caldata, false); + if (ret) { +@@ -225,6 +226,9 @@ + ath9k_htc_vif_reconfig(priv); + ieee80211_wake_queues(priv->hw); + ++ mod_timer(&priv->tx.cleanup_timer, ++ jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); ++ + ath9k_htc_ps_restore(priv); + mutex_unlock(&priv->mutex); + } +@@ -250,11 +254,16 @@ + fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); + + ath9k_htc_ps_wakeup(priv); +- htc_stop(priv->htc); ++ ++ del_timer_sync(&priv->tx.cleanup_timer); ++ ath9k_htc_tx_drain(priv); ++ + WMI_CMD(WMI_DISABLE_INTR_CMDID); + WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); + WMI_CMD(WMI_STOP_RECV_CMDID); + ++ ath9k_wmi_event_drain(priv); ++ + ath_dbg(common, ATH_DBG_CONFIG, + "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n", + priv->ah->curchan->channel, +@@ -263,6 +272,7 @@ + + if (!fastcc) + caldata = &priv->caldata; ++ + ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); + if (ret) { + ath_err(common, +@@ -296,6 +306,9 @@ + !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) + ath9k_htc_vif_reconfig(priv); + ++ mod_timer(&priv->tx.cleanup_timer, ++ jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); ++ + err: + ath9k_htc_ps_restore(priv); + return ret; +@@ -319,6 +332,11 @@ + memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); + hvif.index = priv->mon_vif_idx; + WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); ++ if (ret) { ++ ath_err(common, "Unable to remove monitor interface at idx: %d\n", ++ priv->mon_vif_idx); ++ } ++ + priv->nvifs--; + priv->vif_slot &= ~(1 << priv->mon_vif_idx); + } +@@ -349,7 +367,7 @@ + memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); + memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); + +- hvif.opmode = cpu_to_be32(HTC_M_MONITOR); ++ hvif.opmode = HTC_M_MONITOR; + hvif.index = ffz(priv->vif_slot); + + WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); +@@ -382,7 +400,7 @@ + tsta.is_vif_sta = 1; + tsta.sta_index = sta_idx; + tsta.vif_index = hvif.index; +- tsta.maxampdu = 0xffff; ++ tsta.maxampdu = cpu_to_be16(0xffff); + + WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); + if (ret) { +@@ -449,6 +467,7 @@ + struct ath9k_htc_sta *ista; + int ret, sta_idx; + u8 cmd_rsp; ++ u16 maxampdu; + + if (priv->nstations >= ATH9K_HTC_MAX_STA) + return -ENOBUFS; +@@ -463,9 +482,7 @@ + ista = (struct ath9k_htc_sta *) sta->drv_priv; + memcpy(&tsta.macaddr, sta->addr, ETH_ALEN); + memcpy(&tsta.bssid, common->curbssid, ETH_ALEN); +- tsta.associd = common->curaid; + tsta.is_vif_sta = 0; +- tsta.valid = true; + ista->index = sta_idx; + } else { + memcpy(&tsta.macaddr, vif->addr, ETH_ALEN); +@@ -474,7 +491,15 @@ + + tsta.sta_index = sta_idx; + tsta.vif_index = avp->index; +- tsta.maxampdu = 0xffff; ++ ++ if (!sta) { ++ tsta.maxampdu = cpu_to_be16(0xffff); ++ } else { ++ maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + ++ sta->ht_cap.ampdu_factor); ++ tsta.maxampdu = cpu_to_be16(maxampdu); ++ } ++ + if (sta && sta->ht_cap.ht_supported) + tsta.flags = cpu_to_be16(ATH_HTC_STA_HT); + +@@ -547,7 +572,8 @@ + return 0; + } + +-int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv) ++int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv, ++ u8 enable_coex) + { + struct ath9k_htc_cap_target tcap; + int ret; +@@ -555,13 +581,9 @@ + + memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target)); + +- /* FIXME: Values are hardcoded */ +- tcap.flags = 0x240c40; +- tcap.flags_ext = 0x80601000; +- tcap.ampdu_limit = 0xffff0000; +- tcap.ampdu_subframes = 20; +- tcap.tx_chainmask_legacy = priv->ah->caps.tx_chainmask; +- tcap.protmode = 1; ++ tcap.ampdu_limit = cpu_to_be32(0xffff); ++ tcap.ampdu_subframes = priv->hw->max_tx_aggregation_subframes; ++ tcap.enable_coex = enable_coex; + tcap.tx_chainmask = priv->ah->caps.tx_chainmask; + + WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap); +@@ -709,218 +731,13 @@ + (aggr.aggr_enable) ? "Starting" : "Stopping", + sta->addr, tid); + +- spin_lock_bh(&priv->tx_lock); ++ spin_lock_bh(&priv->tx.tx_lock); + ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP; +- spin_unlock_bh(&priv->tx_lock); ++ spin_unlock_bh(&priv->tx.tx_lock); + + return ret; + } + +-/*********/ +-/* DEBUG */ +-/*********/ +- +-#ifdef CONFIG_ATH9K_HTC_DEBUGFS +- +-static int ath9k_debugfs_open(struct inode *inode, struct file *file) +-{ +- file->private_data = inode->i_private; +- return 0; +-} +- +-static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- struct ath9k_htc_priv *priv = file->private_data; +- struct ath9k_htc_target_stats cmd_rsp; +- char buf[512]; +- unsigned int len = 0; +- int ret = 0; +- +- memset(&cmd_rsp, 0, sizeof(cmd_rsp)); +- +- WMI_CMD(WMI_TGT_STATS_CMDID); +- if (ret) +- return -EINVAL; +- +- +- len += snprintf(buf + len, sizeof(buf) - len, +- "%19s : %10u\n", "TX Short Retries", +- be32_to_cpu(cmd_rsp.tx_shortretry)); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%19s : %10u\n", "TX Long Retries", +- be32_to_cpu(cmd_rsp.tx_longretry)); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%19s : %10u\n", "TX Xretries", +- be32_to_cpu(cmd_rsp.tx_xretries)); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%19s : %10u\n", "TX Unaggr. Xretries", +- be32_to_cpu(cmd_rsp.ht_txunaggr_xretry)); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%19s : %10u\n", "TX Xretries (HT)", +- be32_to_cpu(cmd_rsp.ht_tx_xretries)); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%19s : %10u\n", "TX Rate", priv->debug.txrate); +- +- if (len > sizeof(buf)) +- len = sizeof(buf); +- +- return simple_read_from_buffer(user_buf, count, ppos, buf, len); +-} +- +-static const struct file_operations fops_tgt_stats = { +- .read = read_file_tgt_stats, +- .open = ath9k_debugfs_open, +- .owner = THIS_MODULE, +- .llseek = default_llseek, +-}; +- +-static ssize_t read_file_xmit(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- struct ath9k_htc_priv *priv = file->private_data; +- char buf[512]; +- unsigned int len = 0; +- +- len += snprintf(buf + len, sizeof(buf) - len, +- "%20s : %10u\n", "Buffers queued", +- priv->debug.tx_stats.buf_queued); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%20s : %10u\n", "Buffers completed", +- priv->debug.tx_stats.buf_completed); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%20s : %10u\n", "SKBs queued", +- priv->debug.tx_stats.skb_queued); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%20s : %10u\n", "SKBs completed", +- priv->debug.tx_stats.skb_completed); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%20s : %10u\n", "SKBs dropped", +- priv->debug.tx_stats.skb_dropped); +- +- len += snprintf(buf + len, sizeof(buf) - len, +- "%20s : %10u\n", "BE queued", +- priv->debug.tx_stats.queue_stats[WME_AC_BE]); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%20s : %10u\n", "BK queued", +- priv->debug.tx_stats.queue_stats[WME_AC_BK]); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%20s : %10u\n", "VI queued", +- priv->debug.tx_stats.queue_stats[WME_AC_VI]); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%20s : %10u\n", "VO queued", +- priv->debug.tx_stats.queue_stats[WME_AC_VO]); +- +- if (len > sizeof(buf)) +- len = sizeof(buf); +- +- return simple_read_from_buffer(user_buf, count, ppos, buf, len); +-} +- +-static const struct file_operations fops_xmit = { +- .read = read_file_xmit, +- .open = ath9k_debugfs_open, +- .owner = THIS_MODULE, +- .llseek = default_llseek, +-}; +- +-static ssize_t read_file_recv(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- struct ath9k_htc_priv *priv = file->private_data; +- char buf[512]; +- unsigned int len = 0; +- +- len += snprintf(buf + len, sizeof(buf) - len, +- "%20s : %10u\n", "SKBs allocated", +- priv->debug.rx_stats.skb_allocated); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%20s : %10u\n", "SKBs completed", +- priv->debug.rx_stats.skb_completed); +- len += snprintf(buf + len, sizeof(buf) - len, +- "%20s : %10u\n", "SKBs Dropped", +- priv->debug.rx_stats.skb_dropped); +- +- if (len > sizeof(buf)) +- len = sizeof(buf); +- +- return simple_read_from_buffer(user_buf, count, ppos, buf, len); +-} +- +-static const struct file_operations fops_recv = { +- .read = read_file_recv, +- .open = ath9k_debugfs_open, +- .owner = THIS_MODULE, +- .llseek = default_llseek, +-}; +- +-int ath9k_htc_init_debug(struct ath_hw *ah) +-{ +- struct ath_common *common = ath9k_hw_common(ah); +- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; +- +- if (!ath9k_debugfs_root) +- return -ENOENT; +- +- priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy), +- ath9k_debugfs_root); +- if (!priv->debug.debugfs_phy) +- goto err; +- +- priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR, +- priv->debug.debugfs_phy, +- priv, &fops_tgt_stats); +- if (!priv->debug.debugfs_tgt_stats) +- goto err; +- +- +- priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR, +- priv->debug.debugfs_phy, +- priv, &fops_xmit); +- if (!priv->debug.debugfs_xmit) +- goto err; +- +- priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR, +- priv->debug.debugfs_phy, +- priv, &fops_recv); +- if (!priv->debug.debugfs_recv) +- goto err; +- +- return 0; +- +-err: +- ath9k_htc_exit_debug(ah); +- return -ENOMEM; +-} +- +-void ath9k_htc_exit_debug(struct ath_hw *ah) +-{ +- struct ath_common *common = ath9k_hw_common(ah); +- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; +- +- debugfs_remove(priv->debug.debugfs_recv); +- debugfs_remove(priv->debug.debugfs_xmit); +- debugfs_remove(priv->debug.debugfs_tgt_stats); +- debugfs_remove(priv->debug.debugfs_phy); +-} +- +-int ath9k_htc_debug_create_root(void) +-{ +- ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); +- if (!ath9k_debugfs_root) +- return -ENOENT; +- +- return 0; +-} +- +-void ath9k_htc_debug_remove_root(void) +-{ +- debugfs_remove(ath9k_debugfs_root); +- ath9k_debugfs_root = NULL; +-} +- +-#endif /* CONFIG_ATH9K_HTC_DEBUGFS */ +- + /*******/ + /* ANI */ + /*******/ +@@ -1040,7 +857,8 @@ + { + struct ieee80211_hdr *hdr; + struct ath9k_htc_priv *priv = hw->priv; +- int padpos, padsize, ret; ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ int padpos, padsize, ret, slot; + + hdr = (struct ieee80211_hdr *) skb->data; + +@@ -1048,30 +866,32 @@ + padpos = ath9k_cmn_padpos(hdr->frame_control); + padsize = padpos & 3; + if (padsize && skb->len > padpos) { +- if (skb_headroom(skb) < padsize) ++ if (skb_headroom(skb) < padsize) { ++ ath_dbg(common, ATH_DBG_XMIT, "No room for padding\n"); + goto fail_tx; ++ } + skb_push(skb, padsize); + memmove(skb->data, skb->data + padsize, padpos); + } + +- ret = ath9k_htc_tx_start(priv, skb); +- if (ret != 0) { +- if (ret == -ENOMEM) { +- ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, +- "Stopping TX queues\n"); +- ieee80211_stop_queues(hw); +- spin_lock_bh(&priv->tx_lock); +- priv->tx_queues_stop = true; +- spin_unlock_bh(&priv->tx_lock); +- } else { +- ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, +- "Tx failed\n"); +- } ++ slot = ath9k_htc_tx_get_slot(priv); ++ if (slot < 0) { ++ ath_dbg(common, ATH_DBG_XMIT, "No free TX slot\n"); + goto fail_tx; + } + ++ ret = ath9k_htc_tx_start(priv, skb, slot, false); ++ if (ret != 0) { ++ ath_dbg(common, ATH_DBG_XMIT, "Tx failed\n"); ++ goto clear_slot; ++ } ++ ++ ath9k_htc_check_stop_queues(priv); ++ + return; + ++clear_slot: ++ ath9k_htc_tx_clear_slot(priv, slot); + fail_tx: + dev_kfree_skb_any(skb); + } +@@ -1122,7 +942,7 @@ + + ath9k_host_rx_init(priv); + +- ret = ath9k_htc_update_cap_target(priv); ++ ret = ath9k_htc_update_cap_target(priv, 0); + if (ret) + ath_dbg(common, ATH_DBG_CONFIG, + "Failed to update capability in target\n"); +@@ -1130,12 +950,15 @@ + priv->op_flags &= ~OP_INVALID; + htc_start(priv->htc); + +- spin_lock_bh(&priv->tx_lock); +- priv->tx_queues_stop = false; +- spin_unlock_bh(&priv->tx_lock); ++ spin_lock_bh(&priv->tx.tx_lock); ++ priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP; ++ spin_unlock_bh(&priv->tx.tx_lock); + + ieee80211_wake_queues(hw); + ++ mod_timer(&priv->tx.cleanup_timer, ++ jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); ++ + if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) { + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); +@@ -1152,7 +975,7 @@ + struct ath9k_htc_priv *priv = hw->priv; + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); +- int ret = 0; ++ int ret __attribute__ ((unused)); + u8 cmd_rsp; + + mutex_lock(&priv->mutex); +@@ -1164,25 +987,27 @@ + } + + ath9k_htc_ps_wakeup(priv); +- htc_stop(priv->htc); ++ + WMI_CMD(WMI_DISABLE_INTR_CMDID); + WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); + WMI_CMD(WMI_STOP_RECV_CMDID); + +- tasklet_kill(&priv->swba_tasklet); + tasklet_kill(&priv->rx_tasklet); +- tasklet_kill(&priv->tx_tasklet); + +- skb_queue_purge(&priv->tx_queue); ++ del_timer_sync(&priv->tx.cleanup_timer); ++ ath9k_htc_tx_drain(priv); ++ ath9k_wmi_event_drain(priv); + + mutex_unlock(&priv->mutex); + + /* Cancel all the running timers/work .. */ + cancel_work_sync(&priv->fatal_work); + cancel_work_sync(&priv->ps_work); +- cancel_delayed_work_sync(&priv->ath9k_led_blink_work); ++ ++#ifdef CONFIG_MAC80211_LEDS ++ cancel_work_sync(&priv->led_work); ++#endif + ath9k_htc_stop_ani(priv); +- ath9k_led_stop_brightness(priv); + + mutex_lock(&priv->mutex); + +@@ -1245,13 +1070,13 @@ + + switch (vif->type) { + case NL80211_IFTYPE_STATION: +- hvif.opmode = cpu_to_be32(HTC_M_STA); ++ hvif.opmode = HTC_M_STA; + break; + case NL80211_IFTYPE_ADHOC: +- hvif.opmode = cpu_to_be32(HTC_M_IBSS); ++ hvif.opmode = HTC_M_IBSS; + break; + case NL80211_IFTYPE_AP: +- hvif.opmode = cpu_to_be32(HTC_M_HOSTAP); ++ hvif.opmode = HTC_M_HOSTAP; + break; + default: + ath_err(common, +@@ -1281,14 +1106,20 @@ + + priv->vif_slot |= (1 << avp->index); + priv->nvifs++; +- priv->vif = vif; + + INC_VIF(priv, vif->type); ++ ++ if ((vif->type == NL80211_IFTYPE_AP) || ++ (vif->type == NL80211_IFTYPE_ADHOC)) ++ ath9k_htc_assign_bslot(priv, vif); ++ + ath9k_htc_set_opmode(priv); + + if ((priv->ah->opmode == NL80211_IFTYPE_AP) && +- !(priv->op_flags & OP_ANI_RUNNING)) ++ !(priv->op_flags & OP_ANI_RUNNING)) { ++ ath9k_hw_set_tsfadjust(priv->ah, 1); + ath9k_htc_start_ani(priv); ++ } + + ath_dbg(common, ATH_DBG_CONFIG, + "Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index); +@@ -1317,13 +1148,21 @@ + memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); + hvif.index = avp->index; + WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); ++ if (ret) { ++ ath_err(common, "Unable to remove interface at idx: %d\n", ++ avp->index); ++ } + priv->nvifs--; + priv->vif_slot &= ~(1 << avp->index); + + ath9k_htc_remove_station(priv, vif, NULL); +- priv->vif = NULL; + + DEC_VIF(priv, vif->type); ++ ++ if ((vif->type == NL80211_IFTYPE_AP) || ++ (vif->type == NL80211_IFTYPE_ADHOC)) ++ ath9k_htc_remove_bslot(priv, vif); ++ + ath9k_htc_set_opmode(priv); + + /* +@@ -1493,10 +1332,13 @@ + struct ieee80211_sta *sta) + { + struct ath9k_htc_priv *priv = hw->priv; ++ struct ath9k_htc_sta *ista; + int ret; + + mutex_lock(&priv->mutex); + ath9k_htc_ps_wakeup(priv); ++ ista = (struct ath9k_htc_sta *) sta->drv_priv; ++ htc_sta_drain(priv->htc, ista->index); + ret = ath9k_htc_remove_station(priv, vif, sta); + ath9k_htc_ps_restore(priv); + mutex_unlock(&priv->mutex); +@@ -1644,6 +1486,7 @@ + if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) { + ath_dbg(common, ATH_DBG_CONFIG, + "Beacon enabled for BSS: %pM\n", bss_conf->bssid); ++ ath9k_htc_set_tsfadjust(priv, vif); + priv->op_flags |= OP_ENABLE_BEACON; + ath9k_htc_beacon_config(priv, vif); + } +@@ -1741,6 +1584,7 @@ + int ret = 0; + + mutex_lock(&priv->mutex); ++ ath9k_htc_ps_wakeup(priv); + + switch (action) { + case IEEE80211_AMPDU_RX_START: +@@ -1758,14 +1602,15 @@ + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + ista = (struct ath9k_htc_sta *) sta->drv_priv; +- spin_lock_bh(&priv->tx_lock); ++ spin_lock_bh(&priv->tx.tx_lock); + ista->tid_state[tid] = AGGR_OPERATIONAL; +- spin_unlock_bh(&priv->tx_lock); ++ spin_unlock_bh(&priv->tx.tx_lock); + break; + default: + ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n"); + } + ++ ath9k_htc_ps_restore(priv); + mutex_unlock(&priv->mutex); + + return ret; +@@ -1816,6 +1661,55 @@ + mutex_unlock(&priv->mutex); + } + ++/* ++ * Currently, this is used only for selecting the minimum rate ++ * for management frames, rate selection for data frames remain ++ * unaffected. ++ */ ++static int ath9k_htc_set_bitrate_mask(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ const struct cfg80211_bitrate_mask *mask) ++{ ++ struct ath9k_htc_priv *priv = hw->priv; ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ struct ath9k_htc_target_rate_mask tmask; ++ struct ath9k_htc_vif *avp = (void *)vif->drv_priv; ++ int ret = 0; ++ u8 cmd_rsp; ++ ++ memset(&tmask, 0, sizeof(struct ath9k_htc_target_rate_mask)); ++ ++ tmask.vif_index = avp->index; ++ tmask.band = IEEE80211_BAND_2GHZ; ++ tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_2GHZ].legacy); ++ ++ WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask); ++ if (ret) { ++ ath_err(common, ++ "Unable to set 2G rate mask for " ++ "interface at idx: %d\n", avp->index); ++ goto out; ++ } ++ ++ tmask.band = IEEE80211_BAND_5GHZ; ++ tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_5GHZ].legacy); ++ ++ WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask); ++ if (ret) { ++ ath_err(common, ++ "Unable to set 5G rate mask for " ++ "interface at idx: %d\n", avp->index); ++ goto out; ++ } ++ ++ ath_dbg(common, ATH_DBG_CONFIG, ++ "Set bitrate masks: 0x%x, 0x%x\n", ++ mask->control[IEEE80211_BAND_2GHZ].legacy, ++ mask->control[IEEE80211_BAND_5GHZ].legacy); ++out: ++ return ret; ++} ++ + struct ieee80211_ops ath9k_htc_ops = { + .tx = ath9k_htc_tx, + .start = ath9k_htc_start, +@@ -1838,4 +1732,5 @@ + .set_rts_threshold = ath9k_htc_set_rts_threshold, + .rfkill_poll = ath9k_htc_rfkill_poll_state, + .set_coverage_class = ath9k_htc_set_coverage_class, ++ .set_bitrate_mask = ath9k_htc_set_bitrate_mask, + }; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c 2011-05-05 23:29:49.077485265 +0200 +@@ -53,6 +53,138 @@ + } + } + ++void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv) ++{ ++ spin_lock_bh(&priv->tx.tx_lock); ++ priv->tx.queued_cnt++; ++ if ((priv->tx.queued_cnt >= ATH9K_HTC_TX_THRESHOLD) && ++ !(priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) { ++ priv->tx.flags |= ATH9K_HTC_OP_TX_QUEUES_STOP; ++ ieee80211_stop_queues(priv->hw); ++ } ++ spin_unlock_bh(&priv->tx.tx_lock); ++} ++ ++void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv) ++{ ++ spin_lock_bh(&priv->tx.tx_lock); ++ if ((priv->tx.queued_cnt < ATH9K_HTC_TX_THRESHOLD) && ++ (priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) { ++ priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP; ++ ieee80211_wake_queues(priv->hw); ++ } ++ spin_unlock_bh(&priv->tx.tx_lock); ++} ++ ++int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv) ++{ ++ int slot; ++ ++ spin_lock_bh(&priv->tx.tx_lock); ++ slot = find_first_zero_bit(priv->tx.tx_slot, MAX_TX_BUF_NUM); ++ if (slot >= MAX_TX_BUF_NUM) { ++ spin_unlock_bh(&priv->tx.tx_lock); ++ return -ENOBUFS; ++ } ++ __set_bit(slot, priv->tx.tx_slot); ++ spin_unlock_bh(&priv->tx.tx_lock); ++ ++ return slot; ++} ++ ++void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot) ++{ ++ spin_lock_bh(&priv->tx.tx_lock); ++ __clear_bit(slot, priv->tx.tx_slot); ++ spin_unlock_bh(&priv->tx.tx_lock); ++} ++ ++static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, ++ u16 qnum) ++{ ++ enum htc_endpoint_id epid; ++ ++ switch (qnum) { ++ case 0: ++ TX_QSTAT_INC(WME_AC_VO); ++ epid = priv->data_vo_ep; ++ break; ++ case 1: ++ TX_QSTAT_INC(WME_AC_VI); ++ epid = priv->data_vi_ep; ++ break; ++ case 2: ++ TX_QSTAT_INC(WME_AC_BE); ++ epid = priv->data_be_ep; ++ break; ++ case 3: ++ default: ++ TX_QSTAT_INC(WME_AC_BK); ++ epid = priv->data_bk_ep; ++ break; ++ } ++ ++ return epid; ++} ++ ++static inline struct sk_buff_head* ++get_htc_epid_queue(struct ath9k_htc_priv *priv, u8 epid) ++{ ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ struct sk_buff_head *epid_queue = NULL; ++ ++ if (epid == priv->mgmt_ep) ++ epid_queue = &priv->tx.mgmt_ep_queue; ++ else if (epid == priv->cab_ep) ++ epid_queue = &priv->tx.cab_ep_queue; ++ else if (epid == priv->data_be_ep) ++ epid_queue = &priv->tx.data_be_queue; ++ else if (epid == priv->data_bk_ep) ++ epid_queue = &priv->tx.data_bk_queue; ++ else if (epid == priv->data_vi_ep) ++ epid_queue = &priv->tx.data_vi_queue; ++ else if (epid == priv->data_vo_ep) ++ epid_queue = &priv->tx.data_vo_queue; ++ else ++ ath_err(common, "Invalid EPID: %d\n", epid); ++ ++ return epid_queue; ++} ++ ++/* ++ * Removes the driver header and returns the TX slot number ++ */ ++static inline int strip_drv_header(struct ath9k_htc_priv *priv, ++ struct sk_buff *skb) ++{ ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ struct ath9k_htc_tx_ctl *tx_ctl; ++ int slot; ++ ++ tx_ctl = HTC_SKB_CB(skb); ++ ++ if (tx_ctl->epid == priv->mgmt_ep) { ++ struct tx_mgmt_hdr *tx_mhdr = ++ (struct tx_mgmt_hdr *)skb->data; ++ slot = tx_mhdr->cookie; ++ skb_pull(skb, sizeof(struct tx_mgmt_hdr)); ++ } else if ((tx_ctl->epid == priv->data_bk_ep) || ++ (tx_ctl->epid == priv->data_be_ep) || ++ (tx_ctl->epid == priv->data_vi_ep) || ++ (tx_ctl->epid == priv->data_vo_ep) || ++ (tx_ctl->epid == priv->cab_ep)) { ++ struct tx_frame_hdr *tx_fhdr = ++ (struct tx_frame_hdr *)skb->data; ++ slot = tx_fhdr->cookie; ++ skb_pull(skb, sizeof(struct tx_frame_hdr)); ++ } else { ++ ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid); ++ slot = -EINVAL; ++ } ++ ++ return slot; ++} ++ + int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, + struct ath9k_tx_queue_info *qinfo) + { +@@ -79,23 +211,140 @@ + return error; + } + +-int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) ++static void ath9k_htc_tx_mgmt(struct ath9k_htc_priv *priv, ++ struct ath9k_htc_vif *avp, ++ struct sk_buff *skb, ++ u8 sta_idx, u8 vif_idx, u8 slot) ++{ ++ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); ++ struct ieee80211_mgmt *mgmt; ++ struct ieee80211_hdr *hdr; ++ struct tx_mgmt_hdr mgmt_hdr; ++ struct ath9k_htc_tx_ctl *tx_ctl; ++ u8 *tx_fhdr; ++ ++ tx_ctl = HTC_SKB_CB(skb); ++ hdr = (struct ieee80211_hdr *) skb->data; ++ ++ memset(tx_ctl, 0, sizeof(*tx_ctl)); ++ memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); ++ ++ /* ++ * Set the TSF adjust value for probe response ++ * frame also. ++ */ ++ if (avp && unlikely(ieee80211_is_probe_resp(hdr->frame_control))) { ++ mgmt = (struct ieee80211_mgmt *)skb->data; ++ mgmt->u.probe_resp.timestamp = avp->tsfadjust; ++ } ++ ++ tx_ctl->type = ATH9K_HTC_MGMT; ++ ++ mgmt_hdr.node_idx = sta_idx; ++ mgmt_hdr.vif_idx = vif_idx; ++ mgmt_hdr.tidno = 0; ++ mgmt_hdr.flags = 0; ++ mgmt_hdr.cookie = slot; ++ ++ mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); ++ if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) ++ mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; ++ else ++ mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; ++ ++ tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); ++ memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); ++ tx_ctl->epid = priv->mgmt_ep; ++} ++ ++static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv, ++ struct ieee80211_vif *vif, ++ struct sk_buff *skb, ++ u8 sta_idx, u8 vif_idx, u8 slot, ++ bool is_cab) ++{ ++ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); ++ struct ieee80211_hdr *hdr; ++ struct ath9k_htc_tx_ctl *tx_ctl; ++ struct tx_frame_hdr tx_hdr; ++ u32 flags = 0; ++ u8 *qc, *tx_fhdr; ++ u16 qnum; ++ ++ tx_ctl = HTC_SKB_CB(skb); ++ hdr = (struct ieee80211_hdr *) skb->data; ++ ++ memset(tx_ctl, 0, sizeof(*tx_ctl)); ++ memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); ++ ++ tx_hdr.node_idx = sta_idx; ++ tx_hdr.vif_idx = vif_idx; ++ tx_hdr.cookie = slot; ++ ++ /* ++ * This is a bit redundant but it helps to get ++ * the per-packet index quickly when draining the ++ * TX queue in the HIF layer. Otherwise we would ++ * have to parse the packet contents ... ++ */ ++ tx_ctl->sta_idx = sta_idx; ++ ++ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { ++ tx_ctl->type = ATH9K_HTC_AMPDU; ++ tx_hdr.data_type = ATH9K_HTC_AMPDU; ++ } else { ++ tx_ctl->type = ATH9K_HTC_NORMAL; ++ tx_hdr.data_type = ATH9K_HTC_NORMAL; ++ } ++ ++ if (ieee80211_is_data_qos(hdr->frame_control)) { ++ qc = ieee80211_get_qos_ctl(hdr); ++ tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; ++ } ++ ++ /* Check for RTS protection */ ++ if (priv->hw->wiphy->rts_threshold != (u32) -1) ++ if (skb->len > priv->hw->wiphy->rts_threshold) ++ flags |= ATH9K_HTC_TX_RTSCTS; ++ ++ /* CTS-to-self */ ++ if (!(flags & ATH9K_HTC_TX_RTSCTS) && ++ (vif && vif->bss_conf.use_cts_prot)) ++ flags |= ATH9K_HTC_TX_CTSONLY; ++ ++ tx_hdr.flags = cpu_to_be32(flags); ++ tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); ++ if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) ++ tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; ++ else ++ tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; ++ ++ tx_fhdr = skb_push(skb, sizeof(tx_hdr)); ++ memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); ++ ++ if (is_cab) { ++ CAB_STAT_INC; ++ tx_ctl->epid = priv->cab_ep; ++ return; ++ } ++ ++ qnum = skb_get_queue_mapping(skb); ++ tx_ctl->epid = get_htc_epid(priv, qnum); ++} ++ ++int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, ++ struct sk_buff *skb, ++ u8 slot, bool is_cab) + { + struct ieee80211_hdr *hdr; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = tx_info->control.sta; + struct ieee80211_vif *vif = tx_info->control.vif; + struct ath9k_htc_sta *ista; +- struct ath9k_htc_vif *avp; +- struct ath9k_htc_tx_ctl tx_ctl; +- enum htc_endpoint_id epid; +- u16 qnum; +- __le16 fc; +- u8 *tx_fhdr; ++ struct ath9k_htc_vif *avp = NULL; + u8 sta_idx, vif_idx; + + hdr = (struct ieee80211_hdr *) skb->data; +- fc = hdr->frame_control; + + /* + * Find out on which interface this packet has to be +@@ -124,218 +373,430 @@ + sta_idx = priv->vif_sta_pos[vif_idx]; + } + +- memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); ++ if (ieee80211_is_data(hdr->frame_control)) ++ ath9k_htc_tx_data(priv, vif, skb, ++ sta_idx, vif_idx, slot, is_cab); ++ else ++ ath9k_htc_tx_mgmt(priv, avp, skb, ++ sta_idx, vif_idx, slot); + +- if (ieee80211_is_data(fc)) { +- struct tx_frame_hdr tx_hdr; +- u32 flags = 0; +- u8 *qc; + +- memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); ++ return htc_send(priv->htc, skb); ++} + +- tx_hdr.node_idx = sta_idx; +- tx_hdr.vif_idx = vif_idx; ++static inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, ++ struct ath9k_htc_sta *ista, u8 tid) ++{ ++ bool ret = false; + +- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { +- tx_ctl.type = ATH9K_HTC_AMPDU; +- tx_hdr.data_type = ATH9K_HTC_AMPDU; +- } else { +- tx_ctl.type = ATH9K_HTC_NORMAL; +- tx_hdr.data_type = ATH9K_HTC_NORMAL; +- } ++ spin_lock_bh(&priv->tx.tx_lock); ++ if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP)) ++ ret = true; ++ spin_unlock_bh(&priv->tx.tx_lock); ++ ++ return ret; ++} ++ ++static void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, ++ struct ieee80211_vif *vif, ++ struct sk_buff *skb) ++{ ++ struct ieee80211_sta *sta; ++ struct ieee80211_hdr *hdr; ++ __le16 fc; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ fc = hdr->frame_control; ++ ++ rcu_read_lock(); + ++ sta = ieee80211_find_sta(vif, hdr->addr1); ++ if (!sta) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ if (sta && conf_is_ht(&priv->hw->conf) && ++ !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { + if (ieee80211_is_data_qos(fc)) { ++ u8 *qc, tid; ++ struct ath9k_htc_sta *ista; ++ + qc = ieee80211_get_qos_ctl(hdr); +- tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; ++ tid = qc[0] & 0xf; ++ ista = (struct ath9k_htc_sta *)sta->drv_priv; ++ if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) { ++ ieee80211_start_tx_ba_session(sta, tid, 0); ++ spin_lock_bh(&priv->tx.tx_lock); ++ ista->tid_state[tid] = AGGR_PROGRESS; ++ spin_unlock_bh(&priv->tx.tx_lock); ++ } + } ++ } + +- /* Check for RTS protection */ +- if (priv->hw->wiphy->rts_threshold != (u32) -1) +- if (skb->len > priv->hw->wiphy->rts_threshold) +- flags |= ATH9K_HTC_TX_RTSCTS; +- +- /* CTS-to-self */ +- if (!(flags & ATH9K_HTC_TX_RTSCTS) && +- (vif && vif->bss_conf.use_cts_prot)) +- flags |= ATH9K_HTC_TX_CTSONLY; +- +- tx_hdr.flags = cpu_to_be32(flags); +- tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); +- if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) +- tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; +- else +- tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; +- +- tx_fhdr = skb_push(skb, sizeof(tx_hdr)); +- memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); +- +- qnum = skb_get_queue_mapping(skb); +- +- switch (qnum) { +- case 0: +- TX_QSTAT_INC(WME_AC_VO); +- epid = priv->data_vo_ep; +- break; +- case 1: +- TX_QSTAT_INC(WME_AC_VI); +- epid = priv->data_vi_ep; +- break; +- case 2: +- TX_QSTAT_INC(WME_AC_BE); +- epid = priv->data_be_ep; +- break; +- case 3: +- default: +- TX_QSTAT_INC(WME_AC_BK); +- epid = priv->data_bk_ep; +- break; +- } +- } else { +- struct tx_mgmt_hdr mgmt_hdr; ++ rcu_read_unlock(); ++} ++ ++static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, ++ struct sk_buff *skb, ++ struct __wmi_event_txstatus *txs) ++{ ++ struct ieee80211_vif *vif; ++ struct ath9k_htc_tx_ctl *tx_ctl; ++ struct ieee80211_tx_info *tx_info; ++ struct ieee80211_tx_rate *rate; ++ struct ieee80211_conf *cur_conf = &priv->hw->conf; ++ bool txok; ++ int slot; ++ ++ slot = strip_drv_header(priv, skb); ++ if (slot < 0) { ++ dev_kfree_skb_any(skb); ++ return; ++ } ++ ++ tx_ctl = HTC_SKB_CB(skb); ++ txok = tx_ctl->txok; ++ tx_info = IEEE80211_SKB_CB(skb); ++ vif = tx_info->control.vif; ++ rate = &tx_info->status.rates[0]; + +- memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); ++ memset(&tx_info->status, 0, sizeof(tx_info->status)); + +- tx_ctl.type = ATH9K_HTC_NORMAL; ++ /* ++ * URB submission failed for this frame, it never reached ++ * the target. ++ */ ++ if (!txok || !vif || !txs) ++ goto send_mac80211; ++ ++ if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) ++ tx_info->flags |= IEEE80211_TX_STAT_ACK; + +- mgmt_hdr.node_idx = sta_idx; +- mgmt_hdr.vif_idx = vif_idx; +- mgmt_hdr.tidno = 0; +- mgmt_hdr.flags = 0; ++ if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT) ++ tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + +- mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); +- if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) +- mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; +- else +- mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; ++ if (txs->ts_flags & ATH9K_HTC_TXSTAT_RTC_CTS) ++ rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; + +- tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); +- memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); +- epid = priv->mgmt_ep; ++ rate->count = 1; ++ rate->idx = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_RATE); ++ ++ if (txs->ts_flags & ATH9K_HTC_TXSTAT_MCS) { ++ rate->flags |= IEEE80211_TX_RC_MCS; ++ ++ if (txs->ts_flags & ATH9K_HTC_TXSTAT_CW40) ++ rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; ++ if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI) ++ rate->flags |= IEEE80211_TX_RC_SHORT_GI; ++ } else { ++ if (cur_conf->channel->band == IEEE80211_BAND_5GHZ) ++ rate->idx += 4; /* No CCK rates */ + } + +- return htc_send(priv->htc, skb, epid, &tx_ctl); ++ ath9k_htc_check_tx_aggr(priv, vif, skb); ++ ++send_mac80211: ++ spin_lock_bh(&priv->tx.tx_lock); ++ if (WARN_ON(--priv->tx.queued_cnt < 0)) ++ priv->tx.queued_cnt = 0; ++ spin_unlock_bh(&priv->tx.tx_lock); ++ ++ ath9k_htc_tx_clear_slot(priv, slot); ++ ++ /* Send status to mac80211 */ ++ ieee80211_tx_status(priv->hw, skb); + } + +-static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, +- struct ath9k_htc_sta *ista, u8 tid) ++static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv, ++ struct sk_buff_head *queue) + { +- bool ret = false; ++ struct sk_buff *skb; + +- spin_lock_bh(&priv->tx_lock); +- if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP)) +- ret = true; +- spin_unlock_bh(&priv->tx_lock); ++ while ((skb = skb_dequeue(queue)) != NULL) { ++ ath9k_htc_tx_process(priv, skb, NULL); ++ } ++} + +- return ret; ++void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) ++{ ++ struct ath9k_htc_tx_event *event, *tmp; ++ ++ spin_lock_bh(&priv->tx.tx_lock); ++ priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN; ++ spin_unlock_bh(&priv->tx.tx_lock); ++ ++ /* ++ * Ensure that all pending TX frames are flushed, ++ * and that the TX completion/failed tasklets is killed. ++ */ ++ htc_stop(priv->htc); ++ tasklet_kill(&priv->wmi->wmi_event_tasklet); ++ tasklet_kill(&priv->tx_failed_tasklet); ++ ++ ath9k_htc_tx_drainq(priv, &priv->tx.mgmt_ep_queue); ++ ath9k_htc_tx_drainq(priv, &priv->tx.cab_ep_queue); ++ ath9k_htc_tx_drainq(priv, &priv->tx.data_be_queue); ++ ath9k_htc_tx_drainq(priv, &priv->tx.data_bk_queue); ++ ath9k_htc_tx_drainq(priv, &priv->tx.data_vi_queue); ++ ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue); ++ ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); ++ ++ /* ++ * The TX cleanup timer has already been killed. ++ */ ++ spin_lock_bh(&priv->wmi->event_lock); ++ list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { ++ list_del(&event->list); ++ kfree(event); ++ } ++ spin_unlock_bh(&priv->wmi->event_lock); ++ ++ spin_lock_bh(&priv->tx.tx_lock); ++ priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN; ++ spin_unlock_bh(&priv->tx.tx_lock); + } + +-void ath9k_tx_tasklet(unsigned long data) ++void ath9k_tx_failed_tasklet(unsigned long data) + { + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; +- struct ieee80211_vif *vif; +- struct ieee80211_sta *sta; +- struct ieee80211_hdr *hdr; +- struct ieee80211_tx_info *tx_info; +- struct sk_buff *skb = NULL; +- __le16 fc; + +- while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) { ++ spin_lock_bh(&priv->tx.tx_lock); ++ if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { ++ spin_unlock_bh(&priv->tx.tx_lock); ++ return; ++ } ++ spin_unlock_bh(&priv->tx.tx_lock); + +- hdr = (struct ieee80211_hdr *) skb->data; +- fc = hdr->frame_control; +- tx_info = IEEE80211_SKB_CB(skb); +- vif = tx_info->control.vif; ++ ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); ++} + +- memset(&tx_info->status, 0, sizeof(tx_info->status)); ++static inline bool check_cookie(struct ath9k_htc_priv *priv, ++ struct sk_buff *skb, ++ u8 cookie, u8 epid) ++{ ++ u8 fcookie = 0; + +- if (!vif) +- goto send_mac80211; ++ if (epid == priv->mgmt_ep) { ++ struct tx_mgmt_hdr *hdr; ++ hdr = (struct tx_mgmt_hdr *) skb->data; ++ fcookie = hdr->cookie; ++ } else if ((epid == priv->data_bk_ep) || ++ (epid == priv->data_be_ep) || ++ (epid == priv->data_vi_ep) || ++ (epid == priv->data_vo_ep) || ++ (epid == priv->cab_ep)) { ++ struct tx_frame_hdr *hdr; ++ hdr = (struct tx_frame_hdr *) skb->data; ++ fcookie = hdr->cookie; ++ } + +- rcu_read_lock(); ++ if (fcookie == cookie) ++ return true; + +- sta = ieee80211_find_sta(vif, hdr->addr1); +- if (!sta) { +- rcu_read_unlock(); +- ieee80211_tx_status(priv->hw, skb); +- continue; +- } ++ return false; ++} + +- /* Check if we need to start aggregation */ ++static struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv, ++ struct __wmi_event_txstatus *txs) ++{ ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ struct sk_buff_head *epid_queue; ++ struct sk_buff *skb, *tmp; ++ unsigned long flags; ++ u8 epid = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_EPID); + +- if (sta && conf_is_ht(&priv->hw->conf) && +- !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { +- if (ieee80211_is_data_qos(fc)) { +- u8 *qc, tid; +- struct ath9k_htc_sta *ista; +- +- qc = ieee80211_get_qos_ctl(hdr); +- tid = qc[0] & 0xf; +- ista = (struct ath9k_htc_sta *)sta->drv_priv; +- +- if (ath9k_htc_check_tx_aggr(priv, ista, tid)) { +- ieee80211_start_tx_ba_session(sta, tid, 0); +- spin_lock_bh(&priv->tx_lock); +- ista->tid_state[tid] = AGGR_PROGRESS; +- spin_unlock_bh(&priv->tx_lock); +- } +- } ++ epid_queue = get_htc_epid_queue(priv, epid); ++ if (!epid_queue) ++ return NULL; ++ ++ spin_lock_irqsave(&epid_queue->lock, flags); ++ skb_queue_walk_safe(epid_queue, skb, tmp) { ++ if (check_cookie(priv, skb, txs->cookie, epid)) { ++ __skb_unlink(skb, epid_queue); ++ spin_unlock_irqrestore(&epid_queue->lock, flags); ++ return skb; + } ++ } ++ spin_unlock_irqrestore(&epid_queue->lock, flags); + +- rcu_read_unlock(); ++ ath_dbg(common, ATH_DBG_XMIT, ++ "No matching packet for cookie: %d, epid: %d\n", ++ txs->cookie, epid); + +- send_mac80211: +- /* Send status to mac80211 */ +- ieee80211_tx_status(priv->hw, skb); ++ return NULL; ++} ++ ++void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) ++{ ++ struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event; ++ struct __wmi_event_txstatus *__txs; ++ struct sk_buff *skb; ++ struct ath9k_htc_tx_event *tx_pend; ++ int i; ++ ++ for (i = 0; i < txs->cnt; i++) { ++ WARN_ON(txs->cnt > HTC_MAX_TX_STATUS); ++ ++ __txs = &txs->txstatus[i]; ++ ++ skb = ath9k_htc_tx_get_packet(priv, __txs); ++ if (!skb) { ++ /* ++ * Store this event, so that the TX cleanup ++ * routine can check later for the needed packet. ++ */ ++ tx_pend = kzalloc(sizeof(struct ath9k_htc_tx_event), ++ GFP_ATOMIC); ++ if (!tx_pend) ++ continue; ++ ++ memcpy(&tx_pend->txs, __txs, ++ sizeof(struct __wmi_event_txstatus)); ++ ++ spin_lock(&priv->wmi->event_lock); ++ list_add_tail(&tx_pend->list, ++ &priv->wmi->pending_tx_events); ++ spin_unlock(&priv->wmi->event_lock); ++ ++ continue; ++ } ++ ++ ath9k_htc_tx_process(priv, skb, __txs); + } + + /* Wake TX queues if needed */ +- spin_lock_bh(&priv->tx_lock); +- if (priv->tx_queues_stop) { +- priv->tx_queues_stop = false; +- spin_unlock_bh(&priv->tx_lock); +- ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, +- "Waking up TX queues\n"); +- ieee80211_wake_queues(priv->hw); +- return; +- } +- spin_unlock_bh(&priv->tx_lock); ++ ath9k_htc_check_wake_queues(priv); + } + + void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, + enum htc_endpoint_id ep_id, bool txok) + { + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; +- struct ath_common *common = ath9k_hw_common(priv->ah); +- struct ieee80211_tx_info *tx_info; ++ struct ath9k_htc_tx_ctl *tx_ctl; ++ struct sk_buff_head *epid_queue; + +- if (!skb) ++ tx_ctl = HTC_SKB_CB(skb); ++ tx_ctl->txok = txok; ++ tx_ctl->timestamp = jiffies; ++ ++ if (!txok) { ++ skb_queue_tail(&priv->tx.tx_failed, skb); ++ tasklet_schedule(&priv->tx_failed_tasklet); + return; ++ } + +- if (ep_id == priv->mgmt_ep) { +- skb_pull(skb, sizeof(struct tx_mgmt_hdr)); +- } else if ((ep_id == priv->data_bk_ep) || +- (ep_id == priv->data_be_ep) || +- (ep_id == priv->data_vi_ep) || +- (ep_id == priv->data_vo_ep)) { +- skb_pull(skb, sizeof(struct tx_frame_hdr)); +- } else { +- ath_err(common, "Unsupported TX EPID: %d\n", ep_id); ++ epid_queue = get_htc_epid_queue(priv, ep_id); ++ if (!epid_queue) { + dev_kfree_skb_any(skb); + return; + } + +- tx_info = IEEE80211_SKB_CB(skb); ++ skb_queue_tail(epid_queue, skb); ++} + +- if (txok) +- tx_info->flags |= IEEE80211_TX_STAT_ACK; ++static inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb) ++{ ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ struct ath9k_htc_tx_ctl *tx_ctl; + +- skb_queue_tail(&priv->tx_queue, skb); +- tasklet_schedule(&priv->tx_tasklet); ++ tx_ctl = HTC_SKB_CB(skb); ++ ++ if (time_after(jiffies, ++ tx_ctl->timestamp + ++ msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) { ++ ath_dbg(common, ATH_DBG_XMIT, ++ "Dropping a packet due to TX timeout\n"); ++ return true; ++ } ++ ++ return false; ++} ++ ++static void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv, ++ struct sk_buff_head *epid_queue) ++{ ++ bool process = false; ++ unsigned long flags; ++ struct sk_buff *skb, *tmp; ++ struct sk_buff_head queue; ++ ++ skb_queue_head_init(&queue); ++ ++ spin_lock_irqsave(&epid_queue->lock, flags); ++ skb_queue_walk_safe(epid_queue, skb, tmp) { ++ if (check_packet(priv, skb)) { ++ __skb_unlink(skb, epid_queue); ++ __skb_queue_tail(&queue, skb); ++ process = true; ++ } ++ } ++ spin_unlock_irqrestore(&epid_queue->lock, flags); ++ ++ if (process) { ++ skb_queue_walk_safe(&queue, skb, tmp) { ++ __skb_unlink(skb, &queue); ++ ath9k_htc_tx_process(priv, skb, NULL); ++ } ++ } ++} ++ ++void ath9k_htc_tx_cleanup_timer(unsigned long data) ++{ ++ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) data; ++ struct ath_common *common = ath9k_hw_common(priv->ah); ++ struct ath9k_htc_tx_event *event, *tmp; ++ struct sk_buff *skb; ++ ++ spin_lock(&priv->wmi->event_lock); ++ list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { ++ ++ skb = ath9k_htc_tx_get_packet(priv, &event->txs); ++ if (skb) { ++ ath_dbg(common, ATH_DBG_XMIT, ++ "Found packet for cookie: %d, epid: %d\n", ++ event->txs.cookie, ++ MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID)); ++ ++ ath9k_htc_tx_process(priv, skb, &event->txs); ++ list_del(&event->list); ++ kfree(event); ++ continue; ++ } ++ ++ if (++event->count >= ATH9K_HTC_TX_TIMEOUT_COUNT) { ++ list_del(&event->list); ++ kfree(event); ++ } ++ } ++ spin_unlock(&priv->wmi->event_lock); ++ ++ /* ++ * Check if status-pending packets have to be cleaned up. ++ */ ++ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.mgmt_ep_queue); ++ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.cab_ep_queue); ++ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_be_queue); ++ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_bk_queue); ++ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vi_queue); ++ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vo_queue); ++ ++ /* Wake TX queues if needed */ ++ ath9k_htc_check_wake_queues(priv); ++ ++ mod_timer(&priv->tx.cleanup_timer, ++ jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); + } + + int ath9k_tx_init(struct ath9k_htc_priv *priv) + { +- skb_queue_head_init(&priv->tx_queue); ++ skb_queue_head_init(&priv->tx.mgmt_ep_queue); ++ skb_queue_head_init(&priv->tx.cab_ep_queue); ++ skb_queue_head_init(&priv->tx.data_be_queue); ++ skb_queue_head_init(&priv->tx.data_bk_queue); ++ skb_queue_head_init(&priv->tx.data_vi_queue); ++ skb_queue_head_init(&priv->tx.data_vo_queue); ++ skb_queue_head_init(&priv->tx.tx_failed); + return 0; + } + +@@ -507,8 +968,9 @@ + int last_rssi = ATH_RSSI_DUMMY_MARKER; + __le16 fc; + +- if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) { +- ath_err(common, "Corrupted RX frame, dropping\n"); ++ if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { ++ ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", ++ skb->len); + goto rx_next; + } + +@@ -522,6 +984,8 @@ + goto rx_next; + } + ++ ath9k_htc_err_stat_rx(priv, rxstatus); ++ + /* Get the RX status information */ + memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); + skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc.h 2011-05-05 23:29:49.001484345 +0200 +@@ -66,13 +66,13 @@ + HTC_M_WDS = 2 + }; + +-#define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr) +-#define ATH9K_HTC_AMPDU 1 ++#define ATH9K_HTC_AMPDU 1 + #define ATH9K_HTC_NORMAL 2 ++#define ATH9K_HTC_BEACON 3 ++#define ATH9K_HTC_MGMT 4 + + #define ATH9K_HTC_TX_CTSONLY 0x1 + #define ATH9K_HTC_TX_RTSCTS 0x2 +-#define ATH9K_HTC_TX_USE_MIN_RATE 0x100 + + struct tx_frame_hdr { + u8 data_type; +@@ -82,7 +82,8 @@ + __be32 flags; /* ATH9K_HTC_TX_* */ + u8 key_type; + u8 keyix; +- u8 reserved[26]; ++ u8 cookie; ++ u8 pad; + } __packed; + + struct tx_mgmt_hdr { +@@ -92,50 +93,34 @@ + u8 flags; + u8 key_type; + u8 keyix; +- u16 reserved; ++ u8 cookie; ++ u8 pad; + } __packed; + + struct tx_beacon_header { +- u8 len_changed; + u8 vif_index; ++ u8 len_changed; + u16 rev; + } __packed; + +-struct ath9k_htc_target_hw { +- u32 flags; +- u32 flags_ext; +- u32 ampdu_limit; +- u8 ampdu_subframes; +- u8 tx_chainmask; +- u8 tx_chainmask_legacy; +- u8 rtscts_ratecode; +- u8 protmode; +-} __packed; ++#define MAX_TX_AMPDU_SUBFRAMES_9271 17 ++#define MAX_TX_AMPDU_SUBFRAMES_7010 22 + + struct ath9k_htc_cap_target { +- u32 flags; +- u32 flags_ext; +- u32 ampdu_limit; ++ __be32 ampdu_limit; + u8 ampdu_subframes; ++ u8 enable_coex; + u8 tx_chainmask; +- u8 tx_chainmask_legacy; +- u8 rtscts_ratecode; +- u8 protmode; ++ u8 pad; + } __packed; + + struct ath9k_htc_target_vif { + u8 index; +- u8 des_bssid[ETH_ALEN]; +- __be32 opmode; ++ u8 opmode; + u8 myaddr[ETH_ALEN]; +- u8 bssid[ETH_ALEN]; +- u32 flags; +- u32 flags_ext; +- u16 ps_sta; +- __be16 rtsthreshold; + u8 ath_cap; +- u8 node; +- s8 mcast_rate; ++ __be16 rtsthreshold; ++ u8 pad; + } __packed; + + #define ATH_HTC_STA_AUTH 0x0001 +@@ -143,27 +128,16 @@ + #define ATH_HTC_STA_ERP 0x0004 + #define ATH_HTC_STA_HT 0x0008 + +-/* FIXME: UAPSD variables */ + struct ath9k_htc_target_sta { +- u16 associd; +- u16 txpower; +- u32 ucastkey; + u8 macaddr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u8 sta_index; + u8 vif_index; +- u8 vif_sta; +- __be16 flags; /* ATH_HTC_STA_* */ +- u16 htcap; +- u8 valid; +- u16 capinfo; +- struct ath9k_htc_target_hw *hw; +- struct ath9k_htc_target_vif *vif; +- u16 txseqmgmt; + u8 is_vif_sta; +- u16 maxampdu; +- u16 iv16; +- u32 iv32; ++ __be16 flags; /* ATH_HTC_STA_* */ ++ __be16 htcap; ++ __be16 maxampdu; ++ u8 pad; + } __packed; + + struct ath9k_htc_target_aggr { +@@ -197,12 +171,38 @@ + struct ath9k_htc_rate rates; + }; + +-struct ath9k_htc_target_stats { +- __be32 tx_shortretry; +- __be32 tx_longretry; +- __be32 tx_xretries; +- __be32 ht_txunaggr_xretry; +- __be32 ht_tx_xretries; ++struct ath9k_htc_target_rate_mask { ++ u8 vif_index; ++ u8 band; ++ __be32 mask; ++ u16 pad; ++} __packed; ++ ++struct ath9k_htc_target_int_stats { ++ __be32 rx; ++ __be32 rxorn; ++ __be32 rxeol; ++ __be32 txurn; ++ __be32 txto; ++ __be32 cst; ++} __packed; ++ ++struct ath9k_htc_target_tx_stats { ++ __be32 xretries; ++ __be32 fifoerr; ++ __be32 filtered; ++ __be32 timer_exp; ++ __be32 shortretries; ++ __be32 longretries; ++ __be32 qnull; ++ __be32 encap_fail; ++ __be32 nobuf; ++} __packed; ++ ++struct ath9k_htc_target_rx_stats { ++ __be32 nobuf; ++ __be32 host_send; ++ __be32 host_done; + } __packed; + + #define ATH9K_HTC_MAX_VIF 2 +@@ -244,6 +244,8 @@ + u8 index; + u16 seq_no; + bool beacon_configured; ++ int bslot; ++ __le64 tsfadjust; + }; + + struct ath9k_vif_iter_data { +@@ -282,23 +284,65 @@ + spinlock_t rxbuflock; + }; + ++#define ATH9K_HTC_TX_CLEANUP_INTERVAL 50 /* ms */ ++#define ATH9K_HTC_TX_TIMEOUT_INTERVAL 2500 /* ms */ ++#define ATH9K_HTC_TX_RESERVE 10 ++#define ATH9K_HTC_TX_TIMEOUT_COUNT 20 ++#define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE) ++ ++#define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0) ++#define ATH9K_HTC_OP_TX_DRAIN BIT(1) ++ ++struct ath9k_htc_tx { ++ u8 flags; ++ int queued_cnt; ++ struct sk_buff_head mgmt_ep_queue; ++ struct sk_buff_head cab_ep_queue; ++ struct sk_buff_head data_be_queue; ++ struct sk_buff_head data_bk_queue; ++ struct sk_buff_head data_vi_queue; ++ struct sk_buff_head data_vo_queue; ++ struct sk_buff_head tx_failed; ++ DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); ++ struct timer_list cleanup_timer; ++ spinlock_t tx_lock; ++}; ++ + struct ath9k_htc_tx_ctl { + u8 type; /* ATH9K_HTC_* */ ++ u8 epid; ++ u8 txok; ++ u8 sta_idx; ++ unsigned long timestamp; + }; + ++static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) ++{ ++ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); ++ ++ BUILD_BUG_ON(sizeof(struct ath9k_htc_tx_ctl) > ++ IEEE80211_TX_INFO_DRIVER_DATA_SIZE); ++ return (struct ath9k_htc_tx_ctl *) &tx_info->driver_data; ++} ++ + #ifdef CONFIG_ATH9K_HTC_DEBUGFS + + #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++) + #define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++) ++#define CAB_STAT_INC priv->debug.tx_stats.cab_queued++ + + #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++) + ++void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, ++ struct ath_htc_rx_status *rxs); ++ + struct ath_tx_stats { + u32 buf_queued; + u32 buf_completed; + u32 skb_queued; +- u32 skb_completed; +- u32 skb_dropped; ++ u32 skb_success; ++ u32 skb_failed; ++ u32 cab_queued; + u32 queue_stats[WME_NUM_AC]; + }; + +@@ -306,55 +350,57 @@ + u32 skb_allocated; + u32 skb_completed; + u32 skb_dropped; ++ u32 err_crc; ++ u32 err_decrypt_crc; ++ u32 err_mic; ++ u32 err_pre_delim; ++ u32 err_post_delim; ++ u32 err_decrypt_busy; ++ u32 err_phy; ++ u32 err_phy_stats[ATH9K_PHYERR_MAX]; + }; + + struct ath9k_debug { + struct dentry *debugfs_phy; +- struct dentry *debugfs_tgt_stats; +- struct dentry *debugfs_xmit; +- struct dentry *debugfs_recv; + struct ath_tx_stats tx_stats; + struct ath_rx_stats rx_stats; +- u32 txrate; + }; + + #else + + #define TX_STAT_INC(c) do { } while (0) + #define RX_STAT_INC(c) do { } while (0) ++#define CAB_STAT_INC do { } while (0) + + #define TX_QSTAT_INC(c) do { } while (0) + ++static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, ++ struct ath_htc_rx_status *rxs) ++{ ++} ++ + #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ + + #define ATH_LED_PIN_DEF 1 +-#define ATH_LED_PIN_9287 8 ++#define ATH_LED_PIN_9287 10 + #define ATH_LED_PIN_9271 15 + #define ATH_LED_PIN_7010 12 +-#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ +-#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ + +-enum ath_led_type { +- ATH_LED_RADIO, +- ATH_LED_ASSOC, +- ATH_LED_TX, +- ATH_LED_RX +-}; ++#define BSTUCK_THRESHOLD 10 + +-struct ath_led { +- struct ath9k_htc_priv *priv; +- struct led_classdev led_cdev; +- enum ath_led_type led_type; +- struct delayed_work brightness_work; +- char name[32]; +- bool registered; +- int brightness; +-}; ++/* ++ * Adjust these when the max. no of beaconing interfaces is ++ * increased. ++ */ ++#define DEFAULT_SWBA_RESPONSE 40 /* in TUs */ ++#define MIN_SWBA_RESPONSE 10 /* in TUs */ + + struct htc_beacon_config { ++ struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; + u16 beacon_interval; + u16 dtim_period; + u16 bmiss_timeout; ++ u32 bmiss_cnt; + }; + + struct ath_btcoex { +@@ -372,14 +418,11 @@ + + #define OP_INVALID BIT(0) + #define OP_SCANNING BIT(1) +-#define OP_LED_ASSOCIATED BIT(2) +-#define OP_LED_ON BIT(3) +-#define OP_ENABLE_BEACON BIT(4) +-#define OP_LED_DEINIT BIT(5) +-#define OP_BT_PRIORITY_DETECTED BIT(6) +-#define OP_BT_SCAN BIT(7) +-#define OP_ANI_RUNNING BIT(8) +-#define OP_TSF_RESET BIT(9) ++#define OP_ENABLE_BEACON BIT(2) ++#define OP_BT_PRIORITY_DETECTED BIT(3) ++#define OP_BT_SCAN BIT(4) ++#define OP_ANI_RUNNING BIT(5) ++#define OP_TSF_RESET BIT(6) + + struct ath9k_htc_priv { + struct device *dev; +@@ -388,6 +431,9 @@ + struct htc_target *htc; + struct wmi *wmi; + ++ u16 fw_version_major; ++ u16 fw_version_minor; ++ + enum htc_endpoint_id wmi_cmd_ep; + enum htc_endpoint_id beacon_ep; + enum htc_endpoint_id cab_ep; +@@ -411,27 +457,23 @@ + u16 txpowlimit; + u16 nvifs; + u16 nstations; +- u32 bmiss_cnt; + bool rearm_ani; + bool reconfig_beacon; ++ unsigned int rxfilter; + + struct ath9k_hw_cal_data caldata; ++ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; + + spinlock_t beacon_lock; ++ struct htc_beacon_config cur_beacon_conf; + +- bool tx_queues_stop; +- spinlock_t tx_lock; ++ struct ath9k_htc_rx rx; ++ struct ath9k_htc_tx tx; + +- struct ieee80211_vif *vif; +- struct htc_beacon_config cur_beacon_conf; +- unsigned int rxfilter; + struct tasklet_struct swba_tasklet; + struct tasklet_struct rx_tasklet; +- struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; +- struct ath9k_htc_rx rx; +- struct tasklet_struct tx_tasklet; +- struct sk_buff_head tx_queue; + struct delayed_work ani_work; ++ struct tasklet_struct tx_failed_tasklet; + struct work_struct ps_work; + struct work_struct fatal_work; + +@@ -440,15 +482,13 @@ + bool ps_enabled; + bool ps_idle; + +- struct ath_led radio_led; +- struct ath_led assoc_led; +- struct ath_led tx_led; +- struct ath_led rx_led; +- struct delayed_work ath9k_led_blink_work; +- int led_on_duration; +- int led_off_duration; +- int led_on_cnt; +- int led_off_cnt; ++#ifdef CONFIG_MAC80211_LEDS ++ enum led_brightness brightness; ++ bool led_registered; ++ char led_name[32]; ++ struct led_classdev led_cdev; ++ struct work_struct led_work; ++#endif + + int beaconq; + int cabq; +@@ -470,11 +510,18 @@ + + void ath9k_htc_reset(struct ath9k_htc_priv *priv); + ++void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, ++ struct ieee80211_vif *vif); ++void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, ++ struct ieee80211_vif *vif); ++void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, ++ struct ieee80211_vif *vif); + void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv); + void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif); + void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv); +-void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending); ++void ath9k_htc_swba(struct ath9k_htc_priv *priv, ++ struct wmi_event_swba *swba); + + void ath9k_htc_rxep(void *priv, struct sk_buff *skb, + enum htc_endpoint_id ep_id); +@@ -483,7 +530,8 @@ + void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, + enum htc_endpoint_id ep_id, bool txok); + +-int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv); ++int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv, ++ u8 enable_coex); + void ath9k_htc_station_work(struct work_struct *work); + void ath9k_htc_aggr_work(struct work_struct *work); + void ath9k_htc_ani_work(struct work_struct *work); +@@ -491,14 +539,23 @@ + void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); + + int ath9k_tx_init(struct ath9k_htc_priv *priv); +-void ath9k_tx_tasklet(unsigned long data); +-int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb); ++int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, ++ struct sk_buff *skb, u8 slot, bool is_cab); + void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); + bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype); + int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv); + int get_hw_qnum(u16 queue, int *hwq_map); + int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, + struct ath9k_tx_queue_info *qinfo); ++void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv); ++void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv); ++int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv); ++void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot); ++void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); ++void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event); ++void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv); ++void ath9k_tx_failed_tasklet(unsigned long data); ++void ath9k_htc_tx_cleanup_timer(unsigned long data); + + int ath9k_rx_init(struct ath9k_htc_priv *priv); + void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); +@@ -516,9 +573,24 @@ + void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw); + void ath9k_htc_radio_enable(struct ieee80211_hw *hw); + void ath9k_htc_radio_disable(struct ieee80211_hw *hw); +-void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv); ++ ++#ifdef CONFIG_MAC80211_LEDS + void ath9k_init_leds(struct ath9k_htc_priv *priv); + void ath9k_deinit_leds(struct ath9k_htc_priv *priv); ++void ath9k_led_work(struct work_struct *work); ++#else ++static inline void ath9k_init_leds(struct ath9k_htc_priv *priv) ++{ ++} ++ ++static inline void ath9k_deinit_leds(struct ath9k_htc_priv *priv) ++{ ++} ++ ++static inline void ath9k_led_work(struct work_struct *work) ++{ ++} ++#endif + + int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, + u16 devid, char *product, u32 drv_info); +@@ -528,15 +600,9 @@ + int ath9k_htc_resume(struct htc_target *htc_handle); + #endif + #ifdef CONFIG_ATH9K_HTC_DEBUGFS +-int ath9k_htc_debug_create_root(void); +-void ath9k_htc_debug_remove_root(void); + int ath9k_htc_init_debug(struct ath_hw *ah); +-void ath9k_htc_exit_debug(struct ath_hw *ah); + #else +-static inline int ath9k_htc_debug_create_root(void) { return 0; }; +-static inline void ath9k_htc_debug_remove_root(void) {}; + static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; }; +-static inline void ath9k_htc_exit_debug(struct ath_hw *ah) {}; + #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ + + #endif /* HTC_H */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_hst.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_hst.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_hst.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_hst.c 2011-05-05 23:29:49.070485179 +0200 +@@ -17,8 +17,8 @@ + #include "htc.h" + + static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, +- u16 len, u8 flags, u8 epid, +- struct ath9k_htc_tx_ctl *tx_ctl) ++ u16 len, u8 flags, u8 epid) ++ + { + struct htc_frame_hdr *hdr; + struct htc_endpoint *endpoint = &target->endpoint[epid]; +@@ -30,8 +30,8 @@ + hdr->flags = flags; + hdr->payload_len = cpu_to_be16(len); + +- status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb, +- tx_ctl); ++ status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb); ++ + return status; + } + +@@ -162,7 +162,7 @@ + + target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS; + +- ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); ++ ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); + if (ret) + goto err; + +@@ -197,7 +197,7 @@ + + target->htc_flags |= HTC_OP_START_WAIT; + +- ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); ++ ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); + if (ret) + goto err; + +@@ -268,7 +268,7 @@ + conn_msg->dl_pipeid = endpoint->dl_pipeid; + conn_msg->ul_pipeid = endpoint->ul_pipeid; + +- ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); ++ ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); + if (ret) + goto err; + +@@ -286,35 +286,33 @@ + return ret; + } + +-int htc_send(struct htc_target *target, struct sk_buff *skb, +- enum htc_endpoint_id epid, struct ath9k_htc_tx_ctl *tx_ctl) ++int htc_send(struct htc_target *target, struct sk_buff *skb) + { +- return htc_issue_send(target, skb, skb->len, 0, epid, tx_ctl); ++ struct ath9k_htc_tx_ctl *tx_ctl; ++ ++ tx_ctl = HTC_SKB_CB(skb); ++ return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid); + } + +-void htc_stop(struct htc_target *target) ++int htc_send_epid(struct htc_target *target, struct sk_buff *skb, ++ enum htc_endpoint_id epid) + { +- enum htc_endpoint_id epid; +- struct htc_endpoint *endpoint; ++ return htc_issue_send(target, skb, skb->len, 0, epid); ++} + +- for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) { +- endpoint = &target->endpoint[epid]; +- if (endpoint->service_id != 0) +- target->hif->stop(target->hif_dev, endpoint->ul_pipeid); +- } ++void htc_stop(struct htc_target *target) ++{ ++ target->hif->stop(target->hif_dev); + } + + void htc_start(struct htc_target *target) + { +- enum htc_endpoint_id epid; +- struct htc_endpoint *endpoint; ++ target->hif->start(target->hif_dev); ++} + +- for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) { +- endpoint = &target->endpoint[epid]; +- if (endpoint->service_id != 0) +- target->hif->start(target->hif_dev, +- endpoint->ul_pipeid); +- } ++void htc_sta_drain(struct htc_target *target, u8 idx) ++{ ++ target->hif->sta_drain(target->hif_dev, idx); + } + + void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_hst.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_hst.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/htc_hst.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/htc_hst.h 2011-05-05 23:29:49.073485215 +0200 +@@ -33,10 +33,10 @@ + u8 control_dl_pipe; + u8 control_ul_pipe; + +- void (*start) (void *hif_handle, u8 pipe); +- void (*stop) (void *hif_handle, u8 pipe); +- int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf, +- struct ath9k_htc_tx_ctl *tx_ctl); ++ void (*start) (void *hif_handle); ++ void (*stop) (void *hif_handle); ++ void (*sta_drain) (void *hif_handle, u8 idx); ++ int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf); + }; + + enum htc_endpoint_id { +@@ -83,21 +83,10 @@ + void (*rx) (void *, struct sk_buff *, enum htc_endpoint_id); + }; + +-#define HTC_TX_QUEUE_SIZE 256 +- +-struct htc_txq { +- struct sk_buff *buf[HTC_TX_QUEUE_SIZE]; +- u32 txqdepth; +- u16 txbuf_cnt; +- u16 txq_head; +- u16 txq_tail; +-}; +- + struct htc_endpoint { + u16 service_id; + + struct htc_ep_callbacks ep_callbacks; +- struct htc_txq htc_txq; + u32 max_txqdepth; + int max_msglen; + +@@ -205,10 +194,12 @@ + int htc_connect_service(struct htc_target *target, + struct htc_service_connreq *service_connreq, + enum htc_endpoint_id *conn_rsp_eid); +-int htc_send(struct htc_target *target, struct sk_buff *skb, +- enum htc_endpoint_id eid, struct ath9k_htc_tx_ctl *tx_ctl); ++int htc_send(struct htc_target *target, struct sk_buff *skb); ++int htc_send_epid(struct htc_target *target, struct sk_buff *skb, ++ enum htc_endpoint_id epid); + void htc_stop(struct htc_target *target); + void htc_start(struct htc_target *target); ++void htc_sta_drain(struct htc_target *target, u8 idx); + + void ath9k_htc_rx_msg(struct htc_target *htc_handle, + struct sk_buff *skb, u32 len, u8 pipe_id); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/hw.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/hw.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/hw.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/hw.c 2011-05-05 23:29:49.090485421 +0200 +@@ -130,6 +130,20 @@ + } + EXPORT_SYMBOL(ath9k_hw_wait); + ++void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, ++ int column, unsigned int *writecnt) ++{ ++ int r; ++ ++ ENABLE_REGWRITE_BUFFER(ah); ++ for (r = 0; r < array->ia_rows; r++) { ++ REG_WRITE(ah, INI_RA(array, r, 0), ++ INI_RA(array, r, column)); ++ DO_DELAY(*writecnt); ++ } ++ REGWRITE_BUFFER_FLUSH(ah); ++} ++ + u32 ath9k_hw_reverse_bits(u32 val, u32 n) + { + u32 retval; +@@ -142,25 +156,6 @@ + return retval; + } + +-bool ath9k_get_channel_edges(struct ath_hw *ah, +- u16 flags, u16 *low, +- u16 *high) +-{ +- struct ath9k_hw_capabilities *pCap = &ah->caps; +- +- if (flags & CHANNEL_5GHZ) { +- *low = pCap->low_5ghz_chan; +- *high = pCap->high_5ghz_chan; +- return true; +- } +- if ((flags & CHANNEL_2GHZ)) { +- *low = pCap->low_2ghz_chan; +- *high = pCap->high_2ghz_chan; +- return true; +- } +- return false; +-} +- + u16 ath9k_hw_computetxtime(struct ath_hw *ah, + u8 phy, int kbps, + u32 frameLen, u16 rateix, +@@ -252,6 +247,17 @@ + { + u32 val; + ++ switch (ah->hw_version.devid) { ++ case AR5416_AR9100_DEVID: ++ ah->hw_version.macVersion = AR_SREV_VERSION_9100; ++ break; ++ case AR9300_DEVID_AR9340: ++ ah->hw_version.macVersion = AR_SREV_VERSION_9340; ++ val = REG_READ(ah, AR_SREV); ++ ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); ++ return; ++ } ++ + val = REG_READ(ah, AR_SREV) & AR_SREV_ID; + + if (val == 0xFF) { +@@ -364,11 +370,6 @@ + ah->config.spurchans[i][1] = AR_NO_SPUR; + } + +- if (ah->hw_version.devid != AR2427_DEVID_PCIE) +- ah->config.ht_enable = 1; +- else +- ah->config.ht_enable = 0; +- + /* PAPRD needs some more work to be enabled */ + ah->config.paprd_disable = 1; + +@@ -410,6 +411,8 @@ + ah->sta_id1_defaults = + AR_STA_ID1_CRPT_MIC_ENABLE | + AR_STA_ID1_MCAST_KSRCH; ++ if (AR_SREV_9100(ah)) ++ ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX; + ah->enable_32kHz_clock = DONT_USE_32KHZ; + ah->slottime = 20; + ah->globaltxtimeout = (u32) -1; +@@ -470,7 +473,7 @@ + return ecode; + } + +- if (!AR_SREV_9100(ah)) { ++ if (!AR_SREV_9100(ah) && !AR_SREV_9340(ah)) { + ath9k_hw_ani_setup(ah); + ath9k_hw_ani_init(ah); + } +@@ -492,9 +495,6 @@ + struct ath_common *common = ath9k_hw_common(ah); + int r = 0; + +- if (ah->hw_version.devid == AR5416_AR9100_DEVID) +- ah->hw_version.macVersion = AR_SREV_VERSION_9100; +- + ath9k_hw_read_revisions(ah); + + /* +@@ -552,6 +552,7 @@ + case AR_SREV_VERSION_9271: + case AR_SREV_VERSION_9300: + case AR_SREV_VERSION_9485: ++ case AR_SREV_VERSION_9340: + break; + default: + ath_err(common, +@@ -560,7 +561,7 @@ + return -EOPNOTSUPP; + } + +- if (AR_SREV_9271(ah) || AR_SREV_9100(ah)) ++ if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah)) + ah->is_pciexpress = false; + + ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); +@@ -629,6 +630,7 @@ + case AR2427_DEVID_PCIE: + case AR9300_DEVID_PCIE: + case AR9300_DEVID_AR9485_PCIE: ++ case AR9300_DEVID_AR9340: + break; + default: + if (common->bus_ops->ath_bus_type == ATH_USB) +@@ -671,48 +673,89 @@ + REGWRITE_BUFFER_FLUSH(ah); + } + +-unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) ++u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) + { +- REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) & ~(PLL3_DO_MEAS_MASK))); +- udelay(100); +- REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) | PLL3_DO_MEAS_MASK)); ++ REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); ++ udelay(100); ++ REG_SET_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); + +- while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) +- udelay(100); ++ while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) ++ udelay(100); + +- return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; ++ return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; + } + EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); + +-#define DPLL2_KD_VAL 0x3D +-#define DPLL2_KI_VAL 0x06 +-#define DPLL3_PHASE_SHIFT_VAL 0x1 +- + static void ath9k_hw_init_pll(struct ath_hw *ah, + struct ath9k_channel *chan) + { + u32 pll; + + if (AR_SREV_9485(ah)) { +- REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); +- REG_WRITE(ah, AR_CH0_DDR_DPLL2, 0x19e82f01); + +- REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3, +- AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); +- +- REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); +- udelay(1000); ++ /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */ ++ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, ++ AR_CH0_BB_DPLL2_PLL_PWD, 0x1); ++ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, ++ AR_CH0_DPLL2_KD, 0x40); ++ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, ++ AR_CH0_DPLL2_KI, 0x4); + +- REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); ++ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1, ++ AR_CH0_BB_DPLL1_REFDIV, 0x5); ++ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1, ++ AR_CH0_BB_DPLL1_NINI, 0x58); ++ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1, ++ AR_CH0_BB_DPLL1_NFRAC, 0x0); + + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, +- AR_CH0_DPLL2_KD, DPLL2_KD_VAL); ++ AR_CH0_BB_DPLL2_OUTDIV, 0x1); ++ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, ++ AR_CH0_BB_DPLL2_LOCAL_PLL, 0x1); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, +- AR_CH0_DPLL2_KI, DPLL2_KI_VAL); ++ AR_CH0_BB_DPLL2_EN_NEGTRIG, 0x1); + ++ /* program BB PLL phase_shift to 0x6 */ + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, +- AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); +- REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); ++ AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x6); ++ ++ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, ++ AR_CH0_BB_DPLL2_PLL_PWD, 0x0); ++ udelay(1000); ++ } else if (AR_SREV_9340(ah)) { ++ u32 regval, pll2_divint, pll2_divfrac, refdiv; ++ ++ REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); ++ udelay(1000); ++ ++ REG_SET_BIT(ah, AR_PHY_PLL_MODE, 0x1 << 16); ++ udelay(100); ++ ++ if (ah->is_clk_25mhz) { ++ pll2_divint = 0x54; ++ pll2_divfrac = 0x1eb85; ++ refdiv = 3; ++ } else { ++ pll2_divint = 88; ++ pll2_divfrac = 0; ++ refdiv = 5; ++ } ++ ++ regval = REG_READ(ah, AR_PHY_PLL_MODE); ++ regval |= (0x1 << 16); ++ REG_WRITE(ah, AR_PHY_PLL_MODE, regval); ++ udelay(100); ++ ++ REG_WRITE(ah, AR_PHY_PLL_CONTROL, (refdiv << 27) | ++ (pll2_divint << 18) | pll2_divfrac); ++ udelay(100); ++ ++ regval = REG_READ(ah, AR_PHY_PLL_MODE); ++ regval = (regval & 0x80071fff) | (0x1 << 30) | (0x1 << 13) | ++ (0x4 << 26) | (0x18 << 19); ++ REG_WRITE(ah, AR_PHY_PLL_MODE, regval); ++ REG_WRITE(ah, AR_PHY_PLL_MODE, ++ REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); + udelay(1000); + } + +@@ -720,6 +763,9 @@ + + REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); + ++ if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) ++ udelay(1000); ++ + /* Switch the core clock for ar9271 to 117Mhz */ + if (AR_SREV_9271(ah)) { + udelay(500); +@@ -729,17 +775,34 @@ + udelay(RTC_PLL_SETTLE_DELAY); + + REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); ++ ++ if (AR_SREV_9340(ah)) { ++ if (ah->is_clk_25mhz) { ++ REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1); ++ REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); ++ REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae); ++ } else { ++ REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1); ++ REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400); ++ REG_WRITE(ah, AR_SLP32_INC, 0x0001e800); ++ } ++ udelay(100); ++ } + } + + static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, + enum nl80211_iftype opmode) + { ++ u32 sync_default = AR_INTR_SYNC_DEFAULT; + u32 imr_reg = AR_IMR_TXERR | + AR_IMR_TXURN | + AR_IMR_RXERR | + AR_IMR_RXORN | + AR_IMR_BCNMISC; + ++ if (AR_SREV_9340(ah)) ++ sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; ++ + if (AR_SREV_9300_20_OR_LATER(ah)) { + imr_reg |= AR_IMR_RXOK_HP; + if (ah->config.rx_intr_mitigation) +@@ -770,7 +833,7 @@ + + if (!AR_SREV_9100(ah)) { + REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); +- REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); ++ REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); + REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); + } + +@@ -830,8 +893,7 @@ + ah->misc_mode); + + if (ah->misc_mode != 0) +- REG_WRITE(ah, AR_PCU_MISC, +- REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); ++ REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode); + + if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ) + sifstime = 16; +@@ -899,23 +961,19 @@ + static inline void ath9k_hw_set_dma(struct ath_hw *ah) + { + struct ath_common *common = ath9k_hw_common(ah); +- u32 regval; + + ENABLE_REGWRITE_BUFFER(ah); + + /* + * set AHB_MODE not to do cacheline prefetches + */ +- if (!AR_SREV_9300_20_OR_LATER(ah)) { +- regval = REG_READ(ah, AR_AHB_MODE); +- REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); +- } ++ if (!AR_SREV_9300_20_OR_LATER(ah)) ++ REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN); + + /* + * let mac dma reads be in 128 byte chunks + */ +- regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; +- REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); ++ REG_RMW(ah, AR_TXCFG, AR_TXCFG_DMASZ_128B, AR_TXCFG_DMASZ_MASK); + + REGWRITE_BUFFER_FLUSH(ah); + +@@ -932,8 +990,7 @@ + /* + * let mac dma writes be in 128 byte chunks + */ +- regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; +- REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); ++ REG_RMW(ah, AR_RXCFG, AR_RXCFG_DMASZ_128B, AR_RXCFG_DMASZ_MASK); + + /* + * Setup receive FIFO threshold to hold off TX activities +@@ -972,30 +1029,27 @@ + + static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) + { +- u32 val; ++ u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC; ++ u32 set = AR_STA_ID1_KSRCH_MODE; + +- val = REG_READ(ah, AR_STA_ID1); +- val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); + switch (opmode) { +- case NL80211_IFTYPE_AP: +- REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP +- | AR_STA_ID1_KSRCH_MODE); +- REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); +- break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: +- REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC +- | AR_STA_ID1_KSRCH_MODE); ++ set |= AR_STA_ID1_ADHOC; + REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); + break; ++ case NL80211_IFTYPE_AP: ++ set |= AR_STA_ID1_STA_AP; ++ /* fall through */ + case NL80211_IFTYPE_STATION: +- REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); ++ REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); + break; + default: +- if (ah->is_monitoring) +- REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); ++ if (!ah->is_monitoring) ++ set = 0; + break; + } ++ REG_RMW(ah, AR_STA_ID1, set, mask); + } + + void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, +@@ -1021,10 +1075,8 @@ + u32 tmpReg; + + if (AR_SREV_9100(ah)) { +- u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK); +- val &= ~AR_RTC_DERIVED_CLK_PERIOD; +- val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD); +- REG_WRITE(ah, AR_RTC_DERIVED_CLK, val); ++ REG_RMW_FIELD(ah, AR_RTC_DERIVED_CLK, ++ AR_RTC_DERIVED_CLK_PERIOD, 1); + (void)REG_READ(ah, AR_RTC_DERIVED_CLK); + } + +@@ -1212,6 +1264,20 @@ + return true; + } + ++static void ath9k_hw_apply_gpio_override(struct ath_hw *ah) ++{ ++ u32 gpio_mask = ah->gpio_mask; ++ int i; ++ ++ for (i = 0; gpio_mask; i++, gpio_mask >>= 1) { ++ if (!(gpio_mask & 1)) ++ continue; ++ ++ ath9k_hw_cfg_output(ah, i, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ++ ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i))); ++ } ++} ++ + bool ath9k_hw_check_alive(struct ath_hw *ah) + { + int count = 50; +@@ -1409,7 +1475,7 @@ + REGWRITE_BUFFER_FLUSH(ah); + + ah->intr_txqs = 0; +- for (i = 0; i < ah->caps.total_queues; i++) ++ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + ath9k_hw_resettxqueue(ah, i); + + ath9k_hw_init_interrupt_masks(ah, ah->opmode); +@@ -1426,8 +1492,7 @@ + ar9002_hw_enable_wep_aggregation(ah); + } + +- REG_WRITE(ah, AR_STA_ID1, +- REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); ++ REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); + + ath9k_hw_set_dma(ah); + +@@ -1480,7 +1545,9 @@ + REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); + } + #ifdef __BIG_ENDIAN +- else ++ else if (AR_SREV_9340(ah)) ++ REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0); ++ else + REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); + #endif + } +@@ -1491,6 +1558,8 @@ + if (AR_SREV_9300_20_OR_LATER(ah)) + ar9003_hw_bb_watchdog_config(ah); + ++ ath9k_hw_apply_gpio_override(ah); ++ + return 0; + } + EXPORT_SYMBOL(ath9k_hw_reset); +@@ -1670,21 +1739,15 @@ + case NL80211_IFTYPE_MESH_POINT: + REG_SET_BIT(ah, AR_TXCFG, + AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); +- REG_WRITE(ah, AR_NEXT_NDP_TIMER, +- TU_TO_USEC(next_beacon + +- (ah->atim_window ? ah-> +- atim_window : 1))); ++ REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon + ++ TU_TO_USEC(ah->atim_window ? ah->atim_window : 1)); + flags |= AR_NDP_TIMER_EN; + case NL80211_IFTYPE_AP: +- REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); +- REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, +- TU_TO_USEC(next_beacon - +- ah->config. +- dma_beacon_response_time)); +- REG_WRITE(ah, AR_NEXT_SWBA, +- TU_TO_USEC(next_beacon - +- ah->config. +- sw_beacon_response_time)); ++ REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); ++ REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon - ++ TU_TO_USEC(ah->config.dma_beacon_response_time)); ++ REG_WRITE(ah, AR_NEXT_SWBA, next_beacon - ++ TU_TO_USEC(ah->config.sw_beacon_response_time)); + flags |= + AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; + break; +@@ -1696,18 +1759,13 @@ + break; + } + +- REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period)); +- REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period)); +- REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period)); +- REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period)); ++ REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period); ++ REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period); ++ REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period); ++ REG_WRITE(ah, AR_NDP_PERIOD, beacon_period); + + REGWRITE_BUFFER_FLUSH(ah); + +- beacon_period &= ~ATH9K_BEACON_ENA; +- if (beacon_period & ATH9K_BEACON_RESET_TSF) { +- ath9k_hw_reset_tsf(ah); +- } +- + REG_SET_BIT(ah, AR_TIMER_MODE, flags); + } + EXPORT_SYMBOL(ath9k_hw_beaconinit); +@@ -1795,7 +1853,7 @@ + struct ath_common *common = ath9k_hw_common(ah); + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; + +- u16 capField = 0, eeval; ++ u16 eeval; + u8 ant_div_ctl1, tx_chainmask, rx_chainmask; + + eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); +@@ -1806,8 +1864,6 @@ + eeval |= AR9285_RDEXT_DEFAULT; + regulatory->current_rd_ext = eeval; + +- capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP); +- + if (ah->opmode != NL80211_IFTYPE_AP && + ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) { + if (regulatory->current_rd == 0x64 || +@@ -1842,6 +1898,8 @@ + !(AR_SREV_9271(ah))) + /* CB71: GPIO 0 is pulled down to indicate 3 rx chains */ + pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7; ++ else if (AR_SREV_9100(ah)) ++ pCap->rx_chainmask = 0x7; + else + /* Use rx_chainmask from EEPROM. */ + pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); +@@ -1852,36 +1910,13 @@ + if (AR_SREV_9300_20_OR_LATER(ah)) + ah->misc_mode |= AR_PCU_ALWAYS_PERFORM_KEYSEARCH; + +- pCap->low_2ghz_chan = 2312; +- pCap->high_2ghz_chan = 2732; +- +- pCap->low_5ghz_chan = 4920; +- pCap->high_5ghz_chan = 6100; +- + common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; + +- if (ah->config.ht_enable) ++ if (ah->hw_version.devid != AR2427_DEVID_PCIE) + pCap->hw_caps |= ATH9K_HW_CAP_HT; + else + pCap->hw_caps &= ~ATH9K_HW_CAP_HT; + +- if (capField & AR_EEPROM_EEPCAP_MAXQCU) +- pCap->total_queues = +- MS(capField, AR_EEPROM_EEPCAP_MAXQCU); +- else +- pCap->total_queues = ATH9K_NUM_TX_QUEUES; +- +- if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) +- pCap->keycache_size = +- 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); +- else +- pCap->keycache_size = AR_KEYTABLE_SIZE; +- +- if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) +- pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1; +- else +- pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; +- + if (AR_SREV_9271(ah)) + pCap->num_gpio_pins = AR9271_NUM_GPIO; + else if (AR_DEVID_7010(ah)) +@@ -1900,8 +1935,6 @@ + pCap->rts_aggr_limit = (8 * 1024); + } + +- pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; +- + #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); + if (ah->rfsilent & EEP_RFSILENT_ENABLED) { +@@ -1923,32 +1956,23 @@ + else + pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; + +- if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { +- pCap->reg_cap = +- AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | +- AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | +- AR_EEPROM_EEREGCAP_EN_KK_U2 | +- AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; +- } else { +- pCap->reg_cap = +- AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | +- AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; +- } +- +- /* Advertise midband for AR5416 with FCC midband set in eeprom */ +- if (regulatory->current_rd_ext & (1 << REG_EXT_FCC_MIDBAND) && +- AR_SREV_5416(ah)) +- pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; +- +- if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) { +- btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO; +- btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO; +- +- if (AR_SREV_9285(ah)) { ++ if (common->btcoex_enabled) { ++ if (AR_SREV_9300_20_OR_LATER(ah)) { + btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; +- btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO; +- } else { +- btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; ++ btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; ++ btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; ++ btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300; ++ } else if (AR_SREV_9280_20_OR_LATER(ah)) { ++ btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280; ++ btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280; ++ ++ if (AR_SREV_9285(ah)) { ++ btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; ++ btcoex_hw->btpriority_gpio = ++ ATH_BTPRIORITY_GPIO_9285; ++ } else { ++ btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; ++ } + } + } else { + btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE; +@@ -2186,11 +2210,9 @@ + REG_WRITE(ah, AR_PHY_ERR, phybits); + + if (phybits) +- REG_WRITE(ah, AR_RXCFG, +- REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); ++ REG_SET_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA); + else +- REG_WRITE(ah, AR_RXCFG, +- REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); ++ REG_CLR_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA); + + REGWRITE_BUFFER_FLUSH(ah); + } +@@ -2366,10 +2388,11 @@ + return timer_table->gen_timer_index[b]; + } + +-static u32 ath9k_hw_gettsf32(struct ath_hw *ah) ++u32 ath9k_hw_gettsf32(struct ath_hw *ah) + { + return REG_READ(ah, AR_TSF_L32); + } ++EXPORT_SYMBOL(ath9k_hw_gettsf32); + + struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, + void (*trigger)(void *), +@@ -2402,11 +2425,11 @@ + + void ath9k_hw_gen_timer_start(struct ath_hw *ah, + struct ath_gen_timer *timer, +- u32 timer_next, ++ u32 trig_timeout, + u32 timer_period) + { + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; +- u32 tsf; ++ u32 tsf, timer_next; + + BUG_ON(!timer_period); + +@@ -2414,18 +2437,13 @@ + + tsf = ath9k_hw_gettsf32(ah); + ++ timer_next = tsf + trig_timeout; ++ + ath_dbg(ath9k_hw_common(ah), ATH_DBG_HWTIMER, + "current tsf %x period %x timer_next %x\n", + tsf, timer_period, timer_next); + + /* +- * Pull timer_next forward if the current TSF already passed it +- * because of software latency +- */ +- if (timer_next < tsf) +- timer_next = tsf + timer_period; +- +- /* + * Program generic timer registers + */ + REG_WRITE(ah, gen_tmr_configuration[timer->index].next_addr, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/hw.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/hw.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/hw.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/hw.h 2011-05-05 23:29:49.079485289 +0200 +@@ -43,6 +43,7 @@ + #define AR9287_DEVID_PCI 0x002d + #define AR9287_DEVID_PCIE 0x002e + #define AR9300_DEVID_PCIE 0x0030 ++#define AR9300_DEVID_AR9340 0x0031 + #define AR9300_DEVID_AR9485_PCIE 0x0032 + + #define AR5416_AR9100_DEVID 0x000b +@@ -55,6 +56,9 @@ + #define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa + #define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab + ++#define AR9300_NUM_BT_WEIGHTS 4 ++#define AR9300_NUM_WLAN_WEIGHTS 4 ++ + #define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) + + #define ATH_DEFAULT_NOISE_FLOOR -95 +@@ -65,53 +69,49 @@ + + /* Register read/write primitives */ + #define REG_WRITE(_ah, _reg, _val) \ +- ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg)) ++ (_ah)->reg_ops.write((_ah), (_val), (_reg)) + + #define REG_READ(_ah, _reg) \ +- ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) ++ (_ah)->reg_ops.read((_ah), (_reg)) + + #define REG_READ_MULTI(_ah, _addr, _val, _cnt) \ +- ath9k_hw_common(_ah)->ops->multi_read((_ah), (_addr), (_val), (_cnt)) ++ (_ah)->reg_ops.multi_read((_ah), (_addr), (_val), (_cnt)) ++ ++#define REG_RMW(_ah, _reg, _set, _clr) \ ++ (_ah)->reg_ops.rmw((_ah), (_reg), (_set), (_clr)) + + #define ENABLE_REGWRITE_BUFFER(_ah) \ + do { \ +- if (ath9k_hw_common(_ah)->ops->enable_write_buffer) \ +- ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \ ++ if ((_ah)->reg_ops.enable_write_buffer) \ ++ (_ah)->reg_ops.enable_write_buffer((_ah)); \ + } while (0) + + #define REGWRITE_BUFFER_FLUSH(_ah) \ + do { \ +- if (ath9k_hw_common(_ah)->ops->write_flush) \ +- ath9k_hw_common(_ah)->ops->write_flush((_ah)); \ ++ if ((_ah)->reg_ops.write_flush) \ ++ (_ah)->reg_ops.write_flush((_ah)); \ + } while (0) + + #define SM(_v, _f) (((_v) << _f##_S) & _f) + #define MS(_v, _f) (((_v) & _f) >> _f##_S) +-#define REG_RMW(_a, _r, _set, _clr) \ +- REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set)) + #define REG_RMW_FIELD(_a, _r, _f, _v) \ +- REG_WRITE(_a, _r, \ +- (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f)) ++ REG_RMW(_a, _r, (((_v) << _f##_S) & _f), (_f)) + #define REG_READ_FIELD(_a, _r, _f) \ + (((REG_READ(_a, _r) & _f) >> _f##_S)) + #define REG_SET_BIT(_a, _r, _f) \ +- REG_WRITE(_a, _r, REG_READ(_a, _r) | (_f)) ++ REG_RMW(_a, _r, (_f), 0) + #define REG_CLR_BIT(_a, _r, _f) \ +- REG_WRITE(_a, _r, REG_READ(_a, _r) & ~(_f)) ++ REG_RMW(_a, _r, 0, (_f)) + +-#define DO_DELAY(x) do { \ +- if ((++(x) % 64) == 0) \ +- udelay(1); \ ++#define DO_DELAY(x) do { \ ++ if (((++(x) % 64) == 0) && \ ++ (ath9k_hw_common(ah)->bus_ops->ath_bus_type \ ++ != ATH_USB)) \ ++ udelay(1); \ + } while (0) + +-#define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ +- int r; \ +- for (r = 0; r < ((iniarray)->ia_rows); r++) { \ +- REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ +- INI_RA((iniarray), r, (column))); \ +- DO_DELAY(regWr); \ +- } \ +- } while (0) ++#define REG_WRITE_ARRAY(iniarray, column, regWr) \ ++ ath9k_hw_write_array(ah, iniarray, column, &(regWr)) + + #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 + #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 +@@ -125,7 +125,7 @@ + #define AR_GPIO_BIT(_gpio) (1 << (_gpio)) + + #define BASE_ACTIVATE_DELAY 100 +-#define RTC_PLL_SETTLE_DELAY 100 ++#define RTC_PLL_SETTLE_DELAY (AR_SREV_9340(ah) ? 1000 : 100) + #define COEF_SCALE_S 24 + #define HT40_CHANNEL_CENTER_SHIFT 10 + +@@ -178,7 +178,6 @@ + ATH9K_HW_CAP_HT = BIT(0), + ATH9K_HW_CAP_RFSILENT = BIT(1), + ATH9K_HW_CAP_CST = BIT(2), +- ATH9K_HW_CAP_ENHANCEDPM = BIT(3), + ATH9K_HW_CAP_AUTOSLEEP = BIT(4), + ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(5), + ATH9K_HW_CAP_EDMA = BIT(6), +@@ -195,17 +194,11 @@ + + struct ath9k_hw_capabilities { + u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ +- u16 total_queues; +- u16 keycache_size; +- u16 low_5ghz_chan, high_5ghz_chan; +- u16 low_2ghz_chan, high_2ghz_chan; + u16 rts_aggr_limit; + u8 tx_chainmask; + u8 rx_chainmask; + u8 max_txchains; + u8 max_rxchains; +- u16 tx_triglevel_max; +- u16 reg_cap; + u8 num_gpio_pins; + u8 rx_hp_qdepth; + u8 rx_lp_qdepth; +@@ -227,7 +220,6 @@ + u8 pcie_clock_req; + u32 pcie_waen; + u8 analog_shiftreg; +- u8 ht_enable; + u8 paprd_disable; + u32 ofdm_trig_low; + u32 ofdm_trig_high; +@@ -412,8 +404,6 @@ + u32 bs_nextdtim; + u32 bs_intval; + #define ATH9K_BEACON_PERIOD 0x0000ffff +-#define ATH9K_BEACON_ENA 0x00800000 +-#define ATH9K_BEACON_RESET_TSF 0x01000000 + #define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */ + u32 bs_dtimperiod; + u16 bs_cfpperiod; +@@ -640,8 +630,7 @@ + void (*clr11n_aggr)(struct ath_hw *ah, void *ds); + void (*set11n_burstduration)(struct ath_hw *ah, void *ds, + u32 burstDuration); +- void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds, +- u32 vmf); ++ void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val); + }; + + struct ath_nf_limits { +@@ -655,6 +644,8 @@ + #define AH_UNPLUGGED 0x2 /* The card has been physically removed. */ + + struct ath_hw { ++ struct ath_ops reg_ops; ++ + struct ieee80211_hw *hw; + struct ath_common common; + struct ath9k_hw_version hw_version; +@@ -784,6 +775,8 @@ + + /* Bluetooth coexistance */ + struct ath_btcoex_hw btcoex_hw; ++ u32 bt_coex_bt_weight[AR9300_NUM_BT_WEIGHTS]; ++ u32 bt_coex_wlan_weight[AR9300_NUM_WLAN_WEIGHTS]; + + u32 intr_txqs; + u8 txchainmask; +@@ -794,7 +787,9 @@ + u32 originalGain[22]; + int initPDADC; + int PDADCdelta; +- u8 led_pin; ++ int led_pin; ++ u32 gpio_mask; ++ u32 gpio_val; + + struct ar5416IniArray iniModes; + struct ar5416IniArray iniCommon; +@@ -810,6 +805,7 @@ + struct ar5416IniArray iniPcieSerdes; + struct ar5416IniArray iniPcieSerdesLowPower; + struct ar5416IniArray iniModesAdditional; ++ struct ar5416IniArray iniModesAdditional_40M; + struct ar5416IniArray iniModesRxGain; + struct ar5416IniArray iniModesTxGain; + struct ar5416IniArray iniModes_9271_1_0_only; +@@ -856,6 +852,16 @@ + + /* Enterprise mode cap */ + u32 ent_mode; ++ ++ bool is_clk_25mhz; ++}; ++ ++struct ath_bus_ops { ++ enum ath_bus_type ath_bus_type; ++ void (*read_cachesize)(struct ath_common *common, int *csz); ++ bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); ++ void (*bt_coex_prep)(struct ath_common *common); ++ void (*extn_synch_en)(struct ath_common *common); + }; + + static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) +@@ -907,8 +913,9 @@ + + /* General Operation */ + bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); ++void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, ++ int column, unsigned int *writecnt); + u32 ath9k_hw_reverse_bits(u32 val, u32 n); +-bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); + u16 ath9k_hw_computetxtime(struct ath_hw *ah, + u8 phy, int kbps, + u32 frameLen, u16 rateix, bool shortPreamble); +@@ -924,12 +931,13 @@ + void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); + void ath9k_hw_setbssidmask(struct ath_hw *ah); + void ath9k_hw_write_associd(struct ath_hw *ah); ++u32 ath9k_hw_gettsf32(struct ath_hw *ah); + u64 ath9k_hw_gettsf64(struct ath_hw *ah); + void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); + void ath9k_hw_reset_tsf(struct ath_hw *ah); + void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); + void ath9k_hw_init_global_settings(struct ath_hw *ah); +-unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); ++u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); + void ath9k_hw_set11nmac2040(struct ath_hw *ah); + void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); + void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/hw-ops.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/hw-ops.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/hw-ops.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/hw-ops.h 2011-05-05 23:29:49.085485361 +0200 +@@ -122,10 +122,9 @@ + ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration); + } + +-static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, +- u32 vmf) ++static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) + { +- ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf); ++ ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val); + } + + /* Private hardware call ops */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/init.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/init.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/init.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/init.c 2011-05-05 23:29:49.083485337 +0200 +@@ -15,6 +15,7 @@ + */ + + #include ++#include + + #include "ath9k.h" + +@@ -195,10 +196,27 @@ + return val; + } + +-static const struct ath_ops ath9k_common_ops = { +- .read = ath9k_ioread32, +- .write = ath9k_iowrite32, +-}; ++static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) ++{ ++ struct ath_hw *ah = (struct ath_hw *) hw_priv; ++ struct ath_common *common = ath9k_hw_common(ah); ++ struct ath_softc *sc = (struct ath_softc *) common->priv; ++ unsigned long uninitialized_var(flags); ++ u32 val; ++ ++ if (ah->config.serialize_regmode == SER_REG_MODE_ON) ++ spin_lock_irqsave(&sc->sc_serial_rw, flags); ++ ++ val = ioread32(sc->mem + reg_offset); ++ val &= ~clr; ++ val |= set; ++ iowrite32(val, sc->mem + reg_offset); ++ ++ if (ah->config.serialize_regmode == SER_REG_MODE_ON) ++ spin_unlock_irqrestore(&sc->sc_serial_rw, flags); ++ ++ return val; ++} + + /**************************/ + /* Initialization */ +@@ -389,13 +407,7 @@ + int i = 0; + + /* Get the hardware key cache size. */ +- common->keymax = sc->sc_ah->caps.keycache_size; +- if (common->keymax > ATH_KEYMAX) { +- ath_dbg(common, ATH_DBG_ANY, +- "Warning, using only %u entries in %u key cache\n", +- ATH_KEYMAX, common->keymax); +- common->keymax = ATH_KEYMAX; +- } ++ common->keymax = AR_KEYTABLE_SIZE; + + /* + * Reset the key cache since some parts do not +@@ -537,6 +549,7 @@ + static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, + const struct ath_bus_ops *bus_ops) + { ++ struct ath9k_platform_data *pdata = sc->dev->platform_data; + struct ath_hw *ah = NULL; + struct ath_common *common; + int ret = 0, i; +@@ -549,13 +562,23 @@ + ah->hw = sc->hw; + ah->hw_version.devid = devid; + ah->hw_version.subsysid = subsysid; ++ ah->reg_ops.read = ath9k_ioread32; ++ ah->reg_ops.write = ath9k_iowrite32; ++ ah->reg_ops.rmw = ath9k_reg_rmw; + sc->sc_ah = ah; + +- if (!sc->dev->platform_data) ++ if (!pdata) { + ah->ah_flags |= AH_USE_EEPROM; ++ sc->sc_ah->led_pin = -1; ++ } else { ++ sc->sc_ah->gpio_mask = pdata->gpio_mask; ++ sc->sc_ah->gpio_val = pdata->gpio_val; ++ sc->sc_ah->led_pin = pdata->led_pin; ++ ah->is_clk_25mhz = pdata->is_clk_25mhz; ++ } + + common = ath9k_hw_common(ah); +- common->ops = &ath9k_common_ops; ++ common->ops = &ah->reg_ops; + common->bus_ops = bus_ops; + common->ah = ah; + common->hw = sc->hw; +@@ -587,6 +610,9 @@ + if (ret) + goto err_hw; + ++ if (pdata && pdata->macaddr) ++ memcpy(common->macaddr, pdata->macaddr, ETH_ALEN); ++ + ret = ath9k_init_queues(sc); + if (ret) + goto err_queues; +@@ -679,6 +705,8 @@ + if (AR_SREV_5416(sc->sc_ah)) + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + ++ hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; ++ + hw->queues = 4; + hw->max_rates = 4; + hw->channel_change_time = 5000; +@@ -773,6 +801,7 @@ + + INIT_WORK(&sc->hw_check_work, ath_hw_check); + INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); ++ INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); + sc->last_rssi = ATH_RSSI_DUMMY_MARKER; + + ath_init_leds(sc); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/Kconfig linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/Kconfig +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/Kconfig 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/Kconfig 2011-05-05 23:29:49.097485505 +0200 +@@ -5,7 +5,7 @@ + + config ATH9K + tristate "Atheros 802.11n wireless cards support" +- depends on PCI && MAC80211 ++ depends on MAC80211 + select ATH9K_HW + select MAC80211_LEDS + select LEDS_CLASS +@@ -23,6 +23,25 @@ + + If you choose to build a module, it'll be called ath9k. + ++config ATH9K_PCI ++ bool "Atheros ath9k PCI/PCIe bus support" ++ depends on ATH9K && PCI ++ default PCI ++ ---help--- ++ This option enables the PCI bus support in ath9k. ++ ++ Say Y, if you have a compatible PCI/PCIe wireless card. ++ ++config ATH9K_AHB ++ bool "Atheros ath9k AHB bus support" ++ depends on ATH9K ++ default n ++ ---help--- ++ This option enables the AHB bus support in ath9k. ++ ++ Say Y, if you have a SoC with a compatible built-in ++ wireless MAC. Say N if unsure. ++ + config ATH9K_DEBUGFS + bool "Atheros ath9k debugging" + depends on ATH9K && DEBUG_FS +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/mac.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/mac.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/mac.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/mac.c 2011-05-05 23:29:49.078485277 +0200 +@@ -209,15 +209,8 @@ + { + u32 cw; + struct ath_common *common = ath9k_hw_common(ah); +- struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath9k_tx_queue_info *qi; + +- if (q >= pCap->total_queues) { +- ath_dbg(common, ATH_DBG_QUEUE, +- "Set TXQ properties, invalid queue: %u\n", q); +- return false; +- } +- + qi = &ah->txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + ath_dbg(common, ATH_DBG_QUEUE, +@@ -280,15 +273,8 @@ + struct ath9k_tx_queue_info *qinfo) + { + struct ath_common *common = ath9k_hw_common(ah); +- struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath9k_tx_queue_info *qi; + +- if (q >= pCap->total_queues) { +- ath_dbg(common, ATH_DBG_QUEUE, +- "Get TXQ properties, invalid queue: %u\n", q); +- return false; +- } +- + qi = &ah->txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + ath_dbg(common, ATH_DBG_QUEUE, +@@ -320,28 +306,27 @@ + { + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_tx_queue_info *qi; +- struct ath9k_hw_capabilities *pCap = &ah->caps; + int q; + + switch (type) { + case ATH9K_TX_QUEUE_BEACON: +- q = pCap->total_queues - 1; ++ q = ATH9K_NUM_TX_QUEUES - 1; + break; + case ATH9K_TX_QUEUE_CAB: +- q = pCap->total_queues - 2; ++ q = ATH9K_NUM_TX_QUEUES - 2; + break; + case ATH9K_TX_QUEUE_PSPOLL: + q = 1; + break; + case ATH9K_TX_QUEUE_UAPSD: +- q = pCap->total_queues - 3; ++ q = ATH9K_NUM_TX_QUEUES - 3; + break; + case ATH9K_TX_QUEUE_DATA: +- for (q = 0; q < pCap->total_queues; q++) ++ for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++) + if (ah->txq[q].tqi_type == + ATH9K_TX_QUEUE_INACTIVE) + break; +- if (q == pCap->total_queues) { ++ if (q == ATH9K_NUM_TX_QUEUES) { + ath_err(common, "No available TX queue\n"); + return -1; + } +@@ -382,15 +367,9 @@ + + bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) + { +- struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_tx_queue_info *qi; + +- if (q >= pCap->total_queues) { +- ath_dbg(common, ATH_DBG_QUEUE, +- "Release TXQ, invalid queue: %u\n", q); +- return false; +- } + qi = &ah->txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + ath_dbg(common, ATH_DBG_QUEUE, +@@ -414,18 +393,11 @@ + + bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) + { +- struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_channel *chan = ah->curchan; + struct ath9k_tx_queue_info *qi; + u32 cwMin, chanCwMin, value; + +- if (q >= pCap->total_queues) { +- ath_dbg(common, ATH_DBG_QUEUE, +- "Reset TXQ, invalid queue: %u\n", q); +- return false; +- } +- + qi = &ah->txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + ath_dbg(common, ATH_DBG_QUEUE, +@@ -465,10 +437,9 @@ + REG_WRITE(ah, AR_QCBRCFG(q), + SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | + SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH)); +- REG_WRITE(ah, AR_QMISC(q), +- REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | +- (qi->tqi_cbrOverflowLimit ? +- AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); ++ REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_CBR | ++ (qi->tqi_cbrOverflowLimit ? ++ AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); + } + if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { + REG_WRITE(ah, AR_QRDYTIMECFG(q), +@@ -481,40 +452,31 @@ + (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); + + if (qi->tqi_burstTime +- && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { +- REG_WRITE(ah, AR_QMISC(q), +- REG_READ(ah, AR_QMISC(q)) | +- AR_Q_MISC_RDYTIME_EXP_POLICY); ++ && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) ++ REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_RDYTIME_EXP_POLICY); + +- } +- +- if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { +- REG_WRITE(ah, AR_DMISC(q), +- REG_READ(ah, AR_DMISC(q)) | +- AR_D_MISC_POST_FR_BKOFF_DIS); +- } ++ if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) ++ REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS); + + REGWRITE_BUFFER_FLUSH(ah); + +- if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { +- REG_WRITE(ah, AR_DMISC(q), +- REG_READ(ah, AR_DMISC(q)) | +- AR_D_MISC_FRAG_BKOFF_EN); +- } ++ if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) ++ REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_FRAG_BKOFF_EN); ++ + switch (qi->tqi_type) { + case ATH9K_TX_QUEUE_BEACON: + ENABLE_REGWRITE_BUFFER(ah); + +- REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) +- | AR_Q_MISC_FSP_DBA_GATED +- | AR_Q_MISC_BEACON_USE +- | AR_Q_MISC_CBR_INCR_DIS1); ++ REG_SET_BIT(ah, AR_QMISC(q), ++ AR_Q_MISC_FSP_DBA_GATED ++ | AR_Q_MISC_BEACON_USE ++ | AR_Q_MISC_CBR_INCR_DIS1); + +- REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) +- | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << ++ REG_SET_BIT(ah, AR_DMISC(q), ++ (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + AR_D_MISC_ARB_LOCKOUT_CNTRL_S) +- | AR_D_MISC_BEACON_USE +- | AR_D_MISC_POST_FR_BKOFF_DIS); ++ | AR_D_MISC_BEACON_USE ++ | AR_D_MISC_POST_FR_BKOFF_DIS); + + REGWRITE_BUFFER_FLUSH(ah); + +@@ -533,41 +495,38 @@ + case ATH9K_TX_QUEUE_CAB: + ENABLE_REGWRITE_BUFFER(ah); + +- REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) +- | AR_Q_MISC_FSP_DBA_GATED +- | AR_Q_MISC_CBR_INCR_DIS1 +- | AR_Q_MISC_CBR_INCR_DIS0); ++ REG_SET_BIT(ah, AR_QMISC(q), ++ AR_Q_MISC_FSP_DBA_GATED ++ | AR_Q_MISC_CBR_INCR_DIS1 ++ | AR_Q_MISC_CBR_INCR_DIS0); + value = (qi->tqi_readyTime - + (ah->config.sw_beacon_response_time - + ah->config.dma_beacon_response_time) - + ah->config.additional_swba_backoff) * 1024; + REG_WRITE(ah, AR_QRDYTIMECFG(q), + value | AR_Q_RDYTIMECFG_EN); +- REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) +- | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << ++ REG_SET_BIT(ah, AR_DMISC(q), ++ (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); + + REGWRITE_BUFFER_FLUSH(ah); + + break; + case ATH9K_TX_QUEUE_PSPOLL: +- REG_WRITE(ah, AR_QMISC(q), +- REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); ++ REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_CBR_INCR_DIS1); + break; + case ATH9K_TX_QUEUE_UAPSD: +- REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | +- AR_D_MISC_POST_FR_BKOFF_DIS); ++ REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS); + break; + default: + break; + } + + if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { +- REG_WRITE(ah, AR_DMISC(q), +- REG_READ(ah, AR_DMISC(q)) | +- SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, +- AR_D_MISC_ARB_LOCKOUT_CNTRL) | +- AR_D_MISC_POST_FR_BKOFF_DIS); ++ REG_SET_BIT(ah, AR_DMISC(q), ++ SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, ++ AR_D_MISC_ARB_LOCKOUT_CNTRL) | ++ AR_D_MISC_POST_FR_BKOFF_DIS); + } + + if (AR_SREV_9300_20_OR_LATER(ah)) +@@ -754,7 +713,6 @@ + bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset) + { + #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ +-#define AH_RX_TIME_QUANTUM 100 /* usec */ + struct ath_common *common = ath9k_hw_common(ah); + u32 mac_status, last_mac_status = 0; + int i; +@@ -797,7 +755,6 @@ + return true; + } + +-#undef AH_RX_TIME_QUANTUM + #undef AH_RX_STOP_DMA_TIMEOUT + } + EXPORT_SYMBOL(ath9k_hw_stopdmarecv); +@@ -855,10 +812,14 @@ + void ath9k_hw_enable_interrupts(struct ath_hw *ah) + { + struct ath_common *common = ath9k_hw_common(ah); ++ u32 sync_default = AR_INTR_SYNC_DEFAULT; + + if (!(ah->imask & ATH9K_INT_GLOBAL)) + return; + ++ if (AR_SREV_9340(ah)) ++ sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; ++ + ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n"); + REG_WRITE(ah, AR_IER, AR_IER_ENABLE); + if (!AR_SREV_9100(ah)) { +@@ -867,10 +828,8 @@ + REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); + + +- REG_WRITE(ah, AR_INTR_SYNC_ENABLE, +- AR_INTR_SYNC_DEFAULT); +- REG_WRITE(ah, AR_INTR_SYNC_MASK, +- AR_INTR_SYNC_DEFAULT); ++ REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); ++ REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default); + } + ath_dbg(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", + REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); +@@ -926,6 +885,9 @@ + mask |= AR_IMR_GENTMR; + } + ++ if (ints & ATH9K_INT_GENTIMER) ++ mask |= AR_IMR_GENTMR; ++ + if (ints & (ATH9K_INT_BMISC)) { + mask |= AR_IMR_BCNMISC; + if (ints & ATH9K_INT_TIM) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/mac.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/mac.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/mac.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/mac.h 2011-05-05 23:29:49.078485277 +0200 +@@ -239,7 +239,6 @@ + void *ds_vdata; + } __packed __aligned(4); + +-#define ATH9K_TXDESC_CLRDMASK 0x0001 + #define ATH9K_TXDESC_NOACK 0x0002 + #define ATH9K_TXDESC_RTSENA 0x0004 + #define ATH9K_TXDESC_CTSENA 0x0008 +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/main.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/main.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/main.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/main.c 2011-05-05 23:29:49.085485361 +0200 +@@ -299,7 +299,7 @@ + + if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { + if (sc->sc_flags & SC_OP_BEACONS) +- ath_beacon_config(sc, NULL); ++ ath_set_beacon(sc); + ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); + ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); + ath_start_ani(common); +@@ -624,6 +624,43 @@ + ath9k_ps_restore(sc); + } + ++static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) ++{ ++ static int count; ++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); ++ ++ if (pll_sqsum >= 0x40000) { ++ count++; ++ if (count == 3) { ++ /* Rx is hung for more than 500ms. Reset it */ ++ ath_dbg(common, ATH_DBG_RESET, ++ "Possible RX hang, resetting"); ++ ath_reset(sc, true); ++ count = 0; ++ } ++ } else ++ count = 0; ++} ++ ++void ath_hw_pll_work(struct work_struct *work) ++{ ++ struct ath_softc *sc = container_of(work, struct ath_softc, ++ hw_pll_work.work); ++ u32 pll_sqsum; ++ ++ if (AR_SREV_9485(sc->sc_ah)) { ++ ++ ath9k_ps_wakeup(sc); ++ pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); ++ ath9k_ps_restore(sc); ++ ++ ath_hw_pll_rx_hang_check(sc, pll_sqsum); ++ ++ ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); ++ } ++} ++ ++ + void ath9k_tasklet(unsigned long data) + { + struct ath_softc *sc = (struct ath_softc *)data; +@@ -828,48 +865,6 @@ + #undef SCHED_INTR + } + +-static void ath9k_bss_assoc_info(struct ath_softc *sc, +- struct ieee80211_hw *hw, +- struct ieee80211_vif *vif, +- struct ieee80211_bss_conf *bss_conf) +-{ +- struct ath_hw *ah = sc->sc_ah; +- struct ath_common *common = ath9k_hw_common(ah); +- +- if (bss_conf->assoc) { +- ath_dbg(common, ATH_DBG_CONFIG, +- "Bss Info ASSOC %d, bssid: %pM\n", +- bss_conf->aid, common->curbssid); +- +- /* New association, store aid */ +- common->curaid = bss_conf->aid; +- ath9k_hw_write_associd(ah); +- +- /* +- * Request a re-configuration of Beacon related timers +- * on the receipt of the first Beacon frame (i.e., +- * after time sync with the AP). +- */ +- sc->ps_flags |= PS_BEACON_SYNC; +- +- /* Configure the beacon */ +- ath_beacon_config(sc, vif); +- +- /* Reset rssi stats */ +- sc->last_rssi = ATH_RSSI_DUMMY_MARKER; +- sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; +- +- sc->sc_flags |= SC_OP_ANI_RUN; +- ath_start_ani(common); +- } else { +- ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); +- common->curaid = 0; +- /* Stop ANI */ +- sc->sc_flags &= ~SC_OP_ANI_RUN; +- del_timer_sync(&common->ani.timer); +- } +-} +- + void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) + { + struct ath_hw *ah = sc->sc_ah; +@@ -899,7 +894,7 @@ + goto out; + } + if (sc->sc_flags & SC_OP_BEACONS) +- ath_beacon_config(sc, NULL); /* restart beacons */ ++ ath_set_beacon(sc); /* restart beacons */ + + /* Re-Enable interrupts */ + ath9k_hw_set_interrupts(ah, ah->imask); +@@ -1006,7 +1001,7 @@ + sc->config.txpowlimit, &sc->curtxpow); + + if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) +- ath_beacon_config(sc, NULL); /* restart beacons */ ++ ath_set_beacon(sc); /* restart beacons */ + + ath9k_hw_set_interrupts(ah, ah->imask); + +@@ -1452,7 +1447,6 @@ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); +- struct ath_vif *avp = (void *)vif->drv_priv; + int ret = 0; + + ath9k_ps_wakeup(sc); +@@ -1482,8 +1476,9 @@ + } + } + +- if ((vif->type == NL80211_IFTYPE_ADHOC) && +- sc->nvifs > 0) { ++ if ((ah->opmode == NL80211_IFTYPE_ADHOC) || ++ ((vif->type == NL80211_IFTYPE_ADHOC) && ++ sc->nvifs > 0)) { + ath_err(common, "Cannot create ADHOC interface when other" + " interfaces already exist.\n"); + ret = -EINVAL; +@@ -1493,10 +1488,6 @@ + ath_dbg(common, ATH_DBG_CONFIG, + "Attach a VIF of type: %d\n", vif->type); + +- /* Set the VIF opmode */ +- avp->av_opmode = vif->type; +- avp->av_bslot = -1; +- + sc->nvifs++; + + ath9k_do_vif_add_setup(hw, vif); +@@ -1782,23 +1773,63 @@ + struct ieee80211_sta *sta) + { + struct ath_softc *sc = hw->priv; ++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); ++ struct ath_node *an = (struct ath_node *) sta->drv_priv; ++ struct ieee80211_key_conf ps_key = { }; + + ath_node_attach(sc, sta); ++ an->ps_key = ath_key_config(common, vif, sta, &ps_key); + + return 0; + } + ++static void ath9k_del_ps_key(struct ath_softc *sc, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta) ++{ ++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); ++ struct ath_node *an = (struct ath_node *) sta->drv_priv; ++ struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key }; ++ ++ if (!an->ps_key) ++ return; ++ ++ ath_key_delete(common, &ps_key); ++} ++ + static int ath9k_sta_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) + { + struct ath_softc *sc = hw->priv; + ++ ath9k_del_ps_key(sc, vif, sta); + ath_node_detach(sc, sta); + + return 0; + } + ++static void ath9k_sta_notify(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ enum sta_notify_cmd cmd, ++ struct ieee80211_sta *sta) ++{ ++ struct ath_softc *sc = hw->priv; ++ struct ath_node *an = (struct ath_node *) sta->drv_priv; ++ ++ switch (cmd) { ++ case STA_NOTIFY_SLEEP: ++ an->sleeping = true; ++ if (ath_tx_aggr_sleep(sc, an)) ++ ieee80211_sta_set_tim(sta); ++ break; ++ case STA_NOTIFY_AWAKE: ++ an->sleeping = false; ++ ath_tx_aggr_wakeup(sc, an); ++ break; ++ } ++} ++ + static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) + { +@@ -1855,12 +1886,29 @@ + if (ath9k_modparam_nohwcrypt) + return -ENOSPC; + ++ if (vif->type == NL80211_IFTYPE_ADHOC && ++ (key->cipher == WLAN_CIPHER_SUITE_TKIP || ++ key->cipher == WLAN_CIPHER_SUITE_CCMP) && ++ !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { ++ /* ++ * For now, disable hw crypto for the RSN IBSS group keys. This ++ * could be optimized in the future to use a modified key cache ++ * design to support per-STA RX GTK, but until that gets ++ * implemented, use of software crypto for group addressed ++ * frames is a acceptable to allow RSN IBSS to be used. ++ */ ++ return -EOPNOTSUPP; ++ } ++ + mutex_lock(&sc->mutex); + ath9k_ps_wakeup(sc); + ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n"); + + switch (cmd) { + case SET_KEY: ++ if (sta) ++ ath9k_del_ps_key(sc, vif, sta); ++ + ret = ath_key_config(common, vif, sta, key); + if (ret >= 0) { + key->hw_key_idx = ret; +@@ -1886,6 +1934,92 @@ + + return ret; + } ++static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) ++{ ++ struct ath_softc *sc = data; ++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); ++ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; ++ struct ath_vif *avp = (void *)vif->drv_priv; ++ ++ switch (sc->sc_ah->opmode) { ++ case NL80211_IFTYPE_ADHOC: ++ /* There can be only one vif available */ ++ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); ++ common->curaid = bss_conf->aid; ++ ath9k_hw_write_associd(sc->sc_ah); ++ /* configure beacon */ ++ if (bss_conf->enable_beacon) ++ ath_beacon_config(sc, vif); ++ break; ++ case NL80211_IFTYPE_STATION: ++ /* ++ * Skip iteration if primary station vif's bss info ++ * was not changed ++ */ ++ if (sc->sc_flags & SC_OP_PRIM_STA_VIF) ++ break; ++ ++ if (bss_conf->assoc) { ++ sc->sc_flags |= SC_OP_PRIM_STA_VIF; ++ avp->primary_sta_vif = true; ++ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); ++ common->curaid = bss_conf->aid; ++ ath9k_hw_write_associd(sc->sc_ah); ++ ath_dbg(common, ATH_DBG_CONFIG, ++ "Bss Info ASSOC %d, bssid: %pM\n", ++ bss_conf->aid, common->curbssid); ++ ath_beacon_config(sc, vif); ++ /* ++ * Request a re-configuration of Beacon related timers ++ * on the receipt of the first Beacon frame (i.e., ++ * after time sync with the AP). ++ */ ++ sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; ++ /* Reset rssi stats */ ++ sc->last_rssi = ATH_RSSI_DUMMY_MARKER; ++ sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; ++ ++ sc->sc_flags |= SC_OP_ANI_RUN; ++ ath_start_ani(common); ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) ++{ ++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); ++ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; ++ struct ath_vif *avp = (void *)vif->drv_priv; ++ ++ /* Reconfigure bss info */ ++ if (avp->primary_sta_vif && !bss_conf->assoc) { ++ ath_dbg(common, ATH_DBG_CONFIG, ++ "Bss Info DISASSOC %d, bssid %pM\n", ++ common->curaid, common->curbssid); ++ sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS); ++ avp->primary_sta_vif = false; ++ memset(common->curbssid, 0, ETH_ALEN); ++ common->curaid = 0; ++ } ++ ++ ieee80211_iterate_active_interfaces_atomic( ++ sc->hw, ath9k_bss_iter, sc); ++ ++ /* ++ * None of station vifs are associated. ++ * Clear bssid & aid ++ */ ++ if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && ++ !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) { ++ ath9k_hw_write_associd(sc->sc_ah); ++ /* Stop ANI */ ++ sc->sc_flags &= ~SC_OP_ANI_RUN; ++ del_timer_sync(&common->ani.timer); ++ } ++} + + static void ath9k_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +@@ -1893,7 +2027,6 @@ + u32 changed) + { + struct ath_softc *sc = hw->priv; +- struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_vif *avp = (void *)vif->drv_priv; +@@ -1904,20 +2037,13 @@ + mutex_lock(&sc->mutex); + + if (changed & BSS_CHANGED_BSSID) { +- /* Set BSSID */ +- memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); +- memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); +- common->curaid = 0; +- ath9k_hw_write_associd(ah); ++ ath9k_config_bss(sc, vif); + + /* Set aggregation protection mode parameters */ + sc->config.ath_aggr_prot = 0; + + ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n", + common->curbssid, common->curaid); +- +- /* need to reconfigure the beacon */ +- sc->sc_flags &= ~SC_OP_BEACONS ; + } + + /* Enable transmission of beacons (AP, IBSS, MESH) */ +@@ -1958,7 +2084,6 @@ + } + + if (changed & BSS_CHANGED_BEACON_INT) { +- cur_conf->beacon_interval = bss_conf->beacon_int; + /* + * In case of AP mode, the HW TSF has to be reset + * when the beacon interval changes. +@@ -1970,9 +2095,8 @@ + if (!error) + ath_beacon_config(sc, vif); + ath9k_set_beaconing_status(sc, true); +- } else { ++ } else + ath_beacon_config(sc, vif); +- } + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { +@@ -1994,12 +2118,6 @@ + sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; + } + +- if (changed & BSS_CHANGED_ASSOC) { +- ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", +- bss_conf->assoc); +- ath9k_bss_assoc_info(sc, hw, vif, bss_conf); +- } +- + mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); + } +@@ -2144,9 +2262,7 @@ + int timeout = 200; /* ms */ + int i, j; + +- ath9k_ps_wakeup(sc); + mutex_lock(&sc->mutex); +- + cancel_delayed_work_sync(&sc->tx_complete_work); + + if (drop) +@@ -2169,15 +2285,30 @@ + goto out; + } + ++ ath9k_ps_wakeup(sc); + if (!ath_drain_all_txq(sc, false)) + ath_reset(sc, false); +- ++ ath9k_ps_restore(sc); + ieee80211_wake_queues(hw); + + out: + ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); + mutex_unlock(&sc->mutex); +- ath9k_ps_restore(sc); ++} ++ ++static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) ++{ ++ struct ath_softc *sc = hw->priv; ++ int i; ++ ++ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { ++ if (!ATH_TXQ_SETUP(sc, i)) ++ continue; ++ ++ if (ath9k_has_pending_frames(sc, &sc->tx.txq[i])) ++ return true; ++ } ++ return false; + } + + struct ieee80211_ops ath9k_ops = { +@@ -2191,6 +2322,7 @@ + .configure_filter = ath9k_configure_filter, + .sta_add = ath9k_sta_add, + .sta_remove = ath9k_sta_remove, ++ .sta_notify = ath9k_sta_notify, + .conf_tx = ath9k_conf_tx, + .bss_info_changed = ath9k_bss_info_changed, + .set_key = ath9k_set_key, +@@ -2202,4 +2334,5 @@ + .rfkill_poll = ath9k_rfkill_poll_state, + .set_coverage_class = ath9k_set_coverage_class, + .flush = ath9k_flush, ++ .tx_frames_pending = ath9k_tx_frames_pending, + }; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/Makefile linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/Makefile +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/Makefile 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/Makefile 2011-05-05 23:29:49.076485252 +0200 +@@ -6,8 +6,8 @@ + xmit.o \ + + ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o +-ath9k-$(CONFIG_PCI) += pci.o +-ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o ++ath9k-$(CONFIG_ATH9K_PCI) += pci.o ++ath9k-$(CONFIG_ATH9K_AHB) += ahb.o + ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o + + obj-$(CONFIG_ATH9K) += ath9k.o +@@ -48,4 +48,6 @@ + htc_drv_init.o \ + htc_drv_gpio.o + ++ath9k_htc-$(CONFIG_ATH9K_HTC_DEBUGFS) += htc_drv_debug.o ++ + obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/phy.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/phy.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/phy.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/phy.h 2011-05-05 23:29:49.075485239 +0200 +@@ -19,7 +19,6 @@ + + #define CHANSEL_DIV 15 + #define CHANSEL_2G(_freq) (((_freq) * 0x10000) / CHANSEL_DIV) +-#define CHANSEL_2G_9485(_freq) ((((_freq) * 0x10000) - 215) / CHANSEL_DIV) + #define CHANSEL_5G(_freq) (((_freq) * 0x8000) / CHANSEL_DIV) + + #define AR_PHY_BASE 0x9800 +@@ -38,26 +37,15 @@ + #define AR_PHY_CLC_Q0 0x0000ffd0 + #define AR_PHY_CLC_Q0_S 5 + +-#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do { \ +- int r; \ +- for (r = 0; r < ((iniarray)->ia_rows); r++) { \ +- REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \ +- DO_DELAY(regWr); \ +- } \ +- } while (0) +- + #define ANTSWAP_AB 0x0001 + #define REDUCE_CHAIN_0 0x00000050 + #define REDUCE_CHAIN_1 0x00000051 + #define AR_PHY_CHIP_ID 0x9818 + +-#define RF_BANK_SETUP(_bank, _iniarray, _col) do { \ +- int i; \ +- for (i = 0; i < (_iniarray)->ia_rows; i++) \ +- (_bank)[i] = INI_RA((_iniarray), i, _col);; \ +- } while (0) +- + #define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 + #define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 + ++#define AR_PHY_PLL_CONTROL 0x16180 ++#define AR_PHY_PLL_MODE 0x16184 ++ + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/rc.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/rc.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/rc.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/rc.c 2011-05-05 23:29:49.098485517 +0200 +@@ -854,14 +854,13 @@ + ath_rc_rate_set_rtscts(sc, rate_table, tx_info); + } + +-static bool ath_rc_update_per(struct ath_softc *sc, ++static void ath_rc_update_per(struct ath_softc *sc, + const struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + struct ieee80211_tx_info *tx_info, + int tx_rate, int xretries, int retries, + u32 now_msec) + { +- bool state_change = false; + int count, n_bad_frames; + u8 last_per; + static const u32 nretry_to_per_lookup[10] = { +@@ -992,8 +991,6 @@ + + } + } +- +- return state_change; + } + + static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, +@@ -1017,7 +1014,6 @@ + u32 now_msec = jiffies_to_msecs(jiffies); + int rate; + u8 last_per; +- bool state_change = false; + const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; + int size = ath_rc_priv->rate_table_size; + +@@ -1027,9 +1023,9 @@ + last_per = ath_rc_priv->per[tx_rate]; + + /* Update PER first */ +- state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, +- tx_info, tx_rate, xretries, +- retries, now_msec); ++ ath_rc_update_per(sc, rate_table, ath_rc_priv, ++ tx_info, tx_rate, xretries, ++ retries, now_msec); + + /* + * If this rate looks bad (high PER) then stop using it for +@@ -1092,8 +1088,7 @@ + if (!(rate->flags & IEEE80211_TX_RC_MCS)) + return rate->idx; + +- while (rate->idx > mcs_rix_off[i] && +- i < ARRAY_SIZE(mcs_rix_off)) { ++ while (i < ARRAY_SIZE(mcs_rix_off) && rate->idx > mcs_rix_off[i]) { + rix++; i++; + } + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/recv.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/recv.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/recv.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/recv.c 2011-05-05 23:29:49.084485349 +0200 +@@ -75,7 +75,6 @@ + *sc->rx.rxlink = bf->bf_daddr; + + sc->rx.rxlink = &ds->ds_link; +- ath9k_hw_rxena(ah); + } + + static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) +@@ -426,9 +425,7 @@ + else + rfilt |= ATH9K_RX_FILTER_BEACON; + +- if ((AR_SREV_9280_20_OR_LATER(sc->sc_ah) || +- AR_SREV_9285_12_OR_LATER(sc->sc_ah)) && +- (sc->sc_ah->opmode == NL80211_IFTYPE_AP) && ++ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || + (sc->rx.rxfilter & FIF_PSPOLL)) + rfilt |= ATH9K_RX_FILTER_PSPOLL; + +@@ -574,7 +571,7 @@ + sc->ps_flags &= ~PS_BEACON_SYNC; + ath_dbg(common, ATH_DBG_PS, + "Reconfigure Beacon timers based on timestamp from the AP\n"); +- ath_beacon_config(sc, NULL); ++ ath_set_beacon(sc); + } + + if (ath_beacon_dtim_pending_cab(skb)) { +@@ -1342,7 +1339,7 @@ + struct ath_hw_antcomb_conf div_ant_conf; + struct ath_ant_comb *antcomb = &sc->ant_comb; + int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; +- int curr_main_set, curr_bias; ++ int curr_main_set; + int main_rssi = rs->rs_rssi_ctl0; + int alt_rssi = rs->rs_rssi_ctl1; + int rx_ant_conf, main_ant_conf; +@@ -1396,7 +1393,6 @@ + ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf); + curr_alt_set = div_ant_conf.alt_lna_conf; + curr_main_set = div_ant_conf.main_lna_conf; +- curr_bias = div_ant_conf.fast_div_bias; + + antcomb->count++; + +@@ -1746,7 +1742,7 @@ + if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | + PS_WAIT_FOR_CAB | + PS_WAIT_FOR_PSPOLL_DATA)) || +- unlikely(ath9k_check_auto_sleep(sc))) ++ ath9k_check_auto_sleep(sc)) + ath_rx_ps(sc, skb); + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + +@@ -1767,6 +1763,7 @@ + } else { + list_move_tail(&bf->list, &sc->rx.rxbuf); + ath_rx_buf_link(sc, bf); ++ ath9k_hw_rxena(ah); + } + } while (1); + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/reg.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/reg.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/reg.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/reg.h 2011-05-05 23:29:49.093485457 +0200 +@@ -693,7 +693,7 @@ + #define AR_RC_APB 0x00000002 + #define AR_RC_HOSTIF 0x00000100 + +-#define AR_WA 0x4004 ++#define AR_WA (AR_SREV_9340(ah) ? 0x40c4 : 0x4004) + #define AR_WA_BIT6 (1 << 6) + #define AR_WA_BIT7 (1 << 7) + #define AR_WA_BIT23 (1 << 23) +@@ -712,7 +712,7 @@ + #define AR_PM_STATE 0x4008 + #define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000 + +-#define AR_HOST_TIMEOUT 0x4018 ++#define AR_HOST_TIMEOUT (AR_SREV_9340(ah) ? 0x4008 : 0x4018) + #define AR_HOST_TIMEOUT_APB_CNTR 0x0000FFFF + #define AR_HOST_TIMEOUT_APB_CNTR_S 0 + #define AR_HOST_TIMEOUT_LCL_CNTR 0xFFFF0000 +@@ -742,7 +742,8 @@ + #define EEPROM_PROTECT_WP_1024_2047 0x8000 + + #define AR_SREV \ +- ((AR_SREV_9100(ah)) ? 0x0600 : 0x4020) ++ ((AR_SREV_9100(ah)) ? 0x0600 : (AR_SREV_9340(ah) \ ++ ? 0x400c : 0x4020)) + + #define AR_SREV_ID \ + ((AR_SREV_9100(ah)) ? 0x00000FFF : 0x000000FF) +@@ -790,6 +791,7 @@ + #define AR_SREV_VERSION_9485 0x240 + #define AR_SREV_REVISION_9485_10 0 + #define AR_SREV_REVISION_9485_11 1 ++#define AR_SREV_VERSION_9340 0x300 + + #define AR_SREV_5416(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ +@@ -858,9 +860,7 @@ + #define AR_SREV_9300(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300)) + #define AR_SREV_9300_20_OR_LATER(_ah) \ +- (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9300) || \ +- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \ +- ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9300_20))) ++ ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300) + + #define AR_SREV_9485(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485)) +@@ -870,6 +870,11 @@ + #define AR_SREV_9485_11(_ah) \ + (AR_SREV_9485(_ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11)) ++#define AR_SREV_9485_OR_LATER(_ah) \ ++ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485)) ++ ++#define AR_SREV_9340(_ah) \ ++ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340)) + + #define AR_SREV_9285E_20(_ah) \ + (AR_SREV_9285_12_OR_LATER(_ah) && \ +@@ -912,11 +917,11 @@ + #define AR_INTR_SPURIOUS 0xFFFFFFFF + + +-#define AR_INTR_SYNC_CAUSE_CLR 0x4028 ++#define AR_INTR_SYNC_CAUSE (AR_SREV_9340(ah) ? 0x4010 : 0x4028) ++#define AR_INTR_SYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4010 : 0x4028) + +-#define AR_INTR_SYNC_CAUSE 0x4028 + +-#define AR_INTR_SYNC_ENABLE 0x402c ++#define AR_INTR_SYNC_ENABLE (AR_SREV_9340(ah) ? 0x4014 : 0x402c) + #define AR_INTR_SYNC_ENABLE_GPIO 0xFFFC0000 + #define AR_INTR_SYNC_ENABLE_GPIO_S 18 + +@@ -956,24 +961,24 @@ + + }; + +-#define AR_INTR_ASYNC_MASK 0x4030 ++#define AR_INTR_ASYNC_MASK (AR_SREV_9340(ah) ? 0x4018 : 0x4030) + #define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000 + #define AR_INTR_ASYNC_MASK_GPIO_S 18 + +-#define AR_INTR_SYNC_MASK 0x4034 ++#define AR_INTR_SYNC_MASK (AR_SREV_9340(ah) ? 0x401c : 0x4034) + #define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000 + #define AR_INTR_SYNC_MASK_GPIO_S 18 + +-#define AR_INTR_ASYNC_CAUSE_CLR 0x4038 +-#define AR_INTR_ASYNC_CAUSE 0x4038 ++#define AR_INTR_ASYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4020 : 0x4038) ++#define AR_INTR_ASYNC_CAUSE (AR_SREV_9340(ah) ? 0x4020 : 0x4038) + +-#define AR_INTR_ASYNC_ENABLE 0x403c ++#define AR_INTR_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4024 : 0x403c) + #define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000 + #define AR_INTR_ASYNC_ENABLE_GPIO_S 18 + + #define AR_PCIE_SERDES 0x4040 + #define AR_PCIE_SERDES2 0x4044 +-#define AR_PCIE_PM_CTRL 0x4014 ++#define AR_PCIE_PM_CTRL (AR_SREV_9340(ah) ? 0x4004 : 0x4014) + #define AR_PCIE_PM_CTRL_ENA 0x00080000 + + #define AR_NUM_GPIO 14 +@@ -984,7 +989,7 @@ + #define AR9300_NUM_GPIO 17 + #define AR7010_NUM_GPIO 16 + +-#define AR_GPIO_IN_OUT 0x4048 ++#define AR_GPIO_IN_OUT (AR_SREV_9340(ah) ? 0x4028 : 0x4048) + #define AR_GPIO_IN_VAL 0x0FFFC000 + #define AR_GPIO_IN_VAL_S 14 + #define AR928X_GPIO_IN_VAL 0x000FFC00 +@@ -998,11 +1003,12 @@ + #define AR7010_GPIO_IN_VAL 0x0000FFFF + #define AR7010_GPIO_IN_VAL_S 0 + +-#define AR_GPIO_IN 0x404c ++#define AR_GPIO_IN (AR_SREV_9340(ah) ? 0x402c : 0x404c) + #define AR9300_GPIO_IN_VAL 0x0001FFFF + #define AR9300_GPIO_IN_VAL_S 0 + +-#define AR_GPIO_OE_OUT (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c) ++#define AR_GPIO_OE_OUT (AR_SREV_9340(ah) ? 0x4030 : \ ++ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)) + #define AR_GPIO_OE_OUT_DRV 0x3 + #define AR_GPIO_OE_OUT_DRV_NO 0x0 + #define AR_GPIO_OE_OUT_DRV_LOW 0x1 +@@ -1024,11 +1030,13 @@ + #define AR7010_GPIO_INT_MASK 0x52024 + #define AR7010_GPIO_FUNCTION 0x52028 + +-#define AR_GPIO_INTR_POL (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050) ++#define AR_GPIO_INTR_POL (AR_SREV_9340(ah) ? 0x4038 : \ ++ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050)) + #define AR_GPIO_INTR_POL_VAL 0x0001FFFF + #define AR_GPIO_INTR_POL_VAL_S 0 + +-#define AR_GPIO_INPUT_EN_VAL (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054) ++#define AR_GPIO_INPUT_EN_VAL (AR_SREV_9340(ah) ? 0x403c : \ ++ (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054)) + #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF 0x00000004 + #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S 2 + #define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF 0x00000008 +@@ -1046,13 +1054,15 @@ + #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 + #define AR_GPIO_JTAG_DISABLE 0x00020000 + +-#define AR_GPIO_INPUT_MUX1 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058) ++#define AR_GPIO_INPUT_MUX1 (AR_SREV_9340(ah) ? 0x4040 : \ ++ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058)) + #define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000 + #define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16 + #define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00 + #define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8 + +-#define AR_GPIO_INPUT_MUX2 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c) ++#define AR_GPIO_INPUT_MUX2 (AR_SREV_9340(ah) ? 0x4044 : \ ++ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c)) + #define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f + #define AR_GPIO_INPUT_MUX2_CLK25_S 0 + #define AR_GPIO_INPUT_MUX2_RFSILENT 0x000000f0 +@@ -1060,13 +1070,18 @@ + #define AR_GPIO_INPUT_MUX2_RTC_RESET 0x00000f00 + #define AR_GPIO_INPUT_MUX2_RTC_RESET_S 8 + +-#define AR_GPIO_OUTPUT_MUX1 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060) +-#define AR_GPIO_OUTPUT_MUX2 (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064) +-#define AR_GPIO_OUTPUT_MUX3 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068) ++#define AR_GPIO_OUTPUT_MUX1 (AR_SREV_9340(ah) ? 0x4048 : \ ++ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060)) ++#define AR_GPIO_OUTPUT_MUX2 (AR_SREV_9340(ah) ? 0x404c : \ ++ (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064)) ++#define AR_GPIO_OUTPUT_MUX3 (AR_SREV_9340(ah) ? 0x4050 : \ ++ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068)) + +-#define AR_INPUT_STATE (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c) ++#define AR_INPUT_STATE (AR_SREV_9340(ah) ? 0x4054 : \ ++ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c)) + +-#define AR_EEPROM_STATUS_DATA (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c) ++#define AR_EEPROM_STATUS_DATA (AR_SREV_9340(ah) ? 0x40c8 : \ ++ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c)) + #define AR_EEPROM_STATUS_DATA_VAL 0x0000ffff + #define AR_EEPROM_STATUS_DATA_VAL_S 0 + #define AR_EEPROM_STATUS_DATA_BUSY 0x00010000 +@@ -1074,28 +1089,51 @@ + #define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000 + #define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000 + +-#define AR_OBS (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080) ++#define AR_OBS (AR_SREV_9340(ah) ? 0x405c : \ ++ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080)) + + #define AR_GPIO_PDPU (AR_SREV_9300_20_OR_LATER(ah) ? 0x4090 : 0x4088) + +-#define AR_PCIE_MSI (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094) ++#define AR_PCIE_MSI (AR_SREV_9340(ah) ? 0x40d8 : \ ++ (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094)) + #define AR_PCIE_MSI_ENABLE 0x00000001 + +-#define AR_INTR_PRIO_SYNC_ENABLE 0x40c4 +-#define AR_INTR_PRIO_ASYNC_MASK 0x40c8 +-#define AR_INTR_PRIO_SYNC_MASK 0x40cc +-#define AR_INTR_PRIO_ASYNC_ENABLE 0x40d4 ++#define AR_INTR_PRIO_SYNC_ENABLE (AR_SREV_9340(ah) ? 0x4088 : 0x40c4) ++#define AR_INTR_PRIO_ASYNC_MASK (AR_SREV_9340(ah) ? 0x408c : 0x40c8) ++#define AR_INTR_PRIO_SYNC_MASK (AR_SREV_9340(ah) ? 0x4090 : 0x40cc) ++#define AR_INTR_PRIO_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4094 : 0x40d4) + #define AR_ENT_OTP 0x40d8 + #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 + #define AR_ENT_OTP_MPSD 0x00800000 +-#define AR_CH0_BB_DPLL2 0x16184 ++ ++#define AR_CH0_BB_DPLL1 0x16180 ++#define AR_CH0_BB_DPLL1_REFDIV 0xF8000000 ++#define AR_CH0_BB_DPLL1_REFDIV_S 27 ++#define AR_CH0_BB_DPLL1_NINI 0x07FC0000 ++#define AR_CH0_BB_DPLL1_NINI_S 18 ++#define AR_CH0_BB_DPLL1_NFRAC 0x0003FFFF ++#define AR_CH0_BB_DPLL1_NFRAC_S 0 ++ ++#define AR_CH0_BB_DPLL2 0x16184 ++#define AR_CH0_BB_DPLL2_LOCAL_PLL 0x40000000 ++#define AR_CH0_BB_DPLL2_LOCAL_PLL_S 30 ++#define AR_CH0_DPLL2_KI 0x3C000000 ++#define AR_CH0_DPLL2_KI_S 26 ++#define AR_CH0_DPLL2_KD 0x03F80000 ++#define AR_CH0_DPLL2_KD_S 19 ++#define AR_CH0_BB_DPLL2_EN_NEGTRIG 0x00040000 ++#define AR_CH0_BB_DPLL2_EN_NEGTRIG_S 18 ++#define AR_CH0_BB_DPLL2_PLL_PWD 0x00010000 ++#define AR_CH0_BB_DPLL2_PLL_PWD_S 16 ++#define AR_CH0_BB_DPLL2_OUTDIV 0x0000E000 ++#define AR_CH0_BB_DPLL2_OUTDIV_S 13 ++ + #define AR_CH0_BB_DPLL3 0x16188 ++#define AR_CH0_BB_DPLL3_PHASE_SHIFT 0x3F800000 ++#define AR_CH0_BB_DPLL3_PHASE_SHIFT_S 23 ++ + #define AR_CH0_DDR_DPLL2 0x16244 + #define AR_CH0_DDR_DPLL3 0x16248 +-#define AR_CH0_DPLL2_KD 0x03F80000 +-#define AR_CH0_DPLL2_KD_S 19 +-#define AR_CH0_DPLL2_KI 0x3C000000 +-#define AR_CH0_DPLL2_KI_S 26 + #define AR_CH0_DPLL3_PHASE_SHIFT 0x3F800000 + #define AR_CH0_DPLL3_PHASE_SHIFT_S 23 + #define AR_PHY_CCA_NOM_VAL_2GHZ -118 +@@ -1144,6 +1182,7 @@ + #define AR_RTC_PLL_REFDIV_5 0x000000c0 + #define AR_RTC_PLL_CLKSEL 0x00000300 + #define AR_RTC_PLL_CLKSEL_S 8 ++#define AR_RTC_PLL_BYPASS 0x00010000 + + #define PLL3 0x16188 + #define PLL3_DO_MEAS_MASK 0x40000000 +@@ -1190,7 +1229,8 @@ + + /* RTC_DERIVED_* - only for AR9100 */ + +-#define AR_RTC_DERIVED_CLK (AR_RTC_BASE + 0x0038) ++#define AR_RTC_DERIVED_CLK \ ++ (AR_SREV_9100(ah) ? (AR_RTC_BASE + 0x0038) : 0x7038) + #define AR_RTC_DERIVED_CLK_PERIOD 0x0000fffe + #define AR_RTC_DERIVED_CLK_PERIOD_S 1 + +@@ -1396,6 +1436,7 @@ + #define AR_STA_ID1_PCF 0x00100000 + #define AR_STA_ID1_USE_DEFANT 0x00200000 + #define AR_STA_ID1_DEFANT_UPDATE 0x00400000 ++#define AR_STA_ID1_AR9100_BA_FIX 0x00400000 + #define AR_STA_ID1_RTS_USE_DEF 0x00800000 + #define AR_STA_ID1_ACKCTS_6MB 0x01000000 + #define AR_STA_ID1_BASE_RATE_11B 0x02000000 +@@ -1668,6 +1709,22 @@ + #define AR_BTCOEX_WL_WGHT 0xffff0000 + #define AR_BTCOEX_WL_WGHT_S 16 + ++#define AR_BT_COEX_WL_WEIGHTS0 0x8174 ++#define AR_BT_COEX_WL_WEIGHTS1 0x81c4 ++ ++#define AR_BT_COEX_BT_WEIGHTS0 0x83ac ++#define AR_BT_COEX_BT_WEIGHTS1 0x83b0 ++#define AR_BT_COEX_BT_WEIGHTS2 0x83b4 ++#define AR_BT_COEX_BT_WEIGHTS3 0x83b8 ++ ++#define AR9300_BT_WGHT 0xcccc4444 ++#define AR9300_STOMP_ALL_WLAN_WGHT0 0xfffffff0 ++#define AR9300_STOMP_ALL_WLAN_WGHT1 0xfffffff0 ++#define AR9300_STOMP_LOW_WLAN_WGHT0 0x88888880 ++#define AR9300_STOMP_LOW_WLAN_WGHT1 0x88888880 ++#define AR9300_STOMP_NONE_WLAN_WGHT0 0x00000000 ++#define AR9300_STOMP_NONE_WLAN_WGHT1 0x00000000 ++ + #define AR_BT_COEX_MODE2 0x817c + #define AR_BT_BCN_MISS_THRESH 0x000000ff + #define AR_BT_BCN_MISS_THRESH_S 0 +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/wmi.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/wmi.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/wmi.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/wmi.c 2011-05-05 23:29:49.094485469 +0200 +@@ -23,20 +23,18 @@ + return "WMI_ECHO_CMDID"; + case WMI_ACCESS_MEMORY_CMDID: + return "WMI_ACCESS_MEMORY_CMDID"; ++ case WMI_GET_FW_VERSION: ++ return "WMI_GET_FW_VERSION"; + case WMI_DISABLE_INTR_CMDID: + return "WMI_DISABLE_INTR_CMDID"; + case WMI_ENABLE_INTR_CMDID: + return "WMI_ENABLE_INTR_CMDID"; +- case WMI_RX_LINK_CMDID: +- return "WMI_RX_LINK_CMDID"; + case WMI_ATH_INIT_CMDID: + return "WMI_ATH_INIT_CMDID"; + case WMI_ABORT_TXQ_CMDID: + return "WMI_ABORT_TXQ_CMDID"; + case WMI_STOP_TX_DMA_CMDID: + return "WMI_STOP_TX_DMA_CMDID"; +- case WMI_STOP_DMA_RECV_CMDID: +- return "WMI_STOP_DMA_RECV_CMDID"; + case WMI_ABORT_TX_DMA_CMDID: + return "WMI_ABORT_TX_DMA_CMDID"; + case WMI_DRAIN_TXQ_CMDID: +@@ -51,8 +49,6 @@ + return "WMI_FLUSH_RECV_CMDID"; + case WMI_SET_MODE_CMDID: + return "WMI_SET_MODE_CMDID"; +- case WMI_RESET_CMDID: +- return "WMI_RESET_CMDID"; + case WMI_NODE_CREATE_CMDID: + return "WMI_NODE_CREATE_CMDID"; + case WMI_NODE_REMOVE_CMDID: +@@ -61,8 +57,6 @@ + return "WMI_VAP_REMOVE_CMDID"; + case WMI_VAP_CREATE_CMDID: + return "WMI_VAP_CREATE_CMDID"; +- case WMI_BEACON_UPDATE_CMDID: +- return "WMI_BEACON_UPDATE_CMDID"; + case WMI_REG_READ_CMDID: + return "WMI_REG_READ_CMDID"; + case WMI_REG_WRITE_CMDID: +@@ -71,22 +65,22 @@ + return "WMI_RC_STATE_CHANGE_CMDID"; + case WMI_RC_RATE_UPDATE_CMDID: + return "WMI_RC_RATE_UPDATE_CMDID"; +- case WMI_DEBUG_INFO_CMDID: +- return "WMI_DEBUG_INFO_CMDID"; +- case WMI_HOST_ATTACH: +- return "WMI_HOST_ATTACH"; + case WMI_TARGET_IC_UPDATE_CMDID: + return "WMI_TARGET_IC_UPDATE_CMDID"; +- case WMI_TGT_STATS_CMDID: +- return "WMI_TGT_STATS_CMDID"; + case WMI_TX_AGGR_ENABLE_CMDID: + return "WMI_TX_AGGR_ENABLE_CMDID"; + case WMI_TGT_DETACH_CMDID: + return "WMI_TGT_DETACH_CMDID"; +- case WMI_TGT_TXQ_ENABLE_CMDID: +- return "WMI_TGT_TXQ_ENABLE_CMDID"; +- case WMI_AGGR_LIMIT_CMD: +- return "WMI_AGGR_LIMIT_CMD"; ++ case WMI_NODE_UPDATE_CMDID: ++ return "WMI_NODE_UPDATE_CMDID"; ++ case WMI_INT_STATS_CMDID: ++ return "WMI_INT_STATS_CMDID"; ++ case WMI_TX_STATS_CMDID: ++ return "WMI_TX_STATS_CMDID"; ++ case WMI_RX_STATS_CMDID: ++ return "WMI_RX_STATS_CMDID"; ++ case WMI_BITRATE_MASK_CMDID: ++ return "WMI_BITRATE_MASK_CMDID"; + } + + return "Bogus"; +@@ -102,9 +96,15 @@ + + wmi->drv_priv = priv; + wmi->stopped = false; ++ skb_queue_head_init(&wmi->wmi_event_queue); ++ spin_lock_init(&wmi->wmi_lock); ++ spin_lock_init(&wmi->event_lock); + mutex_init(&wmi->op_mutex); + mutex_init(&wmi->multi_write_mutex); + init_completion(&wmi->cmd_wait); ++ INIT_LIST_HEAD(&wmi->pending_tx_events); ++ tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet, ++ (unsigned long)wmi); + + return wmi; + } +@@ -120,11 +120,65 @@ + kfree(priv->wmi); + } + +-void ath9k_swba_tasklet(unsigned long data) ++void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv) + { +- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; ++ unsigned long flags; ++ ++ tasklet_kill(&priv->wmi->wmi_event_tasklet); ++ spin_lock_irqsave(&priv->wmi->wmi_lock, flags); ++ __skb_queue_purge(&priv->wmi->wmi_event_queue); ++ spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); ++} ++ ++void ath9k_wmi_event_tasklet(unsigned long data) ++{ ++ struct wmi *wmi = (struct wmi *)data; ++ struct ath9k_htc_priv *priv = wmi->drv_priv; ++ struct wmi_cmd_hdr *hdr; ++ void *wmi_event; ++ struct wmi_event_swba *swba; ++ struct sk_buff *skb = NULL; ++ unsigned long flags; ++ u16 cmd_id; ++ ++ do { ++ spin_lock_irqsave(&wmi->wmi_lock, flags); ++ skb = __skb_dequeue(&wmi->wmi_event_queue); ++ if (!skb) { ++ spin_unlock_irqrestore(&wmi->wmi_lock, flags); ++ return; ++ } ++ spin_unlock_irqrestore(&wmi->wmi_lock, flags); ++ ++ hdr = (struct wmi_cmd_hdr *) skb->data; ++ cmd_id = be16_to_cpu(hdr->command_id); ++ wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); ++ ++ switch (cmd_id) { ++ case WMI_SWBA_EVENTID: ++ swba = (struct wmi_event_swba *) wmi_event; ++ ath9k_htc_swba(priv, swba); ++ break; ++ case WMI_FATAL_EVENTID: ++ ieee80211_queue_work(wmi->drv_priv->hw, ++ &wmi->drv_priv->fatal_work); ++ break; ++ case WMI_TXSTATUS_EVENTID: ++ spin_lock_bh(&priv->tx.tx_lock); ++ if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { ++ spin_unlock_bh(&priv->tx.tx_lock); ++ break; ++ } ++ spin_unlock_bh(&priv->tx.tx_lock); + +- ath9k_htc_swba(priv, priv->wmi->beacon_pending); ++ ath9k_htc_txstatus(priv, wmi_event); ++ break; ++ default: ++ break; ++ } ++ ++ kfree_skb(skb); ++ } while (1); + } + + void ath9k_fatal_work(struct work_struct *work) +@@ -153,10 +207,6 @@ + struct wmi *wmi = (struct wmi *) priv; + struct wmi_cmd_hdr *hdr; + u16 cmd_id; +- void *wmi_event; +-#ifdef CONFIG_ATH9K_HTC_DEBUGFS +- __be32 txrate; +-#endif + + if (unlikely(wmi->stopped)) + goto free_skb; +@@ -165,26 +215,10 @@ + cmd_id = be16_to_cpu(hdr->command_id); + + if (cmd_id & 0x1000) { +- wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); +- switch (cmd_id) { +- case WMI_SWBA_EVENTID: +- wmi->beacon_pending = *(u8 *)wmi_event; +- tasklet_schedule(&wmi->drv_priv->swba_tasklet); +- break; +- case WMI_FATAL_EVENTID: +- ieee80211_queue_work(wmi->drv_priv->hw, +- &wmi->drv_priv->fatal_work); +- break; +- case WMI_TXRATE_EVENTID: +-#ifdef CONFIG_ATH9K_HTC_DEBUGFS +- txrate = ((struct wmi_event_txrate *)wmi_event)->txrate; +- wmi->drv_priv->debug.txrate = be32_to_cpu(txrate); +-#endif +- break; +- default: +- break; +- } +- kfree_skb(skb); ++ spin_lock(&wmi->wmi_lock); ++ __skb_queue_tail(&wmi->wmi_event_queue, skb); ++ spin_unlock(&wmi->wmi_lock); ++ tasklet_schedule(&wmi->wmi_event_tasklet); + return; + } + +@@ -243,7 +277,7 @@ + hdr->command_id = cpu_to_be16(cmd); + hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); + +- return htc_send(wmi->htc, skb, wmi->ctrl_epid, NULL); ++ return htc_send_epid(wmi->htc, skb, wmi->ctrl_epid); + } + + int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/wmi.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/wmi.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/wmi.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/wmi.h 2011-05-05 23:29:49.071485191 +0200 +@@ -17,7 +17,6 @@ + #ifndef WMI_H + #define WMI_H + +- + struct wmi_event_txrate { + __be32 txrate; + struct { +@@ -31,18 +30,65 @@ + __be16 seq_no; + } __packed; + ++struct wmi_fw_version { ++ __be16 major; ++ __be16 minor; ++ ++} __packed; ++ ++struct wmi_event_swba { ++ __be64 tsf; ++ u8 beacon_pending; ++}; ++ ++/* ++ * 64 - HTC header - WMI header - 1 / txstatus ++ * And some other hdr. space is also accounted for. ++ * 12 seems to be the magic number. ++ */ ++#define HTC_MAX_TX_STATUS 12 ++ ++#define ATH9K_HTC_TXSTAT_ACK BIT(0) ++#define ATH9K_HTC_TXSTAT_FILT BIT(1) ++#define ATH9K_HTC_TXSTAT_RTC_CTS BIT(2) ++#define ATH9K_HTC_TXSTAT_MCS BIT(3) ++#define ATH9K_HTC_TXSTAT_CW40 BIT(4) ++#define ATH9K_HTC_TXSTAT_SGI BIT(5) ++ ++/* ++ * Legacy rates are indicated as indices. ++ * HT rates are indicated as dot11 numbers. ++ * This allows us to resrict the rate field ++ * to 4 bits. ++ */ ++#define ATH9K_HTC_TXSTAT_RATE 0x0f ++#define ATH9K_HTC_TXSTAT_RATE_S 0 ++ ++#define ATH9K_HTC_TXSTAT_EPID 0xf0 ++#define ATH9K_HTC_TXSTAT_EPID_S 4 ++ ++struct __wmi_event_txstatus { ++ u8 cookie; ++ u8 ts_rate; /* Also holds EP ID */ ++ u8 ts_flags; ++}; ++ ++struct wmi_event_txstatus { ++ u8 cnt; ++ struct __wmi_event_txstatus txstatus[HTC_MAX_TX_STATUS]; ++} __packed; ++ + enum wmi_cmd_id { + WMI_ECHO_CMDID = 0x0001, + WMI_ACCESS_MEMORY_CMDID, + + /* Commands to Target */ ++ WMI_GET_FW_VERSION, + WMI_DISABLE_INTR_CMDID, + WMI_ENABLE_INTR_CMDID, +- WMI_RX_LINK_CMDID, + WMI_ATH_INIT_CMDID, + WMI_ABORT_TXQ_CMDID, + WMI_STOP_TX_DMA_CMDID, +- WMI_STOP_DMA_RECV_CMDID, + WMI_ABORT_TX_DMA_CMDID, + WMI_DRAIN_TXQ_CMDID, + WMI_DRAIN_TXQ_ALL_CMDID, +@@ -50,24 +96,22 @@ + WMI_STOP_RECV_CMDID, + WMI_FLUSH_RECV_CMDID, + WMI_SET_MODE_CMDID, +- WMI_RESET_CMDID, + WMI_NODE_CREATE_CMDID, + WMI_NODE_REMOVE_CMDID, + WMI_VAP_REMOVE_CMDID, + WMI_VAP_CREATE_CMDID, +- WMI_BEACON_UPDATE_CMDID, + WMI_REG_READ_CMDID, + WMI_REG_WRITE_CMDID, + WMI_RC_STATE_CHANGE_CMDID, + WMI_RC_RATE_UPDATE_CMDID, +- WMI_DEBUG_INFO_CMDID, +- WMI_HOST_ATTACH, + WMI_TARGET_IC_UPDATE_CMDID, +- WMI_TGT_STATS_CMDID, + WMI_TX_AGGR_ENABLE_CMDID, + WMI_TGT_DETACH_CMDID, +- WMI_TGT_TXQ_ENABLE_CMDID, +- WMI_AGGR_LIMIT_CMD = 0x0026, ++ WMI_NODE_UPDATE_CMDID, ++ WMI_INT_STATS_CMDID, ++ WMI_TX_STATS_CMDID, ++ WMI_RX_STATS_CMDID, ++ WMI_BITRATE_MASK_CMDID, + }; + + enum wmi_event_id { +@@ -76,9 +120,8 @@ + WMI_FATAL_EVENTID, + WMI_TXTO_EVENTID, + WMI_BMISS_EVENTID, +- WMI_WLAN_TXCOMP_EVENTID, + WMI_DELBA_EVENTID, +- WMI_TXRATE_EVENTID, ++ WMI_TXSTATUS_EVENTID, + }; + + #define MAX_CMD_NUMBER 62 +@@ -88,6 +131,12 @@ + __be32 val; + }; + ++struct ath9k_htc_tx_event { ++ int count; ++ struct __wmi_event_txstatus txs; ++ struct list_head list; ++}; ++ + struct wmi { + struct ath9k_htc_priv *drv_priv; + struct htc_target *htc; +@@ -95,12 +144,16 @@ + struct mutex op_mutex; + struct completion cmd_wait; + enum wmi_cmd_id last_cmd_id; ++ struct sk_buff_head wmi_event_queue; ++ struct tasklet_struct wmi_event_tasklet; + u16 tx_seq_id; + u8 *cmd_rsp_buf; + u32 cmd_rsp_len; + bool stopped; + +- u8 beacon_pending; ++ struct list_head pending_tx_events; ++ spinlock_t event_lock; ++ + spinlock_t wmi_lock; + + atomic_t mwrite_cnt; +@@ -117,8 +170,9 @@ + u8 *cmd_buf, u32 cmd_len, + u8 *rsp_buf, u32 rsp_len, + u32 timeout); +-void ath9k_swba_tasklet(unsigned long data); ++void ath9k_wmi_event_tasklet(unsigned long data); + void ath9k_fatal_work(struct work_struct *work); ++void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv); + + #define WMI_CMD(_wmi_cmd) \ + do { \ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/xmit.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/xmit.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath9k/xmit.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath9k/xmit.c 2011-05-05 23:29:49.072485203 +0200 +@@ -357,6 +357,7 @@ + struct ath_frame_info *fi; + int nframes; + u8 tidno; ++ bool clear_filter; + + skb = bf->bf_mpdu; + hdr = (struct ieee80211_hdr *)skb->data; +@@ -441,22 +442,24 @@ + /* transmit completion */ + acked_cnt++; + } else { +- if (!(tid->state & AGGR_CLEANUP) && retry) { +- if (fi->retries < ATH_MAX_SW_RETRIES) { +- ath_tx_set_retry(sc, txq, bf->bf_mpdu); +- txpending = 1; +- } else { +- bf->bf_state.bf_type |= BUF_XRETRY; +- txfail = 1; +- sendbar = 1; +- txfail_cnt++; +- } +- } else { ++ if ((tid->state & AGGR_CLEANUP) || !retry) { + /* + * cleanup in progress, just fail + * the un-acked sub-frames + */ + txfail = 1; ++ } else if (fi->retries < ATH_MAX_SW_RETRIES) { ++ if (!(ts->ts_status & ATH9K_TXERR_FILT) || ++ !an->sleeping) ++ ath_tx_set_retry(sc, txq, bf->bf_mpdu); ++ ++ clear_filter = true; ++ txpending = 1; ++ } else { ++ bf->bf_state.bf_type |= BUF_XRETRY; ++ txfail = 1; ++ sendbar = 1; ++ txfail_cnt++; + } + } + +@@ -496,6 +499,7 @@ + !txfail, sendbar); + } else { + /* retry the un-acked ones */ ++ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false); + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) { + if (bf->bf_next == NULL && bf_last->bf_stale) { + struct ath_buf *tbf; +@@ -546,7 +550,12 @@ + + /* prepend un-acked frames to the beginning of the pending frame queue */ + if (!list_empty(&bf_pending)) { ++ if (an->sleeping) ++ ieee80211_sta_set_tim(sta); ++ + spin_lock_bh(&txq->axq_lock); ++ if (clear_filter) ++ tid->ac->clear_ps_filter = true; + list_splice(&bf_pending, &tid->buf_q); + ath_tx_queue_tid(txq, tid); + spin_unlock_bh(&txq->axq_lock); +@@ -816,6 +825,11 @@ + bf = list_first_entry(&bf_q, struct ath_buf, list); + bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); + ++ if (tid->ac->clear_ps_filter) { ++ tid->ac->clear_ps_filter = false; ++ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true); ++ } ++ + /* if only one frame, send as non-aggregate */ + if (bf == bf->bf_lastbf) { + fi = get_frame_info(bf->bf_mpdu); +@@ -896,6 +910,67 @@ + ath_tx_flush_tid(sc, txtid); + } + ++bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) ++{ ++ struct ath_atx_tid *tid; ++ struct ath_atx_ac *ac; ++ struct ath_txq *txq; ++ bool buffered = false; ++ int tidno; ++ ++ for (tidno = 0, tid = &an->tid[tidno]; ++ tidno < WME_NUM_TID; tidno++, tid++) { ++ ++ if (!tid->sched) ++ continue; ++ ++ ac = tid->ac; ++ txq = ac->txq; ++ ++ spin_lock_bh(&txq->axq_lock); ++ ++ if (!list_empty(&tid->buf_q)) ++ buffered = true; ++ ++ tid->sched = false; ++ list_del(&tid->list); ++ ++ if (ac->sched) { ++ ac->sched = false; ++ list_del(&ac->list); ++ } ++ ++ spin_unlock_bh(&txq->axq_lock); ++ } ++ ++ return buffered; ++} ++ ++void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) ++{ ++ struct ath_atx_tid *tid; ++ struct ath_atx_ac *ac; ++ struct ath_txq *txq; ++ int tidno; ++ ++ for (tidno = 0, tid = &an->tid[tidno]; ++ tidno < WME_NUM_TID; tidno++, tid++) { ++ ++ ac = tid->ac; ++ txq = ac->txq; ++ ++ spin_lock_bh(&txq->axq_lock); ++ ac->clear_ps_filter = true; ++ ++ if (!list_empty(&tid->buf_q) && !tid->paused) { ++ ath_tx_queue_tid(txq, tid); ++ ath_txq_schedule(sc, txq); ++ } ++ ++ spin_unlock_bh(&txq->axq_lock); ++ } ++} ++ + void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) + { + struct ath_atx_tid *txtid; +@@ -1451,7 +1526,7 @@ + struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; + struct ieee80211_hdr *hdr; + struct ath_frame_info *fi = get_frame_info(skb); +- struct ath_node *an; ++ struct ath_node *an = NULL; + struct ath_atx_tid *tid; + enum ath9k_key_type keytype; + u16 seqno = 0; +@@ -1459,11 +1534,13 @@ + + keytype = ath9k_cmn_get_hw_crypto_keytype(skb); + ++ if (sta) ++ an = (struct ath_node *) sta->drv_priv; ++ + hdr = (struct ieee80211_hdr *)skb->data; +- if (sta && ieee80211_is_data_qos(hdr->frame_control) && ++ if (an && ieee80211_is_data_qos(hdr->frame_control) && + conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) { + +- an = (struct ath_node *) sta->drv_priv; + tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; + + /* +@@ -1479,6 +1556,8 @@ + memset(fi, 0, sizeof(*fi)); + if (hw_key) + fi->keyix = hw_key->hw_key_idx; ++ else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0) ++ fi->keyix = an->ps_key; + else + fi->keyix = ATH9K_TXKEYIX_INVALID; + fi->keytype = keytype; +@@ -1491,7 +1570,6 @@ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + int flags = 0; + +- flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ + flags |= ATH9K_TXDESC_INTREQ; + + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) +@@ -1754,6 +1832,9 @@ + if (txctl->paprd) + bf->bf_state.bfs_paprd_timestamp = jiffies; + ++ if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) ++ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true); ++ + ath_tx_send_normal(sc, txctl->txq, tid, &bf_head); + } + +@@ -1980,7 +2061,7 @@ + if (ieee80211_is_data(hdr->frame_control) && + (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | + ATH9K_TX_DELIM_UNDERRUN)) && +- ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max) ++ ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level) + tx_info->status.rates[tx_rateindex].count = + hw->max_rate_tries; + } +@@ -2099,28 +2180,6 @@ + } + } + +-static void ath_hw_pll_work(struct work_struct *work) +-{ +- struct ath_softc *sc = container_of(work, struct ath_softc, +- hw_pll_work.work); +- static int count; +- +- if (AR_SREV_9485(sc->sc_ah)) { +- if (ar9003_get_pll_sqsum_dvc(sc->sc_ah) >= 0x40000) { +- count++; +- +- if (count == 3) { +- /* Rx is hung for more than 500ms. Reset it */ +- ath_reset(sc, true); +- count = 0; +- } +- } else +- count = 0; +- +- ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); +- } +-} +- + static void ath_tx_complete_poll_work(struct work_struct *work) + { + struct ath_softc *sc = container_of(work, struct ath_softc, +@@ -2144,33 +2203,6 @@ + } else { + txq->axq_tx_inprogress = true; + } +- } else { +- /* If the queue has pending buffers, then it +- * should be doing tx work (and have axq_depth). +- * Shouldn't get to this state I think..but +- * we do. +- */ +- if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && +- (txq->pending_frames > 0 || +- !list_empty(&txq->axq_acq) || +- txq->stopped)) { +- ath_err(ath9k_hw_common(sc->sc_ah), +- "txq: %p axq_qnum: %u," +- " mac80211_qnum: %i" +- " axq_link: %p" +- " pending frames: %i" +- " axq_acq empty: %i" +- " stopped: %i" +- " axq_depth: 0 Attempting to" +- " restart tx logic.\n", +- txq, txq->axq_qnum, +- txq->mac80211_qnum, +- txq->axq_link, +- txq->pending_frames, +- list_empty(&txq->axq_acq), +- txq->stopped); +- ath_txq_schedule(sc, txq); +- } + } + spin_unlock_bh(&txq->axq_lock); + } +@@ -2342,7 +2374,6 @@ + } + + INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); +- INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + error = ath_tx_edma_init(sc); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/ath.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/ath.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/ath.h 2011-05-05 23:29:49.113485699 +0200 +@@ -119,17 +119,11 @@ + void (*write)(void *, u32 val, u32 reg_offset); + void (*enable_write_buffer)(void *); + void (*write_flush) (void *); ++ u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr); + }; + + struct ath_common; +- +-struct ath_bus_ops { +- enum ath_bus_type ath_bus_type; +- void (*read_cachesize)(struct ath_common *common, int *csz); +- bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); +- void (*bt_coex_prep)(struct ath_common *common); +- void (*extn_synch_en)(struct ath_common *common); +-}; ++struct ath_bus_ops; + + struct ath_common { + void *ah; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/carl9170/carl9170.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/carl9170/carl9170.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/carl9170/carl9170.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/carl9170/carl9170.h 2011-05-05 23:29:48.973484007 +0200 +@@ -448,6 +448,8 @@ + + struct carl9170_sta_info { + bool ht_sta; ++ bool sleeping; ++ atomic_t pending_frames; + unsigned int ampdu_max_len; + struct carl9170_sta_tid *agg[CARL9170_NUM_TID]; + struct carl9170_ba_stats stats[CARL9170_NUM_TID]; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/carl9170/main.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/carl9170/main.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/carl9170/main.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/carl9170/main.c 2011-05-05 23:29:48.978484068 +0200 +@@ -1193,6 +1193,8 @@ + struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; + unsigned int i; + ++ atomic_set(&sta_info->pending_frames, 0); ++ + if (sta->ht_cap.ht_supported) { + if (sta->ht_cap.ampdu_density > 6) { + /* +@@ -1467,99 +1469,17 @@ + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) + { +- struct ar9170 *ar = hw->priv; + struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; +- struct sk_buff *skb, *tmp; +- struct sk_buff_head free; +- int i; + + switch (cmd) { + case STA_NOTIFY_SLEEP: +- /* +- * Since the peer is no longer listening, we have to return +- * as many SKBs as possible back to the mac80211 stack. +- * It will deal with the retry procedure, once the peer +- * has become available again. +- * +- * NB: Ideally, the driver should return the all frames in +- * the correct, ascending order. However, I think that this +- * functionality should be implemented in the stack and not +- * here... +- */ +- +- __skb_queue_head_init(&free); +- +- if (sta->ht_cap.ht_supported) { +- rcu_read_lock(); +- for (i = 0; i < CARL9170_NUM_TID; i++) { +- struct carl9170_sta_tid *tid_info; +- +- tid_info = rcu_dereference(sta_info->agg[i]); +- +- if (!tid_info) +- continue; +- +- spin_lock_bh(&ar->tx_ampdu_list_lock); +- if (tid_info->state > +- CARL9170_TID_STATE_SUSPEND) +- tid_info->state = +- CARL9170_TID_STATE_SUSPEND; +- spin_unlock_bh(&ar->tx_ampdu_list_lock); +- +- spin_lock_bh(&tid_info->lock); +- while ((skb = __skb_dequeue(&tid_info->queue))) +- __skb_queue_tail(&free, skb); +- spin_unlock_bh(&tid_info->lock); +- } +- rcu_read_unlock(); +- } +- +- for (i = 0; i < ar->hw->queues; i++) { +- spin_lock_bh(&ar->tx_pending[i].lock); +- skb_queue_walk_safe(&ar->tx_pending[i], skb, tmp) { +- struct _carl9170_tx_superframe *super; +- struct ieee80211_hdr *hdr; +- struct ieee80211_tx_info *info; +- +- super = (void *) skb->data; +- hdr = (void *) super->frame_data; +- +- if (compare_ether_addr(hdr->addr1, sta->addr)) +- continue; +- +- __skb_unlink(skb, &ar->tx_pending[i]); +- +- info = IEEE80211_SKB_CB(skb); +- if (info->flags & IEEE80211_TX_CTL_AMPDU) +- atomic_dec(&ar->tx_ampdu_upload); +- +- carl9170_tx_status(ar, skb, false); +- } +- spin_unlock_bh(&ar->tx_pending[i].lock); +- } +- +- while ((skb = __skb_dequeue(&free))) +- carl9170_tx_status(ar, skb, false); +- ++ sta_info->sleeping = true; ++ if (atomic_read(&sta_info->pending_frames)) ++ ieee80211_sta_block_awake(hw, sta, true); + break; + + case STA_NOTIFY_AWAKE: +- if (!sta->ht_cap.ht_supported) +- return; +- +- rcu_read_lock(); +- for (i = 0; i < CARL9170_NUM_TID; i++) { +- struct carl9170_sta_tid *tid_info; +- +- tid_info = rcu_dereference(sta_info->agg[i]); +- +- if (!tid_info) +- continue; +- +- if ((tid_info->state == CARL9170_TID_STATE_SUSPEND)) +- tid_info->state = CARL9170_TID_STATE_IDLE; +- } +- rcu_read_unlock(); ++ sta_info->sleeping = false; + break; + } + } +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/carl9170/tx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/carl9170/tx.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/carl9170/tx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/carl9170/tx.c 2011-05-05 23:29:48.951483741 +0200 +@@ -104,6 +104,56 @@ + spin_unlock_bh(&ar->tx_stats_lock); + } + ++/* needs rcu_read_lock */ ++static struct ieee80211_sta *__carl9170_get_tx_sta(struct ar9170 *ar, ++ struct sk_buff *skb) ++{ ++ struct _carl9170_tx_superframe *super = (void *) skb->data; ++ struct ieee80211_hdr *hdr = (void *) super->frame_data; ++ struct ieee80211_vif *vif; ++ unsigned int vif_id; ++ ++ vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> ++ CARL9170_TX_SUPER_MISC_VIF_ID_S; ++ ++ if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC)) ++ return NULL; ++ ++ vif = rcu_dereference(ar->vif_priv[vif_id].vif); ++ if (unlikely(!vif)) ++ return NULL; ++ ++ /* ++ * Normally we should use wrappers like ieee80211_get_DA to get ++ * the correct peer ieee80211_sta. ++ * ++ * But there is a problem with indirect traffic (broadcasts, or ++ * data which is designated for other stations) in station mode. ++ * The frame will be directed to the AP for distribution and not ++ * to the actual destination. ++ */ ++ ++ return ieee80211_find_sta(vif, hdr->addr1); ++} ++ ++static void carl9170_tx_ps_unblock(struct ar9170 *ar, struct sk_buff *skb) ++{ ++ struct ieee80211_sta *sta; ++ struct carl9170_sta_info *sta_info; ++ ++ rcu_read_lock(); ++ sta = __carl9170_get_tx_sta(ar, skb); ++ if (unlikely(!sta)) ++ goto out_rcu; ++ ++ sta_info = (struct carl9170_sta_info *) sta->drv_priv; ++ if (atomic_dec_return(&sta_info->pending_frames) == 0) ++ ieee80211_sta_block_awake(ar->hw, sta, false); ++ ++out_rcu: ++ rcu_read_unlock(); ++} ++ + static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) + { + struct ieee80211_tx_info *txinfo; +@@ -135,6 +185,7 @@ + } + + spin_unlock_bh(&ar->tx_stats_lock); ++ + if (atomic_dec_and_test(&ar->tx_total_queued)) + complete(&ar->tx_flush); + } +@@ -329,13 +380,10 @@ + { + struct _carl9170_tx_superframe *super = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *) super->frame_data; +- struct ieee80211_tx_info *tx_info; + struct carl9170_tx_info *ar_info; +- struct carl9170_sta_info *sta_info; + struct ieee80211_sta *sta; ++ struct carl9170_sta_info *sta_info; + struct carl9170_sta_tid *tid_info; +- struct ieee80211_vif *vif; +- unsigned int vif_id; + u8 tid; + + if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) || +@@ -343,30 +391,10 @@ + (!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR)))) + return; + +- tx_info = IEEE80211_SKB_CB(skb); +- ar_info = (void *) tx_info->rate_driver_data; +- +- vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> +- CARL9170_TX_SUPER_MISC_VIF_ID_S; +- +- if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC)) +- return; ++ ar_info = (void *) txinfo->rate_driver_data; + + rcu_read_lock(); +- vif = rcu_dereference(ar->vif_priv[vif_id].vif); +- if (unlikely(!vif)) +- goto out_rcu; +- +- /* +- * Normally we should use wrappers like ieee80211_get_DA to get +- * the correct peer ieee80211_sta. +- * +- * But there is a problem with indirect traffic (broadcasts, or +- * data which is designated for other stations) in station mode. +- * The frame will be directed to the AP for distribution and not +- * to the actual destination. +- */ +- sta = ieee80211_find_sta(vif, hdr->addr1); ++ sta = __carl9170_get_tx_sta(ar, skb); + if (unlikely(!sta)) + goto out_rcu; + +@@ -427,6 +455,7 @@ + if (txinfo->flags & IEEE80211_TX_CTL_AMPDU) + carl9170_tx_status_process_ampdu(ar, skb, txinfo); + ++ carl9170_tx_ps_unblock(ar, skb); + carl9170_tx_put_skb(skb); + } + +@@ -540,11 +569,7 @@ + struct sk_buff *skb; + struct ieee80211_tx_info *txinfo; + struct carl9170_tx_info *arinfo; +- struct _carl9170_tx_superframe *super; + struct ieee80211_sta *sta; +- struct ieee80211_vif *vif; +- struct ieee80211_hdr *hdr; +- unsigned int vif_id; + + rcu_read_lock(); + list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) { +@@ -562,20 +587,7 @@ + msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT))) + goto unlock; + +- super = (void *) skb->data; +- hdr = (void *) super->frame_data; +- +- vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> +- CARL9170_TX_SUPER_MISC_VIF_ID_S; +- +- if (WARN_ON(vif_id >= AR9170_MAX_VIRTUAL_MAC)) +- goto unlock; +- +- vif = rcu_dereference(ar->vif_priv[vif_id].vif); +- if (WARN_ON(!vif)) +- goto unlock; +- +- sta = ieee80211_find_sta(vif, hdr->addr1); ++ sta = __carl9170_get_tx_sta(ar, skb); + if (WARN_ON(!sta)) + goto unlock; + +@@ -1199,15 +1211,6 @@ + arinfo = (void *) info->rate_driver_data; + + arinfo->timeout = jiffies; +- +- /* +- * increase ref count to "2". +- * Ref counting is the easiest way to solve the race between +- * the the urb's completion routine: carl9170_tx_callback and +- * wlan tx status functions: carl9170_tx_status/janitor. +- */ +- carl9170_tx_get_skb(skb); +- + return skb; + + err_unlock: +@@ -1228,6 +1231,36 @@ + __carl9170_tx_process_status(ar, super->s.cookie, q); + } + ++static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb) ++{ ++ struct ieee80211_sta *sta; ++ struct carl9170_sta_info *sta_info; ++ ++ rcu_read_lock(); ++ sta = __carl9170_get_tx_sta(ar, skb); ++ if (!sta) ++ goto out_rcu; ++ ++ sta_info = (void *) sta->drv_priv; ++ if (unlikely(sta_info->sleeping)) { ++ struct ieee80211_tx_info *tx_info; ++ ++ rcu_read_unlock(); ++ ++ tx_info = IEEE80211_SKB_CB(skb); ++ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) ++ atomic_dec(&ar->tx_ampdu_upload); ++ ++ tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; ++ carl9170_tx_status(ar, skb, false); ++ return true; ++ } ++ ++out_rcu: ++ rcu_read_unlock(); ++ return false; ++} ++ + static void carl9170_tx(struct ar9170 *ar) + { + struct sk_buff *skb; +@@ -1247,6 +1280,9 @@ + if (unlikely(!skb)) + break; + ++ if (unlikely(carl9170_tx_ps_drop(ar, skb))) ++ continue; ++ + atomic_inc(&ar->tx_total_pending); + + q = __carl9170_get_queue(ar, i); +@@ -1256,6 +1292,16 @@ + */ + skb_queue_tail(&ar->tx_status[q], skb); + ++ /* ++ * increase ref count to "2". ++ * Ref counting is the easiest way to solve the ++ * race between the urb's completion routine: ++ * carl9170_tx_callback ++ * and wlan tx status functions: ++ * carl9170_tx_status/janitor. ++ */ ++ carl9170_tx_get_skb(skb); ++ + carl9170_usb_tx(ar, skb); + schedule_garbagecollector = true; + } +@@ -1368,6 +1414,11 @@ + * all ressouces which are associated with the frame. + */ + ++ if (sta) { ++ struct carl9170_sta_info *stai = (void *) sta->drv_priv; ++ atomic_inc(&stai->pending_frames); ++ } ++ + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + run = carl9170_tx_ampdu_queue(ar, sta, skb); + if (run) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/Kconfig linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/Kconfig +--- linux-2.6.39-rc6/drivers/net/wireless/ath/Kconfig 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/Kconfig 2011-05-05 23:29:49.145486085 +0200 +@@ -24,7 +24,6 @@ + + source "drivers/net/wireless/ath/ath5k/Kconfig" + source "drivers/net/wireless/ath/ath9k/Kconfig" +-source "drivers/net/wireless/ath/ar9170/Kconfig" + source "drivers/net/wireless/ath/carl9170/Kconfig" + + endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/key.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/key.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/key.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/key.c 2011-05-05 23:29:49.136485977 +0200 +@@ -23,6 +23,14 @@ + + #define REG_READ (common->ops->read) + #define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) ++#define ENABLE_REGWRITE_BUFFER(_ah) \ ++ if (common->ops->enable_write_buffer) \ ++ common->ops->enable_write_buffer((_ah)); ++ ++#define REGWRITE_BUFFER_FLUSH(_ah) \ ++ if (common->ops->write_flush) \ ++ common->ops->write_flush((_ah)); ++ + + #define IEEE80211_WEP_NKID 4 /* number of key ids */ + +@@ -42,6 +50,8 @@ + + keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); + ++ ENABLE_REGWRITE_BUFFER(ah); ++ + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); +@@ -66,6 +76,8 @@ + + } + ++ REGWRITE_BUFFER_FLUSH(ah); ++ + return true; + } + EXPORT_SYMBOL(ath_hw_keyreset); +@@ -104,9 +116,13 @@ + } else { + macLo = macHi = 0; + } ++ ENABLE_REGWRITE_BUFFER(ah); ++ + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); + REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag); + ++ REGWRITE_BUFFER_FLUSH(ah); ++ + return true; + } + +@@ -223,6 +239,8 @@ + mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; + mic4 = get_unaligned_le32(k->kv_txmic + 4); + ++ ENABLE_REGWRITE_BUFFER(ah); ++ + /* Write RX[31:0] and TX[31:16] */ + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); +@@ -236,6 +254,8 @@ + REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), + AR_KEYTABLE_TYPE_CLR); + ++ REGWRITE_BUFFER_FLUSH(ah); ++ + } else { + /* + * TKIP uses four key cache entries (two for group +@@ -258,6 +278,8 @@ + mic0 = get_unaligned_le32(k->kv_mic + 0); + mic2 = get_unaligned_le32(k->kv_mic + 4); + ++ ENABLE_REGWRITE_BUFFER(ah); ++ + /* Write MIC key[31:0] */ + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); +@@ -270,8 +292,12 @@ + REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), + AR_KEYTABLE_TYPE_CLR); ++ ++ REGWRITE_BUFFER_FLUSH(ah); + } + ++ ENABLE_REGWRITE_BUFFER(ah); ++ + /* MAC address registers are reserved for the MIC entry */ + REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); +@@ -283,7 +309,11 @@ + */ + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); ++ ++ REGWRITE_BUFFER_FLUSH(ah); + } else { ++ ENABLE_REGWRITE_BUFFER(ah); ++ + /* Write key[47:0] */ + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); +@@ -296,6 +326,8 @@ + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + ++ REGWRITE_BUFFER_FLUSH(ah); ++ + /* Write MAC address for the entry */ + (void) ath_hw_keysetmac(common, entry, mac); + } +@@ -451,6 +483,9 @@ + memset(&hk, 0, sizeof(hk)); + + switch (key->cipher) { ++ case 0: ++ hk.kv_type = ATH_CIPHER_CLR; ++ break; + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + hk.kv_type = ATH_CIPHER_WEP; +@@ -466,7 +501,8 @@ + } + + hk.kv_len = key->keylen; +- memcpy(hk.kv_val, key->key, key->keylen); ++ if (key->keylen) ++ memcpy(hk.kv_val, key->key, key->keylen); + + if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + switch (vif->type) { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/Makefile linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/Makefile +--- linux-2.6.39-rc6/drivers/net/wireless/ath/Makefile 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/Makefile 2011-05-05 23:29:49.115485723 +0200 +@@ -1,6 +1,5 @@ + obj-$(CONFIG_ATH5K) += ath5k/ + obj-$(CONFIG_ATH9K_HW) += ath9k/ +-obj-$(CONFIG_AR9170_USB) += ar9170/ + obj-$(CONFIG_CARL9170) += carl9170/ + + obj-$(CONFIG_ATH_COMMON) += ath.o +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/regd.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/regd.c +--- linux-2.6.39-rc6/drivers/net/wireless/ath/regd.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/regd.c 2011-05-05 23:29:48.947483693 +0200 +@@ -97,8 +97,8 @@ + } + }; + +-/* Can be used by 0x67, 0x6A and 0x68 */ +-static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = { ++/* Can be used by 0x67, 0x68, 0x6A and 0x6C */ ++static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { +@@ -151,7 +151,8 @@ + case 0x67: + case 0x68: + case 0x6A: +- return &ath_world_regdom_67_68_6A; ++ case 0x6C: ++ return &ath_world_regdom_67_68_6A_6C; + default: + WARN_ON(1); + return ath_default_world_regdomain(); +@@ -333,6 +334,7 @@ + case 0x63: + case 0x66: + case 0x67: ++ case 0x6C: + ath_reg_apply_beaconing_flags(wiphy, initiator); + break; + case 0x68: +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/ath/regd_common.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/regd_common.h +--- linux-2.6.39-rc6/drivers/net/wireless/ath/regd_common.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/ath/regd_common.h 2011-05-05 23:29:49.114485711 +0200 +@@ -86,6 +86,7 @@ + WOR9_WORLD = 0x69, + WORA_WORLD = 0x6A, + WORB_WORLD = 0x6B, ++ WORC_WORLD = 0x6C, + + MKK3_MKKB = 0x80, + MKK3_MKKA2 = 0x81, +@@ -282,6 +283,7 @@ + {WOR9_WORLD, NO_CTL, NO_CTL}, + {WORA_WORLD, NO_CTL, NO_CTL}, + {WORB_WORLD, NO_CTL, NO_CTL}, ++ {WORC_WORLD, NO_CTL, NO_CTL}, + }; + + static struct country_code_to_enum_rd allCountries[] = { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/b43/phy_n.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/b43/phy_n.c +--- linux-2.6.39-rc6/drivers/net/wireless/b43/phy_n.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/b43/phy_n.c 2011-05-05 23:29:49.401489179 +0200 +@@ -2281,6 +2281,7 @@ + save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); + save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0); + save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1); ++ save_regs_phy[8] = 0; + } else { + save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); + save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); +@@ -2289,6 +2290,8 @@ + save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER); + save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1); + save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2); ++ save_regs_phy[7] = 0; ++ save_regs_phy[8] = 0; + } + + b43_nphy_rssi_select(dev, 5, type); +@@ -3845,8 +3848,8 @@ + { + struct b43_phy *phy = &dev->phy; + +- const struct b43_nphy_channeltab_entry_rev2 *tabent_r2; +- const struct b43_nphy_channeltab_entry_rev3 *tabent_r3; ++ const struct b43_nphy_channeltab_entry_rev2 *tabent_r2 = NULL; ++ const struct b43_nphy_channeltab_entry_rev3 *tabent_r3 = NULL; + + u8 tmp; + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl3945-base.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl3945-base.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl3945-base.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl3945-base.c 2011-05-05 23:29:47.275463493 +0200 +@@ -2748,11 +2748,12 @@ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, init_alive_start.work); + ++ mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) +- return; ++ goto out; + +- mutex_lock(&priv->mutex); + iwl3945_init_alive_start(priv); ++out: + mutex_unlock(&priv->mutex); + } + +@@ -2761,11 +2762,12 @@ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, alive_start.work); + ++ mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) +- return; ++ goto out; + +- mutex_lock(&priv->mutex); + iwl3945_alive_start(priv); ++out: + mutex_unlock(&priv->mutex); + } + +@@ -2995,10 +2997,12 @@ + } else { + iwl3945_down(priv); + +- if (test_bit(STATUS_EXIT_PENDING, &priv->status)) ++ mutex_lock(&priv->mutex); ++ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { ++ mutex_unlock(&priv->mutex); + return; ++ } + +- mutex_lock(&priv->mutex); + __iwl3945_up(priv); + mutex_unlock(&priv->mutex); + } +@@ -3009,11 +3013,12 @@ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, rx_replenish); + ++ mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) +- return; ++ goto out; + +- mutex_lock(&priv->mutex); + iwl3945_rx_replenish(priv); ++out: + mutex_unlock(&priv->mutex); + } + +@@ -3810,7 +3815,6 @@ + INIT_LIST_HEAD(&priv->free_frames); + + mutex_init(&priv->mutex); +- mutex_init(&priv->sync_cmd_mutex); + + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl4965-base.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl4965-base.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl4965-base.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl4965-base.c 2011-05-05 23:29:46.838458213 +0200 +@@ -1069,9 +1069,12 @@ + } + + /* Re-enable all interrupts */ +- /* only Re-enable if diabled by irq */ ++ /* only Re-enable if disabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl_legacy_enable_interrupts(priv); ++ /* Re-enable RF_KILL if it occurred */ ++ else if (handled & CSR_INT_BIT_RF_KILL) ++ iwl_legacy_enable_rfkill_int(priv); + + #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG + if (iwl_legacy_get_debug_level(priv) & (IWL_DL_ISR)) { +@@ -2139,7 +2142,7 @@ + static void __iwl4965_down(struct iwl_priv *priv) + { + unsigned long flags; +- int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); ++ int exit_pending; + + IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); + +@@ -2401,11 +2404,12 @@ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, init_alive_start.work); + ++ mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) +- return; ++ goto out; + +- mutex_lock(&priv->mutex); + priv->cfg->ops->lib->init_alive_start(priv); ++out: + mutex_unlock(&priv->mutex); + } + +@@ -2414,11 +2418,12 @@ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, alive_start.work); + ++ mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) +- return; ++ goto out; + +- mutex_lock(&priv->mutex); + iwl4965_alive_start(priv); ++out: + mutex_unlock(&priv->mutex); + } + +@@ -2468,10 +2473,12 @@ + } else { + iwl4965_down(priv); + +- if (test_bit(STATUS_EXIT_PENDING, &priv->status)) ++ mutex_lock(&priv->mutex); ++ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { ++ mutex_unlock(&priv->mutex); + return; ++ } + +- mutex_lock(&priv->mutex); + __iwl4965_up(priv); + mutex_unlock(&priv->mutex); + } +@@ -2624,9 +2631,10 @@ + + flush_workqueue(priv->workqueue); + +- /* enable interrupts again in order to receive rfkill changes */ ++ /* User space software may expect getting rfkill changes ++ * even if interface is down */ + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); +- iwl_legacy_enable_interrupts(priv); ++ iwl_legacy_enable_rfkill_int(priv); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + } +@@ -2847,21 +2855,22 @@ + + IWL_DEBUG_MAC80211(priv, "enter\n"); + ++ mutex_lock(&priv->mutex); ++ + if (iwl_legacy_is_rfkill(priv)) +- goto out_exit; ++ goto out; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + test_bit(STATUS_SCANNING, &priv->status)) +- goto out_exit; ++ goto out; + + if (!iwl_legacy_is_associated_ctx(ctx)) +- goto out_exit; ++ goto out; + + /* channel switch in progress */ + if (priv->switch_rxon.switch_in_progress == true) +- goto out_exit; ++ goto out; + +- mutex_lock(&priv->mutex); + if (priv->cfg->ops->lib->set_channel_switch) { + + ch = channel->hw_value; +@@ -2917,7 +2926,6 @@ + } + out: + mutex_unlock(&priv->mutex); +-out_exit: + if (!priv->switch_rxon.switch_in_progress) + ieee80211_chswitch_done(ctx->vif, false); + IWL_DEBUG_MAC80211(priv, "leave\n"); +@@ -3116,7 +3124,6 @@ + INIT_LIST_HEAD(&priv->free_frames); + + mutex_init(&priv->mutex); +- mutex_init(&priv->sync_cmd_mutex); + + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; +@@ -3173,7 +3180,7 @@ + { + priv->hw_rev = _iwl_legacy_read32(priv, CSR_HW_REV); + priv->hw_wa_rev = _iwl_legacy_read32(priv, CSR_HW_REV_WA_REG); +- pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id); ++ priv->rev_id = priv->pci_dev->revision; + IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); + } + +@@ -3406,14 +3413,14 @@ + * 8. Enable interrupts and read RFKILL state + *********************************************/ + +- /* enable interrupts if needed: hw bug w/a */ ++ /* enable rfkill interrupt: hw bug w/a */ + pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); + if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { + pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); + } + +- iwl_legacy_enable_interrupts(priv); ++ iwl_legacy_enable_rfkill_int(priv); + + /* If platform's RF_KILL switch is NOT set to KILL */ + if (iwl_read32(priv, CSR_GP_CNTRL) & +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-4965-lib.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-4965-lib.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-4965-lib.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-4965-lib.c 2011-05-05 23:29:47.072461039 +0200 +@@ -955,9 +955,6 @@ + if (priv->cfg->scan_rx_antennas[band]) + rx_ant = priv->cfg->scan_rx_antennas[band]; + +- if (priv->cfg->scan_tx_antennas[band]) +- scan_tx_antennas = priv->cfg->scan_tx_antennas[band]; +- + priv->scan_tx_ant[band] = iwl4965_toggle_tx_ant(priv, + priv->scan_tx_ant[band], + scan_tx_antennas); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-4965-rs.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-4965-rs.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-4965-rs.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-4965-rs.c 2011-05-05 23:29:47.107461463 +0200 +@@ -2860,7 +2860,6 @@ + + int iwl4965_rate_control_register(void) + { +- pr_err("Registering 4965 rate control operations\n"); + return ieee80211_rate_control_register(&rs_4965_ops); + } + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-core.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-core.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-core.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-core.c 2011-05-05 23:29:47.210462707 +0200 +@@ -211,10 +211,7 @@ + if (!iwl_legacy_is_channel_valid(ch)) + continue; + +- if (iwl_legacy_is_channel_a_band(ch)) +- sband = &priv->bands[IEEE80211_BAND_5GHZ]; +- else +- sband = &priv->bands[IEEE80211_BAND_2GHZ]; ++ sband = &priv->bands[ch->band]; + + geo_ch = &sband->channels[sband->n_channels++]; + +@@ -2117,10 +2114,9 @@ + IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", + channel->hw_value, changed); + +- if (unlikely(!priv->cfg->mod_params->disable_hw_scan && +- test_bit(STATUS_SCANNING, &priv->status))) { ++ if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { + scan_active = 1; +- IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); ++ IWL_DEBUG_MAC80211(priv, "scan active\n"); + } + + if (changed & (IEEE80211_CONF_CHANGE_SMPS | +@@ -2433,11 +2429,13 @@ + + IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); + +- if (!iwl_legacy_is_alive(priv)) +- return; +- + mutex_lock(&priv->mutex); + ++ if (!iwl_legacy_is_alive(priv)) { ++ mutex_unlock(&priv->mutex); ++ return; ++ } ++ + if (changes & BSS_CHANGED_QOS) { + unsigned long flags; + +@@ -2646,7 +2644,7 @@ + + none: + /* re-enable interrupts here since we don't have anything to service. */ +- /* only Re-enable if diabled by irq */ ++ /* only Re-enable if disabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl_legacy_enable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-core.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-core.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-core.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-core.h 2011-05-05 23:29:47.311463927 +0200 +@@ -287,7 +287,6 @@ + struct iwl_base_params *base_params; + /* params likely to change within a device family */ + u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; +- u8 scan_tx_antennas[IEEE80211_NUM_BANDS]; + enum iwl_led_mode led_mode; + }; + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-dev.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-dev.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-dev.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-dev.h 2011-05-05 23:29:47.218462803 +0200 +@@ -134,7 +134,7 @@ + * space more than this */ + int high_mark; /* high watermark, stop queue if free + * space less than this */ +-} __packed; ++}; + + /* One for each TFD */ + struct iwl_tx_info { +@@ -290,6 +290,7 @@ + CMD_SIZE_HUGE = (1 << 0), + CMD_ASYNC = (1 << 1), + CMD_WANT_SKB = (1 << 2), ++ CMD_MAPPED = (1 << 3), + }; + + #define DEF_CMD_PAYLOAD_SIZE 320 +@@ -1076,7 +1077,6 @@ + spinlock_t hcmd_lock; /* protect hcmd */ + spinlock_t reg_lock; /* protect hw register access */ + struct mutex mutex; +- struct mutex sync_cmd_mutex; /* enable serialization of sync commands */ + + /* basic pci-network driver stuff */ + struct pci_dev *pci_dev; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-hcmd.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-hcmd.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-hcmd.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-hcmd.c 2011-05-05 23:29:47.123461655 +0200 +@@ -145,6 +145,8 @@ + int cmd_idx; + int ret; + ++ lockdep_assert_held(&priv->mutex); ++ + BUG_ON(cmd->flags & CMD_ASYNC); + + /* A synchronous command can not have a callback set. */ +@@ -152,7 +154,6 @@ + + IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", + iwl_legacy_get_cmd_string(cmd->id)); +- mutex_lock(&priv->sync_cmd_mutex); + + set_bit(STATUS_HCMD_ACTIVE, &priv->status); + IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", +@@ -224,7 +225,6 @@ + cmd->reply_page = 0; + } + out: +- mutex_unlock(&priv->sync_cmd_mutex); + return ret; + } + EXPORT_SYMBOL(iwl_legacy_send_cmd_sync); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-helpers.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-helpers.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-helpers.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-helpers.h 2011-05-05 23:29:47.183462381 +0200 +@@ -149,6 +149,12 @@ + IWL_DEBUG_ISR(priv, "Disabled interrupts\n"); + } + ++static inline void iwl_legacy_enable_rfkill_int(struct iwl_priv *priv) ++{ ++ IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n"); ++ iwl_write32(priv, CSR_INT_MASK, CSR_INT_BIT_RF_KILL); ++} ++ + static inline void iwl_legacy_enable_interrupts(struct iwl_priv *priv) + { + IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-tx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-tx.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlegacy/iwl-tx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlegacy/iwl-tx.c 2011-05-05 23:29:46.814457923 +0200 +@@ -146,33 +146,32 @@ + { + struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; + struct iwl_queue *q = &txq->q; +- bool huge = false; + int i; + + if (q->n_bd == 0) + return; + + while (q->read_ptr != q->write_ptr) { +- /* we have no way to tell if it is a huge cmd ATM */ + i = iwl_legacy_get_cmd_index(q, q->read_ptr, 0); + +- if (txq->meta[i].flags & CMD_SIZE_HUGE) +- huge = true; +- else ++ if (txq->meta[i].flags & CMD_MAPPED) { + pci_unmap_single(priv->pci_dev, + dma_unmap_addr(&txq->meta[i], mapping), + dma_unmap_len(&txq->meta[i], len), + PCI_DMA_BIDIRECTIONAL); ++ txq->meta[i].flags = 0; ++ } + + q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd); + } + +- if (huge) { +- i = q->n_window; ++ i = q->n_window; ++ if (txq->meta[i].flags & CMD_MAPPED) { + pci_unmap_single(priv->pci_dev, + dma_unmap_addr(&txq->meta[i], mapping), + dma_unmap_len(&txq->meta[i], len), + PCI_DMA_BIDIRECTIONAL); ++ txq->meta[i].flags = 0; + } + } + EXPORT_SYMBOL(iwl_legacy_cmd_queue_unmap); +@@ -467,29 +466,27 @@ + return -EIO; + } + ++ spin_lock_irqsave(&priv->hcmd_lock, flags); ++ + if (iwl_legacy_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { +- IWL_ERR(priv, "No space in command queue\n"); +- IWL_ERR(priv, "Restarting adapter due to queue full\n"); ++ spin_unlock_irqrestore(&priv->hcmd_lock, flags); ++ ++ IWL_ERR(priv, "Restarting adapter due to command queue full\n"); + queue_work(priv->workqueue, &priv->restart); + return -ENOSPC; + } + +- spin_lock_irqsave(&priv->hcmd_lock, flags); +- +- /* If this is a huge cmd, mark the huge flag also on the meta.flags +- * of the _original_ cmd. This is used for DMA mapping clean up. +- */ +- if (cmd->flags & CMD_SIZE_HUGE) { +- idx = iwl_legacy_get_cmd_index(q, q->write_ptr, 0); +- txq->meta[idx].flags = CMD_SIZE_HUGE; +- } +- + idx = iwl_legacy_get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); + out_cmd = txq->cmd[idx]; + out_meta = &txq->meta[idx]; + ++ if (WARN_ON(out_meta->flags & CMD_MAPPED)) { ++ spin_unlock_irqrestore(&priv->hcmd_lock, flags); ++ return -ENOSPC; ++ } ++ + memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ +- out_meta->flags = cmd->flags; ++ out_meta->flags = cmd->flags | CMD_MAPPED; + if (cmd->flags & CMD_WANT_SKB) + out_meta->source = cmd; + if (cmd->flags & CMD_ASYNC) +@@ -610,6 +607,7 @@ + struct iwl_device_cmd *cmd; + struct iwl_cmd_meta *meta; + struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; ++ unsigned long flags; + + /* If a Tx command is being handled and it isn't in the actual + * command queue then there a command routing bug has been introduced +@@ -623,14 +621,6 @@ + return; + } + +- /* If this is a huge cmd, clear the huge flag on the meta.flags +- * of the _original_ cmd. So that iwl_legacy_cmd_queue_free won't unmap +- * the DMA buffer for the scan (huge) command. +- */ +- if (huge) { +- cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, 0); +- txq->meta[cmd_index].flags = 0; +- } + cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, huge); + cmd = txq->cmd[cmd_index]; + meta = &txq->meta[cmd_index]; +@@ -647,6 +637,8 @@ + } else if (meta->callback) + meta->callback(priv, cmd, pkt); + ++ spin_lock_irqsave(&priv->hcmd_lock, flags); ++ + iwl_legacy_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); + + if (!(meta->flags & CMD_ASYNC)) { +@@ -655,6 +647,10 @@ + iwl_legacy_get_cmd_string(cmd->hdr.cmd)); + wake_up_interruptible(&priv->wait_command_queue); + } ++ ++ /* Mark as unmapped */ + meta->flags = 0; ++ ++ spin_unlock_irqrestore(&priv->hcmd_lock, flags); + } + EXPORT_SYMBOL(iwl_legacy_tx_cmd_complete); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-1000.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-1000.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-1000.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-1000.c 2011-05-05 23:29:45.326439943 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -45,8 +45,6 @@ + #include "iwl-agn.h" + #include "iwl-helpers.h" + #include "iwl-agn-hw.h" +-#include "iwl-agn-led.h" +-#include "iwl-agn-debugfs.h" + + /* Highest firmware API version supported */ + #define IWL1000_UCODE_API_MAX 5 +@@ -57,12 +55,10 @@ + #define IWL100_UCODE_API_MIN 5 + + #define IWL1000_FW_PRE "iwlwifi-1000-" +-#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" +-#define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api) ++#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" + + #define IWL100_FW_PRE "iwlwifi-100-" +-#define _IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode" +-#define IWL100_MODULE_FIRMWARE(api) _IWL100_MODULE_FIRMWARE(api) ++#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode" + + + /* +@@ -124,10 +120,10 @@ + + static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) + { +- if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && +- priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) ++ if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && ++ iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) + priv->cfg->base_params->num_of_queues = +- priv->cfg->mod_params->num_of_queues; ++ iwlagn_mod_params.num_of_queues; + + priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; +@@ -141,7 +137,6 @@ + priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; + +- priv->hw_params.max_bsm_size = 0; + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; +@@ -179,21 +174,12 @@ + .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwlagn_txq_set_sched, +- .txq_agg_enable = iwlagn_txq_agg_enable, +- .txq_agg_disable = iwlagn_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, + .rx_handler_setup = iwlagn_rx_handler_setup, + .setup_deferred_work = iwlagn_setup_deferred_work, + .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, +- .load_ucode = iwlagn_load_ucode, +- .dump_nic_event_log = iwl_dump_nic_event_log, +- .dump_nic_error_log = iwl_dump_nic_error_log, +- .dump_csr = iwl_dump_csr, +- .dump_fh = iwl_dump_fh, +- .init_alive_start = iwlagn_init_alive_start, +- .alive_notify = iwlagn_alive_notify, + .send_tx_power = iwlagn_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .apm_ops = { +@@ -208,45 +194,21 @@ + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_REG_BAND_24_HT40_CHANNELS, +- EEPROM_REG_BAND_52_HT40_CHANNELS ++ EEPROM_REGULATORY_BAND_NO_HT40, + }, +- .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, +- .release_semaphore = iwlcore_eeprom_release_semaphore, +- .calib_version = iwlagn_eeprom_calib_version, + .query_addr = iwlagn_eeprom_query_addr, + }, +- .isr_ops = { +- .isr = iwl_isr_ict, +- .free = iwl_free_isr_ict, +- .alloc = iwl_alloc_isr_ict, +- .reset = iwl_reset_ict, +- .disable = iwl_disable_ict, +- }, + .temp_ops = { + .temperature = iwlagn_temperature, + }, +- .debugfs_ops = { +- .rx_stats_read = iwl_ucode_rx_stats_read, +- .tx_stats_read = iwl_ucode_tx_stats_read, +- .general_stats_read = iwl_ucode_general_stats_read, +- .bt_stats_read = iwl_ucode_bt_stats_read, +- .reply_tx_error = iwl_reply_tx_error_read, +- }, + .txfifo_flush = iwlagn_txfifo_flush, + .dev_txfifo_flush = iwlagn_dev_txfifo_flush, +- .tt_ops = { +- .lower_power_detection = iwl_tt_is_low_power_state, +- .tt_power_mode = iwl_tt_current_power_mode, +- .ct_kill_check = iwl_check_for_ct_kill, +- } + }; + + static const struct iwl_ops iwl1000_ops = { + .lib = &iwl1000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, +- .led = &iwlagn_led_ops, +- .ieee80211_ops = &iwlagn_hw_ops, + }; + + static struct iwl_base_params iwl1000_base_params = { +@@ -254,8 +216,6 @@ + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, +- .set_l0s = true, +- .use_bsm = false, + .max_ll_items = OTP_MAX_LL_ITEMS_1000, + .shadow_ram_support = false, + .led_compensation = 51, +@@ -265,9 +225,6 @@ + .chain_noise_scale = 1000, + .wd_timeout = IWL_DEF_WD_TIMEOUT, + .max_event_log_size = 128, +- .ucode_tracing = true, +- .sensitivity_calib_by_driver = true, +- .chain_noise_calib_by_driver = true, + }; + static struct iwl_ht_params iwl1000_ht_params = { + .ht_greenfield_support = true, +@@ -281,7 +238,6 @@ + .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ + .ops = &iwl1000_ops, \ +- .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl1000_base_params, \ + .led_mode = IWL_LED_BLINK + +@@ -303,7 +259,6 @@ + .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ + .ops = &iwl1000_ops, \ +- .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl1000_base_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .rx_with_siso_diversity = true +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-2000.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-2000.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-2000.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-2000.c 2011-05-05 23:29:45.339440101 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -46,30 +46,25 @@ + #include "iwl-helpers.h" + #include "iwl-agn-hw.h" + #include "iwl-6000-hw.h" +-#include "iwl-agn-led.h" +-#include "iwl-agn-debugfs.h" + + /* Highest firmware API version supported */ + #define IWL2030_UCODE_API_MAX 5 + #define IWL2000_UCODE_API_MAX 5 +-#define IWL200_UCODE_API_MAX 5 ++#define IWL105_UCODE_API_MAX 5 + + /* Lowest firmware API version supported */ + #define IWL2030_UCODE_API_MIN 5 + #define IWL2000_UCODE_API_MIN 5 +-#define IWL200_UCODE_API_MIN 5 ++#define IWL105_UCODE_API_MIN 5 + + #define IWL2030_FW_PRE "iwlwifi-2030-" +-#define _IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" +-#define IWL2030_MODULE_FIRMWARE(api) _IWL2030_MODULE_FIRMWARE(api) ++#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" + + #define IWL2000_FW_PRE "iwlwifi-2000-" +-#define _IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" +-#define IWL2000_MODULE_FIRMWARE(api) _IWL2000_MODULE_FIRMWARE(api) ++#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" + +-#define IWL200_FW_PRE "iwlwifi-200-" +-#define _IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode" +-#define IWL200_MODULE_FIRMWARE(api) _IWL200_MODULE_FIRMWARE(api) ++#define IWL105_FW_PRE "iwlwifi-105-" ++#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE #api ".ucode" + + static void iwl2000_set_ct_threshold(struct iwl_priv *priv) + { +@@ -101,6 +96,8 @@ + iwl_set_bit(priv, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); + ++ if (priv->cfg->disable_otp_refresh) ++ iwl_write_prph(priv, APMG_ANALOG_SVR_REG, 0x80000010); + } + + static struct iwl_sensitivity_ranges iwl2000_sensitivity = { +@@ -130,10 +127,10 @@ + + static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) + { +- if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && +- priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) ++ if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && ++ iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) + priv->cfg->base_params->num_of_queues = +- priv->cfg->mod_params->num_of_queues; ++ iwlagn_mod_params.num_of_queues; + + priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; +@@ -147,7 +144,6 @@ + priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; + +- priv->hw_params.max_bsm_size = 0; + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; +@@ -259,8 +255,6 @@ + .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwlagn_txq_set_sched, +- .txq_agg_enable = iwlagn_txq_agg_enable, +- .txq_agg_disable = iwlagn_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, +@@ -268,13 +262,6 @@ + .setup_deferred_work = iwlagn_bt_setup_deferred_work, + .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, + .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, +- .load_ucode = iwlagn_load_ucode, +- .dump_nic_event_log = iwl_dump_nic_event_log, +- .dump_nic_error_log = iwl_dump_nic_error_log, +- .dump_csr = iwl_dump_csr, +- .dump_fh = iwl_dump_fh, +- .init_alive_start = iwlagn_init_alive_start, +- .alive_notify = iwlagn_alive_notify, + .send_tx_power = iwlagn_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl2030_hw_channel_switch, +@@ -290,70 +277,40 @@ + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_6000_REG_BAND_24_HT40_CHANNELS, +- EEPROM_REG_BAND_52_HT40_CHANNELS ++ EEPROM_REGULATORY_BAND_NO_HT40, + }, +- .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, +- .release_semaphore = iwlcore_eeprom_release_semaphore, +- .calib_version = iwlagn_eeprom_calib_version, + .query_addr = iwlagn_eeprom_query_addr, + .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, + }, +- .isr_ops = { +- .isr = iwl_isr_ict, +- .free = iwl_free_isr_ict, +- .alloc = iwl_alloc_isr_ict, +- .reset = iwl_reset_ict, +- .disable = iwl_disable_ict, +- }, + .temp_ops = { + .temperature = iwlagn_temperature, + }, +- .debugfs_ops = { +- .rx_stats_read = iwl_ucode_rx_stats_read, +- .tx_stats_read = iwl_ucode_tx_stats_read, +- .general_stats_read = iwl_ucode_general_stats_read, +- .bt_stats_read = iwl_ucode_bt_stats_read, +- .reply_tx_error = iwl_reply_tx_error_read, +- }, + .txfifo_flush = iwlagn_txfifo_flush, + .dev_txfifo_flush = iwlagn_dev_txfifo_flush, +- .tt_ops = { +- .lower_power_detection = iwl_tt_is_low_power_state, +- .tt_power_mode = iwl_tt_current_power_mode, +- .ct_kill_check = iwl_check_for_ct_kill, +- } + }; + + static const struct iwl_ops iwl2000_ops = { + .lib = &iwl2000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, +- .led = &iwlagn_led_ops, +- .ieee80211_ops = &iwlagn_hw_ops, + }; + + static const struct iwl_ops iwl2030_ops = { + .lib = &iwl2000_lib, + .hcmd = &iwlagn_bt_hcmd, + .utils = &iwlagn_hcmd_utils, +- .led = &iwlagn_led_ops, +- .ieee80211_ops = &iwlagn_hw_ops, + }; + +-static const struct iwl_ops iwl200_ops = { ++static const struct iwl_ops iwl105_ops = { + .lib = &iwl2000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, +- .led = &iwlagn_led_ops, +- .ieee80211_ops = &iwlagn_hw_ops, + }; + +-static const struct iwl_ops iwl230_ops = { ++static const struct iwl_ops iwl135_ops = { + .lib = &iwl2000_lib, + .hcmd = &iwlagn_bt_hcmd, + .utils = &iwlagn_hcmd_utils, +- .led = &iwlagn_led_ops, +- .ieee80211_ops = &iwlagn_hw_ops, + }; + + static struct iwl_base_params iwl2000_base_params = { +@@ -361,8 +318,6 @@ + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .pll_cfg_val = 0, +- .set_l0s = true, +- .use_bsm = false, + .max_ll_items = OTP_MAX_LL_ITEMS_2x00, + .shadow_ram_support = true, + .led_compensation = 51, +@@ -373,9 +328,6 @@ + .chain_noise_scale = 1000, + .wd_timeout = IWL_DEF_WD_TIMEOUT, + .max_event_log_size = 512, +- .ucode_tracing = true, +- .sensitivity_calib_by_driver = true, +- .chain_noise_calib_by_driver = true, + .shadow_reg_enable = true, + }; + +@@ -385,8 +337,6 @@ + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .pll_cfg_val = 0, +- .set_l0s = true, +- .use_bsm = false, + .max_ll_items = OTP_MAX_LL_ITEMS_2x00, + .shadow_ram_support = true, + .led_compensation = 57, +@@ -397,9 +347,6 @@ + .chain_noise_scale = 1000, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, +- .ucode_tracing = true, +- .sensitivity_calib_by_driver = true, +- .chain_noise_calib_by_driver = true, + .shadow_reg_enable = true, + }; + +@@ -409,7 +356,6 @@ + }; + + static struct iwl_bt_params iwl2030_bt_params = { +- .bt_statistics = true, + /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ + .advanced_bt_coexist = true, + .agg_time_limit = BT_AGG_THRESHOLD_DEF, +@@ -426,12 +372,12 @@ + .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .ops = &iwl2000_ops, \ +- .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl2000_base_params, \ + .need_dc_calib = true, \ + .need_temp_offset_calib = true, \ + .led_mode = IWL_LED_RF_STATE, \ +- .iq_invert = true \ ++ .iq_invert = true, \ ++ .disable_otp_refresh = true \ + + struct iwl_cfg iwl2000_2bgn_cfg = { + .name = "2000 Series 2x2 BGN", +@@ -451,7 +397,6 @@ + .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .ops = &iwl2030_ops, \ +- .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl2030_base_params, \ + .bt_params = &iwl2030_bt_params, \ + .need_dc_calib = true, \ +@@ -471,45 +416,13 @@ + IWL_DEVICE_2030, + }; + +-#define IWL_DEVICE_6035 \ +- .fw_name_pre = IWL2030_FW_PRE, \ +- .ucode_api_max = IWL2030_UCODE_API_MAX, \ +- .ucode_api_min = IWL2030_UCODE_API_MIN, \ +- .eeprom_ver = EEPROM_6035_EEPROM_VERSION, \ +- .eeprom_calib_ver = EEPROM_6035_TX_POWER_VERSION, \ +- .ops = &iwl2030_ops, \ +- .mod_params = &iwlagn_mod_params, \ +- .base_params = &iwl2030_base_params, \ +- .bt_params = &iwl2030_bt_params, \ +- .need_dc_calib = true, \ +- .need_temp_offset_calib = true, \ +- .led_mode = IWL_LED_RF_STATE, \ +- .adv_pm = true \ +- +-struct iwl_cfg iwl6035_2agn_cfg = { +- .name = "2000 Series 2x2 AGN/BT", +- IWL_DEVICE_6035, +- .ht_params = &iwl2000_ht_params, +-}; +- +-struct iwl_cfg iwl6035_2abg_cfg = { +- .name = "2000 Series 2x2 ABG/BT", +- IWL_DEVICE_6035, +-}; +- +-struct iwl_cfg iwl6035_2bg_cfg = { +- .name = "2000 Series 2x2 BG/BT", +- IWL_DEVICE_6035, +-}; +- +-#define IWL_DEVICE_200 \ +- .fw_name_pre = IWL200_FW_PRE, \ +- .ucode_api_max = IWL200_UCODE_API_MAX, \ +- .ucode_api_min = IWL200_UCODE_API_MIN, \ ++#define IWL_DEVICE_105 \ ++ .fw_name_pre = IWL105_FW_PRE, \ ++ .ucode_api_max = IWL105_UCODE_API_MAX, \ ++ .ucode_api_min = IWL105_UCODE_API_MIN, \ + .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ +- .ops = &iwl200_ops, \ +- .mod_params = &iwlagn_mod_params, \ ++ .ops = &iwl105_ops, \ + .base_params = &iwl2000_base_params, \ + .need_dc_calib = true, \ + .need_temp_offset_calib = true, \ +@@ -517,25 +430,24 @@ + .adv_pm = true, \ + .rx_with_siso_diversity = true \ + +-struct iwl_cfg iwl200_bg_cfg = { +- .name = "200 Series 1x1 BG", +- IWL_DEVICE_200, ++struct iwl_cfg iwl105_bg_cfg = { ++ .name = "105 Series 1x1 BG", ++ IWL_DEVICE_105, + }; + +-struct iwl_cfg iwl200_bgn_cfg = { +- .name = "200 Series 1x1 BGN", +- IWL_DEVICE_200, ++struct iwl_cfg iwl105_bgn_cfg = { ++ .name = "105 Series 1x1 BGN", ++ IWL_DEVICE_105, + .ht_params = &iwl2000_ht_params, + }; + +-#define IWL_DEVICE_230 \ +- .fw_name_pre = IWL200_FW_PRE, \ +- .ucode_api_max = IWL200_UCODE_API_MAX, \ +- .ucode_api_min = IWL200_UCODE_API_MIN, \ ++#define IWL_DEVICE_135 \ ++ .fw_name_pre = IWL105_FW_PRE, \ ++ .ucode_api_max = IWL105_UCODE_API_MAX, \ ++ .ucode_api_min = IWL105_UCODE_API_MIN, \ + .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ +- .ops = &iwl230_ops, \ +- .mod_params = &iwlagn_mod_params, \ ++ .ops = &iwl135_ops, \ + .base_params = &iwl2030_base_params, \ + .bt_params = &iwl2030_bt_params, \ + .need_dc_calib = true, \ +@@ -544,17 +456,17 @@ + .adv_pm = true, \ + .rx_with_siso_diversity = true \ + +-struct iwl_cfg iwl230_bg_cfg = { +- .name = "200 Series 1x1 BG/BT", +- IWL_DEVICE_230, ++struct iwl_cfg iwl135_bg_cfg = { ++ .name = "105 Series 1x1 BG/BT", ++ IWL_DEVICE_135, + }; + +-struct iwl_cfg iwl230_bgn_cfg = { +- .name = "200 Series 1x1 BGN/BT", +- IWL_DEVICE_230, ++struct iwl_cfg iwl135_bgn_cfg = { ++ .name = "105 Series 1x1 BGN/BT", ++ IWL_DEVICE_135, + .ht_params = &iwl2000_ht_params, + }; + + MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX)); + MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX)); +-MODULE_FIRMWARE(IWL200_MODULE_FIRMWARE(IWL200_UCODE_API_MAX)); ++MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX)); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-5000.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-5000.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-5000.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-5000.c 2011-05-05 23:29:45.408440933 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2007 - 2011 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 +@@ -45,10 +45,8 @@ + #include "iwl-sta.h" + #include "iwl-helpers.h" + #include "iwl-agn.h" +-#include "iwl-agn-led.h" + #include "iwl-agn-hw.h" + #include "iwl-5000-hw.h" +-#include "iwl-agn-debugfs.h" + + /* Highest firmware API version supported */ + #define IWL5000_UCODE_API_MAX 5 +@@ -59,12 +57,10 @@ + #define IWL5150_UCODE_API_MIN 1 + + #define IWL5000_FW_PRE "iwlwifi-5000-" +-#define _IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" +-#define IWL5000_MODULE_FIRMWARE(api) _IWL5000_MODULE_FIRMWARE(api) ++#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" + + #define IWL5150_FW_PRE "iwlwifi-5150-" +-#define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" +-#define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api) ++#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" + + /* NIC configuration for 5000 series */ + static void iwl5000_nic_config(struct iwl_priv *priv) +@@ -168,10 +164,10 @@ + + static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) + { +- if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && +- priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) ++ if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && ++ iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) + priv->cfg->base_params->num_of_queues = +- priv->cfg->mod_params->num_of_queues; ++ iwlagn_mod_params.num_of_queues; + + priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; +@@ -185,7 +181,6 @@ + priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; + +- priv->hw_params.max_bsm_size = 0; + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; +@@ -214,10 +209,10 @@ + + static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) + { +- if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && +- priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) ++ if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && ++ iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) + priv->cfg->base_params->num_of_queues = +- priv->cfg->mod_params->num_of_queues; ++ iwlagn_mod_params.num_of_queues; + + priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; +@@ -231,7 +226,6 @@ + priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; + +- priv->hw_params.max_bsm_size = 0; + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; +@@ -263,7 +257,7 @@ + u32 vt = 0; + s32 offset = iwl_temp_calib_to_offset(priv); + +- vt = le32_to_cpu(priv->_agn.statistics.general.common.temperature); ++ vt = le32_to_cpu(priv->statistics.common.temperature); + vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; + /* now vt hold the temperature in Kelvin */ + priv->temperature = KELVIN_TO_CELSIUS(vt); +@@ -348,21 +342,12 @@ + .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwlagn_txq_set_sched, +- .txq_agg_enable = iwlagn_txq_agg_enable, +- .txq_agg_disable = iwlagn_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, + .rx_handler_setup = iwlagn_rx_handler_setup, + .setup_deferred_work = iwlagn_setup_deferred_work, + .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, +- .dump_nic_event_log = iwl_dump_nic_event_log, +- .dump_nic_error_log = iwl_dump_nic_error_log, +- .dump_csr = iwl_dump_csr, +- .dump_fh = iwl_dump_fh, +- .load_ucode = iwlagn_load_ucode, +- .init_alive_start = iwlagn_init_alive_start, +- .alive_notify = iwlagn_alive_notify, + .send_tx_power = iwlagn_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl5000_hw_channel_switch, +@@ -380,35 +365,13 @@ + EEPROM_REG_BAND_24_HT40_CHANNELS, + EEPROM_REG_BAND_52_HT40_CHANNELS + }, +- .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, +- .release_semaphore = iwlcore_eeprom_release_semaphore, +- .calib_version = iwlagn_eeprom_calib_version, + .query_addr = iwlagn_eeprom_query_addr, + }, +- .isr_ops = { +- .isr = iwl_isr_ict, +- .free = iwl_free_isr_ict, +- .alloc = iwl_alloc_isr_ict, +- .reset = iwl_reset_ict, +- .disable = iwl_disable_ict, +- }, + .temp_ops = { + .temperature = iwlagn_temperature, + }, +- .debugfs_ops = { +- .rx_stats_read = iwl_ucode_rx_stats_read, +- .tx_stats_read = iwl_ucode_tx_stats_read, +- .general_stats_read = iwl_ucode_general_stats_read, +- .bt_stats_read = iwl_ucode_bt_stats_read, +- .reply_tx_error = iwl_reply_tx_error_read, +- }, + .txfifo_flush = iwlagn_txfifo_flush, + .dev_txfifo_flush = iwlagn_dev_txfifo_flush, +- .tt_ops = { +- .lower_power_detection = iwl_tt_is_low_power_state, +- .tt_power_mode = iwl_tt_current_power_mode, +- .ct_kill_check = iwl_check_for_ct_kill, +- } + }; + + static struct iwl_lib_ops iwl5150_lib = { +@@ -416,20 +379,12 @@ + .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwlagn_txq_set_sched, +- .txq_agg_enable = iwlagn_txq_agg_enable, +- .txq_agg_disable = iwlagn_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, + .rx_handler_setup = iwlagn_rx_handler_setup, + .setup_deferred_work = iwlagn_setup_deferred_work, + .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, +- .dump_nic_event_log = iwl_dump_nic_event_log, +- .dump_nic_error_log = iwl_dump_nic_error_log, +- .dump_csr = iwl_dump_csr, +- .load_ucode = iwlagn_load_ucode, +- .init_alive_start = iwlagn_init_alive_start, +- .alive_notify = iwlagn_alive_notify, + .send_tx_power = iwlagn_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl5000_hw_channel_switch, +@@ -447,51 +402,25 @@ + EEPROM_REG_BAND_24_HT40_CHANNELS, + EEPROM_REG_BAND_52_HT40_CHANNELS + }, +- .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, +- .release_semaphore = iwlcore_eeprom_release_semaphore, +- .calib_version = iwlagn_eeprom_calib_version, + .query_addr = iwlagn_eeprom_query_addr, + }, +- .isr_ops = { +- .isr = iwl_isr_ict, +- .free = iwl_free_isr_ict, +- .alloc = iwl_alloc_isr_ict, +- .reset = iwl_reset_ict, +- .disable = iwl_disable_ict, +- }, + .temp_ops = { + .temperature = iwl5150_temperature, + }, +- .debugfs_ops = { +- .rx_stats_read = iwl_ucode_rx_stats_read, +- .tx_stats_read = iwl_ucode_tx_stats_read, +- .general_stats_read = iwl_ucode_general_stats_read, +- .bt_stats_read = iwl_ucode_bt_stats_read, +- .reply_tx_error = iwl_reply_tx_error_read, +- }, + .txfifo_flush = iwlagn_txfifo_flush, + .dev_txfifo_flush = iwlagn_dev_txfifo_flush, +- .tt_ops = { +- .lower_power_detection = iwl_tt_is_low_power_state, +- .tt_power_mode = iwl_tt_current_power_mode, +- .ct_kill_check = iwl_check_for_ct_kill, +- } + }; + + static const struct iwl_ops iwl5000_ops = { + .lib = &iwl5000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, +- .led = &iwlagn_led_ops, +- .ieee80211_ops = &iwlagn_hw_ops, + }; + + static const struct iwl_ops iwl5150_ops = { + .lib = &iwl5150_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, +- .led = &iwlagn_led_ops, +- .ieee80211_ops = &iwlagn_hw_ops, + }; + + static struct iwl_base_params iwl5000_base_params = { +@@ -499,17 +428,12 @@ + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, +- .set_l0s = true, +- .use_bsm = false, + .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, + .chain_noise_scale = 1000, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, +- .ucode_tracing = true, +- .sensitivity_calib_by_driver = true, +- .chain_noise_calib_by_driver = true, + }; + static struct iwl_ht_params iwl5000_ht_params = { + .ht_greenfield_support = true, +@@ -523,7 +447,6 @@ + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ + .ops = &iwl5000_ops, \ +- .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl5000_base_params, \ + .led_mode = IWL_LED_BLINK + +@@ -567,7 +490,6 @@ + .eeprom_ver = EEPROM_5050_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, + .ops = &iwl5000_ops, +- .mod_params = &iwlagn_mod_params, + .base_params = &iwl5000_base_params, + .ht_params = &iwl5000_ht_params, + .led_mode = IWL_LED_BLINK, +@@ -581,7 +503,6 @@ + .eeprom_ver = EEPROM_5050_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ + .ops = &iwl5150_ops, \ +- .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl5000_base_params, \ + .need_dc_calib = true, \ + .led_mode = IWL_LED_BLINK, \ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-5000-hw.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-5000-hw.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-5000-hw.h 2011-05-05 23:29:45.290439508 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2007 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-6000.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-6000.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-6000.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-6000.c 2011-05-05 23:29:45.377440559 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -46,8 +46,6 @@ + #include "iwl-helpers.h" + #include "iwl-agn-hw.h" + #include "iwl-6000-hw.h" +-#include "iwl-agn-led.h" +-#include "iwl-agn-debugfs.h" + + /* Highest firmware API version supported */ + #define IWL6000_UCODE_API_MAX 4 +@@ -60,20 +58,16 @@ + #define IWL6000G2_UCODE_API_MIN 4 + + #define IWL6000_FW_PRE "iwlwifi-6000-" +-#define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" +-#define IWL6000_MODULE_FIRMWARE(api) _IWL6000_MODULE_FIRMWARE(api) ++#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" + + #define IWL6050_FW_PRE "iwlwifi-6050-" +-#define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" +-#define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api) ++#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" + + #define IWL6005_FW_PRE "iwlwifi-6000g2a-" +-#define _IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode" +-#define IWL6005_MODULE_FIRMWARE(api) _IWL6005_MODULE_FIRMWARE(api) ++#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode" + + #define IWL6030_FW_PRE "iwlwifi-6000g2b-" +-#define _IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode" +-#define IWL6030_MODULE_FIRMWARE(api) _IWL6030_MODULE_FIRMWARE(api) ++#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode" + + static void iwl6000_set_ct_threshold(struct iwl_priv *priv) + { +@@ -85,7 +79,7 @@ + static void iwl6050_additional_nic_config(struct iwl_priv *priv) + { + /* Indicate calibration version to uCode. */ +- if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) ++ if (iwlagn_eeprom_calib_version(priv) >= 6) + iwl_set_bit(priv, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); + } +@@ -93,7 +87,7 @@ + static void iwl6150_additional_nic_config(struct iwl_priv *priv) + { + /* Indicate calibration version to uCode. */ +- if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) ++ if (iwlagn_eeprom_calib_version(priv) >= 6) + iwl_set_bit(priv, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); + iwl_set_bit(priv, CSR_GP_DRIVER_REG, +@@ -159,10 +153,10 @@ + + static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) + { +- if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && +- priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) ++ if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && ++ iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) + priv->cfg->base_params->num_of_queues = +- priv->cfg->mod_params->num_of_queues; ++ iwlagn_mod_params.num_of_queues; + + priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; +@@ -176,7 +170,6 @@ + priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; + +- priv->hw_params.max_bsm_size = 0; + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; +@@ -288,21 +281,12 @@ + .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwlagn_txq_set_sched, +- .txq_agg_enable = iwlagn_txq_agg_enable, +- .txq_agg_disable = iwlagn_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, + .rx_handler_setup = iwlagn_rx_handler_setup, + .setup_deferred_work = iwlagn_setup_deferred_work, + .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, +- .load_ucode = iwlagn_load_ucode, +- .dump_nic_event_log = iwl_dump_nic_event_log, +- .dump_nic_error_log = iwl_dump_nic_error_log, +- .dump_csr = iwl_dump_csr, +- .dump_fh = iwl_dump_fh, +- .init_alive_start = iwlagn_init_alive_start, +- .alive_notify = iwlagn_alive_notify, + .send_tx_power = iwlagn_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl6000_hw_channel_switch, +@@ -320,36 +304,14 @@ + EEPROM_6000_REG_BAND_24_HT40_CHANNELS, + EEPROM_REG_BAND_52_HT40_CHANNELS + }, +- .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, +- .release_semaphore = iwlcore_eeprom_release_semaphore, +- .calib_version = iwlagn_eeprom_calib_version, + .query_addr = iwlagn_eeprom_query_addr, + .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, + }, +- .isr_ops = { +- .isr = iwl_isr_ict, +- .free = iwl_free_isr_ict, +- .alloc = iwl_alloc_isr_ict, +- .reset = iwl_reset_ict, +- .disable = iwl_disable_ict, +- }, + .temp_ops = { + .temperature = iwlagn_temperature, + }, +- .debugfs_ops = { +- .rx_stats_read = iwl_ucode_rx_stats_read, +- .tx_stats_read = iwl_ucode_tx_stats_read, +- .general_stats_read = iwl_ucode_general_stats_read, +- .bt_stats_read = iwl_ucode_bt_stats_read, +- .reply_tx_error = iwl_reply_tx_error_read, +- }, + .txfifo_flush = iwlagn_txfifo_flush, + .dev_txfifo_flush = iwlagn_dev_txfifo_flush, +- .tt_ops = { +- .lower_power_detection = iwl_tt_is_low_power_state, +- .tt_power_mode = iwl_tt_current_power_mode, +- .ct_kill_check = iwl_check_for_ct_kill, +- } + }; + + static struct iwl_lib_ops iwl6030_lib = { +@@ -357,8 +319,6 @@ + .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwlagn_txq_set_sched, +- .txq_agg_enable = iwlagn_txq_agg_enable, +- .txq_agg_disable = iwlagn_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, +@@ -366,13 +326,6 @@ + .setup_deferred_work = iwlagn_bt_setup_deferred_work, + .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, + .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, +- .load_ucode = iwlagn_load_ucode, +- .dump_nic_event_log = iwl_dump_nic_event_log, +- .dump_nic_error_log = iwl_dump_nic_error_log, +- .dump_csr = iwl_dump_csr, +- .dump_fh = iwl_dump_fh, +- .init_alive_start = iwlagn_init_alive_start, +- .alive_notify = iwlagn_alive_notify, + .send_tx_power = iwlagn_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl6000_hw_channel_switch, +@@ -390,36 +343,14 @@ + EEPROM_6000_REG_BAND_24_HT40_CHANNELS, + EEPROM_REG_BAND_52_HT40_CHANNELS + }, +- .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, +- .release_semaphore = iwlcore_eeprom_release_semaphore, +- .calib_version = iwlagn_eeprom_calib_version, + .query_addr = iwlagn_eeprom_query_addr, + .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, + }, +- .isr_ops = { +- .isr = iwl_isr_ict, +- .free = iwl_free_isr_ict, +- .alloc = iwl_alloc_isr_ict, +- .reset = iwl_reset_ict, +- .disable = iwl_disable_ict, +- }, + .temp_ops = { + .temperature = iwlagn_temperature, + }, +- .debugfs_ops = { +- .rx_stats_read = iwl_ucode_rx_stats_read, +- .tx_stats_read = iwl_ucode_tx_stats_read, +- .general_stats_read = iwl_ucode_general_stats_read, +- .bt_stats_read = iwl_ucode_bt_stats_read, +- .reply_tx_error = iwl_reply_tx_error_read, +- }, + .txfifo_flush = iwlagn_txfifo_flush, + .dev_txfifo_flush = iwlagn_dev_txfifo_flush, +- .tt_ops = { +- .lower_power_detection = iwl_tt_is_low_power_state, +- .tt_power_mode = iwl_tt_current_power_mode, +- .ct_kill_check = iwl_check_for_ct_kill, +- } + }; + + static struct iwl_nic_ops iwl6050_nic_ops = { +@@ -434,34 +365,26 @@ + .lib = &iwl6000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, +- .led = &iwlagn_led_ops, +- .ieee80211_ops = &iwlagn_hw_ops, + }; + + static const struct iwl_ops iwl6050_ops = { + .lib = &iwl6000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, +- .led = &iwlagn_led_ops, + .nic = &iwl6050_nic_ops, +- .ieee80211_ops = &iwlagn_hw_ops, + }; + + static const struct iwl_ops iwl6150_ops = { + .lib = &iwl6000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, +- .led = &iwlagn_led_ops, + .nic = &iwl6150_nic_ops, +- .ieee80211_ops = &iwlagn_hw_ops, + }; + + static const struct iwl_ops iwl6030_ops = { + .lib = &iwl6030_lib, + .hcmd = &iwlagn_bt_hcmd, + .utils = &iwlagn_hcmd_utils, +- .led = &iwlagn_led_ops, +- .ieee80211_ops = &iwlagn_hw_ops, + }; + + static struct iwl_base_params iwl6000_base_params = { +@@ -469,8 +392,6 @@ + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .pll_cfg_val = 0, +- .set_l0s = true, +- .use_bsm = false, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .led_compensation = 51, +@@ -481,9 +402,6 @@ + .chain_noise_scale = 1000, + .wd_timeout = IWL_DEF_WD_TIMEOUT, + .max_event_log_size = 512, +- .ucode_tracing = true, +- .sensitivity_calib_by_driver = true, +- .chain_noise_calib_by_driver = true, + .shadow_reg_enable = true, + }; + +@@ -492,8 +410,6 @@ + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .pll_cfg_val = 0, +- .set_l0s = true, +- .use_bsm = false, + .max_ll_items = OTP_MAX_LL_ITEMS_6x50, + .shadow_ram_support = true, + .led_compensation = 51, +@@ -504,9 +420,6 @@ + .chain_noise_scale = 1500, + .wd_timeout = IWL_DEF_WD_TIMEOUT, + .max_event_log_size = 1024, +- .ucode_tracing = true, +- .sensitivity_calib_by_driver = true, +- .chain_noise_calib_by_driver = true, + .shadow_reg_enable = true, + }; + static struct iwl_base_params iwl6000_g2_base_params = { +@@ -514,8 +427,6 @@ + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .pll_cfg_val = 0, +- .set_l0s = true, +- .use_bsm = false, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .led_compensation = 57, +@@ -526,9 +437,6 @@ + .chain_noise_scale = 1000, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, +- .ucode_tracing = true, +- .sensitivity_calib_by_driver = true, +- .chain_noise_calib_by_driver = true, + .shadow_reg_enable = true, + }; + +@@ -538,7 +446,6 @@ + }; + + static struct iwl_bt_params iwl6000_bt_params = { +- .bt_statistics = true, + /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ + .advanced_bt_coexist = true, + .agg_time_limit = BT_AGG_THRESHOLD_DEF, +@@ -554,7 +461,6 @@ + .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ + .ops = &iwl6000_ops, \ +- .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl6000_g2_base_params, \ + .need_dc_calib = true, \ + .need_temp_offset_calib = true, \ +@@ -583,7 +489,6 @@ + .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ + .ops = &iwl6030_ops, \ +- .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl6000_g2_base_params, \ + .bt_params = &iwl6000_bt_params, \ + .need_dc_calib = true, \ +@@ -613,6 +518,22 @@ + IWL_DEVICE_6030, + }; + ++struct iwl_cfg iwl6035_2agn_cfg = { ++ .name = "6035 Series 2x2 AGN/BT", ++ IWL_DEVICE_6030, ++ .ht_params = &iwl6000_ht_params, ++}; ++ ++struct iwl_cfg iwl6035_2abg_cfg = { ++ .name = "6035 Series 2x2 ABG/BT", ++ IWL_DEVICE_6030, ++}; ++ ++struct iwl_cfg iwl6035_2bg_cfg = { ++ .name = "6035 Series 2x2 BG/BT", ++ IWL_DEVICE_6030, ++}; ++ + struct iwl_cfg iwl1030_bgn_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN", + IWL_DEVICE_6030, +@@ -649,7 +570,6 @@ + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, \ + .ops = &iwl6000_ops, \ +- .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl6000_base_params, \ + .pa_type = IWL_PA_INTERNAL, \ + .led_mode = IWL_LED_BLINK +@@ -679,7 +599,6 @@ + .ops = &iwl6050_ops, \ + .eeprom_ver = EEPROM_6050_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \ +- .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl6050_base_params, \ + .need_dc_calib = true, \ + .led_mode = IWL_LED_BLINK, \ +@@ -704,7 +623,6 @@ + .eeprom_ver = EEPROM_6150_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION, + .ops = &iwl6150_ops, +- .mod_params = &iwlagn_mod_params, + .base_params = &iwl6050_base_params, + .ht_params = &iwl6000_ht_params, + .need_dc_calib = true, +@@ -720,7 +638,6 @@ + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, + .ops = &iwl6000_ops, +- .mod_params = &iwlagn_mod_params, + .base_params = &iwl6000_base_params, + .ht_params = &iwl6000_ht_params, + .need_dc_calib = true, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-6000-hw.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-6000-hw.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-6000-hw.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-6000-hw.h 2011-05-05 23:29:45.358440329 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2007 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn.c 2011-05-05 23:29:45.404440885 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. +@@ -59,7 +59,6 @@ + #include "iwl-sta.h" + #include "iwl-agn-calib.h" + #include "iwl-agn.h" +-#include "iwl-agn-led.h" + + + /****************************************************************************** +@@ -254,6 +253,10 @@ + struct iwl_frame *frame; + unsigned int frame_size; + int rc; ++ struct iwl_host_cmd cmd = { ++ .id = REPLY_TX_BEACON, ++ .flags = CMD_SIZE_HUGE, ++ }; + + frame = iwl_get_free_frame(priv); + if (!frame) { +@@ -269,8 +272,10 @@ + return -EINVAL; + } + +- rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, +- &frame->u.cmd[0]); ++ cmd.len = frame_size; ++ cmd.data = &frame->u.cmd[0]; ++ ++ rc = iwl_send_cmd_sync(priv, &cmd); + + iwl_free_frame(priv, frame); + +@@ -395,7 +400,9 @@ + return -EINVAL; + } + +- BUG_ON(addr & ~DMA_BIT_MASK(36)); ++ if (WARN_ON(addr & ~DMA_BIT_MASK(36))) ++ return -EINVAL; ++ + if (unlikely(addr & ~IWL_TX_DMA_MASK)) + IWL_ERR(priv, "Unaligned address = %llx\n", + (unsigned long long)addr); +@@ -409,7 +416,7 @@ + * Tell nic where to find circular buffer of Tx Frame Descriptors for + * given Tx queue, and enable the DMA channel used for that queue. + * +- * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA ++ * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA + * channels supported in hardware. + */ + int iwl_hw_tx_queue_init(struct iwl_priv *priv, +@@ -483,12 +490,14 @@ + container_of(work, struct iwl_priv, bt_full_concurrency); + struct iwl_rxon_context *ctx; + ++ mutex_lock(&priv->mutex); ++ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) +- return; ++ goto out; + + /* dont send host command if rf-kill is on */ + if (!iwl_is_ready_rf(priv)) +- return; ++ goto out; + + IWL_DEBUG_INFO(priv, "BT coex in %s mode\n", + priv->bt_full_concurrent ? +@@ -498,15 +507,15 @@ + * LQ & RXON updated cmds must be sent before BT Config cmd + * to avoid 3-wire collisions + */ +- mutex_lock(&priv->mutex); + for_each_context(priv, ctx) { + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); + iwlcore_commit_rxon(priv, ctx); + } +- mutex_unlock(&priv->mutex); + + priv->cfg->ops->hcmd->send_bt_config(priv); ++out: ++ mutex_unlock(&priv->mutex); + } + + /** +@@ -556,7 +565,7 @@ + } + + /* Set starting address; reads will auto-increment */ +- _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); ++ iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); + rmb(); + + /* +@@ -564,13 +573,13 @@ + * place event id # at far right for easier visual parsing. + */ + for (i = 0; i < num_events; i++) { +- ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); +- time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); ++ ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); ++ time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + if (mode == 0) { + trace_iwlwifi_dev_ucode_cont_event(priv, + 0, time, ev); + } else { +- data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); ++ data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + trace_iwlwifi_dev_ucode_cont_event(priv, + time, data, ev); + } +@@ -588,10 +597,7 @@ + u32 num_wraps; /* # times uCode wrapped to top of log */ + u32 next_entry; /* index of next entry to be written by uCode */ + +- if (priv->ucode_type == UCODE_INIT) +- base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); +- else +- base = le32_to_cpu(priv->card_alive.log_event_table_ptr); ++ base = priv->device_pointers.error_event_table; + if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + capacity = iwl_read_targ_mem(priv, base); + num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); +@@ -720,7 +726,10 @@ + /* If an RXB doesn't have a Rx queue slot associated with it, + * then a bug has been introduced in the queue refilling + * routines -- catch it here */ +- BUG_ON(rxb == NULL); ++ if (WARN_ON(rxb == NULL)) { ++ i = (i + 1) & RX_QUEUE_MASK; ++ continue; ++ } + + rxq->queue[i] = NULL; + +@@ -760,7 +769,7 @@ + if (w->cmd == pkt->hdr.cmd) { + w->triggered = true; + if (w->fn) +- w->fn(priv, pkt); ++ w->fn(priv, pkt, w->fn_data); + } + } + spin_unlock(&priv->_agn.notif_wait_lock); +@@ -837,199 +846,6 @@ + iwlagn_rx_queue_restock(priv); + } + +-/* call this function to flush any scheduled tasklet */ +-static inline void iwl_synchronize_irq(struct iwl_priv *priv) +-{ +- /* wait to make sure we flush pending tasklet*/ +- synchronize_irq(priv->pci_dev->irq); +- tasklet_kill(&priv->irq_tasklet); +-} +- +-static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) +-{ +- u32 inta, handled = 0; +- u32 inta_fh; +- unsigned long flags; +- u32 i; +-#ifdef CONFIG_IWLWIFI_DEBUG +- u32 inta_mask; +-#endif +- +- spin_lock_irqsave(&priv->lock, flags); +- +- /* Ack/clear/reset pending uCode interrupts. +- * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, +- * and will clear only when CSR_FH_INT_STATUS gets cleared. */ +- inta = iwl_read32(priv, CSR_INT); +- iwl_write32(priv, CSR_INT, inta); +- +- /* Ack/clear/reset pending flow-handler (DMA) interrupts. +- * Any new interrupts that happen after this, either while we're +- * in this tasklet, or later, will show up in next ISR/tasklet. */ +- inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); +- iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); +- +-#ifdef CONFIG_IWLWIFI_DEBUG +- if (iwl_get_debug_level(priv) & IWL_DL_ISR) { +- /* just for debug */ +- inta_mask = iwl_read32(priv, CSR_INT_MASK); +- IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", +- inta, inta_mask, inta_fh); +- } +-#endif +- +- spin_unlock_irqrestore(&priv->lock, flags); +- +- /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not +- * atomic, make sure that inta covers all the interrupts that +- * we've discovered, even if FH interrupt came in just after +- * reading CSR_INT. */ +- if (inta_fh & CSR49_FH_INT_RX_MASK) +- inta |= CSR_INT_BIT_FH_RX; +- if (inta_fh & CSR49_FH_INT_TX_MASK) +- inta |= CSR_INT_BIT_FH_TX; +- +- /* Now service all interrupt bits discovered above. */ +- if (inta & CSR_INT_BIT_HW_ERR) { +- IWL_ERR(priv, "Hardware error detected. Restarting.\n"); +- +- /* Tell the device to stop sending interrupts */ +- iwl_disable_interrupts(priv); +- +- priv->isr_stats.hw++; +- iwl_irq_handle_error(priv); +- +- handled |= CSR_INT_BIT_HW_ERR; +- +- return; +- } +- +-#ifdef CONFIG_IWLWIFI_DEBUG +- if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { +- /* NIC fires this, but we don't use it, redundant with WAKEUP */ +- if (inta & CSR_INT_BIT_SCD) { +- IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " +- "the frame/frames.\n"); +- priv->isr_stats.sch++; +- } +- +- /* Alive notification via Rx interrupt will do the real work */ +- if (inta & CSR_INT_BIT_ALIVE) { +- IWL_DEBUG_ISR(priv, "Alive interrupt\n"); +- priv->isr_stats.alive++; +- } +- } +-#endif +- /* Safely ignore these bits for debug checks below */ +- inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); +- +- /* HW RF KILL switch toggled */ +- if (inta & CSR_INT_BIT_RF_KILL) { +- int hw_rf_kill = 0; +- if (!(iwl_read32(priv, CSR_GP_CNTRL) & +- CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) +- hw_rf_kill = 1; +- +- IWL_WARN(priv, "RF_KILL bit toggled to %s.\n", +- hw_rf_kill ? "disable radio" : "enable radio"); +- +- priv->isr_stats.rfkill++; +- +- /* driver only loads ucode once setting the interface up. +- * the driver allows loading the ucode even if the radio +- * is killed. Hence update the killswitch state here. The +- * rfkill handler will care about restarting if needed. +- */ +- if (!test_bit(STATUS_ALIVE, &priv->status)) { +- if (hw_rf_kill) +- set_bit(STATUS_RF_KILL_HW, &priv->status); +- else +- clear_bit(STATUS_RF_KILL_HW, &priv->status); +- wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); +- } +- +- handled |= CSR_INT_BIT_RF_KILL; +- } +- +- /* Chip got too hot and stopped itself */ +- if (inta & CSR_INT_BIT_CT_KILL) { +- IWL_ERR(priv, "Microcode CT kill error detected.\n"); +- priv->isr_stats.ctkill++; +- handled |= CSR_INT_BIT_CT_KILL; +- } +- +- /* Error detected by uCode */ +- if (inta & CSR_INT_BIT_SW_ERR) { +- IWL_ERR(priv, "Microcode SW error detected. " +- " Restarting 0x%X.\n", inta); +- priv->isr_stats.sw++; +- iwl_irq_handle_error(priv); +- handled |= CSR_INT_BIT_SW_ERR; +- } +- +- /* +- * uCode wakes up after power-down sleep. +- * Tell device about any new tx or host commands enqueued, +- * and about any Rx buffers made available while asleep. +- */ +- if (inta & CSR_INT_BIT_WAKEUP) { +- IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); +- iwl_rx_queue_update_write_ptr(priv, &priv->rxq); +- for (i = 0; i < priv->hw_params.max_txq_num; i++) +- iwl_txq_update_write_ptr(priv, &priv->txq[i]); +- priv->isr_stats.wakeup++; +- handled |= CSR_INT_BIT_WAKEUP; +- } +- +- /* All uCode command responses, including Tx command responses, +- * Rx "responses" (frame-received notification), and other +- * notifications from uCode come through here*/ +- if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { +- iwl_rx_handle(priv); +- priv->isr_stats.rx++; +- handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); +- } +- +- /* This "Tx" DMA channel is used only for loading uCode */ +- if (inta & CSR_INT_BIT_FH_TX) { +- IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); +- priv->isr_stats.tx++; +- handled |= CSR_INT_BIT_FH_TX; +- /* Wake up uCode load routine, now that load is complete */ +- priv->ucode_write_complete = 1; +- wake_up_interruptible(&priv->wait_command_queue); +- } +- +- if (inta & ~handled) { +- IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); +- priv->isr_stats.unhandled++; +- } +- +- if (inta & ~(priv->inta_mask)) { +- IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", +- inta & ~priv->inta_mask); +- IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); +- } +- +- /* Re-enable all interrupts */ +- /* only Re-enable if disabled by irq */ +- if (test_bit(STATUS_INT_ENABLED, &priv->status)) +- iwl_enable_interrupts(priv); +- /* Re-enable RF_KILL if it occurred */ +- else if (handled & CSR_INT_BIT_RF_KILL) +- iwl_enable_rfkill_int(priv); +- +-#ifdef CONFIG_IWLWIFI_DEBUG +- if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { +- inta = iwl_read32(priv, CSR_INT); +- inta_mask = iwl_read32(priv, CSR_INT_MASK); +- inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); +- IWL_DEBUG_ISR(priv, "End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " +- "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); +- } +-#endif +-} +- + /* tasklet for iwlagn interrupt */ + static void iwl_irq_tasklet(struct iwl_priv *priv) + { +@@ -1171,7 +987,7 @@ + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { + handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); + iwl_write32(priv, CSR_FH_INT_STATUS, +- CSR49_FH_INT_RX_MASK); ++ CSR_FH_INT_RX_MASK); + } + if (inta & CSR_INT_BIT_RX_PERIODIC) { + handled |= CSR_INT_BIT_RX_PERIODIC; +@@ -1209,7 +1025,7 @@ + + /* This "Tx" DMA channel is used only for loading uCode */ + if (inta & CSR_INT_BIT_FH_TX) { +- iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK); ++ iwl_write32(priv, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); + IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); + priv->isr_stats.tx++; + handled |= CSR_INT_BIT_FH_TX; +@@ -1357,26 +1173,48 @@ + * + ******************************************************************************/ + +-static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) ++static void iwl_free_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc) + { +- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); +- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); +- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); +- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); +- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); +- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); ++ if (desc->v_addr) ++ dma_free_coherent(&pci_dev->dev, desc->len, ++ desc->v_addr, desc->p_addr); ++ desc->v_addr = NULL; ++ desc->len = 0; ++} ++ ++static void iwl_free_fw_img(struct pci_dev *pci_dev, struct fw_img *img) ++{ ++ iwl_free_fw_desc(pci_dev, &img->code); ++ iwl_free_fw_desc(pci_dev, &img->data); ++} ++ ++static int iwl_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc, ++ const void *data, size_t len) ++{ ++ if (!len) { ++ desc->v_addr = NULL; ++ return -EINVAL; ++ } ++ ++ desc->v_addr = dma_alloc_coherent(&pci_dev->dev, len, ++ &desc->p_addr, GFP_KERNEL); ++ if (!desc->v_addr) ++ return -ENOMEM; ++ desc->len = len; ++ memcpy(desc->v_addr, data, len); ++ return 0; + } + +-static void iwl_nic_start(struct iwl_priv *priv) ++static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) + { +- /* Remove all resets to allow NIC to operate */ +- iwl_write32(priv, CSR_RESET, 0); ++ iwl_free_fw_img(priv->pci_dev, &priv->ucode_rt); ++ iwl_free_fw_img(priv->pci_dev, &priv->ucode_init); + } + + struct iwlagn_ucode_capabilities { + u32 max_probe_length; + u32 standard_phy_calibration_size; +- bool pan; ++ u32 flags; + }; + + static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); +@@ -1422,8 +1260,8 @@ + } + + struct iwlagn_firmware_pieces { +- const void *inst, *data, *init, *init_data, *boot; +- size_t inst_size, data_size, init_size, init_data_size, boot_size; ++ const void *inst, *data, *init, *init_data; ++ size_t inst_size, data_size, init_size, init_data_size; + + u32 build; + +@@ -1444,28 +1282,18 @@ + + switch (api_ver) { + default: +- /* +- * 4965 doesn't revision the firmware file format +- * along with the API version, it always uses v1 +- * file format. +- */ +- if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != +- CSR_HW_REV_TYPE_4965) { +- hdr_size = 28; +- if (ucode_raw->size < hdr_size) { +- IWL_ERR(priv, "File size too small!\n"); +- return -EINVAL; +- } +- pieces->build = le32_to_cpu(ucode->u.v2.build); +- pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); +- pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); +- pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); +- pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); +- pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size); +- src = ucode->u.v2.data; +- break; ++ hdr_size = 28; ++ if (ucode_raw->size < hdr_size) { ++ IWL_ERR(priv, "File size too small!\n"); ++ return -EINVAL; + } +- /* fall through for 4965 */ ++ pieces->build = le32_to_cpu(ucode->u.v2.build); ++ pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); ++ pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); ++ pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); ++ pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); ++ src = ucode->u.v2.data; ++ break; + case 0: + case 1: + case 2: +@@ -1479,7 +1307,6 @@ + pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); + pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); + pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size); +- pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size); + src = ucode->u.v1.data; + break; + } +@@ -1487,7 +1314,7 @@ + /* Verify size of file vs. image size info in file's header */ + if (ucode_raw->size != hdr_size + pieces->inst_size + + pieces->data_size + pieces->init_size + +- pieces->init_data_size + pieces->boot_size) { ++ pieces->init_data_size) { + + IWL_ERR(priv, + "uCode file size %d does not match expected size\n", +@@ -1503,8 +1330,6 @@ + src += pieces->init_size; + pieces->init_data = src; + src += pieces->init_data_size; +- pieces->boot = src; +- src += pieces->boot_size; + + return 0; + } +@@ -1605,8 +1430,7 @@ + pieces->init_data_size = tlv_len; + break; + case IWL_UCODE_TLV_BOOT: +- pieces->boot = tlv_data; +- pieces->boot_size = tlv_len; ++ IWL_ERR(priv, "Found unexpected BOOT ucode\n"); + break; + case IWL_UCODE_TLV_PROBE_MAX_LEN: + if (tlv_len != sizeof(u32)) +@@ -1617,7 +1441,23 @@ + case IWL_UCODE_TLV_PAN: + if (tlv_len) + goto invalid_tlv_len; +- capa->pan = true; ++ capa->flags |= IWL_UCODE_TLV_FLAGS_PAN; ++ break; ++ case IWL_UCODE_TLV_FLAGS: ++ /* must be at least one u32 */ ++ if (tlv_len < sizeof(u32)) ++ goto invalid_tlv_len; ++ /* and a proper number of u32s */ ++ if (tlv_len % sizeof(u32)) ++ goto invalid_tlv_len; ++ /* ++ * This driver only reads the first u32 as ++ * right now no more features are defined, ++ * if that changes then either the driver ++ * will not work with the new firmware, or ++ * it'll not take advantage of new features. ++ */ ++ capa->flags = le32_to_cpup((__le32 *)tlv_data); + break; + case IWL_UCODE_TLV_INIT_EVTLOG_PTR: + if (tlv_len != sizeof(u32)) +@@ -1667,7 +1507,7 @@ + le32_to_cpup((__le32 *)tlv_data); + break; + default: +- IWL_WARN(priv, "unknown TLV: %d\n", tlv_type); ++ IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type); + break; + } + } +@@ -1806,8 +1646,6 @@ + pieces.init_size); + IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n", + pieces.init_data_size); +- IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n", +- pieces.boot_size); + + /* Verify that uCode images will fit in card's SRAM */ + if (pieces.inst_size > priv->hw_params.max_inst_size) { +@@ -1834,48 +1672,25 @@ + goto try_again; + } + +- if (pieces.boot_size > priv->hw_params.max_bsm_size) { +- IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n", +- pieces.boot_size); +- goto try_again; +- } +- + /* Allocate ucode buffers for card's bus-master loading ... */ + + /* Runtime instructions and 2 copies of data: + * 1) unmodified from disk + * 2) backup cache for save/restore during power-downs */ +- priv->ucode_code.len = pieces.inst_size; +- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); +- +- priv->ucode_data.len = pieces.data_size; +- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); +- +- priv->ucode_data_backup.len = pieces.data_size; +- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); +- +- if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || +- !priv->ucode_data_backup.v_addr) ++ if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.code, ++ pieces.inst, pieces.inst_size)) ++ goto err_pci_alloc; ++ if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.data, ++ pieces.data, pieces.data_size)) + goto err_pci_alloc; + + /* Initialization instructions and data */ + if (pieces.init_size && pieces.init_data_size) { +- priv->ucode_init.len = pieces.init_size; +- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init); +- +- priv->ucode_init_data.len = pieces.init_data_size; +- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data); +- +- if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr) ++ if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.code, ++ pieces.init, pieces.init_size)) + goto err_pci_alloc; +- } +- +- /* Bootstrap (instructions only, no data) */ +- if (pieces.boot_size) { +- priv->ucode_boot.len = pieces.boot_size; +- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); +- +- if (!priv->ucode_boot.v_addr) ++ if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.data, ++ pieces.init_data, pieces.init_data_size)) + goto err_pci_alloc; + } + +@@ -1901,50 +1716,19 @@ + priv->cfg->base_params->max_event_log_size; + priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr; + +- if (ucode_capa.pan) { ++ priv->new_scan_threshold_behaviour = ++ !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); ++ ++ if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { + priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); + priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; + } else + priv->sta_key_max_num = STA_KEY_MAX_NUM; + +- /* Copy images into buffers for card's bus-master reads ... */ +- +- /* Runtime instructions (first block of data in file) */ +- IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", +- pieces.inst_size); +- memcpy(priv->ucode_code.v_addr, pieces.inst, pieces.inst_size); +- +- IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", +- priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); +- +- /* +- * Runtime data +- * NOTE: Copy into backup buffer will be done in iwl_up() +- */ +- IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", +- pieces.data_size); +- memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size); +- memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size); +- +- /* Initialization instructions */ +- if (pieces.init_size) { +- IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n", +- pieces.init_size); +- memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size); +- } +- +- /* Initialization data */ +- if (pieces.init_data_size) { +- IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n", +- pieces.init_data_size); +- memcpy(priv->ucode_init_data.v_addr, pieces.init_data, +- pieces.init_data_size); +- } +- +- /* Bootstrap instructions */ +- IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", +- pieces.boot_size); +- memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size); ++ if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) ++ priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; ++ else ++ priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; + + /* + * figure out the offset of chain noise reset and gain commands +@@ -2076,13 +1860,13 @@ + u32 desc, time, count, base, data1; + u32 blink1, blink2, ilink1, ilink2; + u32 pc, hcmd; ++ struct iwl_error_event_table table; + +- if (priv->ucode_type == UCODE_INIT) { +- base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); ++ base = priv->device_pointers.error_event_table; ++ if (priv->ucode_type == UCODE_SUBTYPE_INIT) { + if (!base) + base = priv->_agn.init_errlog_ptr; + } else { +- base = le32_to_cpu(priv->card_alive.error_event_table_ptr); + if (!base) + base = priv->_agn.inst_errlog_ptr; + } +@@ -2090,11 +1874,15 @@ + if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + IWL_ERR(priv, + "Not valid error log pointer 0x%08X for %s uCode\n", +- base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); ++ base, ++ (priv->ucode_type == UCODE_SUBTYPE_INIT) ++ ? "Init" : "RT"); + return; + } + +- count = iwl_read_targ_mem(priv, base); ++ iwl_read_targ_mem_words(priv, base, &table, sizeof(table)); ++ ++ count = table.valid; + + if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { + IWL_ERR(priv, "Start IWL Error Log Dump:\n"); +@@ -2102,18 +1890,18 @@ + priv->status, count); + } + +- desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); ++ desc = table.error_id; + priv->isr_stats.err_code = desc; +- pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32)); +- blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); +- blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); +- ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); +- ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); +- data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); +- data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); +- line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); +- time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); +- hcmd = iwl_read_targ_mem(priv, base + 22 * sizeof(u32)); ++ pc = table.pc; ++ blink1 = table.blink1; ++ blink2 = table.blink2; ++ ilink1 = table.ilink1; ++ ilink2 = table.ilink2; ++ data1 = table.data1; ++ data2 = table.data2; ++ line = table.line; ++ time = table.tsf_low; ++ hcmd = table.hcmd; + + trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line, + blink1, blink2, ilink1, ilink2); +@@ -2147,12 +1935,11 @@ + if (num_events == 0) + return pos; + +- if (priv->ucode_type == UCODE_INIT) { +- base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); ++ base = priv->device_pointers.log_event_table; ++ if (priv->ucode_type == UCODE_SUBTYPE_INIT) { + if (!base) + base = priv->_agn.init_evtlog_ptr; + } else { +- base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (!base) + base = priv->_agn.inst_evtlog_ptr; + } +@@ -2169,14 +1956,14 @@ + iwl_grab_nic_access(priv); + + /* Set starting address; reads will auto-increment */ +- _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); ++ iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); + rmb(); + + /* "time" is actually "data" for mode 0 (no timestamp). + * place event id # at far right for easier visual parsing. */ + for (i = 0; i < num_events; i++) { +- ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); +- time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); ++ ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); ++ time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + if (mode == 0) { + /* data, ev */ + if (bufsz) { +@@ -2190,7 +1977,7 @@ + time, ev); + } + } else { +- data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); ++ data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + if (bufsz) { + pos += scnprintf(*buf + pos, bufsz - pos, + "EVT_LOGT:%010u:0x%08x:%04u\n", +@@ -2261,13 +2048,12 @@ + int pos = 0; + size_t bufsz = 0; + +- if (priv->ucode_type == UCODE_INIT) { +- base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); ++ base = priv->device_pointers.log_event_table; ++ if (priv->ucode_type == UCODE_SUBTYPE_INIT) { + logsize = priv->_agn.init_evtlog_size; + if (!base) + base = priv->_agn.init_evtlog_ptr; + } else { +- base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + logsize = priv->_agn.inst_evtlog_size; + if (!base) + base = priv->_agn.inst_evtlog_ptr; +@@ -2276,7 +2062,9 @@ + if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + IWL_ERR(priv, + "Invalid event log pointer 0x%08X for %s uCode\n", +- base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); ++ base, ++ (priv->ucode_type == UCODE_SUBTYPE_INIT) ++ ? "Init" : "RT"); + return -EINVAL; + } + +@@ -2423,30 +2211,14 @@ + * from protocol/runtime uCode (initialization uCode's + * Alive gets handled by iwl_init_alive_start()). + */ +-static void iwl_alive_start(struct iwl_priv *priv) ++static int iwl_alive_start(struct iwl_priv *priv) + { + int ret = 0; + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + +- IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); +- +- /* Initialize uCode has loaded Runtime uCode ... verify inst image. +- * This is a paranoid check, because we would not have gotten the +- * "runtime" alive if code weren't properly loaded. */ +- if (iwl_verify_ucode(priv)) { +- /* Runtime instruction load was bad; +- * take it all the way back down so we can try again */ +- IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n"); +- goto restart; +- } +- +- ret = priv->cfg->ops->lib->alive_notify(priv); +- if (ret) { +- IWL_WARN(priv, +- "Could not complete ALIVE transition [ntf]: %d\n", ret); +- goto restart; +- } ++ iwl_reset_ict(priv); + ++ IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); + + /* After the ALIVE response, we can send host commands to the uCode */ + set_bit(STATUS_ALIVE, &priv->status); +@@ -2455,7 +2227,7 @@ + iwl_setup_watchdog(priv); + + if (iwl_is_rfkill(priv)) +- return; ++ return -ERFKILL; + + /* download priority table before any calibration request */ + if (priv->cfg->bt_params && +@@ -2469,10 +2241,14 @@ + iwlagn_send_prio_tbl(priv); + + /* FIXME: w/a to force change uCode BT state machine */ +- iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, +- BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); +- iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, +- BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); ++ ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, ++ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); ++ if (ret) ++ return ret; ++ ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, ++ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); ++ if (ret) ++ return ret; + } + if (priv->hw_params.calib_rt_cfg) + iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg); +@@ -2514,30 +2290,23 @@ + set_bit(STATUS_READY, &priv->status); + + /* Configure the adapter for unassociated operation */ +- iwlcore_commit_rxon(priv, ctx); ++ ret = iwlcore_commit_rxon(priv, ctx); ++ if (ret) ++ return ret; + + /* At this point, the NIC is initialized and operational */ + iwl_rf_kill_ct_config(priv); + + IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); +- wake_up_interruptible(&priv->wait_command_queue); +- +- iwl_power_update_mode(priv, true); +- IWL_DEBUG_INFO(priv, "Updated power mode\n"); + +- +- return; +- +- restart: +- queue_work(priv->workqueue, &priv->restart); ++ return iwl_power_update_mode(priv, true); + } + + static void iwl_cancel_deferred_work(struct iwl_priv *priv); + + static void __iwl_down(struct iwl_priv *priv) + { +- unsigned long flags; +- int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); ++ int exit_pending; + + IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); + +@@ -2563,40 +2332,15 @@ + priv->bt_full_concurrent = false; + priv->bt_ci_compliance = 0; + +- /* Unblock any waiting calls */ +- wake_up_interruptible_all(&priv->wait_command_queue); +- + /* Wipe out the EXIT_PENDING status bit if we are not actually + * exiting the module */ + if (!exit_pending) + clear_bit(STATUS_EXIT_PENDING, &priv->status); + +- /* stop and reset the on-board processor */ +- iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); +- +- /* tell the device to stop sending interrupts */ +- spin_lock_irqsave(&priv->lock, flags); +- iwl_disable_interrupts(priv); +- spin_unlock_irqrestore(&priv->lock, flags); +- iwl_synchronize_irq(priv); +- + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + +- /* If we have not previously called iwl_init() then +- * clear all bits but the RF Kill bit and return */ +- if (!iwl_is_init(priv)) { +- priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << +- STATUS_RF_KILL_HW | +- test_bit(STATUS_GEO_CONFIGURED, &priv->status) << +- STATUS_GEO_CONFIGURED | +- test_bit(STATUS_EXIT_PENDING, &priv->status) << +- STATUS_EXIT_PENDING; +- goto exit; +- } +- +- /* ...otherwise clear out all the status bits but the RF Kill +- * bit and continue taking the NIC down. */ ++ /* Clear out all status bits but a few that are stable across reset */ + priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << + STATUS_RF_KILL_HW | + test_bit(STATUS_GEO_CONFIGURED, &priv->status) << +@@ -2606,25 +2350,7 @@ + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; + +- /* device going down, Stop using ICT table */ +- if (priv->cfg->ops->lib->isr_ops.disable) +- priv->cfg->ops->lib->isr_ops.disable(priv); +- +- iwlagn_txq_ctx_stop(priv); +- iwlagn_rxq_stop(priv); +- +- /* Power-down device's busmaster DMA clocks */ +- iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); +- udelay(5); +- +- /* Make sure (redundant) we've released our request to stay awake */ +- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +- +- /* Stop the device, and put it in low power state */ +- iwl_apm_stop(priv); +- +- exit: +- memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); ++ iwlagn_stop_device(priv); + + dev_kfree_skb(priv->beacon_skb); + priv->beacon_skb = NULL; +@@ -2644,9 +2370,10 @@ + + #define HW_READY_TIMEOUT (50) + ++/* Note: returns poll_bit return value, which is >= 0 if success */ + static int iwl_set_hw_ready(struct iwl_priv *priv) + { +- int ret = 0; ++ int ret; + + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); +@@ -2656,25 +2383,21 @@ + CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, + CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, + HW_READY_TIMEOUT); +- if (ret != -ETIMEDOUT) +- priv->hw_ready = true; +- else +- priv->hw_ready = false; + +- IWL_DEBUG_INFO(priv, "hardware %s\n", +- (priv->hw_ready == 1) ? "ready" : "not ready"); ++ IWL_DEBUG_INFO(priv, "hardware%s ready\n", ret < 0 ? " not" : ""); + return ret; + } + +-static int iwl_prepare_card_hw(struct iwl_priv *priv) ++/* Note: returns standard 0/-ERROR code */ ++int iwl_prepare_card_hw(struct iwl_priv *priv) + { +- int ret = 0; ++ int ret; + + IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter\n"); + + ret = iwl_set_hw_ready(priv); +- if (priv->hw_ready) +- return ret; ++ if (ret >= 0) ++ return 0; + + /* If HW is not ready, prepare the conditions to check again */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, +@@ -2684,10 +2407,13 @@ + ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, + CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); + +- /* HW should be ready by now, check again. */ +- if (ret != -ETIMEDOUT) +- iwl_set_hw_ready(priv); ++ if (ret < 0) ++ return ret; + ++ /* HW should be ready by now, check again. */ ++ ret = iwl_set_hw_ready(priv); ++ if (ret >= 0) ++ return 0; + return ret; + } + +@@ -2696,19 +2422,15 @@ + static int __iwl_up(struct iwl_priv *priv) + { + struct iwl_rxon_context *ctx; +- int i; + int ret; + ++ lockdep_assert_held(&priv->mutex); ++ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); + return -EIO; + } + +- if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { +- IWL_ERR(priv, "ucode not available for device bringup\n"); +- return -EIO; +- } +- + for_each_context(priv, ctx) { + ret = iwlagn_alloc_bcast_station(priv, ctx); + if (ret) { +@@ -2717,89 +2439,33 @@ + } + } + +- iwl_prepare_card_hw(priv); +- +- if (!priv->hw_ready) { +- IWL_WARN(priv, "Exit HW not ready\n"); +- return -EIO; +- } +- +- /* If platform's RF_KILL switch is NOT set to KILL */ +- if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) +- clear_bit(STATUS_RF_KILL_HW, &priv->status); +- else +- set_bit(STATUS_RF_KILL_HW, &priv->status); +- +- if (iwl_is_rfkill(priv)) { +- wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); +- +- iwl_enable_interrupts(priv); +- IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); +- return 0; ++ ret = iwlagn_run_init_ucode(priv); ++ if (ret) { ++ IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret); ++ goto error; + } + +- iwl_write32(priv, CSR_INT, 0xFFFFFFFF); +- +- /* must be initialised before iwl_hw_nic_init */ +- if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) +- priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; +- else +- priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; +- +- ret = iwlagn_hw_nic_init(priv); ++ ret = iwlagn_load_ucode_wait_alive(priv, ++ &priv->ucode_rt, ++ UCODE_SUBTYPE_REGULAR, ++ UCODE_SUBTYPE_REGULAR_NEW); + if (ret) { +- IWL_ERR(priv, "Unable to init nic\n"); +- return ret; ++ IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret); ++ goto error; + } + +- /* make sure rfkill handshake bits are cleared */ +- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); +- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, +- CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); +- +- /* clear (again), then enable host interrupts */ +- iwl_write32(priv, CSR_INT, 0xFFFFFFFF); +- iwl_enable_interrupts(priv); +- +- /* really make sure rfkill handshake bits are cleared */ +- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); +- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); +- +- /* Copy original ucode data image from disk into backup cache. +- * This will be used to initialize the on-board processor's +- * data SRAM for a clean start when the runtime program first loads. */ +- memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, +- priv->ucode_data.len); +- +- for (i = 0; i < MAX_HW_RESTARTS; i++) { +- +- /* load bootstrap state machine, +- * load bootstrap program into processor's memory, +- * prepare to load the "initialize" uCode */ +- ret = priv->cfg->ops->lib->load_ucode(priv); +- +- if (ret) { +- IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n", +- ret); +- continue; +- } +- +- /* start card; "initialize" will load runtime ucode */ +- iwl_nic_start(priv); +- +- IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); +- +- return 0; +- } ++ ret = iwl_alive_start(priv); ++ if (ret) ++ goto error; ++ return 0; + ++ error: + set_bit(STATUS_EXIT_PENDING, &priv->status); + __iwl_down(priv); + clear_bit(STATUS_EXIT_PENDING, &priv->status); + +- /* tried to restart and config the device for as long as our +- * patience could withstand */ +- IWL_ERR(priv, "Unable to initialize device after %d attempts.\n", i); +- return -EIO; ++ IWL_ERR(priv, "Unable to initialize device.\n"); ++ return ret; + } + + +@@ -2809,36 +2475,6 @@ + * + *****************************************************************************/ + +-static void iwl_bg_init_alive_start(struct work_struct *data) +-{ +- struct iwl_priv *priv = +- container_of(data, struct iwl_priv, init_alive_start.work); +- +- if (test_bit(STATUS_EXIT_PENDING, &priv->status)) +- return; +- +- mutex_lock(&priv->mutex); +- priv->cfg->ops->lib->init_alive_start(priv); +- mutex_unlock(&priv->mutex); +-} +- +-static void iwl_bg_alive_start(struct work_struct *data) +-{ +- struct iwl_priv *priv = +- container_of(data, struct iwl_priv, alive_start.work); +- +- if (test_bit(STATUS_EXIT_PENDING, &priv->status)) +- return; +- +- /* enable dram interrupt */ +- if (priv->cfg->ops->lib->isr_ops.reset) +- priv->cfg->ops->lib->isr_ops.reset(priv); +- +- mutex_lock(&priv->mutex); +- iwl_alive_start(priv); +- mutex_unlock(&priv->mutex); +-} +- + static void iwl_bg_run_time_calib_work(struct work_struct *work) + { + struct iwl_priv *priv = container_of(work, struct iwl_priv, +@@ -2853,22 +2489,49 @@ + } + + if (priv->start_calib) { +- if (iwl_bt_statistics(priv)) { +- iwl_chain_noise_calibration(priv, +- (void *)&priv->_agn.statistics_bt); +- iwl_sensitivity_calibration(priv, +- (void *)&priv->_agn.statistics_bt); +- } else { +- iwl_chain_noise_calibration(priv, +- (void *)&priv->_agn.statistics); +- iwl_sensitivity_calibration(priv, +- (void *)&priv->_agn.statistics); +- } ++ iwl_chain_noise_calibration(priv); ++ iwl_sensitivity_calibration(priv); + } + + mutex_unlock(&priv->mutex); + } + ++static void iwlagn_prepare_restart(struct iwl_priv *priv) ++{ ++ struct iwl_rxon_context *ctx; ++ bool bt_full_concurrent; ++ u8 bt_ci_compliance; ++ u8 bt_load; ++ u8 bt_status; ++ ++ lockdep_assert_held(&priv->mutex); ++ ++ for_each_context(priv, ctx) ++ ctx->vif = NULL; ++ priv->is_open = 0; ++ ++ /* ++ * __iwl_down() will clear the BT status variables, ++ * which is correct, but when we restart we really ++ * want to keep them so restore them afterwards. ++ * ++ * The restart process will later pick them up and ++ * re-configure the hw when we reconfigure the BT ++ * command. ++ */ ++ bt_full_concurrent = priv->bt_full_concurrent; ++ bt_ci_compliance = priv->bt_ci_compliance; ++ bt_load = priv->bt_traffic_load; ++ bt_status = priv->bt_status; ++ ++ __iwl_down(priv); ++ ++ priv->bt_full_concurrent = bt_full_concurrent; ++ priv->bt_ci_compliance = bt_ci_compliance; ++ priv->bt_traffic_load = bt_load; ++ priv->bt_status = bt_status; ++} ++ + static void iwl_bg_restart(struct work_struct *data) + { + struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); +@@ -2877,50 +2540,13 @@ + return; + + if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { +- struct iwl_rxon_context *ctx; +- bool bt_full_concurrent; +- u8 bt_ci_compliance; +- u8 bt_load; +- u8 bt_status; +- + mutex_lock(&priv->mutex); +- for_each_context(priv, ctx) +- ctx->vif = NULL; +- priv->is_open = 0; +- +- /* +- * __iwl_down() will clear the BT status variables, +- * which is correct, but when we restart we really +- * want to keep them so restore them afterwards. +- * +- * The restart process will later pick them up and +- * re-configure the hw when we reconfigure the BT +- * command. +- */ +- bt_full_concurrent = priv->bt_full_concurrent; +- bt_ci_compliance = priv->bt_ci_compliance; +- bt_load = priv->bt_traffic_load; +- bt_status = priv->bt_status; +- +- __iwl_down(priv); +- +- priv->bt_full_concurrent = bt_full_concurrent; +- priv->bt_ci_compliance = bt_ci_compliance; +- priv->bt_traffic_load = bt_load; +- priv->bt_status = bt_status; +- ++ iwlagn_prepare_restart(priv); + mutex_unlock(&priv->mutex); + iwl_cancel_deferred_work(priv); + ieee80211_restart_hw(priv->hw); + } else { +- iwl_down(priv); +- +- if (test_bit(STATUS_EXIT_PENDING, &priv->status)) +- return; +- +- mutex_lock(&priv->mutex); +- __iwl_up(priv); +- mutex_unlock(&priv->mutex); ++ WARN_ON(1); + } + } + +@@ -3031,8 +2657,6 @@ + * + *****************************************************************************/ + +-#define UCODE_READY_TIMEOUT (4 * HZ) +- + /* + * Not a mac80211 entry point function, but it fits in with all the + * other mac80211 functions grouped here. +@@ -3055,14 +2679,16 @@ + + hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + +- if (!priv->cfg->base_params->broken_powersave) +- hw->flags |= IEEE80211_HW_SUPPORTS_PS | +- IEEE80211_HW_SUPPORTS_DYNAMIC_PS; ++ hw->flags |= IEEE80211_HW_SUPPORTS_PS | ++ IEEE80211_HW_SUPPORTS_DYNAMIC_PS; + + if (priv->cfg->sku & IWL_SKU_N) + hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | + IEEE80211_HW_SUPPORTS_STATIC_SMPS; + ++ if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP) ++ hw->flags |= IEEE80211_HW_MFP_CAPABLE; ++ + hw->sta_data_size = sizeof(struct iwl_station_priv); + hw->vif_data_size = sizeof(struct iwl_vif_priv); + +@@ -3112,7 +2738,7 @@ + } + + +-int iwlagn_mac_start(struct ieee80211_hw *hw) ++static int iwlagn_mac_start(struct ieee80211_hw *hw) + { + struct iwl_priv *priv = hw->priv; + int ret; +@@ -3123,37 +2749,23 @@ + mutex_lock(&priv->mutex); + ret = __iwl_up(priv); + mutex_unlock(&priv->mutex); +- + if (ret) + return ret; + +- if (iwl_is_rfkill(priv)) +- goto out; +- + IWL_DEBUG_INFO(priv, "Start UP work done.\n"); + +- /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from +- * mac80211 will not be run successfully. */ +- ret = wait_event_interruptible_timeout(priv->wait_command_queue, +- test_bit(STATUS_READY, &priv->status), +- UCODE_READY_TIMEOUT); +- if (!ret) { +- if (!test_bit(STATUS_READY, &priv->status)) { +- IWL_ERR(priv, "START_ALIVE timeout after %dms.\n", +- jiffies_to_msecs(UCODE_READY_TIMEOUT)); +- return -ETIMEDOUT; +- } +- } ++ /* Now we should be done, and the READY bit should be set. */ ++ if (WARN_ON(!test_bit(STATUS_READY, &priv->status))) ++ ret = -EIO; + + iwlagn_led_enable(priv); + +-out: + priv->is_open = 1; + IWL_DEBUG_MAC80211(priv, "leave\n"); + return 0; + } + +-void iwlagn_mac_stop(struct ieee80211_hw *hw) ++static void iwlagn_mac_stop(struct ieee80211_hw *hw) + { + struct iwl_priv *priv = hw->priv; + +@@ -3176,7 +2788,7 @@ + IWL_DEBUG_MAC80211(priv, "leave\n"); + } + +-void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ++static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) + { + struct iwl_priv *priv = hw->priv; + +@@ -3191,11 +2803,11 @@ + IWL_DEBUG_MACDUMP(priv, "leave\n"); + } + +-void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, +- struct ieee80211_vif *vif, +- struct ieee80211_key_conf *keyconf, +- struct ieee80211_sta *sta, +- u32 iv32, u16 *phase1key) ++static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_key_conf *keyconf, ++ struct ieee80211_sta *sta, ++ u32 iv32, u16 *phase1key) + { + struct iwl_priv *priv = hw->priv; + struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; +@@ -3208,9 +2820,10 @@ + IWL_DEBUG_MAC80211(priv, "leave\n"); + } + +-int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +- struct ieee80211_vif *vif, struct ieee80211_sta *sta, +- struct ieee80211_key_conf *key) ++static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, ++ struct ieee80211_key_conf *key) + { + struct iwl_priv *priv = hw->priv; + struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; +@@ -3221,7 +2834,7 @@ + + IWL_DEBUG_MAC80211(priv, "enter\n"); + +- if (priv->cfg->mod_params->sw_crypto) { ++ if (iwlagn_mod_params.sw_crypto) { + IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); + return -EOPNOTSUPP; + } +@@ -3285,11 +2898,11 @@ + return ret; + } + +-int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, +- struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size) ++static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ enum ieee80211_ampdu_mlme_action action, ++ struct ieee80211_sta *sta, u16 tid, u16 *ssn, ++ u8 buf_size) + { + struct iwl_priv *priv = hw->priv; + int ret = -EINVAL; +@@ -3348,6 +2961,10 @@ + } + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: ++ buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); ++ ++ iwlagn_txq_agg_queue_setup(priv, sta, tid, buf_size); ++ + /* + * If the limit is 0, then it wasn't initialised yet, + * use the default. We can do that since we take the +@@ -3392,9 +3009,9 @@ + return ret; + } + +-int iwlagn_mac_sta_add(struct ieee80211_hw *hw, +- struct ieee80211_vif *vif, +- struct ieee80211_sta *sta) ++static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta) + { + struct iwl_priv *priv = hw->priv; + struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; +@@ -3435,8 +3052,8 @@ + return 0; + } + +-void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, +- struct ieee80211_channel_switch *ch_switch) ++static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, ++ struct ieee80211_channel_switch *ch_switch) + { + struct iwl_priv *priv = hw->priv; + const struct iwl_channel_info *ch_info; +@@ -3457,21 +3074,22 @@ + + IWL_DEBUG_MAC80211(priv, "enter\n"); + ++ mutex_lock(&priv->mutex); ++ + if (iwl_is_rfkill(priv)) +- goto out_exit; ++ goto out; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + test_bit(STATUS_SCANNING, &priv->status)) +- goto out_exit; ++ goto out; + + if (!iwl_is_associated_ctx(ctx)) +- goto out_exit; ++ goto out; + + /* channel switch in progress */ + if (priv->switch_rxon.switch_in_progress == true) +- goto out_exit; ++ goto out; + +- mutex_lock(&priv->mutex); + if (priv->cfg->ops->lib->set_channel_switch) { + + ch = channel->hw_value; +@@ -3527,16 +3145,15 @@ + } + out: + mutex_unlock(&priv->mutex); +-out_exit: + if (!priv->switch_rxon.switch_in_progress) + ieee80211_chswitch_done(ctx->vif, false); + IWL_DEBUG_MAC80211(priv, "leave\n"); + } + +-void iwlagn_configure_filter(struct ieee80211_hw *hw, +- unsigned int changed_flags, +- unsigned int *total_flags, +- u64 multicast) ++static void iwlagn_configure_filter(struct ieee80211_hw *hw, ++ unsigned int changed_flags, ++ unsigned int *total_flags, ++ u64 multicast) + { + struct iwl_priv *priv = hw->priv; + __le32 filter_or = 0, filter_nand = 0; +@@ -3583,7 +3200,7 @@ + FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; + } + +-void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) ++static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) + { + struct iwl_priv *priv = hw->priv; + +@@ -3729,8 +3346,6 @@ + INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); + INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency); + INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); +- INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); +- INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); + INIT_DELAYED_WORK(&priv->_agn.hw_roc_work, iwlagn_bg_roc_done); + + iwl_setup_scan_deferred_work(priv); +@@ -3750,12 +3365,8 @@ + priv->watchdog.data = (unsigned long)priv; + priv->watchdog.function = iwl_bg_watchdog; + +- if (!priv->cfg->base_params->use_isr_legacy) +- tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) +- iwl_irq_tasklet, (unsigned long)priv); +- else +- tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) +- iwl_irq_tasklet_legacy, (unsigned long)priv); ++ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) ++ iwl_irq_tasklet, (unsigned long)priv); + } + + static void iwl_cancel_deferred_work(struct iwl_priv *priv) +@@ -3763,8 +3374,6 @@ + if (priv->cfg->ops->lib->cancel_deferred_work) + priv->cfg->ops->lib->cancel_deferred_work(priv); + +- cancel_delayed_work_sync(&priv->init_alive_start); +- cancel_delayed_work(&priv->alive_start); + cancel_work_sync(&priv->run_time_calib_work); + cancel_work_sync(&priv->beacon_update); + +@@ -3808,7 +3417,6 @@ + INIT_LIST_HEAD(&priv->free_frames); + + mutex_init(&priv->mutex); +- mutex_init(&priv->sync_cmd_mutex); + + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; +@@ -3845,12 +3453,6 @@ + priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF; + } + +- /* Set the tx_power_user_lmt to the lowest power level +- * this value will get overwritten by channel max power avg +- * from eeprom */ +- priv->tx_power_user_lmt = IWLAGN_TX_POWER_TARGET_POWER_MIN; +- priv->tx_power_next = IWLAGN_TX_POWER_TARGET_POWER_MIN; +- + ret = iwl_init_channel_map(priv); + if (ret) { + IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); +@@ -3907,26 +3509,27 @@ + .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, + }; + +-static void iwl_hw_detect(struct iwl_priv *priv) ++static u32 iwl_hw_detect(struct iwl_priv *priv) + { +- priv->hw_rev = _iwl_read32(priv, CSR_HW_REV); +- priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG); +- priv->rev_id = priv->pci_dev->revision; +- IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); ++ u8 rev_id; ++ ++ pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); ++ IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); ++ return iwl_read32(priv, CSR_HW_REV); + } + + static int iwl_set_hw_params(struct iwl_priv *priv) + { + priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; + priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; +- if (priv->cfg->mod_params->amsdu_size_8K) ++ if (iwlagn_mod_params.amsdu_size_8K) + priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K); + else + priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K); + + priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL; + +- if (priv->cfg->mod_params->disable_11n) ++ if (iwlagn_mod_params.disable_11n) + priv->cfg->sku &= ~IWL_SKU_N; + + /* Device-specific setup */ +@@ -3955,6 +3558,28 @@ + 7, 6, 5, 4, + }; + ++/* This function both allocates and initializes hw and priv. */ ++static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg) ++{ ++ struct iwl_priv *priv; ++ /* mac80211 allocates memory for this device instance, including ++ * space for this driver's private structure */ ++ struct ieee80211_hw *hw; ++ ++ hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops); ++ if (hw == NULL) { ++ pr_err("%s: Can not allocate network device\n", ++ cfg->name); ++ goto out; ++ } ++ ++ priv = hw->priv; ++ priv->hw = hw; ++ ++out: ++ return hw; ++} ++ + static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + { + int err = 0, i; +@@ -3963,19 +3588,12 @@ + struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); + unsigned long flags; + u16 pci_cmd, num_mac; ++ u32 hw_rev; + + /************************ + * 1. Allocating HW data + ************************/ + +- /* Disabling hardware scan means that mac80211 will perform scans +- * "the hard way", rather than using device's scan. */ +- if (cfg->mod_params->disable_hw_scan) { +- dev_printk(KERN_DEBUG, &(pdev->dev), +- "sw scan support is deprecated\n"); +- iwlagn_hw_ops.hw_scan = NULL; +- } +- + hw = iwl_alloc_all(cfg); + if (!hw) { + err = -ENOMEM; +@@ -3984,6 +3602,8 @@ + priv = hw->priv; + /* At this point both hw and priv are allocated. */ + ++ priv->ucode_type = UCODE_SUBTYPE_NONE_LOADED; ++ + /* + * The default context is always valid, + * more may be discovered when firmware +@@ -4116,16 +3736,15 @@ + */ + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + +- iwl_hw_detect(priv); ++ hw_rev = iwl_hw_detect(priv); + IWL_INFO(priv, "Detected %s, REV=0x%X\n", +- priv->cfg->name, priv->hw_rev); ++ priv->cfg->name, hw_rev); + + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); + +- iwl_prepare_card_hw(priv); +- if (!priv->hw_ready) { ++ if (iwl_prepare_card_hw(priv)) { + IWL_WARN(priv, "Failed, HW not ready\n"); + goto out_iounmap; + } +@@ -4134,7 +3753,7 @@ + * 4. Read EEPROM + *****************/ + /* Read the EEPROM */ +- err = iwl_eeprom_init(priv); ++ err = iwl_eeprom_init(priv, hw_rev); + if (err) { + IWL_ERR(priv, "Unable to init EEPROM\n"); + goto out_iounmap; +@@ -4186,10 +3805,9 @@ + + pci_enable_msi(priv->pci_dev); + +- if (priv->cfg->ops->lib->isr_ops.alloc) +- priv->cfg->ops->lib->isr_ops.alloc(priv); ++ iwl_alloc_isr_ict(priv); + +- err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr, ++ err = request_irq(priv->pci_dev->irq, iwl_isr_ict, + IRQF_SHARED, DRV_NAME, priv); + if (err) { + IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); +@@ -4236,8 +3854,7 @@ + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + free_irq(priv->pci_dev->irq, priv); +- if (priv->cfg->ops->lib->isr_ops.free) +- priv->cfg->ops->lib->isr_ops.free(priv); ++ iwl_free_isr_ict(priv); + out_disable_msi: + pci_disable_msi(priv->pci_dev); + iwl_uninit_drv(priv); +@@ -4283,17 +3900,9 @@ + if (priv->mac80211_registered) { + ieee80211_unregister_hw(priv->hw); + priv->mac80211_registered = 0; +- } else { +- iwl_down(priv); + } + +- /* +- * Make sure device is reset to low power before unloading driver. +- * This may be redundant with iwl_down(), but there are paths to +- * run iwl_down() without calling apm_ops.stop(), and there are +- * paths to avoid running iwl_down() at all before leaving driver. +- * This (inexpensive) call *makes sure* device is reset. +- */ ++ /* Reset to low power before unloading driver. */ + iwl_apm_stop(priv); + + iwl_tt_exit(priv); +@@ -4335,8 +3944,7 @@ + + iwl_uninit_drv(priv); + +- if (priv->cfg->ops->lib->isr_ops.free) +- priv->cfg->ops->lib->isr_ops.free(priv); ++ iwl_free_isr_ict(priv); + + dev_kfree_skb(priv->beacon_skb); + +@@ -4521,21 +4129,21 @@ + {IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)}, + +-/* 200 Series */ +- {IWL_PCI_DEVICE(0x0894, 0x0022, iwl200_bgn_cfg)}, +- {IWL_PCI_DEVICE(0x0895, 0x0222, iwl200_bgn_cfg)}, +- {IWL_PCI_DEVICE(0x0894, 0x0422, iwl200_bgn_cfg)}, +- {IWL_PCI_DEVICE(0x0894, 0x0026, iwl200_bg_cfg)}, +- {IWL_PCI_DEVICE(0x0895, 0x0226, iwl200_bg_cfg)}, +- {IWL_PCI_DEVICE(0x0894, 0x0426, iwl200_bg_cfg)}, +- +-/* 230 Series */ +- {IWL_PCI_DEVICE(0x0892, 0x0062, iwl230_bgn_cfg)}, +- {IWL_PCI_DEVICE(0x0893, 0x0262, iwl230_bgn_cfg)}, +- {IWL_PCI_DEVICE(0x0892, 0x0462, iwl230_bgn_cfg)}, +- {IWL_PCI_DEVICE(0x0892, 0x0066, iwl230_bg_cfg)}, +- {IWL_PCI_DEVICE(0x0893, 0x0266, iwl230_bg_cfg)}, +- {IWL_PCI_DEVICE(0x0892, 0x0466, iwl230_bg_cfg)}, ++/* 105 Series */ ++ {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)}, ++ {IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)}, ++ {IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)}, ++ {IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)}, ++ {IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)}, ++ {IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)}, ++ ++/* 135 Series */ ++ {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)}, ++ {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)}, ++ {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)}, ++ {IWL_PCI_DEVICE(0x0892, 0x0066, iwl135_bg_cfg)}, ++ {IWL_PCI_DEVICE(0x0893, 0x0266, iwl135_bg_cfg)}, ++ {IWL_PCI_DEVICE(0x0892, 0x0466, iwl135_bg_cfg)}, + + {0} + }; +@@ -4585,43 +4193,21 @@ + module_init(iwl_init); + + #ifdef CONFIG_IWLWIFI_DEBUG +-module_param_named(debug50, iwl_debug_level, uint, S_IRUGO); +-MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)"); + module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); + MODULE_PARM_DESC(debug, "debug output mask"); + #endif + +-module_param_named(swcrypto50, iwlagn_mod_params.sw_crypto, bool, S_IRUGO); +-MODULE_PARM_DESC(swcrypto50, +- "using crypto in software (default 0 [hardware]) (deprecated)"); + module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO); + MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); +-module_param_named(queues_num50, +- iwlagn_mod_params.num_of_queues, int, S_IRUGO); +-MODULE_PARM_DESC(queues_num50, +- "number of hw queues in 50xx series (deprecated)"); + module_param_named(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO); + MODULE_PARM_DESC(queues_num, "number of hw queues."); +-module_param_named(11n_disable50, iwlagn_mod_params.disable_11n, int, S_IRUGO); +-MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality (deprecated)"); + module_param_named(11n_disable, iwlagn_mod_params.disable_11n, int, S_IRUGO); + MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); +-module_param_named(amsdu_size_8K50, iwlagn_mod_params.amsdu_size_8K, +- int, S_IRUGO); +-MODULE_PARM_DESC(amsdu_size_8K50, +- "enable 8K amsdu size in 50XX series (deprecated)"); + module_param_named(amsdu_size_8K, iwlagn_mod_params.amsdu_size_8K, + int, S_IRUGO); + MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); +-module_param_named(fw_restart50, iwlagn_mod_params.restart_fw, int, S_IRUGO); +-MODULE_PARM_DESC(fw_restart50, +- "restart firmware in case of error (deprecated)"); + module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO); + MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); +-module_param_named( +- disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO); +-MODULE_PARM_DESC(disable_hw_scan, +- "disable hardware scanning (default 0) (deprecated)"); + + module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int, + S_IRUGO); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-calib.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-calib.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-calib.c 2011-05-05 23:29:45.361440365 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +@@ -605,7 +605,7 @@ + IWL_DEBUG_CALIB(priv, "<lock, flags); +- if (iwl_bt_statistics(priv)) { +- rx_info = &(((struct iwl_bt_notif_statistics *)resp)-> +- rx.general.common); +- ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm); +- cck = &(((struct iwl_bt_notif_statistics *)resp)->rx.cck); +- } else { +- rx_info = &(((struct iwl_notif_statistics *)resp)->rx.general); +- ofdm = &(((struct iwl_notif_statistics *)resp)->rx.ofdm); +- cck = &(((struct iwl_notif_statistics *)resp)->rx.cck); +- } ++ rx_info = &priv->statistics.rx_non_phy; ++ ofdm = &priv->statistics.rx_ofdm; ++ cck = &priv->statistics.rx_cck; + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { + IWL_DEBUG_CALIB(priv, "<< invalid data.\n"); + spin_unlock_irqrestore(&priv->lock, flags); +@@ -851,7 +844,7 @@ + * 1) Which antennas are connected. + * 2) Differential rx gain settings to balance the 3 receivers. + */ +-void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) ++void iwl_chain_noise_calibration(struct iwl_priv *priv) + { + struct iwl_chain_noise_data *data = NULL; + +@@ -896,13 +889,9 @@ + } + + spin_lock_irqsave(&priv->lock, flags); +- if (iwl_bt_statistics(priv)) { +- rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)-> +- rx.general.common); +- } else { +- rx_info = &(((struct iwl_notif_statistics *)stat_resp)-> +- rx.general); +- } ++ ++ rx_info = &priv->statistics.rx_non_phy; ++ + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { + IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n"); + spin_unlock_irqrestore(&priv->lock, flags); +@@ -911,19 +900,9 @@ + + rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK); + rxon_chnum = le16_to_cpu(ctx->staging.channel); +- if (iwl_bt_statistics(priv)) { +- stat_band24 = !!(((struct iwl_bt_notif_statistics *) +- stat_resp)->flag & +- STATISTICS_REPLY_FLG_BAND_24G_MSK); +- stat_chnum = le32_to_cpu(((struct iwl_bt_notif_statistics *) +- stat_resp)->flag) >> 16; +- } else { +- stat_band24 = !!(((struct iwl_notif_statistics *) +- stat_resp)->flag & +- STATISTICS_REPLY_FLG_BAND_24G_MSK); +- stat_chnum = le32_to_cpu(((struct iwl_notif_statistics *) +- stat_resp)->flag) >> 16; +- } ++ stat_band24 = ++ !!(priv->statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK); ++ stat_chnum = le32_to_cpu(priv->statistics.flag) >> 16; + + /* Make sure we accumulate data for just the associated channel + * (even if scanning). */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-calib.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-calib.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-calib.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-calib.h 2011-05-05 23:29:45.373440511 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +@@ -66,8 +66,8 @@ + #include "iwl-core.h" + #include "iwl-commands.h" + +-void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp); +-void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp); ++void iwl_chain_noise_calibration(struct iwl_priv *priv); ++void iwl_sensitivity_calibration(struct iwl_priv *priv); + + void iwl_init_sensitivity(struct iwl_priv *priv); + void iwl_reset_run_time_calib(struct iwl_priv *priv); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,1073 +0,0 @@ +-/****************************************************************************** +-* +-* GPL LICENSE SUMMARY +-* +-* Copyright(c) 2008 - 2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, +-* USA +-* +-* The full GNU General Public License is included in this distribution +-* in the file called LICENSE.GPL. +-* +-* Contact Information: +-* Intel Linux Wireless +-* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +-*****************************************************************************/ +-#include "iwl-agn.h" +-#include "iwl-agn-debugfs.h" +- +-static const char *fmt_value = " %-30s %10u\n"; +-static const char *fmt_hex = " %-30s 0x%02X\n"; +-static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; +-static const char *fmt_header = +- "%-32s current cumulative delta max\n"; +- +-static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) +-{ +- int p = 0; +- u32 flag; +- +- if (iwl_bt_statistics(priv)) +- flag = le32_to_cpu(priv->_agn.statistics_bt.flag); +- else +- flag = le32_to_cpu(priv->_agn.statistics.flag); +- +- p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag); +- if (flag & UCODE_STATISTICS_CLEAR_MSK) +- p += scnprintf(buf + p, bufsz - p, +- "\tStatistics have been cleared\n"); +- p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", +- (flag & UCODE_STATISTICS_FREQUENCY_MSK) +- ? "2.4 GHz" : "5.2 GHz"); +- p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", +- (flag & UCODE_STATISTICS_NARROW_BAND_MSK) +- ? "enabled" : "disabled"); +- +- return p; +-} +- +-ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos) +- { +- struct iwl_priv *priv = file->private_data; +- int pos = 0; +- char *buf; +- int bufsz = sizeof(struct statistics_rx_phy) * 40 + +- sizeof(struct statistics_rx_non_phy) * 40 + +- sizeof(struct statistics_rx_ht_phy) * 40 + 400; +- ssize_t ret; +- struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; +- struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; +- struct statistics_rx_non_phy *general, *accum_general; +- struct statistics_rx_non_phy *delta_general, *max_general; +- struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; +- +- if (!iwl_is_alive(priv)) +- return -EAGAIN; +- +- buf = kzalloc(bufsz, GFP_KERNEL); +- if (!buf) { +- IWL_ERR(priv, "Can not allocate Buffer\n"); +- return -ENOMEM; +- } +- +- /* +- * the statistic information display here is based on +- * the last statistics notification from uCode +- * might not reflect the current uCode activity +- */ +- if (iwl_bt_statistics(priv)) { +- ofdm = &priv->_agn.statistics_bt.rx.ofdm; +- cck = &priv->_agn.statistics_bt.rx.cck; +- general = &priv->_agn.statistics_bt.rx.general.common; +- ht = &priv->_agn.statistics_bt.rx.ofdm_ht; +- accum_ofdm = &priv->_agn.accum_statistics_bt.rx.ofdm; +- accum_cck = &priv->_agn.accum_statistics_bt.rx.cck; +- accum_general = +- &priv->_agn.accum_statistics_bt.rx.general.common; +- accum_ht = &priv->_agn.accum_statistics_bt.rx.ofdm_ht; +- delta_ofdm = &priv->_agn.delta_statistics_bt.rx.ofdm; +- delta_cck = &priv->_agn.delta_statistics_bt.rx.cck; +- delta_general = +- &priv->_agn.delta_statistics_bt.rx.general.common; +- delta_ht = &priv->_agn.delta_statistics_bt.rx.ofdm_ht; +- max_ofdm = &priv->_agn.max_delta_bt.rx.ofdm; +- max_cck = &priv->_agn.max_delta_bt.rx.cck; +- max_general = &priv->_agn.max_delta_bt.rx.general.common; +- max_ht = &priv->_agn.max_delta_bt.rx.ofdm_ht; +- } else { +- ofdm = &priv->_agn.statistics.rx.ofdm; +- cck = &priv->_agn.statistics.rx.cck; +- general = &priv->_agn.statistics.rx.general; +- ht = &priv->_agn.statistics.rx.ofdm_ht; +- accum_ofdm = &priv->_agn.accum_statistics.rx.ofdm; +- accum_cck = &priv->_agn.accum_statistics.rx.cck; +- accum_general = &priv->_agn.accum_statistics.rx.general; +- accum_ht = &priv->_agn.accum_statistics.rx.ofdm_ht; +- delta_ofdm = &priv->_agn.delta_statistics.rx.ofdm; +- delta_cck = &priv->_agn.delta_statistics.rx.cck; +- delta_general = &priv->_agn.delta_statistics.rx.general; +- delta_ht = &priv->_agn.delta_statistics.rx.ofdm_ht; +- max_ofdm = &priv->_agn.max_delta.rx.ofdm; +- max_cck = &priv->_agn.max_delta.rx.cck; +- max_general = &priv->_agn.max_delta.rx.general; +- max_ht = &priv->_agn.max_delta.rx.ofdm_ht; +- } +- +- pos += iwl_statistics_flag(priv, buf, bufsz); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_header, "Statistics_Rx - OFDM:"); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "ina_cnt:", +- le32_to_cpu(ofdm->ina_cnt), +- accum_ofdm->ina_cnt, +- delta_ofdm->ina_cnt, max_ofdm->ina_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "fina_cnt:", +- le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, +- delta_ofdm->fina_cnt, max_ofdm->fina_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "plcp_err:", +- le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, +- delta_ofdm->plcp_err, max_ofdm->plcp_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "crc32_err:", +- le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, +- delta_ofdm->crc32_err, max_ofdm->crc32_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "overrun_err:", +- le32_to_cpu(ofdm->overrun_err), +- accum_ofdm->overrun_err, delta_ofdm->overrun_err, +- max_ofdm->overrun_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "early_overrun_err:", +- le32_to_cpu(ofdm->early_overrun_err), +- accum_ofdm->early_overrun_err, +- delta_ofdm->early_overrun_err, +- max_ofdm->early_overrun_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "crc32_good:", +- le32_to_cpu(ofdm->crc32_good), +- accum_ofdm->crc32_good, delta_ofdm->crc32_good, +- max_ofdm->crc32_good); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "false_alarm_cnt:", +- le32_to_cpu(ofdm->false_alarm_cnt), +- accum_ofdm->false_alarm_cnt, +- delta_ofdm->false_alarm_cnt, +- max_ofdm->false_alarm_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "fina_sync_err_cnt:", +- le32_to_cpu(ofdm->fina_sync_err_cnt), +- accum_ofdm->fina_sync_err_cnt, +- delta_ofdm->fina_sync_err_cnt, +- max_ofdm->fina_sync_err_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "sfd_timeout:", +- le32_to_cpu(ofdm->sfd_timeout), +- accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout, +- max_ofdm->sfd_timeout); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "fina_timeout:", +- le32_to_cpu(ofdm->fina_timeout), +- accum_ofdm->fina_timeout, delta_ofdm->fina_timeout, +- max_ofdm->fina_timeout); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "unresponded_rts:", +- le32_to_cpu(ofdm->unresponded_rts), +- accum_ofdm->unresponded_rts, +- delta_ofdm->unresponded_rts, +- max_ofdm->unresponded_rts); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "rxe_frame_lmt_ovrun:", +- le32_to_cpu(ofdm->rxe_frame_limit_overrun), +- accum_ofdm->rxe_frame_limit_overrun, +- delta_ofdm->rxe_frame_limit_overrun, +- max_ofdm->rxe_frame_limit_overrun); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "sent_ack_cnt:", +- le32_to_cpu(ofdm->sent_ack_cnt), +- accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt, +- max_ofdm->sent_ack_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "sent_cts_cnt:", +- le32_to_cpu(ofdm->sent_cts_cnt), +- accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt, +- max_ofdm->sent_cts_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "sent_ba_rsp_cnt:", +- le32_to_cpu(ofdm->sent_ba_rsp_cnt), +- accum_ofdm->sent_ba_rsp_cnt, +- delta_ofdm->sent_ba_rsp_cnt, +- max_ofdm->sent_ba_rsp_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "dsp_self_kill:", +- le32_to_cpu(ofdm->dsp_self_kill), +- accum_ofdm->dsp_self_kill, +- delta_ofdm->dsp_self_kill, +- max_ofdm->dsp_self_kill); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "mh_format_err:", +- le32_to_cpu(ofdm->mh_format_err), +- accum_ofdm->mh_format_err, +- delta_ofdm->mh_format_err, +- max_ofdm->mh_format_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "re_acq_main_rssi_sum:", +- le32_to_cpu(ofdm->re_acq_main_rssi_sum), +- accum_ofdm->re_acq_main_rssi_sum, +- delta_ofdm->re_acq_main_rssi_sum, +- max_ofdm->re_acq_main_rssi_sum); +- +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_header, "Statistics_Rx - CCK:"); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "ina_cnt:", +- le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, +- delta_cck->ina_cnt, max_cck->ina_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "fina_cnt:", +- le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, +- delta_cck->fina_cnt, max_cck->fina_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "plcp_err:", +- le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, +- delta_cck->plcp_err, max_cck->plcp_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "crc32_err:", +- le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, +- delta_cck->crc32_err, max_cck->crc32_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "overrun_err:", +- le32_to_cpu(cck->overrun_err), +- accum_cck->overrun_err, delta_cck->overrun_err, +- max_cck->overrun_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "early_overrun_err:", +- le32_to_cpu(cck->early_overrun_err), +- accum_cck->early_overrun_err, +- delta_cck->early_overrun_err, +- max_cck->early_overrun_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "crc32_good:", +- le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, +- delta_cck->crc32_good, max_cck->crc32_good); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "false_alarm_cnt:", +- le32_to_cpu(cck->false_alarm_cnt), +- accum_cck->false_alarm_cnt, +- delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "fina_sync_err_cnt:", +- le32_to_cpu(cck->fina_sync_err_cnt), +- accum_cck->fina_sync_err_cnt, +- delta_cck->fina_sync_err_cnt, +- max_cck->fina_sync_err_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "sfd_timeout:", +- le32_to_cpu(cck->sfd_timeout), +- accum_cck->sfd_timeout, delta_cck->sfd_timeout, +- max_cck->sfd_timeout); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "fina_timeout:", +- le32_to_cpu(cck->fina_timeout), +- accum_cck->fina_timeout, delta_cck->fina_timeout, +- max_cck->fina_timeout); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "unresponded_rts:", +- le32_to_cpu(cck->unresponded_rts), +- accum_cck->unresponded_rts, delta_cck->unresponded_rts, +- max_cck->unresponded_rts); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "rxe_frame_lmt_ovrun:", +- le32_to_cpu(cck->rxe_frame_limit_overrun), +- accum_cck->rxe_frame_limit_overrun, +- delta_cck->rxe_frame_limit_overrun, +- max_cck->rxe_frame_limit_overrun); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "sent_ack_cnt:", +- le32_to_cpu(cck->sent_ack_cnt), +- accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt, +- max_cck->sent_ack_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "sent_cts_cnt:", +- le32_to_cpu(cck->sent_cts_cnt), +- accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt, +- max_cck->sent_cts_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "sent_ba_rsp_cnt:", +- le32_to_cpu(cck->sent_ba_rsp_cnt), +- accum_cck->sent_ba_rsp_cnt, +- delta_cck->sent_ba_rsp_cnt, +- max_cck->sent_ba_rsp_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "dsp_self_kill:", +- le32_to_cpu(cck->dsp_self_kill), +- accum_cck->dsp_self_kill, delta_cck->dsp_self_kill, +- max_cck->dsp_self_kill); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "mh_format_err:", +- le32_to_cpu(cck->mh_format_err), +- accum_cck->mh_format_err, delta_cck->mh_format_err, +- max_cck->mh_format_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "re_acq_main_rssi_sum:", +- le32_to_cpu(cck->re_acq_main_rssi_sum), +- accum_cck->re_acq_main_rssi_sum, +- delta_cck->re_acq_main_rssi_sum, +- max_cck->re_acq_main_rssi_sum); +- +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_header, "Statistics_Rx - GENERAL:"); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "bogus_cts:", +- le32_to_cpu(general->bogus_cts), +- accum_general->bogus_cts, delta_general->bogus_cts, +- max_general->bogus_cts); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "bogus_ack:", +- le32_to_cpu(general->bogus_ack), +- accum_general->bogus_ack, delta_general->bogus_ack, +- max_general->bogus_ack); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "non_bssid_frames:", +- le32_to_cpu(general->non_bssid_frames), +- accum_general->non_bssid_frames, +- delta_general->non_bssid_frames, +- max_general->non_bssid_frames); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "filtered_frames:", +- le32_to_cpu(general->filtered_frames), +- accum_general->filtered_frames, +- delta_general->filtered_frames, +- max_general->filtered_frames); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "non_channel_beacons:", +- le32_to_cpu(general->non_channel_beacons), +- accum_general->non_channel_beacons, +- delta_general->non_channel_beacons, +- max_general->non_channel_beacons); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "channel_beacons:", +- le32_to_cpu(general->channel_beacons), +- accum_general->channel_beacons, +- delta_general->channel_beacons, +- max_general->channel_beacons); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "num_missed_bcon:", +- le32_to_cpu(general->num_missed_bcon), +- accum_general->num_missed_bcon, +- delta_general->num_missed_bcon, +- max_general->num_missed_bcon); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "adc_rx_saturation_time:", +- le32_to_cpu(general->adc_rx_saturation_time), +- accum_general->adc_rx_saturation_time, +- delta_general->adc_rx_saturation_time, +- max_general->adc_rx_saturation_time); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "ina_detect_search_tm:", +- le32_to_cpu(general->ina_detection_search_time), +- accum_general->ina_detection_search_time, +- delta_general->ina_detection_search_time, +- max_general->ina_detection_search_time); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "beacon_silence_rssi_a:", +- le32_to_cpu(general->beacon_silence_rssi_a), +- accum_general->beacon_silence_rssi_a, +- delta_general->beacon_silence_rssi_a, +- max_general->beacon_silence_rssi_a); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "beacon_silence_rssi_b:", +- le32_to_cpu(general->beacon_silence_rssi_b), +- accum_general->beacon_silence_rssi_b, +- delta_general->beacon_silence_rssi_b, +- max_general->beacon_silence_rssi_b); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "beacon_silence_rssi_c:", +- le32_to_cpu(general->beacon_silence_rssi_c), +- accum_general->beacon_silence_rssi_c, +- delta_general->beacon_silence_rssi_c, +- max_general->beacon_silence_rssi_c); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "interference_data_flag:", +- le32_to_cpu(general->interference_data_flag), +- accum_general->interference_data_flag, +- delta_general->interference_data_flag, +- max_general->interference_data_flag); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "channel_load:", +- le32_to_cpu(general->channel_load), +- accum_general->channel_load, +- delta_general->channel_load, +- max_general->channel_load); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "dsp_false_alarms:", +- le32_to_cpu(general->dsp_false_alarms), +- accum_general->dsp_false_alarms, +- delta_general->dsp_false_alarms, +- max_general->dsp_false_alarms); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "beacon_rssi_a:", +- le32_to_cpu(general->beacon_rssi_a), +- accum_general->beacon_rssi_a, +- delta_general->beacon_rssi_a, +- max_general->beacon_rssi_a); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "beacon_rssi_b:", +- le32_to_cpu(general->beacon_rssi_b), +- accum_general->beacon_rssi_b, +- delta_general->beacon_rssi_b, +- max_general->beacon_rssi_b); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "beacon_rssi_c:", +- le32_to_cpu(general->beacon_rssi_c), +- accum_general->beacon_rssi_c, +- delta_general->beacon_rssi_c, +- max_general->beacon_rssi_c); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "beacon_energy_a:", +- le32_to_cpu(general->beacon_energy_a), +- accum_general->beacon_energy_a, +- delta_general->beacon_energy_a, +- max_general->beacon_energy_a); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "beacon_energy_b:", +- le32_to_cpu(general->beacon_energy_b), +- accum_general->beacon_energy_b, +- delta_general->beacon_energy_b, +- max_general->beacon_energy_b); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "beacon_energy_c:", +- le32_to_cpu(general->beacon_energy_c), +- accum_general->beacon_energy_c, +- delta_general->beacon_energy_c, +- max_general->beacon_energy_c); +- +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_header, "Statistics_Rx - OFDM_HT:"); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "plcp_err:", +- le32_to_cpu(ht->plcp_err), accum_ht->plcp_err, +- delta_ht->plcp_err, max_ht->plcp_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "overrun_err:", +- le32_to_cpu(ht->overrun_err), accum_ht->overrun_err, +- delta_ht->overrun_err, max_ht->overrun_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "early_overrun_err:", +- le32_to_cpu(ht->early_overrun_err), +- accum_ht->early_overrun_err, +- delta_ht->early_overrun_err, +- max_ht->early_overrun_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "crc32_good:", +- le32_to_cpu(ht->crc32_good), accum_ht->crc32_good, +- delta_ht->crc32_good, max_ht->crc32_good); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "crc32_err:", +- le32_to_cpu(ht->crc32_err), accum_ht->crc32_err, +- delta_ht->crc32_err, max_ht->crc32_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "mh_format_err:", +- le32_to_cpu(ht->mh_format_err), +- accum_ht->mh_format_err, +- delta_ht->mh_format_err, max_ht->mh_format_err); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg_crc32_good:", +- le32_to_cpu(ht->agg_crc32_good), +- accum_ht->agg_crc32_good, +- delta_ht->agg_crc32_good, max_ht->agg_crc32_good); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg_mpdu_cnt:", +- le32_to_cpu(ht->agg_mpdu_cnt), +- accum_ht->agg_mpdu_cnt, +- delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg_cnt:", +- le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt, +- delta_ht->agg_cnt, max_ht->agg_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "unsupport_mcs:", +- le32_to_cpu(ht->unsupport_mcs), +- accum_ht->unsupport_mcs, +- delta_ht->unsupport_mcs, max_ht->unsupport_mcs); +- +- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); +- kfree(buf); +- return ret; +-} +- +-ssize_t iwl_ucode_tx_stats_read(struct file *file, +- char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- struct iwl_priv *priv = file->private_data; +- int pos = 0; +- char *buf; +- int bufsz = (sizeof(struct statistics_tx) * 48) + 250; +- ssize_t ret; +- struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; +- +- if (!iwl_is_alive(priv)) +- return -EAGAIN; +- +- buf = kzalloc(bufsz, GFP_KERNEL); +- if (!buf) { +- IWL_ERR(priv, "Can not allocate Buffer\n"); +- return -ENOMEM; +- } +- +- /* the statistic information display here is based on +- * the last statistics notification from uCode +- * might not reflect the current uCode activity +- */ +- if (iwl_bt_statistics(priv)) { +- tx = &priv->_agn.statistics_bt.tx; +- accum_tx = &priv->_agn.accum_statistics_bt.tx; +- delta_tx = &priv->_agn.delta_statistics_bt.tx; +- max_tx = &priv->_agn.max_delta_bt.tx; +- } else { +- tx = &priv->_agn.statistics.tx; +- accum_tx = &priv->_agn.accum_statistics.tx; +- delta_tx = &priv->_agn.delta_statistics.tx; +- max_tx = &priv->_agn.max_delta.tx; +- } +- +- pos += iwl_statistics_flag(priv, buf, bufsz); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_header, "Statistics_Tx:"); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "preamble:", +- le32_to_cpu(tx->preamble_cnt), +- accum_tx->preamble_cnt, +- delta_tx->preamble_cnt, max_tx->preamble_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "rx_detected_cnt:", +- le32_to_cpu(tx->rx_detected_cnt), +- accum_tx->rx_detected_cnt, +- delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "bt_prio_defer_cnt:", +- le32_to_cpu(tx->bt_prio_defer_cnt), +- accum_tx->bt_prio_defer_cnt, +- delta_tx->bt_prio_defer_cnt, +- max_tx->bt_prio_defer_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "bt_prio_kill_cnt:", +- le32_to_cpu(tx->bt_prio_kill_cnt), +- accum_tx->bt_prio_kill_cnt, +- delta_tx->bt_prio_kill_cnt, +- max_tx->bt_prio_kill_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "few_bytes_cnt:", +- le32_to_cpu(tx->few_bytes_cnt), +- accum_tx->few_bytes_cnt, +- delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "cts_timeout:", +- le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, +- delta_tx->cts_timeout, max_tx->cts_timeout); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "ack_timeout:", +- le32_to_cpu(tx->ack_timeout), +- accum_tx->ack_timeout, +- delta_tx->ack_timeout, max_tx->ack_timeout); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "expected_ack_cnt:", +- le32_to_cpu(tx->expected_ack_cnt), +- accum_tx->expected_ack_cnt, +- delta_tx->expected_ack_cnt, +- max_tx->expected_ack_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "actual_ack_cnt:", +- le32_to_cpu(tx->actual_ack_cnt), +- accum_tx->actual_ack_cnt, +- delta_tx->actual_ack_cnt, +- max_tx->actual_ack_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "dump_msdu_cnt:", +- le32_to_cpu(tx->dump_msdu_cnt), +- accum_tx->dump_msdu_cnt, +- delta_tx->dump_msdu_cnt, +- max_tx->dump_msdu_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "abort_nxt_frame_mismatch:", +- le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), +- accum_tx->burst_abort_next_frame_mismatch_cnt, +- delta_tx->burst_abort_next_frame_mismatch_cnt, +- max_tx->burst_abort_next_frame_mismatch_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "abort_missing_nxt_frame:", +- le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), +- accum_tx->burst_abort_missing_next_frame_cnt, +- delta_tx->burst_abort_missing_next_frame_cnt, +- max_tx->burst_abort_missing_next_frame_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "cts_timeout_collision:", +- le32_to_cpu(tx->cts_timeout_collision), +- accum_tx->cts_timeout_collision, +- delta_tx->cts_timeout_collision, +- max_tx->cts_timeout_collision); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "ack_ba_timeout_collision:", +- le32_to_cpu(tx->ack_or_ba_timeout_collision), +- accum_tx->ack_or_ba_timeout_collision, +- delta_tx->ack_or_ba_timeout_collision, +- max_tx->ack_or_ba_timeout_collision); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg ba_timeout:", +- le32_to_cpu(tx->agg.ba_timeout), +- accum_tx->agg.ba_timeout, +- delta_tx->agg.ba_timeout, +- max_tx->agg.ba_timeout); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg ba_resched_frames:", +- le32_to_cpu(tx->agg.ba_reschedule_frames), +- accum_tx->agg.ba_reschedule_frames, +- delta_tx->agg.ba_reschedule_frames, +- max_tx->agg.ba_reschedule_frames); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg scd_query_agg_frame:", +- le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), +- accum_tx->agg.scd_query_agg_frame_cnt, +- delta_tx->agg.scd_query_agg_frame_cnt, +- max_tx->agg.scd_query_agg_frame_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg scd_query_no_agg:", +- le32_to_cpu(tx->agg.scd_query_no_agg), +- accum_tx->agg.scd_query_no_agg, +- delta_tx->agg.scd_query_no_agg, +- max_tx->agg.scd_query_no_agg); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg scd_query_agg:", +- le32_to_cpu(tx->agg.scd_query_agg), +- accum_tx->agg.scd_query_agg, +- delta_tx->agg.scd_query_agg, +- max_tx->agg.scd_query_agg); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg scd_query_mismatch:", +- le32_to_cpu(tx->agg.scd_query_mismatch), +- accum_tx->agg.scd_query_mismatch, +- delta_tx->agg.scd_query_mismatch, +- max_tx->agg.scd_query_mismatch); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg frame_not_ready:", +- le32_to_cpu(tx->agg.frame_not_ready), +- accum_tx->agg.frame_not_ready, +- delta_tx->agg.frame_not_ready, +- max_tx->agg.frame_not_ready); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg underrun:", +- le32_to_cpu(tx->agg.underrun), +- accum_tx->agg.underrun, +- delta_tx->agg.underrun, max_tx->agg.underrun); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg bt_prio_kill:", +- le32_to_cpu(tx->agg.bt_prio_kill), +- accum_tx->agg.bt_prio_kill, +- delta_tx->agg.bt_prio_kill, +- max_tx->agg.bt_prio_kill); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "agg rx_ba_rsp_cnt:", +- le32_to_cpu(tx->agg.rx_ba_rsp_cnt), +- accum_tx->agg.rx_ba_rsp_cnt, +- delta_tx->agg.rx_ba_rsp_cnt, +- max_tx->agg.rx_ba_rsp_cnt); +- +- if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) { +- pos += scnprintf(buf + pos, bufsz - pos, +- "tx power: (1/2 dB step)\n"); +- if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a) +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_hex, "antenna A:", +- tx->tx_power.ant_a); +- if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b) +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_hex, "antenna B:", +- tx->tx_power.ant_b); +- if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c) +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_hex, "antenna C:", +- tx->tx_power.ant_c); +- } +- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); +- kfree(buf); +- return ret; +-} +- +-ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- struct iwl_priv *priv = file->private_data; +- int pos = 0; +- char *buf; +- int bufsz = sizeof(struct statistics_general) * 10 + 300; +- ssize_t ret; +- struct statistics_general_common *general, *accum_general; +- struct statistics_general_common *delta_general, *max_general; +- struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; +- struct statistics_div *div, *accum_div, *delta_div, *max_div; +- +- if (!iwl_is_alive(priv)) +- return -EAGAIN; +- +- buf = kzalloc(bufsz, GFP_KERNEL); +- if (!buf) { +- IWL_ERR(priv, "Can not allocate Buffer\n"); +- return -ENOMEM; +- } +- +- /* the statistic information display here is based on +- * the last statistics notification from uCode +- * might not reflect the current uCode activity +- */ +- if (iwl_bt_statistics(priv)) { +- general = &priv->_agn.statistics_bt.general.common; +- dbg = &priv->_agn.statistics_bt.general.common.dbg; +- div = &priv->_agn.statistics_bt.general.common.div; +- accum_general = &priv->_agn.accum_statistics_bt.general.common; +- accum_dbg = &priv->_agn.accum_statistics_bt.general.common.dbg; +- accum_div = &priv->_agn.accum_statistics_bt.general.common.div; +- delta_general = &priv->_agn.delta_statistics_bt.general.common; +- max_general = &priv->_agn.max_delta_bt.general.common; +- delta_dbg = &priv->_agn.delta_statistics_bt.general.common.dbg; +- max_dbg = &priv->_agn.max_delta_bt.general.common.dbg; +- delta_div = &priv->_agn.delta_statistics_bt.general.common.div; +- max_div = &priv->_agn.max_delta_bt.general.common.div; +- } else { +- general = &priv->_agn.statistics.general.common; +- dbg = &priv->_agn.statistics.general.common.dbg; +- div = &priv->_agn.statistics.general.common.div; +- accum_general = &priv->_agn.accum_statistics.general.common; +- accum_dbg = &priv->_agn.accum_statistics.general.common.dbg; +- accum_div = &priv->_agn.accum_statistics.general.common.div; +- delta_general = &priv->_agn.delta_statistics.general.common; +- max_general = &priv->_agn.max_delta.general.common; +- delta_dbg = &priv->_agn.delta_statistics.general.common.dbg; +- max_dbg = &priv->_agn.max_delta.general.common.dbg; +- delta_div = &priv->_agn.delta_statistics.general.common.div; +- max_div = &priv->_agn.max_delta.general.common.div; +- } +- +- pos += iwl_statistics_flag(priv, buf, bufsz); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_header, "Statistics_General:"); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_value, "temperature:", +- le32_to_cpu(general->temperature)); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_value, "temperature_m:", +- le32_to_cpu(general->temperature_m)); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_value, "ttl_timestamp:", +- le32_to_cpu(general->ttl_timestamp)); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "burst_check:", +- le32_to_cpu(dbg->burst_check), +- accum_dbg->burst_check, +- delta_dbg->burst_check, max_dbg->burst_check); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "burst_count:", +- le32_to_cpu(dbg->burst_count), +- accum_dbg->burst_count, +- delta_dbg->burst_count, max_dbg->burst_count); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "wait_for_silence_timeout_count:", +- le32_to_cpu(dbg->wait_for_silence_timeout_cnt), +- accum_dbg->wait_for_silence_timeout_cnt, +- delta_dbg->wait_for_silence_timeout_cnt, +- max_dbg->wait_for_silence_timeout_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "sleep_time:", +- le32_to_cpu(general->sleep_time), +- accum_general->sleep_time, +- delta_general->sleep_time, max_general->sleep_time); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "slots_out:", +- le32_to_cpu(general->slots_out), +- accum_general->slots_out, +- delta_general->slots_out, max_general->slots_out); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "slots_idle:", +- le32_to_cpu(general->slots_idle), +- accum_general->slots_idle, +- delta_general->slots_idle, max_general->slots_idle); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "tx_on_a:", +- le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, +- delta_div->tx_on_a, max_div->tx_on_a); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "tx_on_b:", +- le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, +- delta_div->tx_on_b, max_div->tx_on_b); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "exec_time:", +- le32_to_cpu(div->exec_time), accum_div->exec_time, +- delta_div->exec_time, max_div->exec_time); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "probe_time:", +- le32_to_cpu(div->probe_time), accum_div->probe_time, +- delta_div->probe_time, max_div->probe_time); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "rx_enable_counter:", +- le32_to_cpu(general->rx_enable_counter), +- accum_general->rx_enable_counter, +- delta_general->rx_enable_counter, +- max_general->rx_enable_counter); +- pos += scnprintf(buf + pos, bufsz - pos, +- fmt_table, "num_of_sos_states:", +- le32_to_cpu(general->num_of_sos_states), +- accum_general->num_of_sos_states, +- delta_general->num_of_sos_states, +- max_general->num_of_sos_states); +- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); +- kfree(buf); +- return ret; +-} +- +-ssize_t iwl_ucode_bt_stats_read(struct file *file, +- char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- struct iwl_priv *priv = (struct iwl_priv *)file->private_data; +- int pos = 0; +- char *buf; +- int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200; +- ssize_t ret; +- struct statistics_bt_activity *bt, *accum_bt; +- +- if (!iwl_is_alive(priv)) +- return -EAGAIN; +- +- if (!priv->bt_enable_flag) +- return -EINVAL; +- +- /* make request to uCode to retrieve statistics information */ +- mutex_lock(&priv->mutex); +- ret = iwl_send_statistics_request(priv, CMD_SYNC, false); +- mutex_unlock(&priv->mutex); +- +- if (ret) { +- IWL_ERR(priv, +- "Error sending statistics request: %zd\n", ret); +- return -EAGAIN; +- } +- buf = kzalloc(bufsz, GFP_KERNEL); +- if (!buf) { +- IWL_ERR(priv, "Can not allocate Buffer\n"); +- return -ENOMEM; +- } +- +- /* +- * the statistic information display here is based on +- * the last statistics notification from uCode +- * might not reflect the current uCode activity +- */ +- bt = &priv->_agn.statistics_bt.general.activity; +- accum_bt = &priv->_agn.accum_statistics_bt.general.activity; +- +- pos += iwl_statistics_flag(priv, buf, bufsz); +- pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n"); +- pos += scnprintf(buf + pos, bufsz - pos, +- "\t\t\tcurrent\t\t\taccumulative\n"); +- pos += scnprintf(buf + pos, bufsz - pos, +- "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", +- le32_to_cpu(bt->hi_priority_tx_req_cnt), +- accum_bt->hi_priority_tx_req_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n", +- le32_to_cpu(bt->hi_priority_tx_denied_cnt), +- accum_bt->hi_priority_tx_denied_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", +- le32_to_cpu(bt->lo_priority_tx_req_cnt), +- accum_bt->lo_priority_tx_req_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n", +- le32_to_cpu(bt->lo_priority_tx_denied_cnt), +- accum_bt->lo_priority_tx_denied_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", +- le32_to_cpu(bt->hi_priority_rx_req_cnt), +- accum_bt->hi_priority_rx_req_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n", +- le32_to_cpu(bt->hi_priority_rx_denied_cnt), +- accum_bt->hi_priority_rx_denied_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", +- le32_to_cpu(bt->lo_priority_rx_req_cnt), +- accum_bt->lo_priority_rx_req_cnt); +- pos += scnprintf(buf + pos, bufsz - pos, +- "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n", +- le32_to_cpu(bt->lo_priority_rx_denied_cnt), +- accum_bt->lo_priority_rx_denied_cnt); +- +- pos += scnprintf(buf + pos, bufsz - pos, +- "(rx)num_bt_kills:\t\t%u\t\t\t%u\n", +- le32_to_cpu(priv->_agn.statistics_bt.rx. +- general.num_bt_kills), +- priv->_agn.accum_statistics_bt.rx. +- general.num_bt_kills); +- +- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); +- kfree(buf); +- return ret; +-} +- +-ssize_t iwl_reply_tx_error_read(struct file *file, +- char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- struct iwl_priv *priv = (struct iwl_priv *)file->private_data; +- int pos = 0; +- char *buf; +- int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) + +- (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200; +- ssize_t ret; +- +- if (!iwl_is_alive(priv)) +- return -EAGAIN; +- +- buf = kzalloc(bufsz, GFP_KERNEL); +- if (!buf) { +- IWL_ERR(priv, "Can not allocate Buffer\n"); +- return -ENOMEM; +- } +- +- pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n"); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY), +- priv->_agn.reply_tx_stats.pp_delay); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES), +- priv->_agn.reply_tx_stats.pp_few_bytes); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO), +- priv->_agn.reply_tx_stats.pp_bt_prio); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD), +- priv->_agn.reply_tx_stats.pp_quiet_period); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK), +- priv->_agn.reply_tx_stats.pp_calc_ttak); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", +- iwl_get_tx_fail_reason( +- TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY), +- priv->_agn.reply_tx_stats.int_crossed_retry); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT), +- priv->_agn.reply_tx_stats.short_limit); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT), +- priv->_agn.reply_tx_stats.long_limit); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN), +- priv->_agn.reply_tx_stats.fifo_underrun); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW), +- priv->_agn.reply_tx_stats.drain_flow); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH), +- priv->_agn.reply_tx_stats.rfkill_flush); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE), +- priv->_agn.reply_tx_stats.life_expire); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS), +- priv->_agn.reply_tx_stats.dest_ps); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED), +- priv->_agn.reply_tx_stats.host_abort); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY), +- priv->_agn.reply_tx_stats.pp_delay); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID), +- priv->_agn.reply_tx_stats.sta_invalid); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED), +- priv->_agn.reply_tx_stats.frag_drop); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE), +- priv->_agn.reply_tx_stats.tid_disable); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED), +- priv->_agn.reply_tx_stats.fifo_flush); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", +- iwl_get_tx_fail_reason( +- TX_STATUS_FAIL_INSUFFICIENT_CF_POLL), +- priv->_agn.reply_tx_stats.insuff_cf_poll); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX), +- priv->_agn.reply_tx_stats.fail_hw_drop); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", +- iwl_get_tx_fail_reason( +- TX_STATUS_FAIL_NO_BEACON_ON_RADAR), +- priv->_agn.reply_tx_stats.sta_color_mismatch); +- pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", +- priv->_agn.reply_tx_stats.unknown); +- +- pos += scnprintf(buf + pos, bufsz - pos, +- "\nStatistics_Agg_TX_Error:\n"); +- +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK), +- priv->_agn.reply_agg_tx_stats.underrun); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK), +- priv->_agn.reply_agg_tx_stats.bt_prio); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK), +- priv->_agn.reply_agg_tx_stats.few_bytes); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK), +- priv->_agn.reply_agg_tx_stats.abort); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", +- iwl_get_agg_tx_fail_reason( +- AGG_TX_STATE_LAST_SENT_TTL_MSK), +- priv->_agn.reply_agg_tx_stats.last_sent_ttl); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", +- iwl_get_agg_tx_fail_reason( +- AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK), +- priv->_agn.reply_agg_tx_stats.last_sent_try); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", +- iwl_get_agg_tx_fail_reason( +- AGG_TX_STATE_LAST_SENT_BT_KILL_MSK), +- priv->_agn.reply_agg_tx_stats.last_sent_bt_kill); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK), +- priv->_agn.reply_agg_tx_stats.scd_query); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", +- iwl_get_agg_tx_fail_reason( +- AGG_TX_STATE_TEST_BAD_CRC32_MSK), +- priv->_agn.reply_agg_tx_stats.bad_crc32); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK), +- priv->_agn.reply_agg_tx_stats.response); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK), +- priv->_agn.reply_agg_tx_stats.dump_tx); +- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", +- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK), +- priv->_agn.reply_agg_tx_stats.delay_tx); +- pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", +- priv->_agn.reply_agg_tx_stats.unknown); +- +- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); +- kfree(buf); +- return ret; +-} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,70 +0,0 @@ +-/****************************************************************************** +- * +- * GPL LICENSE SUMMARY +- * +- * Copyright(c) 2008 - 2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, +- * USA +- * +- * The full GNU General Public License is included in this distribution +- * in the file called LICENSE.GPL. +- * +- * Contact Information: +- * Intel Linux Wireless +- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +- *****************************************************************************/ +- +-#include "iwl-dev.h" +-#include "iwl-core.h" +-#include "iwl-debug.h" +- +-#ifdef CONFIG_IWLWIFI_DEBUGFS +-ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos); +-ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos); +-ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos); +-ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos); +-ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos); +-#else +-static ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- return 0; +-} +-static ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- return 0; +-} +-static ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- return 0; +-} +-static ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- return 0; +-} +-static ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- return 0; +-} +-#endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c 2011-05-05 23:29:45.374440523 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +@@ -81,52 +81,13 @@ + * + ******************************************************************************/ + +-/* +- * The device's EEPROM semaphore prevents conflicts between driver and uCode +- * when accessing the EEPROM; each access is a series of pulses to/from the +- * EEPROM chip, not a single event, so even reads could conflict if they +- * weren't arbitrated by the semaphore. +- */ +-int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) +-{ +- u16 count; +- int ret; +- +- for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { +- /* Request semaphore */ +- iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, +- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); +- +- /* See if we got it */ +- ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, +- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, +- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, +- EEPROM_SEM_TIMEOUT); +- if (ret >= 0) { +- IWL_DEBUG_IO(priv, +- "Acquired semaphore after %d tries.\n", +- count+1); +- return ret; +- } +- } +- +- return ret; +-} +- +-void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv) +-{ +- iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, +- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); +- +-} +- + int iwl_eeprom_check_version(struct iwl_priv *priv) + { + u16 eeprom_ver; + u16 calib_ver; + + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); +- calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv); ++ calib_ver = iwlagn_eeprom_calib_version(priv); + + if (eeprom_ver < priv->cfg->eeprom_ver || + calib_ver < priv->cfg->eeprom_calib_ver) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn.h 2011-05-05 23:29:45.320439871 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +@@ -66,7 +66,6 @@ + #include "iwl-dev.h" + + /* configuration for the _agn devices */ +-extern struct iwl_cfg iwl4965_agn_cfg; + extern struct iwl_cfg iwl5300_agn_cfg; + extern struct iwl_cfg iwl5100_agn_cfg; + extern struct iwl_cfg iwl5350_agn_cfg; +@@ -103,10 +102,10 @@ + extern struct iwl_cfg iwl6035_2agn_cfg; + extern struct iwl_cfg iwl6035_2abg_cfg; + extern struct iwl_cfg iwl6035_2bg_cfg; +-extern struct iwl_cfg iwl200_bg_cfg; +-extern struct iwl_cfg iwl200_bgn_cfg; +-extern struct iwl_cfg iwl230_bg_cfg; +-extern struct iwl_cfg iwl230_bgn_cfg; ++extern struct iwl_cfg iwl105_bg_cfg; ++extern struct iwl_cfg iwl105_bgn_cfg; ++extern struct iwl_cfg iwl135_bg_cfg; ++extern struct iwl_cfg iwl135_bgn_cfg; + + extern struct iwl_mod_params iwlagn_mod_params; + extern struct iwl_hcmd_ops iwlagn_hcmd; +@@ -114,7 +113,6 @@ + extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils; + + extern struct ieee80211_ops iwlagn_hw_ops; +-extern struct ieee80211_ops iwl4965_hw_ops; + + int iwl_reset_ict(struct iwl_priv *priv); + void iwl_disable_ict(struct iwl_priv *priv); +@@ -122,6 +120,19 @@ + void iwl_free_isr_ict(struct iwl_priv *priv); + irqreturn_t iwl_isr_ict(int irq, void *data); + ++/* call this function to flush any scheduled tasklet */ ++static inline void iwl_synchronize_irq(struct iwl_priv *priv) ++{ ++ /* wait to make sure we flush pending tasklet*/ ++ synchronize_irq(priv->pci_dev->irq); ++ tasklet_kill(&priv->irq_tasklet); ++} ++ ++int iwl_prepare_card_hw(struct iwl_priv *priv); ++ ++int iwlagn_start_device(struct iwl_priv *priv); ++void iwlagn_stop_device(struct iwl_priv *priv); ++ + /* tx queue */ + void iwlagn_set_wr_ptrs(struct iwl_priv *priv, + int txq_id, u32 index); +@@ -133,10 +144,6 @@ + u16 byte_cnt); + void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq); +-int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, +- int tx_fifo, int sta_id, int tid, u16 ssn_idx); +-int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, +- u16 ssn_idx, u8 tx_fifo); + void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask); + void iwl_free_tfds_in_queue(struct iwl_priv *priv, + int sta_id, int tid, int freed); +@@ -151,16 +158,14 @@ + u32 changes); + + /* uCode */ +-int iwlagn_load_ucode(struct iwl_priv *priv); + void iwlagn_rx_calib_result(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); +-void iwlagn_rx_calib_complete(struct iwl_priv *priv, +- struct iwl_rx_mem_buffer *rxb); +-void iwlagn_init_alive_start(struct iwl_priv *priv); +-int iwlagn_alive_notify(struct iwl_priv *priv); +-int iwl_verify_ucode(struct iwl_priv *priv); +-void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); ++int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); + void iwlagn_send_prio_tbl(struct iwl_priv *priv); ++int iwlagn_run_init_ucode(struct iwl_priv *priv); ++int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, ++ struct fw_img *image, ++ int subtype, int alternate_subtype); + + /* lib */ + void iwl_check_abort_status(struct iwl_priv *priv, +@@ -179,8 +184,6 @@ + int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv); + int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); + void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); +-void iwl_dump_csr(struct iwl_priv *priv); +-int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); + + /* rx */ + void iwlagn_rx_queue_restock(struct iwl_priv *priv); +@@ -206,6 +209,9 @@ + struct ieee80211_sta *sta, u16 tid, u16 *ssn); + int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 tid); ++void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv, ++ struct ieee80211_sta *sta, ++ int tid, int frame_limit); + int iwlagn_txq_check_empty(struct iwl_priv *priv, + int sta_id, u8 tid, int txq_id); + void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, +@@ -225,6 +231,7 @@ + case TX_STATUS_DIRECT_DONE: + return IEEE80211_TX_STAT_ACK; + case TX_STATUS_FAIL_DEST_PS: ++ case TX_STATUS_FAIL_PASSIVE_NO_RX: + return IEEE80211_TX_STAT_TX_FILTERED; + default: + return 0; +@@ -249,8 +256,6 @@ + struct ieee80211_vif *vif, bool add); + + /* hcmd */ +-int iwlagn_send_rxon_assoc(struct iwl_priv *priv, +- struct iwl_rxon_context *ctx); + int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant); + int iwlagn_send_beacon_cmd(struct iwl_priv *priv); + +@@ -311,7 +316,7 @@ + + static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) + { +- return le32_to_cpu(rate_n_flags) & 0xFF; ++ return le32_to_cpu(rate_n_flags) & RATE_MCS_RATE_MSK; + } + + static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) +@@ -322,17 +327,17 @@ + /* eeprom */ + void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv); + void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); +-int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); +-void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); + + /* notification wait support */ + void __acquires(wait_entry) + iwlagn_init_notification_wait(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, ++ u8 cmd, + void (*fn)(struct iwl_priv *priv, +- struct iwl_rx_packet *pkt), +- u8 cmd); +-signed long __releases(wait_entry) ++ struct iwl_rx_packet *pkt, ++ void *data), ++ void *fn_data); ++int __must_check __releases(wait_entry) + iwlagn_wait_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + unsigned long timeout); +@@ -340,32 +345,4 @@ + iwlagn_remove_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry); + +-/* mac80211 handlers (for 4965) */ +-void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); +-int iwlagn_mac_start(struct ieee80211_hw *hw); +-void iwlagn_mac_stop(struct ieee80211_hw *hw); +-void iwlagn_configure_filter(struct ieee80211_hw *hw, +- unsigned int changed_flags, +- unsigned int *total_flags, +- u64 multicast); +-int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +- struct ieee80211_vif *vif, struct ieee80211_sta *sta, +- struct ieee80211_key_conf *key); +-void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, +- struct ieee80211_vif *vif, +- struct ieee80211_key_conf *keyconf, +- struct ieee80211_sta *sta, +- u32 iv32, u16 *phase1key); +-int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, +- struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size); +-int iwlagn_mac_sta_add(struct ieee80211_hw *hw, +- struct ieee80211_vif *vif, +- struct ieee80211_sta *sta); +-void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, +- struct ieee80211_channel_switch *ch_switch); +-void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop); +- + #endif /* __iwl_agn_h__ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c 2011-05-05 23:29:45.251439037 +0200 +@@ -2,7 +2,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -37,54 +37,6 @@ + #include "iwl-io.h" + #include "iwl-agn.h" + +-int iwlagn_send_rxon_assoc(struct iwl_priv *priv, +- struct iwl_rxon_context *ctx) +-{ +- int ret = 0; +- struct iwl5000_rxon_assoc_cmd rxon_assoc; +- const struct iwl_rxon_cmd *rxon1 = &ctx->staging; +- const struct iwl_rxon_cmd *rxon2 = &ctx->active; +- +- if ((rxon1->flags == rxon2->flags) && +- (rxon1->filter_flags == rxon2->filter_flags) && +- (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && +- (rxon1->ofdm_ht_single_stream_basic_rates == +- rxon2->ofdm_ht_single_stream_basic_rates) && +- (rxon1->ofdm_ht_dual_stream_basic_rates == +- rxon2->ofdm_ht_dual_stream_basic_rates) && +- (rxon1->ofdm_ht_triple_stream_basic_rates == +- rxon2->ofdm_ht_triple_stream_basic_rates) && +- (rxon1->acquisition_data == rxon2->acquisition_data) && +- (rxon1->rx_chain == rxon2->rx_chain) && +- (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { +- IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); +- return 0; +- } +- +- rxon_assoc.flags = ctx->staging.flags; +- rxon_assoc.filter_flags = ctx->staging.filter_flags; +- rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; +- rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; +- rxon_assoc.reserved1 = 0; +- rxon_assoc.reserved2 = 0; +- rxon_assoc.reserved3 = 0; +- rxon_assoc.ofdm_ht_single_stream_basic_rates = +- ctx->staging.ofdm_ht_single_stream_basic_rates; +- rxon_assoc.ofdm_ht_dual_stream_basic_rates = +- ctx->staging.ofdm_ht_dual_stream_basic_rates; +- rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; +- rxon_assoc.ofdm_ht_triple_stream_basic_rates = +- ctx->staging.ofdm_ht_triple_stream_basic_rates; +- rxon_assoc.acquisition_data = ctx->staging.acquisition_data; +- +- ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd, +- sizeof(rxon_assoc), &rxon_assoc, NULL); +- if (ret) +- return ret; +- +- return ret; +-} +- + int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) + { + struct iwl_tx_ant_config_cmd tx_ant_cmd = { +@@ -364,7 +316,6 @@ + } + + struct iwl_hcmd_ops iwlagn_hcmd = { +- .rxon_assoc = iwlagn_send_rxon_assoc, + .commit_rxon = iwlagn_commit_rxon, + .set_rxon_chain = iwlagn_set_rxon_chain, + .set_tx_ant = iwlagn_send_tx_ant_config, +@@ -373,7 +324,6 @@ + }; + + struct iwl_hcmd_ops iwlagn_bt_hcmd = { +- .rxon_assoc = iwlagn_send_rxon_assoc, + .commit_rxon = iwlagn_commit_rxon, + .set_rxon_chain = iwlagn_set_rxon_chain, + .set_tx_ant = iwlagn_send_tx_ant_config, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-hw.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-hw.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-hw.h 2011-05-05 23:29:45.406440909 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2007 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-ict.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-ict.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-ict.c 2011-05-05 23:29:45.389440705 +0200 +@@ -2,7 +2,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -59,8 +59,6 @@ + int iwl_alloc_isr_ict(struct iwl_priv *priv) + { + +- if (priv->cfg->base_params->use_isr_legacy) +- return 0; + /* allocate shrared data table */ + priv->_agn.ict_tbl_vir = + dma_alloc_coherent(&priv->pci_dev->dev, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-led.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-led.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-led.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-led.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,73 +0,0 @@ +-/****************************************************************************** +- * +- * Copyright(c) 2003 - 2010 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., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +- * +- * The full GNU General Public License is included in this distribution in the +- * file called LICENSE. +- * +- * Contact Information: +- * Intel Linux Wireless +- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +- * +- *****************************************************************************/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "iwl-commands.h" +-#include "iwl-dev.h" +-#include "iwl-core.h" +-#include "iwl-io.h" +-#include "iwl-agn-led.h" +- +-/* Send led command */ +-static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) +-{ +- struct iwl_host_cmd cmd = { +- .id = REPLY_LEDS_CMD, +- .len = sizeof(struct iwl_led_cmd), +- .data = led_cmd, +- .flags = CMD_ASYNC, +- .callback = NULL, +- }; +- u32 reg; +- +- reg = iwl_read32(priv, CSR_LED_REG); +- if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) +- iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); +- +- return iwl_send_cmd(priv, &cmd); +-} +- +-/* Set led register off */ +-void iwlagn_led_enable(struct iwl_priv *priv) +-{ +- iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); +-} +- +-const struct iwl_led_ops iwlagn_led_ops = { +- .cmd = iwl_send_led_cmd, +-}; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-led.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-led.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-led.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-led.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,33 +0,0 @@ +-/****************************************************************************** +- * +- * Copyright(c) 2003 - 2010 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., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +- * +- * The full GNU General Public License is included in this distribution in the +- * file called LICENSE. +- * +- * Contact Information: +- * Intel Linux Wireless +- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +- * +- *****************************************************************************/ +- +-#ifndef __iwl_agn_led_h__ +-#define __iwl_agn_led_h__ +- +-extern const struct iwl_led_ops iwlagn_led_ops; +-void iwlagn_led_enable(struct iwl_priv *priv); +- +-#endif /* __iwl_agn_led_h__ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-lib.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-lib.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-lib.c 2011-05-05 23:29:45.406440909 +0200 +@@ -2,7 +2,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -172,6 +172,7 @@ + + static void iwlagn_set_tx_status(struct iwl_priv *priv, + struct ieee80211_tx_info *info, ++ struct iwl_rxon_context *ctx, + struct iwlagn_tx_resp *tx_resp, + int txq_id, bool is_agg) + { +@@ -186,6 +187,13 @@ + if (!iwl_is_tx_success(status)) + iwlagn_count_tx_err_status(priv, status); + ++ if (status == TX_STATUS_FAIL_PASSIVE_NO_RX && ++ iwl_is_associated_ctx(ctx) && ctx->vif && ++ ctx->vif->type == NL80211_IFTYPE_STATION) { ++ ctx->last_tx_rejected = true; ++ iwl_stop_queue(priv, &priv->txq[txq_id]); ++ } ++ + IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags " + "0x%x retries %d\n", + txq_id, +@@ -242,15 +250,16 @@ + + /* # frames attempted by Tx command */ + if (agg->frame_count == 1) { ++ struct iwl_tx_info *txb; ++ + /* Only one frame was attempted; no block-ack will arrive */ + idx = start_idx; + + IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n", + agg->frame_count, agg->start_idx, idx); +- iwlagn_set_tx_status(priv, +- IEEE80211_SKB_CB( +- priv->txq[txq_id].txb[idx].skb), +- tx_resp, txq_id, true); ++ txb = &priv->txq[txq_id].txb[idx]; ++ iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(txb->skb), ++ txb->ctx, tx_resp, txq_id, true); + agg->wait_for_ba = 0; + } else { + /* Two or more frames were attempted; expect block-ack */ +@@ -391,7 +400,8 @@ + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_tx_info *info; + struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; +- u32 status = le16_to_cpu(tx_resp->status.status); ++ struct iwl_tx_info *txb; ++ u32 status = le16_to_cpu(tx_resp->status.status); + int tid; + int sta_id; + int freed; +@@ -406,7 +416,8 @@ + } + + txq->time_stamp = jiffies; +- info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb); ++ txb = &txq->txb[txq->q.read_ptr]; ++ info = IEEE80211_SKB_CB(txb->skb); + memset(&info->status, 0, sizeof(info->status)); + + tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> +@@ -450,12 +461,14 @@ + iwl_wake_queue(priv, txq); + } + } else { +- iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false); ++ iwlagn_set_tx_status(priv, info, txb->ctx, tx_resp, ++ txq_id, false); + freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); + iwl_free_tfds_in_queue(priv, sta_id, tid, freed); + + if (priv->mac80211_registered && +- (iwl_queue_space(&txq->q) > txq->q.low_mark)) ++ iwl_queue_space(&txq->q) > txq->q.low_mark && ++ status != TX_STATUS_FAIL_PASSIVE_NO_RX) + iwl_wake_queue(priv, txq); + } + +@@ -470,8 +483,6 @@ + /* init calibration handlers */ + priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = + iwlagn_rx_calib_result; +- priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] = +- iwlagn_rx_calib_complete; + priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; + + /* set up notification wait support */ +@@ -482,8 +493,10 @@ + + void iwlagn_setup_deferred_work(struct iwl_priv *priv) + { +- /* in agn, the tx power calibration is done in uCode */ +- priv->disable_tx_power_cal = 1; ++ /* ++ * nothing need to be done here anymore ++ * still keep for future use if needed ++ */ + } + + int iwlagn_hw_valid_rtc_data_addr(u32 addr) +@@ -534,9 +547,7 @@ + void iwlagn_temperature(struct iwl_priv *priv) + { + /* store temperature from correct statistics (in Celsius) */ +- priv->temperature = le32_to_cpu((iwl_bt_statistics(priv)) ? +- priv->_agn.statistics_bt.general.common.temperature : +- priv->_agn.statistics.general.common.temperature); ++ priv->temperature = le32_to_cpu(priv->statistics.common.temperature); + iwl_tt_handler(priv); + } + +@@ -652,10 +663,9 @@ + const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ + u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ + +- if (!priv->cfg->base_params->use_isr_legacy) +- rb_timeout = RX_RB_TIMEOUT; ++ rb_timeout = RX_RB_TIMEOUT; + +- if (priv->cfg->mod_params->amsdu_size_8K) ++ if (iwlagn_mod_params.amsdu_size_8K) + rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; + else + rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; +@@ -913,7 +923,6 @@ + + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; +- priv->alloc_rxb_page++; + + spin_unlock_irqrestore(&rxq->lock, flags); + } +@@ -1285,9 +1294,17 @@ + * mean we never reach it, but at the same time work around + * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER + * here instead of IWL_GOOD_CRC_TH_DISABLED. ++ * ++ * This was fixed in later versions along with some other ++ * scan changes, and the threshold behaves as a flag in those ++ * versions. + */ +- scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : +- IWL_GOOD_CRC_TH_NEVER; ++ if (priv->new_scan_threshold_behaviour) ++ scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : ++ IWL_GOOD_CRC_TH_DISABLED; ++ else ++ scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : ++ IWL_GOOD_CRC_TH_NEVER; + + band = priv->scan_band; + +@@ -2245,34 +2262,44 @@ + /* notification wait support */ + void iwlagn_init_notification_wait(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, ++ u8 cmd, + void (*fn)(struct iwl_priv *priv, +- struct iwl_rx_packet *pkt), +- u8 cmd) ++ struct iwl_rx_packet *pkt, ++ void *data), ++ void *fn_data) + { + wait_entry->fn = fn; ++ wait_entry->fn_data = fn_data; + wait_entry->cmd = cmd; + wait_entry->triggered = false; ++ wait_entry->aborted = false; + + spin_lock_bh(&priv->_agn.notif_wait_lock); + list_add(&wait_entry->list, &priv->_agn.notif_waits); + spin_unlock_bh(&priv->_agn.notif_wait_lock); + } + +-signed long iwlagn_wait_notification(struct iwl_priv *priv, +- struct iwl_notification_wait *wait_entry, +- unsigned long timeout) ++int iwlagn_wait_notification(struct iwl_priv *priv, ++ struct iwl_notification_wait *wait_entry, ++ unsigned long timeout) + { + int ret; + + ret = wait_event_timeout(priv->_agn.notif_waitq, +- wait_entry->triggered, ++ wait_entry->triggered || wait_entry->aborted, + timeout); + + spin_lock_bh(&priv->_agn.notif_wait_lock); + list_del(&wait_entry->list); + spin_unlock_bh(&priv->_agn.notif_wait_lock); + +- return ret; ++ if (wait_entry->aborted) ++ return -EIO; ++ ++ /* return value is always >= 0 */ ++ if (ret <= 0) ++ return -ETIMEDOUT; ++ return 0; + } + + void iwlagn_remove_notification(struct iwl_priv *priv, +@@ -2282,3 +2309,87 @@ + list_del(&wait_entry->list); + spin_unlock_bh(&priv->_agn.notif_wait_lock); + } ++ ++int iwlagn_start_device(struct iwl_priv *priv) ++{ ++ int ret; ++ ++ if (iwl_prepare_card_hw(priv)) { ++ IWL_WARN(priv, "Exit HW not ready\n"); ++ return -EIO; ++ } ++ ++ /* If platform's RF_KILL switch is NOT set to KILL */ ++ if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) ++ clear_bit(STATUS_RF_KILL_HW, &priv->status); ++ else ++ set_bit(STATUS_RF_KILL_HW, &priv->status); ++ ++ if (iwl_is_rfkill(priv)) { ++ wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); ++ iwl_enable_interrupts(priv); ++ return -ERFKILL; ++ } ++ ++ iwl_write32(priv, CSR_INT, 0xFFFFFFFF); ++ ++ ret = iwlagn_hw_nic_init(priv); ++ if (ret) { ++ IWL_ERR(priv, "Unable to init nic\n"); ++ return ret; ++ } ++ ++ /* make sure rfkill handshake bits are cleared */ ++ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); ++ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, ++ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); ++ ++ /* clear (again), then enable host interrupts */ ++ iwl_write32(priv, CSR_INT, 0xFFFFFFFF); ++ iwl_enable_interrupts(priv); ++ ++ /* really make sure rfkill handshake bits are cleared */ ++ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); ++ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); ++ ++ return 0; ++} ++ ++void iwlagn_stop_device(struct iwl_priv *priv) ++{ ++ unsigned long flags; ++ ++ /* stop and reset the on-board processor */ ++ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); ++ ++ /* tell the device to stop sending interrupts */ ++ spin_lock_irqsave(&priv->lock, flags); ++ iwl_disable_interrupts(priv); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ iwl_synchronize_irq(priv); ++ ++ /* device going down, Stop using ICT table */ ++ iwl_disable_ict(priv); ++ ++ /* ++ * If a HW restart happens during firmware loading, ++ * then the firmware loading might call this function ++ * and later it might be called again due to the ++ * restart. So don't process again if the device is ++ * already dead. ++ */ ++ if (test_bit(STATUS_DEVICE_ENABLED, &priv->status)) { ++ iwlagn_txq_ctx_stop(priv); ++ iwlagn_rxq_stop(priv); ++ ++ /* Power-down device's busmaster DMA clocks */ ++ iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); ++ udelay(5); ++ } ++ ++ /* Make sure (redundant) we've released our request to stay awake */ ++ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); ++ ++ /* Stop the device, and put it in low power state */ ++ iwl_apm_stop(priv); ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-rs.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-rs.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-rs.c 2011-05-05 23:29:45.402440861 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 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 +@@ -115,13 +115,18 @@ + /* FIXME:RS: ^^ should be INV (legacy) */ + }; + ++static inline u8 rs_extract_rate(u32 rate_n_flags) ++{ ++ return (u8)(rate_n_flags & RATE_MCS_RATE_MSK); ++} ++ + static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) + { + int idx = 0; + + /* HT rate format */ + if (rate_n_flags & RATE_MCS_HT_MSK) { +- idx = (rate_n_flags & 0xff); ++ idx = rs_extract_rate(rate_n_flags); + + if (idx >= IWL_RATE_MIMO3_6M_PLCP) + idx = idx - IWL_RATE_MIMO3_6M_PLCP; +@@ -138,7 +143,8 @@ + /* legacy rate format, search for match in table */ + } else { + for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) +- if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) ++ if (iwl_rates[idx].plcp == ++ rs_extract_rate(rate_n_flags)) + return idx; + } + +@@ -239,11 +245,6 @@ + + #define MCS_INDEX_PER_STREAM (8) + +-static inline u8 rs_extract_rate(u32 rate_n_flags) +-{ +- return (u8)(rate_n_flags & 0xFF); +-} +- + static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) + { + window->data = 0; +@@ -2770,16 +2771,13 @@ + static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, + gfp_t gfp) + { +- struct iwl_lq_sta *lq_sta; + struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; + struct iwl_priv *priv; + + priv = (struct iwl_priv *)priv_rate; + IWL_DEBUG_RATE(priv, "create station rate scale window\n"); + +- lq_sta = &sta_priv->lq_sta; +- +- return lq_sta; ++ return &sta_priv->lq_sta; + } + + /* +@@ -2912,7 +2910,8 @@ + ant_toggle_cnt = 1; + repeat_rate = IWL_NUMBER_TRY; + } else { +- repeat_rate = IWL_HT_NUMBER_TRY; ++ repeat_rate = min(IWL_HT_NUMBER_TRY, ++ LINK_QUAL_AGG_DISABLE_START_DEF - 1); + } + + lq_cmd->general_params.mimo_delimiter = +@@ -3257,7 +3256,6 @@ + { + char buff[120]; + int desc = 0; +- ssize_t ret; + + struct iwl_lq_sta *lq_sta = file->private_data; + struct iwl_priv *priv; +@@ -3274,8 +3272,7 @@ + "Bit Rate= %d Mb/s\n", + iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); + +- ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); +- return ret; ++ return simple_read_from_buffer(user_buf, count, ppos, buff, desc); + } + + static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-rs.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-rs.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-rs.h 2011-05-05 23:29:45.217438626 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 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 +@@ -41,20 +41,6 @@ + u8 next_rs_tgg; /* next rate used in TGG rs algo */ + }; + +-struct iwl3945_rate_info { +- u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ +- u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ +- u8 prev_ieee; /* previous rate in IEEE speeds */ +- u8 next_ieee; /* next rate in IEEE speeds */ +- u8 prev_rs; /* previous rate used in rs algo */ +- u8 next_rs; /* next rate used in rs algo */ +- u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ +- u8 next_rs_tgg; /* next rate used in TGG rs algo */ +- u8 table_rs_index; /* index in rate scale table cmd */ +- u8 prev_table_rs; /* prev in rate table cmd */ +-}; +- +- + /* + * These serve as indexes into + * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; +@@ -75,7 +61,6 @@ + IWL_RATE_60M_INDEX, + IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ + IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */ +- IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1, + IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, + IWL_RATE_INVALID = IWL_RATE_COUNT, + }; +@@ -98,7 +83,6 @@ + + enum { + IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, +- IWL39_LAST_OFDM_RATE = IWL_RATE_54M_INDEX, + IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX, + IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, + IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, +@@ -213,7 +197,6 @@ + IWL_CCK_BASIC_RATES_MASK) + + #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) +-#define IWL_RATES_MASK_3945 ((1 << IWL_RATE_COUNT_3945) - 1) + + #define IWL_INVALID_VALUE -1 + +@@ -453,19 +436,9 @@ + } + + +-/** +- * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info +- * +- * The specific throughput table used is based on the type of network +- * the associated with, including A, B, G, and G w/ TGG protection +- */ +-extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); +- + /* Initialize station's rate scaling information after adding station */ + extern void iwl_rs_rate_init(struct iwl_priv *priv, + struct ieee80211_sta *sta, u8 sta_id); +-extern void iwl3945_rs_rate_init(struct iwl_priv *priv, +- struct ieee80211_sta *sta, u8 sta_id); + + /** + * iwl_rate_control_register - Register the rate control algorithm callbacks +@@ -478,7 +451,6 @@ + * + */ + extern int iwlagn_rate_control_register(void); +-extern int iwl3945_rate_control_register(void); + + /** + * iwl_rate_control_unregister - Unregister the rate control callbacks +@@ -487,6 +459,5 @@ + * the driver is unloaded. + */ + extern void iwlagn_rate_control_unregister(void); +-extern void iwl3945_rate_control_unregister(void); + + #endif /* __iwl_agn__rs__ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c 2011-05-05 23:29:45.375440535 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 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 +@@ -29,6 +29,7 @@ + #include "iwl-sta.h" + #include "iwl-core.h" + #include "iwl-agn-calib.h" ++#include "iwl-helpers.h" + + static int iwlagn_disable_bss(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, +@@ -57,8 +58,9 @@ + u8 old_dev_type = send->dev_type; + int ret; + +- iwlagn_init_notification_wait(priv, &disable_wait, NULL, +- REPLY_WIPAN_DEACTIVATION_COMPLETE); ++ iwlagn_init_notification_wait(priv, &disable_wait, ++ REPLY_WIPAN_DEACTIVATION_COMPLETE, ++ NULL, NULL); + + send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + send->dev_type = RXON_DEV_TYPE_P2P; +@@ -71,13 +73,9 @@ + IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); + iwlagn_remove_notification(priv, &disable_wait); + } else { +- signed long wait_res; +- +- wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ); +- if (wait_res == 0) { ++ ret = iwlagn_wait_notification(priv, &disable_wait, HZ); ++ if (ret) + IWL_ERR(priv, "Timed out waiting for PAN disable\n"); +- ret = -EIO; +- } + } + + return ret; +@@ -123,6 +121,151 @@ + return iwlagn_send_beacon_cmd(priv); + } + ++static int iwlagn_send_rxon_assoc(struct iwl_priv *priv, ++ struct iwl_rxon_context *ctx) ++{ ++ int ret = 0; ++ struct iwl_rxon_assoc_cmd rxon_assoc; ++ const struct iwl_rxon_cmd *rxon1 = &ctx->staging; ++ const struct iwl_rxon_cmd *rxon2 = &ctx->active; ++ ++ if ((rxon1->flags == rxon2->flags) && ++ (rxon1->filter_flags == rxon2->filter_flags) && ++ (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && ++ (rxon1->ofdm_ht_single_stream_basic_rates == ++ rxon2->ofdm_ht_single_stream_basic_rates) && ++ (rxon1->ofdm_ht_dual_stream_basic_rates == ++ rxon2->ofdm_ht_dual_stream_basic_rates) && ++ (rxon1->ofdm_ht_triple_stream_basic_rates == ++ rxon2->ofdm_ht_triple_stream_basic_rates) && ++ (rxon1->acquisition_data == rxon2->acquisition_data) && ++ (rxon1->rx_chain == rxon2->rx_chain) && ++ (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { ++ IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); ++ return 0; ++ } ++ ++ rxon_assoc.flags = ctx->staging.flags; ++ rxon_assoc.filter_flags = ctx->staging.filter_flags; ++ rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; ++ rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; ++ rxon_assoc.reserved1 = 0; ++ rxon_assoc.reserved2 = 0; ++ rxon_assoc.reserved3 = 0; ++ rxon_assoc.ofdm_ht_single_stream_basic_rates = ++ ctx->staging.ofdm_ht_single_stream_basic_rates; ++ rxon_assoc.ofdm_ht_dual_stream_basic_rates = ++ ctx->staging.ofdm_ht_dual_stream_basic_rates; ++ rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; ++ rxon_assoc.ofdm_ht_triple_stream_basic_rates = ++ ctx->staging.ofdm_ht_triple_stream_basic_rates; ++ rxon_assoc.acquisition_data = ctx->staging.acquisition_data; ++ ++ ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd, ++ sizeof(rxon_assoc), &rxon_assoc, NULL); ++ if (ret) ++ return ret; ++ ++ return ret; ++} ++ ++static int iwlagn_rxon_disconn(struct iwl_priv *priv, ++ struct iwl_rxon_context *ctx) ++{ ++ int ret; ++ struct iwl_rxon_cmd *active = (void *)&ctx->active; ++ ++ if (ctx->ctxid == IWL_RXON_CTX_BSS) ++ ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); ++ else ++ ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); ++ if (ret) ++ return ret; ++ ++ /* ++ * Un-assoc RXON clears the station table and WEP ++ * keys, so we have to restore those afterwards. ++ */ ++ iwl_clear_ucode_stations(priv, ctx); ++ iwl_restore_stations(priv, ctx); ++ ret = iwl_restore_default_wep_keys(priv, ctx); ++ if (ret) { ++ IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); ++ return ret; ++ } ++ ++ memcpy(active, &ctx->staging, sizeof(*active)); ++ return 0; ++} ++ ++static int iwlagn_rxon_connect(struct iwl_priv *priv, ++ struct iwl_rxon_context *ctx) ++{ ++ int ret; ++ struct iwl_rxon_cmd *active = (void *)&ctx->active; ++ ++ /* RXON timing must be before associated RXON */ ++ ret = iwl_send_rxon_timing(priv, ctx); ++ if (ret) { ++ IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); ++ return ret; ++ } ++ /* QoS info may be cleared by previous un-assoc RXON */ ++ iwlagn_update_qos(priv, ctx); ++ ++ /* ++ * We'll run into this code path when beaconing is ++ * enabled, but then we also need to send the beacon ++ * to the device. ++ */ ++ if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { ++ ret = iwlagn_update_beacon(priv, ctx->vif); ++ if (ret) { ++ IWL_ERR(priv, ++ "Error sending required beacon (%d)!\n", ++ ret); ++ return ret; ++ } ++ } ++ ++ priv->start_calib = 0; ++ /* ++ * Apply the new configuration. ++ * ++ * Associated RXON doesn't clear the station table in uCode, ++ * so we don't need to restore stations etc. after this. ++ */ ++ ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, ++ sizeof(struct iwl_rxon_cmd), &ctx->staging); ++ if (ret) { ++ IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); ++ return ret; ++ } ++ memcpy(active, &ctx->staging, sizeof(*active)); ++ ++ iwl_reprogram_ap_sta(priv, ctx); ++ ++ /* IBSS beacon needs to be sent after setting assoc */ ++ if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) ++ if (iwlagn_update_beacon(priv, ctx->vif)) ++ IWL_ERR(priv, "Error sending IBSS beacon\n"); ++ iwl_init_sensitivity(priv); ++ ++ /* ++ * If we issue a new RXON command which required a tune then ++ * we must send a new TXPOWER command or we won't be able to ++ * Tx any frames. ++ * ++ * It's expected we set power here if channel is changing. ++ */ ++ ret = iwl_set_tx_power(priv, priv->tx_power_next, true); ++ if (ret) { ++ IWL_ERR(priv, "Error sending TX power (%d)\n", ret); ++ return ret; ++ } ++ return 0; ++} ++ + /** + * iwlagn_commit_rxon - commit staging_rxon to hardware + * +@@ -130,6 +273,16 @@ + * the active_rxon structure is updated with the new data. This + * function correctly transitions out of the RXON_ASSOC_MSK state if + * a HW tune is required based on the RXON structure changes. ++ * ++ * The connect/disconnect flow should be as the following: ++ * ++ * 1. make sure send RXON command with association bit unset if not connect ++ * this should include the channel and the band for the candidate ++ * to be connected to ++ * 2. Add Station before RXON association with the AP ++ * 3. RXON_timing has to send before RXON for connection ++ * 4. full RXON command - associated bit set ++ * 5. use RXON_ASSOC command to update any flags changes + */ + int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) + { +@@ -179,6 +332,7 @@ + else + ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + ++ iwl_print_rx_config_cmd(priv, ctx); + ret = iwl_check_rxon_cmd(priv, ctx); + if (ret) { + IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); +@@ -202,14 +356,13 @@ + * and other flags for the current radio configuration. + */ + if (!iwl_full_rxon_required(priv, ctx)) { +- ret = iwl_send_rxon_assoc(priv, ctx); ++ ret = iwlagn_send_rxon_assoc(priv, ctx); + if (ret) { + IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); + return ret; + } + + memcpy(active, &ctx->staging, sizeof(*active)); +- iwl_print_rx_config_cmd(priv, ctx); + return 0; + } + +@@ -219,7 +372,7 @@ + return ret; + } + +- iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto); ++ iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto); + + IWL_DEBUG_INFO(priv, + "Going to commit RXON\n" +@@ -237,92 +390,13 @@ + * set up filters in the device. + */ + if ((old_assoc && new_assoc) || !new_assoc) { +- if (ctx->ctxid == IWL_RXON_CTX_BSS) +- ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); +- else +- ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); ++ ret = iwlagn_rxon_disconn(priv, ctx); + if (ret) + return ret; +- +- memcpy(active, &ctx->staging, sizeof(*active)); +- +- /* +- * Un-assoc RXON clears the station table and WEP +- * keys, so we have to restore those afterwards. +- */ +- iwl_clear_ucode_stations(priv, ctx); +- iwl_restore_stations(priv, ctx); +- ret = iwl_restore_default_wep_keys(priv, ctx); +- if (ret) { +- IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); +- return ret; +- } +- } +- +- /* RXON timing must be before associated RXON */ +- ret = iwl_send_rxon_timing(priv, ctx); +- if (ret) { +- IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); +- return ret; +- } +- +- if (new_assoc) { +- /* QoS info may be cleared by previous un-assoc RXON */ +- iwlagn_update_qos(priv, ctx); +- +- /* +- * We'll run into this code path when beaconing is +- * enabled, but then we also need to send the beacon +- * to the device. +- */ +- if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { +- ret = iwlagn_update_beacon(priv, ctx->vif); +- if (ret) { +- IWL_ERR(priv, +- "Error sending required beacon (%d)!\n", +- ret); +- return ret; +- } +- } +- +- priv->start_calib = 0; +- /* +- * Apply the new configuration. +- * +- * Associated RXON doesn't clear the station table in uCode, +- * so we don't need to restore stations etc. after this. +- */ +- ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, +- sizeof(struct iwl_rxon_cmd), &ctx->staging); +- if (ret) { +- IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); +- return ret; +- } +- memcpy(active, &ctx->staging, sizeof(*active)); +- +- iwl_reprogram_ap_sta(priv, ctx); +- +- /* IBSS beacon needs to be sent after setting assoc */ +- if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) +- if (iwlagn_update_beacon(priv, ctx->vif)) +- IWL_ERR(priv, "Error sending IBSS beacon\n"); + } + +- iwl_print_rx_config_cmd(priv, ctx); +- +- iwl_init_sensitivity(priv); +- +- /* +- * If we issue a new RXON command which required a tune then we must +- * send a new TXPOWER command or we won't be able to Tx any frames. +- * +- * It's expected we set power here if channel is changing. +- */ +- ret = iwl_set_tx_power(priv, priv->tx_power_next, true); +- if (ret) { +- IWL_ERR(priv, "Error sending TX power (%d)\n", ret); +- return ret; +- } ++ if (new_assoc) ++ return iwlagn_rxon_connect(priv, ctx); + + return 0; + } +@@ -595,6 +669,18 @@ + priv->timestamp = bss_conf->timestamp; + ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; + } else { ++ /* ++ * If we disassociate while there are pending ++ * frames, just wake up the queues and let the ++ * frames "escape" ... This shouldn't really ++ * be happening to start with, but we should ++ * not get stuck in this case either since it ++ * can happen if userspace gets confused. ++ */ ++ if (ctx->last_tx_rejected) { ++ ctx->last_tx_rejected = false; ++ iwl_wake_any_queue(priv, ctx); ++ } + ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + } + } +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-sta.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-sta.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-sta.c 2011-05-05 23:29:45.267439231 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. +@@ -474,7 +474,7 @@ + memset(&priv->stations[sta_id].keyinfo, 0, + sizeof(struct iwl_hw_key)); + memset(&priv->stations[sta_id].sta.key, 0, +- sizeof(struct iwl4965_keyinfo)); ++ sizeof(struct iwl_keyinfo)); + priv->stations[sta_id].sta.key.key_flags = + STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; + priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-tt.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-tt.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-tt.c 2011-05-05 23:29:45.376440547 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-tt.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-tt.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-tt.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-tt.h 2011-05-05 23:29:45.227438747 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-tx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-tx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-tx.c 2011-05-05 23:29:45.407440921 +0200 +@@ -2,7 +2,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -222,13 +222,8 @@ + scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); + } + +-int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, +- int tx_fifo, int sta_id, int tid, u16 ssn_idx) ++static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, int tid) + { +- unsigned long flags; +- u16 ra_tid; +- int ret; +- + if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || + (IWLAGN_FIRST_AMPDU_QUEUE + + priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { +@@ -240,12 +235,33 @@ + return -EINVAL; + } + +- ra_tid = BUILD_RAxTID(sta_id, tid); +- + /* Modify device's station table to Tx this TID */ +- ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); +- if (ret) +- return ret; ++ return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); ++} ++ ++void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv, ++ struct ieee80211_sta *sta, ++ int tid, int frame_limit) ++{ ++ int sta_id, tx_fifo, txq_id, ssn_idx; ++ u16 ra_tid; ++ unsigned long flags; ++ struct iwl_tid_data *tid_data; ++ ++ sta_id = iwl_sta_id(sta); ++ if (WARN_ON(sta_id == IWL_INVALID_STATION)) ++ return; ++ if (WARN_ON(tid >= MAX_TID_COUNT)) ++ return; ++ ++ spin_lock_irqsave(&priv->sta_lock, flags); ++ tid_data = &priv->stations[sta_id].tid[tid]; ++ ssn_idx = SEQ_TO_SN(tid_data->seq_number); ++ txq_id = tid_data->agg.txq_id; ++ tx_fifo = tid_data->agg.tx_fifo; ++ spin_unlock_irqrestore(&priv->sta_lock, flags); ++ ++ ra_tid = BUILD_RAxTID(sta_id, tid); + + spin_lock_irqsave(&priv->lock, flags); + +@@ -271,10 +287,10 @@ + iwl_write_targ_mem(priv, priv->scd_base_addr + + IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + + sizeof(u32), +- ((SCD_WIN_SIZE << ++ ((frame_limit << + IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & + IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | +- ((SCD_FRAME_LIMIT << ++ ((frame_limit << + IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & + IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); + +@@ -284,12 +300,10 @@ + iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); + + spin_unlock_irqrestore(&priv->lock, flags); +- +- return 0; + } + +-int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, +- u16 ssn_idx, u8 tx_fifo) ++static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, ++ u16 ssn_idx, u8 tx_fifo) + { + if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || + (IWLAGN_FIRST_AMPDU_QUEUE + +@@ -1039,11 +1053,11 @@ + tid_data = &priv->stations[sta_id].tid[tid]; + *ssn = SEQ_TO_SN(tid_data->seq_number); + tid_data->agg.txq_id = txq_id; ++ tid_data->agg.tx_fifo = tx_fifo; + iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id); + spin_unlock_irqrestore(&priv->sta_lock, flags); + +- ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo, +- sta_id, tid, *ssn); ++ ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid); + if (ret) + return ret; + +@@ -1130,8 +1144,7 @@ + * to deactivate the uCode queue, just return "success" to allow + * mac80211 to clean up it own data. + */ +- priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, +- tx_fifo_id); ++ iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo_id); + spin_unlock_irqrestore(&priv->lock, flags); + + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); +@@ -1160,8 +1173,7 @@ + u16 ssn = SEQ_TO_SN(tid_data->seq_number); + int tx_fifo = get_fifo_from_tid(ctx, tid); + IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n"); +- priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, +- ssn, tx_fifo); ++ iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo); + tid_data->agg.state = IWL_AGG_OFF; + ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid); + } +@@ -1260,11 +1272,11 @@ + struct iwl_compressed_ba_resp *ba_resp) + + { +- int i, sh, ack; ++ int sh; + u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); + u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); +- int successes = 0; + struct ieee80211_tx_info *info; ++ u64 bitmap, sent_bitmap; + + if (unlikely(!agg->wait_for_ba)) { + if (unlikely(ba_resp->bitmap)) +@@ -1278,70 +1290,42 @@ + + /* Calculate shift to align block-ack bits with our Tx window bits */ + sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); +- if (sh < 0) /* tbw something is wrong with indices */ ++ if (sh < 0) + sh += 0x100; + +- if (agg->frame_count > (64 - sh)) { +- IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size"); +- return -1; +- } +- if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { ++ /* ++ * Check for success or failure according to the ++ * transmitted bitmap and block-ack bitmap ++ */ ++ bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; ++ sent_bitmap = bitmap & agg->bitmap; ++ ++ /* Sanity check values reported by uCode */ ++ if (ba_resp->txed_2_done > ba_resp->txed) { ++ IWL_DEBUG_TX_REPLY(priv, ++ "bogus sent(%d) and ack(%d) count\n", ++ ba_resp->txed, ba_resp->txed_2_done); + /* +- * sent and ack information provided by uCode +- * use it instead of figure out ourself ++ * set txed_2_done = txed, ++ * so it won't impact rate scale + */ +- if (ba_resp->txed_2_done > ba_resp->txed) { +- IWL_DEBUG_TX_REPLY(priv, +- "bogus sent(%d) and ack(%d) count\n", +- ba_resp->txed, ba_resp->txed_2_done); +- /* +- * set txed_2_done = txed, +- * so it won't impact rate scale +- */ +- ba_resp->txed = ba_resp->txed_2_done; +- } +- IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", +- ba_resp->txed, ba_resp->txed_2_done); +- } else { +- u64 bitmap, sent_bitmap; +- +- /* don't use 64-bit values for now */ +- bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; +- +- /* check for success or failure according to the +- * transmitted bitmap and block-ack bitmap */ +- sent_bitmap = bitmap & agg->bitmap; +- +- /* For each frame attempted in aggregation, +- * update driver's record of tx frame's status. */ +- i = 0; +- while (sent_bitmap) { +- ack = sent_bitmap & 1ULL; +- successes += ack; +- IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n", +- ack ? "ACK" : "NACK", i, +- (agg->start_idx + i) & 0xff, +- agg->start_idx + i); +- sent_bitmap >>= 1; +- ++i; +- } ++ ba_resp->txed = ba_resp->txed_2_done; ++ } ++ IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", ++ ba_resp->txed, ba_resp->txed_2_done); + +- IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", +- (unsigned long long)bitmap); ++ /* Find the first ACKed frame to store the TX status */ ++ while (sent_bitmap && !(sent_bitmap & 1)) { ++ agg->start_idx = (agg->start_idx + 1) & 0xff; ++ sent_bitmap >>= 1; + } + + info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); + memset(&info->status, 0, sizeof(info->status)); + info->flags |= IEEE80211_TX_STAT_ACK; + info->flags |= IEEE80211_TX_STAT_AMPDU; +- if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { +- info->status.ampdu_ack_len = ba_resp->txed_2_done; +- info->status.ampdu_len = ba_resp->txed; +- +- } else { +- info->status.ampdu_ack_len = successes; +- info->status.ampdu_len = agg->frame_count; +- } ++ info->status.ampdu_ack_len = ba_resp->txed_2_done; ++ info->status.ampdu_len = ba_resp->txed; + iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); + + return 0; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c 2011-05-05 23:29:45.326439943 +0200 +@@ -2,7 +2,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -161,47 +161,19 @@ + } + + static int iwlagn_load_given_ucode(struct iwl_priv *priv, +- struct fw_desc *inst_image, +- struct fw_desc *data_image) ++ struct fw_img *image) + { + int ret = 0; + +- ret = iwlagn_load_section(priv, "INST", inst_image, ++ ret = iwlagn_load_section(priv, "INST", &image->code, + IWLAGN_RTC_INST_LOWER_BOUND); + if (ret) + return ret; + +- return iwlagn_load_section(priv, "DATA", data_image, ++ return iwlagn_load_section(priv, "DATA", &image->data, + IWLAGN_RTC_DATA_LOWER_BOUND); + } + +-int iwlagn_load_ucode(struct iwl_priv *priv) +-{ +- int ret = 0; +- +- /* check whether init ucode should be loaded, or rather runtime ucode */ +- if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) { +- IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n"); +- ret = iwlagn_load_given_ucode(priv, +- &priv->ucode_init, &priv->ucode_init_data); +- if (!ret) { +- IWL_DEBUG_INFO(priv, "Init ucode load complete.\n"); +- priv->ucode_type = UCODE_INIT; +- } +- } else { +- IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. " +- "Loading runtime ucode...\n"); +- ret = iwlagn_load_given_ucode(priv, +- &priv->ucode_code, &priv->ucode_data); +- if (!ret) { +- IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n"); +- priv->ucode_type = UCODE_RT; +- } +- } +- +- return ret; +-} +- + /* + * Calibration + */ +@@ -297,33 +269,9 @@ + iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); + } + +-void iwlagn_rx_calib_complete(struct iwl_priv *priv, +- struct iwl_rx_mem_buffer *rxb) +-{ +- IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n"); +- queue_work(priv->workqueue, &priv->restart); +-} +- +-void iwlagn_init_alive_start(struct iwl_priv *priv) ++static int iwlagn_init_alive_start(struct iwl_priv *priv) + { +- int ret = 0; +- +- /* initialize uCode was loaded... verify inst image. +- * This is a paranoid check, because we would not have gotten the +- * "initialize" alive if code weren't properly loaded. */ +- if (iwl_verify_ucode(priv)) { +- /* Runtime instruction load was bad; +- * take it all the way back down so we can try again */ +- IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); +- goto restart; +- } +- +- ret = priv->cfg->ops->lib->alive_notify(priv); +- if (ret) { +- IWL_WARN(priv, +- "Could not complete ALIVE transition: %d\n", ret); +- goto restart; +- } ++ int ret; + + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { +@@ -333,24 +281,25 @@ + * no need to close the envlope since we are going + * to load the runtime uCode later. + */ +- iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, ++ ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, + BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); ++ if (ret) ++ return ret; + + } +- iwlagn_send_calib_cfg(priv); ++ ++ ret = iwlagn_send_calib_cfg(priv); ++ if (ret) ++ return ret; + + /** + * temperature offset calibration is only needed for runtime ucode, + * so prepare the value now. + */ + if (priv->cfg->need_temp_offset_calib) +- iwlagn_set_temperature_offset_calib(priv); +- +- return; ++ return iwlagn_set_temperature_offset_calib(priv); + +-restart: +- /* real restart (first load init_ucode) */ +- queue_work(priv->workqueue, &priv->restart); ++ return 0; + } + + static int iwlagn_send_wimax_coex(struct iwl_priv *priv) +@@ -413,25 +362,30 @@ + IWL_ERR(priv, "failed to send BT prio tbl command\n"); + } + +-void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) ++int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) + { + struct iwl_bt_coex_prot_env_cmd env_cmd; ++ int ret; + + env_cmd.action = action; + env_cmd.type = type; +- if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, +- sizeof(env_cmd), &env_cmd)) ++ ret = iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, ++ sizeof(env_cmd), &env_cmd); ++ if (ret) + IWL_ERR(priv, "failed to send BT env command\n"); ++ return ret; + } + + +-int iwlagn_alive_notify(struct iwl_priv *priv) ++static int iwlagn_alive_notify(struct iwl_priv *priv) + { + const struct queue_to_fifo_ac *queue_to_fifo; ++ struct iwl_rxon_context *ctx; + u32 a; + unsigned long flags; + int i, chan; + u32 reg_val; ++ int ret; + + spin_lock_irqsave(&priv->lock, flags); + +@@ -500,6 +454,8 @@ + memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped)); + for (i = 0; i < 4; i++) + atomic_set(&priv->queue_stop_count[i], 0); ++ for_each_context(priv, ctx) ++ ctx->last_tx_rejected = false; + + /* reset to 0 to enable all the queue first */ + priv->txq_ctx_active_msk = 0; +@@ -527,12 +483,15 @@ + iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + +- iwlagn_send_wimax_coex(priv); ++ ret = iwlagn_send_wimax_coex(priv); ++ if (ret) ++ return ret; + +- iwlagn_set_Xtal_calib(priv); +- iwl_send_calib_results(priv); ++ ret = iwlagn_set_Xtal_calib(priv); ++ if (ret) ++ return ret; + +- return 0; ++ return iwl_send_calib_results(priv); + } + + +@@ -541,11 +500,12 @@ + * using sample data 100 bytes apart. If these sample points are good, + * it's a pretty good bet that everything between them is good, too. + */ +-static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) ++static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, ++ struct fw_desc *fw_desc) + { ++ __le32 *image = (__le32 *)fw_desc->v_addr; ++ u32 len = fw_desc->len; + u32 val; +- int ret = 0; +- u32 errcnt = 0; + u32 i; + + IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); +@@ -556,104 +516,204 @@ + * if IWL_DL_IO is set */ + iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, + i + IWLAGN_RTC_INST_LOWER_BOUND); +- val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); +- if (val != le32_to_cpu(*image)) { +- ret = -EIO; +- errcnt++; +- if (errcnt >= 3) +- break; +- } ++ val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); ++ if (val != le32_to_cpu(*image)) ++ return -EIO; + } + +- return ret; ++ return 0; + } + +-/** +- * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host, +- * looking at all data. +- */ +-static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, +- u32 len) ++static void iwl_print_mismatch_inst(struct iwl_priv *priv, ++ struct fw_desc *fw_desc) + { ++ __le32 *image = (__le32 *)fw_desc->v_addr; ++ u32 len = fw_desc->len; + u32 val; +- u32 save_len = len; +- int ret = 0; +- u32 errcnt; ++ u32 offs; ++ int errors = 0; + + IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); + + iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, + IWLAGN_RTC_INST_LOWER_BOUND); + +- errcnt = 0; +- for (; len > 0; len -= sizeof(u32), image++) { ++ for (offs = 0; ++ offs < len && errors < 20; ++ offs += sizeof(u32), image++) { + /* read data comes through single port, auto-incr addr */ +- /* NOTE: Use the debugless read so we don't flood kernel log +- * if IWL_DL_IO is set */ +- val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); ++ val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { +- IWL_ERR(priv, "uCode INST section is invalid at " +- "offset 0x%x, is 0x%x, s/b 0x%x\n", +- save_len - len, val, le32_to_cpu(*image)); +- ret = -EIO; +- errcnt++; +- if (errcnt >= 20) +- break; ++ IWL_ERR(priv, "uCode INST section at " ++ "offset 0x%x, is 0x%x, s/b 0x%x\n", ++ offs, val, le32_to_cpu(*image)); ++ errors++; + } + } +- +- if (!errcnt) +- IWL_DEBUG_INFO(priv, +- "ucode image in INSTRUCTION memory is good\n"); +- +- return ret; + } + + /** + * iwl_verify_ucode - determine which instruction image is in SRAM, + * and verify its contents + */ +-int iwl_verify_ucode(struct iwl_priv *priv) ++static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img) + { +- __le32 *image; +- u32 len; ++ if (!iwlcore_verify_inst_sparse(priv, &img->code)) { ++ IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n"); ++ return 0; ++ } ++ ++ IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); ++ ++ iwl_print_mismatch_inst(priv, &img->code); ++ return -EIO; ++} ++ ++struct iwlagn_alive_data { ++ bool valid; ++ u8 subtype; ++}; ++ ++static void iwlagn_alive_fn(struct iwl_priv *priv, ++ struct iwl_rx_packet *pkt, ++ void *data) ++{ ++ struct iwlagn_alive_data *alive_data = data; ++ struct iwl_alive_resp *palive; ++ ++ palive = &pkt->u.alive_frame; ++ ++ IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " ++ "0x%01X 0x%01X\n", ++ palive->is_valid, palive->ver_type, ++ palive->ver_subtype); ++ ++ priv->device_pointers.error_event_table = ++ le32_to_cpu(palive->error_event_table_ptr); ++ priv->device_pointers.log_event_table = ++ le32_to_cpu(palive->log_event_table_ptr); ++ ++ alive_data->subtype = palive->ver_subtype; ++ alive_data->valid = palive->is_valid == UCODE_VALID_OK; ++} ++ ++#define UCODE_ALIVE_TIMEOUT HZ ++#define UCODE_CALIB_TIMEOUT (2*HZ) ++ ++int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, ++ struct fw_img *image, ++ int subtype, int alternate_subtype) ++{ ++ struct iwl_notification_wait alive_wait; ++ struct iwlagn_alive_data alive_data; + int ret; ++ enum iwlagn_ucode_subtype old_type; + +- /* Try bootstrap */ +- image = (__le32 *)priv->ucode_boot.v_addr; +- len = priv->ucode_boot.len; +- ret = iwlcore_verify_inst_sparse(priv, image, len); +- if (!ret) { +- IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n"); +- return 0; ++ ret = iwlagn_start_device(priv); ++ if (ret) ++ return ret; ++ ++ iwlagn_init_notification_wait(priv, &alive_wait, REPLY_ALIVE, ++ iwlagn_alive_fn, &alive_data); ++ ++ old_type = priv->ucode_type; ++ priv->ucode_type = subtype; ++ ++ ret = iwlagn_load_given_ucode(priv, image); ++ if (ret) { ++ priv->ucode_type = old_type; ++ iwlagn_remove_notification(priv, &alive_wait); ++ return ret; + } + +- /* Try initialize */ +- image = (__le32 *)priv->ucode_init.v_addr; +- len = priv->ucode_init.len; +- ret = iwlcore_verify_inst_sparse(priv, image, len); +- if (!ret) { +- IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n"); +- return 0; ++ /* Remove all resets to allow NIC to operate */ ++ iwl_write32(priv, CSR_RESET, 0); ++ ++ /* ++ * Some things may run in the background now, but we ++ * just wait for the ALIVE notification here. ++ */ ++ ret = iwlagn_wait_notification(priv, &alive_wait, UCODE_ALIVE_TIMEOUT); ++ if (ret) { ++ priv->ucode_type = old_type; ++ return ret; + } + +- /* Try runtime/protocol */ +- image = (__le32 *)priv->ucode_code.v_addr; +- len = priv->ucode_code.len; +- ret = iwlcore_verify_inst_sparse(priv, image, len); +- if (!ret) { +- IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n"); +- return 0; ++ if (!alive_data.valid) { ++ IWL_ERR(priv, "Loaded ucode is not valid!\n"); ++ priv->ucode_type = old_type; ++ return -EIO; ++ } ++ ++ if (alive_data.subtype != subtype && ++ alive_data.subtype != alternate_subtype) { ++ IWL_ERR(priv, ++ "Loaded ucode is not expected type (got %d, expected %d)!\n", ++ alive_data.subtype, subtype); ++ priv->ucode_type = old_type; ++ return -EIO; + } + +- IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); ++ ret = iwl_verify_ucode(priv, image); ++ if (ret) { ++ priv->ucode_type = old_type; ++ return ret; ++ } ++ ++ /* delay a bit to give rfkill time to run */ ++ msleep(5); ++ ++ ret = iwlagn_alive_notify(priv); ++ if (ret) { ++ IWL_WARN(priv, ++ "Could not complete ALIVE transition: %d\n", ret); ++ priv->ucode_type = old_type; ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int iwlagn_run_init_ucode(struct iwl_priv *priv) ++{ ++ struct iwl_notification_wait calib_wait; ++ int ret; ++ ++ lockdep_assert_held(&priv->mutex); ++ ++ /* No init ucode required? Curious, but maybe ok */ ++ if (!priv->ucode_init.code.len) ++ return 0; ++ ++ if (priv->ucode_type != UCODE_SUBTYPE_NONE_LOADED) ++ return 0; ++ ++ iwlagn_init_notification_wait(priv, &calib_wait, ++ CALIBRATION_COMPLETE_NOTIFICATION, ++ NULL, NULL); ++ ++ /* Will also start the device */ ++ ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init, ++ UCODE_SUBTYPE_INIT, -1); ++ if (ret) ++ goto error; ++ ++ ret = iwlagn_init_alive_start(priv); ++ if (ret) ++ goto error; ++ ++ /* ++ * Some things may run in the background now, but we ++ * just wait for the calibration complete notification. ++ */ ++ ret = iwlagn_wait_notification(priv, &calib_wait, UCODE_CALIB_TIMEOUT); + +- /* Since nothing seems to match, show first several data entries in +- * instruction SRAM, so maybe visual inspection will give a clue. +- * Selection of bootstrap image (vs. other images) is arbitrary. */ +- image = (__le32 *)priv->ucode_boot.v_addr; +- len = priv->ucode_boot.len; +- ret = iwl_verify_inst_full(priv, image, len); ++ goto out; + ++ error: ++ iwlagn_remove_notification(priv, &calib_wait); ++ out: ++ /* Whatever happened, stop the device */ ++ iwlagn_stop_device(priv); + return ret; + } +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-commands.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-commands.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-commands.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-commands.h 2011-05-05 23:29:45.280439387 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +@@ -103,9 +103,7 @@ + REPLY_WEPKEY = 0x20, + + /* RX, TX, LEDs */ +- REPLY_3945_RX = 0x1b, /* 3945 only */ + REPLY_TX = 0x1c, +- REPLY_RATE_SCALE = 0x47, /* 3945 only */ + REPLY_LEDS_CMD = 0x48, + REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* for 4965 and up */ + +@@ -229,7 +227,7 @@ + * There is one exception: uCode sets bit 15 when it originates + * the response/notification, i.e. when the response/notification + * is not a direct response to a command sent by the driver. For +- * example, uCode issues REPLY_3945_RX when it sends a received frame ++ * example, uCode issues REPLY_RX when it sends a received frame + * to the driver; it is not a direct response to any driver command. + * + * The Linux driver uses the following format: +@@ -249,36 +247,6 @@ + + + /** +- * struct iwl3945_tx_power +- * +- * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_SCAN_CMD, REPLY_CHANNEL_SWITCH +- * +- * Each entry contains two values: +- * 1) DSP gain (or sometimes called DSP attenuation). This is a fine-grained +- * linear value that multiplies the output of the digital signal processor, +- * before being sent to the analog radio. +- * 2) Radio gain. This sets the analog gain of the radio Tx path. +- * It is a coarser setting, and behaves in a logarithmic (dB) fashion. +- * +- * Driver obtains values from struct iwl3945_tx_power power_gain_table[][]. +- */ +-struct iwl3945_tx_power { +- u8 tx_gain; /* gain for analog radio */ +- u8 dsp_atten; /* gain for DSP */ +-} __packed; +- +-/** +- * struct iwl3945_power_per_rate +- * +- * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH +- */ +-struct iwl3945_power_per_rate { +- u8 rate; /* plcp */ +- struct iwl3945_tx_power tpc; +- u8 reserved; +-} __packed; +- +-/** + * iwlagn rate_n_flags bit fields + * + * rate_n_flags format is used in following iwlagn commands: +@@ -324,6 +292,8 @@ + #define RATE_MCS_SPATIAL_MSK 0x18 + #define RATE_MCS_HT_DUP_POS 5 + #define RATE_MCS_HT_DUP_MSK 0x20 ++/* Both legacy and HT use bits 7:0 as the CCK/OFDM rate or HT MCS */ ++#define RATE_MCS_RATE_MSK 0xff + + /* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */ + #define RATE_MCS_FLAGS_POS 8 +@@ -375,30 +345,6 @@ + #define IWL_PWR_CCK_ENTRIES 2 + + /** +- * union iwl4965_tx_power_dual_stream +- * +- * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH +- * Use __le32 version (struct tx_power_dual_stream) when building command. +- * +- * Driver provides radio gain and DSP attenuation settings to device in pairs, +- * one value for each transmitter chain. The first value is for transmitter A, +- * second for transmitter B. +- * +- * For SISO bit rates, both values in a pair should be identical. +- * For MIMO rates, one value may be different from the other, +- * in order to balance the Tx output between the two transmitters. +- * +- * See more details in doc for TXPOWER in iwl-4965-hw.h. +- */ +-union iwl4965_tx_power_dual_stream { +- struct { +- u8 radio_tx_gain[2]; +- u8 dsp_predis_atten[2]; +- } s; +- u32 dw; +-}; +- +-/** + * struct tx_power_dual_stream + * + * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH +@@ -410,15 +356,6 @@ + } __packed; + + /** +- * struct iwl4965_tx_power_db +- * +- * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH +- */ +-struct iwl4965_tx_power_db { +- struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; +-} __packed; +- +-/** + * Command REPLY_TX_POWER_DBM_CMD = 0x98 + * struct iwlagn_tx_power_dbm_cmd + */ +@@ -449,55 +386,18 @@ + *****************************************************************************/ + + #define UCODE_VALID_OK cpu_to_le32(0x1) +-#define INITIALIZE_SUBTYPE (9) + +-/* +- * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command) +- * +- * uCode issues this "initialize alive" notification once the initialization +- * uCode image has completed its work, and is ready to load the runtime image. +- * This is the *first* "alive" notification that the driver will receive after +- * rebooting uCode; the "initialize" alive is indicated by subtype field == 9. +- * +- * See comments documenting "BSM" (bootstrap state machine). +- * +- * For 4965, this notification contains important calibration data for +- * calculating txpower settings: +- * +- * 1) Power supply voltage indication. The voltage sensor outputs higher +- * values for lower voltage, and vice verse. +- * +- * 2) Temperature measurement parameters, for each of two channel widths +- * (20 MHz and 40 MHz) supported by the radios. Temperature sensing +- * is done via one of the receiver chains, and channel width influences +- * the results. +- * +- * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation, +- * for each of 5 frequency ranges. +- */ +-struct iwl_init_alive_resp { +- u8 ucode_minor; +- u8 ucode_major; +- __le16 reserved1; +- u8 sw_rev[8]; +- u8 ver_type; +- u8 ver_subtype; /* "9" for initialize alive */ +- __le16 reserved2; +- __le32 log_event_table_ptr; +- __le32 error_event_table_ptr; +- __le32 timestamp; +- __le32 is_valid; +- +- /* calibration values from "initialize" uCode */ +- __le32 voltage; /* signed, higher value is lower voltage */ +- __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */ +- __le32 therm_r2[2]; /* signed */ +- __le32 therm_r3[2]; /* signed */ +- __le32 therm_r4[2]; /* signed */ +- __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups, +- * 2 Tx chains */ +-} __packed; ++enum iwlagn_ucode_subtype { ++ UCODE_SUBTYPE_REGULAR = 0, ++ UCODE_SUBTYPE_REGULAR_NEW = 1, ++ UCODE_SUBTYPE_INIT = 9, + ++ /* ++ * Not a valid subtype, the ucode has just a u8, so ++ * we can use something > 0xff for this value. ++ */ ++ UCODE_SUBTYPE_NONE_LOADED = 0x100, ++}; + + /** + * REPLY_ALIVE = 0x1 (response only, not a command) +@@ -533,49 +433,61 @@ + * + * 2) error_event_table_ptr indicates base of the error log. This contains + * information about any uCode error that occurs. For agn, the format +- * of the error log is: +- * +- * __le32 valid; (nonzero) valid, (0) log is empty +- * __le32 error_id; type of error +- * __le32 pc; program counter +- * __le32 blink1; branch link +- * __le32 blink2; branch link +- * __le32 ilink1; interrupt link +- * __le32 ilink2; interrupt link +- * __le32 data1; error-specific data +- * __le32 data2; error-specific data +- * __le32 line; source code line of error +- * __le32 bcon_time; beacon timer +- * __le32 tsf_low; network timestamp function timer +- * __le32 tsf_hi; network timestamp function timer +- * __le32 gp1; GP1 timer register +- * __le32 gp2; GP2 timer register +- * __le32 gp3; GP3 timer register +- * __le32 ucode_ver; uCode version +- * __le32 hw_ver; HW Silicon version +- * __le32 brd_ver; HW board version +- * __le32 log_pc; log program counter +- * __le32 frame_ptr; frame pointer +- * __le32 stack_ptr; stack pointer +- * __le32 hcmd; last host command +- * __le32 isr0; isr status register LMPM_NIC_ISR0: rxtx_flag +- * __le32 isr1; isr status register LMPM_NIC_ISR1: host_flag +- * __le32 isr2; isr status register LMPM_NIC_ISR2: enc_flag +- * __le32 isr3; isr status register LMPM_NIC_ISR3: time_flag +- * __le32 isr4; isr status register LMPM_NIC_ISR4: wico interrupt +- * __le32 isr_pref; isr status register LMPM_NIC_PREF_STAT +- * __le32 wait_event; wait event() caller address +- * __le32 l2p_control; L2pControlField +- * __le32 l2p_duration; L2pDurationField +- * __le32 l2p_mhvalid; L2pMhValidBits +- * __le32 l2p_addr_match; L2pAddrMatchStat +- * __le32 lmpm_pmg_sel; indicate which clocks are turned on (LMPM_PMG_SEL) +- * __le32 u_timestamp; indicate when the date and time of the compilation +- * __le32 reserved; ++ * of the error log is defined by struct iwl_error_event_table. + * + * The Linux driver can print both logs to the system log when a uCode error + * occurs. + */ ++ ++/* ++ * Note: This structure is read from the device with IO accesses, ++ * and the reading already does the endian conversion. As it is ++ * read with u32-sized accesses, any members with a different size ++ * need to be ordered correctly though! ++ */ ++struct iwl_error_event_table { ++ u32 valid; /* (nonzero) valid, (0) log is empty */ ++ u32 error_id; /* type of error */ ++ u32 pc; /* program counter */ ++ u32 blink1; /* branch link */ ++ u32 blink2; /* branch link */ ++ u32 ilink1; /* interrupt link */ ++ u32 ilink2; /* interrupt link */ ++ u32 data1; /* error-specific data */ ++ u32 data2; /* error-specific data */ ++ u32 line; /* source code line of error */ ++ u32 bcon_time; /* beacon timer */ ++ u32 tsf_low; /* network timestamp function timer */ ++ u32 tsf_hi; /* network timestamp function timer */ ++ u32 gp1; /* GP1 timer register */ ++ u32 gp2; /* GP2 timer register */ ++ u32 gp3; /* GP3 timer register */ ++ u32 ucode_ver; /* uCode version */ ++ u32 hw_ver; /* HW Silicon version */ ++ u32 brd_ver; /* HW board version */ ++ u32 log_pc; /* log program counter */ ++ u32 frame_ptr; /* frame pointer */ ++ u32 stack_ptr; /* stack pointer */ ++ u32 hcmd; /* last host command header */ ++#if 0 ++ /* no need to read the remainder, we don't use the values */ ++ u32 isr0; /* isr status register LMPM_NIC_ISR0: rxtx_flag */ ++ u32 isr1; /* isr status register LMPM_NIC_ISR1: host_flag */ ++ u32 isr2; /* isr status register LMPM_NIC_ISR2: enc_flag */ ++ u32 isr3; /* isr status register LMPM_NIC_ISR3: time_flag */ ++ u32 isr4; /* isr status register LMPM_NIC_ISR4: wico interrupt */ ++ u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ ++ u32 wait_event; /* wait event() caller address */ ++ u32 l2p_control; /* L2pControlField */ ++ u32 l2p_duration; /* L2pDurationField */ ++ u32 l2p_mhvalid; /* L2pMhValidBits */ ++ u32 l2p_addr_match; /* L2pAddrMatchStat */ ++ u32 lmpm_pmg_sel; /* indicate which clocks are turned on (LMPM_PMG_SEL) */ ++ u32 u_timestamp; /* indicate when the date and time of the compilation */ ++ u32 flow_handler; /* FH read/write pointers, RX credit */ ++#endif ++} __packed; ++ + struct iwl_alive_resp { + u8 ucode_minor; + u8 ucode_major; +@@ -722,46 +634,6 @@ + * regardless of whether RXON_FILTER_ASSOC_MSK is set. + */ + +-struct iwl3945_rxon_cmd { +- u8 node_addr[6]; +- __le16 reserved1; +- u8 bssid_addr[6]; +- __le16 reserved2; +- u8 wlap_bssid_addr[6]; +- __le16 reserved3; +- u8 dev_type; +- u8 air_propagation; +- __le16 reserved4; +- u8 ofdm_basic_rates; +- u8 cck_basic_rates; +- __le16 assoc_id; +- __le32 flags; +- __le32 filter_flags; +- __le16 channel; +- __le16 reserved5; +-} __packed; +- +-struct iwl4965_rxon_cmd { +- u8 node_addr[6]; +- __le16 reserved1; +- u8 bssid_addr[6]; +- __le16 reserved2; +- u8 wlap_bssid_addr[6]; +- __le16 reserved3; +- u8 dev_type; +- u8 air_propagation; +- __le16 rx_chain; +- u8 ofdm_basic_rates; +- u8 cck_basic_rates; +- __le16 assoc_id; +- __le32 flags; +- __le32 filter_flags; +- __le16 channel; +- u8 ofdm_ht_single_stream_basic_rates; +- u8 ofdm_ht_dual_stream_basic_rates; +-} __packed; +- +-/* 5000 HW just extend this command */ + struct iwl_rxon_cmd { + u8 node_addr[6]; + __le16 reserved1; +@@ -789,26 +661,7 @@ + /* + * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) + */ +-struct iwl3945_rxon_assoc_cmd { +- __le32 flags; +- __le32 filter_flags; +- u8 ofdm_basic_rates; +- u8 cck_basic_rates; +- __le16 reserved; +-} __packed; +- +-struct iwl4965_rxon_assoc_cmd { +- __le32 flags; +- __le32 filter_flags; +- u8 ofdm_basic_rates; +- u8 cck_basic_rates; +- u8 ofdm_ht_single_stream_basic_rates; +- u8 ofdm_ht_dual_stream_basic_rates; +- __le16 rx_chain_select_flags; +- __le16 reserved; +-} __packed; +- +-struct iwl5000_rxon_assoc_cmd { ++struct iwl_rxon_assoc_cmd { + __le32 flags; + __le32 filter_flags; + u8 ofdm_basic_rates; +@@ -843,26 +696,6 @@ + /* + * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) + */ +-struct iwl3945_channel_switch_cmd { +- u8 band; +- u8 expect_beacon; +- __le16 channel; +- __le32 rxon_flags; +- __le32 rxon_filter_flags; +- __le32 switch_time; +- struct iwl3945_power_per_rate power[IWL_MAX_RATES]; +-} __packed; +- +-struct iwl4965_channel_switch_cmd { +- u8 band; +- u8 expect_beacon; +- __le16 channel; +- __le32 rxon_flags; +- __le32 rxon_filter_flags; +- __le32 switch_time; +- struct iwl4965_tx_power_db tx_power; +-} __packed; +- + /** + * struct iwl5000_channel_switch_cmd + * @band: 0- 5.2GHz, 1- 2.4GHz +@@ -976,15 +809,10 @@ + #define IWL_AP_ID 0 + #define IWL_AP_ID_PAN 1 + #define IWL_STA_ID 2 +-#define IWL3945_BROADCAST_ID 24 +-#define IWL3945_STATION_COUNT 25 +-#define IWL4965_BROADCAST_ID 31 +-#define IWL4965_STATION_COUNT 32 + #define IWLAGN_PAN_BCAST_ID 14 + #define IWLAGN_BROADCAST_ID 15 + #define IWLAGN_STATION_COUNT 16 + +-#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ + #define IWL_INVALID_STATION 255 + + #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) +@@ -1032,16 +860,6 @@ + * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ + #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) + +-struct iwl4965_keyinfo { +- __le16 key_flags; +- u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ +- u8 reserved1; +- __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ +- u8 key_offset; +- u8 reserved2; +- u8 key[16]; /* 16-byte unicast decryption key */ +-} __packed; +- + /* agn */ + struct iwl_keyinfo { + __le16 key_flags; +@@ -1083,7 +901,6 @@ + * with info on security keys, aggregation parameters, and Tx rates for + * initial Tx attempt and any retries (agn devices uses + * REPLY_TX_LINK_QUALITY_CMD, +- * 3945 uses REPLY_RATE_SCALE to set up rate tables). + * + * REPLY_ADD_STA sets up the table entry for one station, either creating + * a new entry, or modifying a pre-existing one. +@@ -1103,72 +920,6 @@ + * entries for all STAs in network, starting with index IWL_STA_ID. + */ + +-struct iwl3945_addsta_cmd { +- u8 mode; /* 1: modify existing, 0: add new station */ +- u8 reserved[3]; +- struct sta_id_modify sta; +- struct iwl4965_keyinfo key; +- __le32 station_flags; /* STA_FLG_* */ +- __le32 station_flags_msk; /* STA_FLG_* */ +- +- /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) +- * corresponding to bit (e.g. bit 5 controls TID 5). +- * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ +- __le16 tid_disable_tx; +- +- __le16 rate_n_flags; +- +- /* TID for which to add block-ack support. +- * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ +- u8 add_immediate_ba_tid; +- +- /* TID for which to remove block-ack support. +- * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ +- u8 remove_immediate_ba_tid; +- +- /* Starting Sequence Number for added block-ack support. +- * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ +- __le16 add_immediate_ba_ssn; +-} __packed; +- +-struct iwl4965_addsta_cmd { +- u8 mode; /* 1: modify existing, 0: add new station */ +- u8 reserved[3]; +- struct sta_id_modify sta; +- struct iwl4965_keyinfo key; +- __le32 station_flags; /* STA_FLG_* */ +- __le32 station_flags_msk; /* STA_FLG_* */ +- +- /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) +- * corresponding to bit (e.g. bit 5 controls TID 5). +- * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ +- __le16 tid_disable_tx; +- +- __le16 reserved1; +- +- /* TID for which to add block-ack support. +- * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ +- u8 add_immediate_ba_tid; +- +- /* TID for which to remove block-ack support. +- * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ +- u8 remove_immediate_ba_tid; +- +- /* Starting Sequence Number for added block-ack support. +- * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ +- __le16 add_immediate_ba_ssn; +- +- /* +- * Number of packets OK to transmit to station even though +- * it is asleep -- used to synchronise PS-poll and u-APSD +- * responses while ucode keeps track of STA sleep state. +- */ +- __le16 sleep_tx_count; +- +- __le16 reserved2; +-} __packed; +- +-/* agn */ + struct iwl_addsta_cmd { + u8 mode; /* 1: modify existing, 0: add new station */ + u8 reserved[3]; +@@ -1337,62 +1088,6 @@ + #define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) + + +-struct iwl3945_rx_frame_stats { +- u8 phy_count; +- u8 id; +- u8 rssi; +- u8 agc; +- __le16 sig_avg; +- __le16 noise_diff; +- u8 payload[0]; +-} __packed; +- +-struct iwl3945_rx_frame_hdr { +- __le16 channel; +- __le16 phy_flags; +- u8 reserved1; +- u8 rate; +- __le16 len; +- u8 payload[0]; +-} __packed; +- +-struct iwl3945_rx_frame_end { +- __le32 status; +- __le64 timestamp; +- __le32 beacon_timestamp; +-} __packed; +- +-/* +- * REPLY_3945_RX = 0x1b (response only, not a command) +- * +- * NOTE: DO NOT dereference from casts to this structure +- * It is provided only for calculating minimum data set size. +- * The actual offsets of the hdr and end are dynamic based on +- * stats.phy_count +- */ +-struct iwl3945_rx_frame { +- struct iwl3945_rx_frame_stats stats; +- struct iwl3945_rx_frame_hdr hdr; +- struct iwl3945_rx_frame_end end; +-} __packed; +- +-#define IWL39_RX_FRAME_SIZE (4 + sizeof(struct iwl3945_rx_frame)) +- +-/* Fixed (non-configurable) rx data from phy */ +- +-#define IWL49_RX_RES_PHY_CNT 14 +-#define IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET (4) +-#define IWL49_RX_PHY_FLAGS_ANTENNAE_MASK (0x70) +-#define IWL49_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ +-#define IWL49_AGC_DB_POS (7) +-struct iwl4965_rx_non_cfg_phy { +- __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ +- __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ +- u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ +- u8 pad[0]; +-} __packed; +- +- + #define IWLAGN_RX_RES_PHY_CNT 8 + #define IWLAGN_RX_RES_AGC_IDX 1 + #define IWLAGN_RX_RES_RSSI_AB_IDX 2 +@@ -1576,80 +1271,6 @@ + * REPLY_TX = 0x1c (command) + */ + +-struct iwl3945_tx_cmd { +- /* +- * MPDU byte count: +- * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, +- * + 8 byte IV for CCM or TKIP (not used for WEP) +- * + Data payload +- * + 8-byte MIC (not used for CCM/WEP) +- * NOTE: Does not include Tx command bytes, post-MAC pad bytes, +- * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i +- * Range: 14-2342 bytes. +- */ +- __le16 len; +- +- /* +- * MPDU or MSDU byte count for next frame. +- * Used for fragmentation and bursting, but not 11n aggregation. +- * Same as "len", but for next frame. Set to 0 if not applicable. +- */ +- __le16 next_frame_len; +- +- __le32 tx_flags; /* TX_CMD_FLG_* */ +- +- u8 rate; +- +- /* Index of recipient station in uCode's station table */ +- u8 sta_id; +- u8 tid_tspec; +- u8 sec_ctl; +- u8 key[16]; +- union { +- u8 byte[8]; +- __le16 word[4]; +- __le32 dw[2]; +- } tkip_mic; +- __le32 next_frame_info; +- union { +- __le32 life_time; +- __le32 attempt; +- } stop_time; +- u8 supp_rates[2]; +- u8 rts_retry_limit; /*byte 50 */ +- u8 data_retry_limit; /*byte 51 */ +- union { +- __le16 pm_frame_timeout; +- __le16 attempt_duration; +- } timeout; +- +- /* +- * Duration of EDCA burst Tx Opportunity, in 32-usec units. +- * Set this if txop time is not specified by HCCA protocol (e.g. by AP). +- */ +- __le16 driver_txop; +- +- /* +- * MAC header goes here, followed by 2 bytes padding if MAC header +- * length is 26 or 30 bytes, followed by payload data +- */ +- u8 payload[0]; +- struct ieee80211_hdr hdr[0]; +-} __packed; +- +-/* +- * REPLY_TX = 0x1c (response) +- */ +-struct iwl3945_tx_resp { +- u8 failure_rts; +- u8 failure_frame; +- u8 bt_kill_count; +- u8 rate; +- __le32 wireless_media_time; +- __le32 status; /* TX status */ +-} __packed; +- +- + /* + * 4965 uCode updates these Tx attempt count values in host DRAM. + * Used for managing Tx retries when expecting block-acks. +@@ -1740,54 +1361,6 @@ + struct ieee80211_hdr hdr[0]; + } __packed; + +-/* TX command response is sent after *3945* transmission attempts. +- * +- * NOTES: +- * +- * TX_STATUS_FAIL_NEXT_FRAG +- * +- * If the fragment flag in the MAC header for the frame being transmitted +- * is set and there is insufficient time to transmit the next frame, the +- * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'. +- * +- * TX_STATUS_FIFO_UNDERRUN +- * +- * Indicates the host did not provide bytes to the FIFO fast enough while +- * a TX was in progress. +- * +- * TX_STATUS_FAIL_MGMNT_ABORT +- * +- * This status is only possible if the ABORT ON MGMT RX parameter was +- * set to true with the TX command. +- * +- * If the MSB of the status parameter is set then an abort sequence is +- * required. This sequence consists of the host activating the TX Abort +- * control line, and then waiting for the TX Abort command response. This +- * indicates that a the device is no longer in a transmit state, and that the +- * command FIFO has been cleared. The host must then deactivate the TX Abort +- * control line. Receiving is still allowed in this case. +- */ +-enum { +- TX_3945_STATUS_SUCCESS = 0x01, +- TX_3945_STATUS_DIRECT_DONE = 0x02, +- TX_3945_STATUS_FAIL_SHORT_LIMIT = 0x82, +- TX_3945_STATUS_FAIL_LONG_LIMIT = 0x83, +- TX_3945_STATUS_FAIL_FIFO_UNDERRUN = 0x84, +- TX_3945_STATUS_FAIL_MGMNT_ABORT = 0x85, +- TX_3945_STATUS_FAIL_NEXT_FRAG = 0x86, +- TX_3945_STATUS_FAIL_LIFE_EXPIRE = 0x87, +- TX_3945_STATUS_FAIL_DEST_PS = 0x88, +- TX_3945_STATUS_FAIL_ABORTED = 0x89, +- TX_3945_STATUS_FAIL_BT_RETRY = 0x8a, +- TX_3945_STATUS_FAIL_STA_INVALID = 0x8b, +- TX_3945_STATUS_FAIL_FRAG_DROPPED = 0x8c, +- TX_3945_STATUS_FAIL_TID_DISABLE = 0x8d, +- TX_3945_STATUS_FAIL_FRAME_FLUSHED = 0x8e, +- TX_3945_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f, +- TX_3945_STATUS_FAIL_TX_LOCKED = 0x90, +- TX_3945_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91, +-}; +- + /* + * TX command response is sent after *agn* transmission attempts. + * +@@ -1905,43 +1478,6 @@ + __le16 sequence; + } __packed; + +-struct iwl4965_tx_resp { +- u8 frame_count; /* 1 no aggregation, >1 aggregation */ +- u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ +- u8 failure_rts; /* # failures due to unsuccessful RTS */ +- u8 failure_frame; /* # failures due to no ACK (unused for agg) */ +- +- /* For non-agg: Rate at which frame was successful. +- * For agg: Rate at which all frames were transmitted. */ +- __le32 rate_n_flags; /* RATE_MCS_* */ +- +- /* For non-agg: RTS + CTS + frame tx attempts time + ACK. +- * For agg: RTS + CTS + aggregation tx time + block-ack time. */ +- __le16 wireless_media_time; /* uSecs */ +- +- __le16 reserved; +- __le32 pa_power1; /* RF power amplifier measurement (not used) */ +- __le32 pa_power2; +- +- /* +- * For non-agg: frame status TX_STATUS_* +- * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status +- * fields follow this one, up to frame_count. +- * Bit fields: +- * 11- 0: AGG_TX_STATE_* status code +- * 15-12: Retry count for 1st frame in aggregation (retries +- * occur if tx failed for this frame when it was a +- * member of a previous aggregation block). If rate +- * scaling is used, retry count indicates the rate +- * table entry used for all frames in the new agg. +- * 31-16: Sequence # for this frame's Tx cmd (not SSN!) +- */ +- union { +- __le32 status; +- struct agg_tx_status agg_status[0]; /* for each agg frame */ +- } u; +-} __packed; +- + /* + * definitions for initial rate index field + * bits [3:0] initial rate index +@@ -2030,51 +1566,7 @@ + /* + * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) + * +- * See details under "TXPOWER" in iwl-4965-hw.h. +- */ +- +-struct iwl3945_txpowertable_cmd { +- u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ +- u8 reserved; +- __le16 channel; +- struct iwl3945_power_per_rate power[IWL_MAX_RATES]; +-} __packed; +- +-struct iwl4965_txpowertable_cmd { +- u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ +- u8 reserved; +- __le16 channel; +- struct iwl4965_tx_power_db tx_power; +-} __packed; +- +- +-/** +- * struct iwl3945_rate_scaling_cmd - Rate Scaling Command & Response +- * +- * REPLY_RATE_SCALE = 0x47 (command, has simple generic response) +- * +- * NOTE: The table of rates passed to the uCode via the +- * RATE_SCALE command sets up the corresponding order of +- * rates used for all related commands, including rate +- * masks, etc. +- * +- * For example, if you set 9MB (PLCP 0x0f) as the first +- * rate in the rate table, the bit mask for that rate +- * when passed through ofdm_basic_rates on the REPLY_RXON +- * command would be bit 0 (1 << 0) + */ +-struct iwl3945_rate_scaling_info { +- __le16 rate_n_flags; +- u8 try_cnt; +- u8 next_rate_index; +-} __packed; +- +-struct iwl3945_rate_scaling_cmd { +- u8 table_id; +- u8 reserved[3]; +- struct iwl3945_rate_scaling_info table[IWL_MAX_RATES]; +-} __packed; +- + + /*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ + #define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1 << 0) +@@ -2130,7 +1622,7 @@ + #define LINK_QUAL_AGG_DISABLE_START_MAX (255) + #define LINK_QUAL_AGG_DISABLE_START_MIN (0) + +-#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31) ++#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) + #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) + #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) + +@@ -2696,14 +2188,6 @@ + #define IWL_POWER_BT_SCO_ENA cpu_to_le16(BIT(8)) + #define IWL_POWER_ADVANCE_PM_ENA_MSK cpu_to_le16(BIT(9)) + +-struct iwl3945_powertable_cmd { +- __le16 flags; +- u8 reserved[2]; +- __le32 rx_data_timeout; +- __le32 tx_data_timeout; +- __le32 sleep_interval[IWL_POWER_VEC_SIZE]; +-} __packed; +- + struct iwl_powertable_cmd { + __le16 flags; + u8 keep_alive_seconds; /* 3945 reserved */ +@@ -2806,25 +2290,6 @@ + * active_dwell < max_out_time + */ + +-/* FIXME: rename to AP1, remove tpc */ +-struct iwl3945_scan_channel { +- /* +- * type is defined as: +- * 0:0 1 = active, 0 = passive +- * 1:4 SSID direct bit map; if a bit is set, then corresponding +- * SSID IE is transmitted in probe request. +- * 5:7 reserved +- */ +- u8 type; +- u8 channel; /* band is selected by iwl3945_scan_cmd "flags" field */ +- struct iwl3945_tx_power tpc; +- __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */ +- __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */ +-} __packed; +- +-/* set number of direct probes u8 type */ +-#define IWL39_SCAN_PROBE_MASK(n) ((BIT(n) | (BIT(n) - BIT(1)))) +- + struct iwl_scan_channel { + /* + * type is defined as: +@@ -2920,50 +2385,6 @@ + * struct iwl_scan_channel. + */ + +-struct iwl3945_scan_cmd { +- __le16 len; +- u8 reserved0; +- u8 channel_count; /* # channels in channel list */ +- __le16 quiet_time; /* dwell only this # millisecs on quiet channel +- * (only for active scan) */ +- __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ +- __le16 good_CRC_th; /* passive -> active promotion threshold */ +- __le16 reserved1; +- __le32 max_out_time; /* max usec to be away from associated (service) +- * channel */ +- __le32 suspend_time; /* pause scan this long (in "extended beacon +- * format") when returning to service channel: +- * 3945; 31:24 # beacons, 19:0 additional usec, +- * 4965; 31:22 # beacons, 21:0 additional usec. +- */ +- __le32 flags; /* RXON_FLG_* */ +- __le32 filter_flags; /* RXON_FILTER_* */ +- +- /* For active scans (set to all-0s for passive scans). +- * Does not include payload. Must specify Tx rate; no rate scaling. */ +- struct iwl3945_tx_cmd tx_cmd; +- +- /* For directed active scans (set to all-0s otherwise) */ +- struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_3945]; +- +- /* +- * Probe request frame, followed by channel list. +- * +- * Size of probe request frame is specified by byte count in tx_cmd. +- * Channel list follows immediately after probe request frame. +- * Number of channels in list is specified by channel_count. +- * Each channel in list is of type: +- * +- * struct iwl3945_scan_channel channels[0]; +- * +- * NOTE: Only one band of channels can be scanned per pass. You +- * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait +- * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) +- * before requesting another scan. +- */ +- u8 data[0]; +-} __packed; +- + enum iwl_scan_flags { + /* BIT(0) currently unused */ + IWL_SCAN_FLAGS_ACTION_FRAME_TX = BIT(1), +@@ -3090,20 +2511,6 @@ + * BEACON_NOTIFICATION = 0x90 (notification only, not a command) + */ + +-struct iwl3945_beacon_notif { +- struct iwl3945_tx_resp beacon_notify_hdr; +- __le32 low_tsf; +- __le32 high_tsf; +- __le32 ibss_mgr_status; +-} __packed; +- +-struct iwl4965_beacon_notif { +- struct iwl4965_tx_resp beacon_notify_hdr; +- __le32 low_tsf; +- __le32 high_tsf; +- __le32 ibss_mgr_status; +-} __packed; +- + struct iwlagn_beacon_notif { + struct iwlagn_tx_resp beacon_notify_hdr; + __le32 low_tsf; +@@ -3115,14 +2522,6 @@ + * REPLY_TX_BEACON = 0x91 (command, has simple generic response) + */ + +-struct iwl3945_tx_beacon_cmd { +- struct iwl3945_tx_cmd tx; +- __le16 tim_idx; +- u8 tim_size; +- u8 reserved1; +- struct ieee80211_hdr frame[0]; /* beacon frame */ +-} __packed; +- + struct iwl_tx_beacon_cmd { + struct iwl_tx_cmd tx; + __le16 tim_idx; +@@ -3159,53 +2558,6 @@ + + /* statistics command response */ + +-struct iwl39_statistics_rx_phy { +- __le32 ina_cnt; +- __le32 fina_cnt; +- __le32 plcp_err; +- __le32 crc32_err; +- __le32 overrun_err; +- __le32 early_overrun_err; +- __le32 crc32_good; +- __le32 false_alarm_cnt; +- __le32 fina_sync_err_cnt; +- __le32 sfd_timeout; +- __le32 fina_timeout; +- __le32 unresponded_rts; +- __le32 rxe_frame_limit_overrun; +- __le32 sent_ack_cnt; +- __le32 sent_cts_cnt; +-} __packed; +- +-struct iwl39_statistics_rx_non_phy { +- __le32 bogus_cts; /* CTS received when not expecting CTS */ +- __le32 bogus_ack; /* ACK received when not expecting ACK */ +- __le32 non_bssid_frames; /* number of frames with BSSID that +- * doesn't belong to the STA BSSID */ +- __le32 filtered_frames; /* count frames that were dumped in the +- * filtering process */ +- __le32 non_channel_beacons; /* beacons with our bss id but not on +- * our serving channel */ +-} __packed; +- +-struct iwl39_statistics_rx { +- struct iwl39_statistics_rx_phy ofdm; +- struct iwl39_statistics_rx_phy cck; +- struct iwl39_statistics_rx_non_phy general; +-} __packed; +- +-struct iwl39_statistics_tx { +- __le32 preamble_cnt; +- __le32 rx_detected_cnt; +- __le32 bt_prio_defer_cnt; +- __le32 bt_prio_kill_cnt; +- __le32 few_bytes_cnt; +- __le32 cts_timeout; +- __le32 ack_timeout; +- __le32 expected_ack_cnt; +- __le32 actual_ack_cnt; +-} __packed; +- + struct statistics_dbg { + __le32 burst_check; + __le32 burst_count; +@@ -3213,23 +2565,6 @@ + __le32 reserved[3]; + } __packed; + +-struct iwl39_statistics_div { +- __le32 tx_on_a; +- __le32 tx_on_b; +- __le32 exec_time; +- __le32 probe_time; +-} __packed; +- +-struct iwl39_statistics_general { +- __le32 temperature; +- struct statistics_dbg dbg; +- __le32 sleep_time; +- __le32 slots_out; +- __le32 slots_idle; +- __le32 ttl_timestamp; +- struct iwl39_statistics_div div; +-} __packed; +- + struct statistics_rx_phy { + __le32 ina_cnt; + __le32 fina_cnt; +@@ -3471,13 +2806,6 @@ + #define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) + #define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8) + +-struct iwl3945_notif_statistics { +- __le32 flag; +- struct iwl39_statistics_rx rx; +- struct iwl39_statistics_tx tx; +- struct iwl39_statistics_general general; +-} __packed; +- + struct iwl_notif_statistics { + __le32 flag; + struct statistics_rx rx; +@@ -4451,10 +3779,6 @@ + __le32 len_n_flags; + struct iwl_cmd_header hdr; + union { +- struct iwl3945_rx_frame rx_frame; +- struct iwl3945_tx_resp tx_resp; +- struct iwl3945_beacon_notif beacon_status; +- + struct iwl_alive_resp alive_frame; + struct iwl_spectrum_notification spectrum_notif; + struct iwl_csa_notification csa_notif; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-core.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-core.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-core.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-core.c 2011-05-05 23:29:45.359440341 +0200 +@@ -2,7 +2,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -41,6 +41,7 @@ + #include "iwl-power.h" + #include "iwl-sta.h" + #include "iwl-helpers.h" ++#include "iwl-agn.h" + + + /* +@@ -67,30 +68,6 @@ + + const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + +- +-/* This function both allocates and initializes hw and priv. */ +-struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg) +-{ +- struct iwl_priv *priv; +- /* mac80211 allocates memory for this device instance, including +- * space for this driver's private structure */ +- struct ieee80211_hw *hw; +- +- hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), +- cfg->ops->ieee80211_ops); +- if (hw == NULL) { +- pr_err("%s: Can not allocate network device\n", +- cfg->name); +- goto out; +- } +- +- priv = hw->priv; +- priv->hw = hw; +- +-out: +- return hw; +-} +- + #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ + #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ + static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, +@@ -118,7 +95,7 @@ + max_bit_rate = MAX_BIT_RATE_40_MHZ; + } + +- if (priv->cfg->mod_params->amsdu_size_8K) ++ if (iwlagn_mod_params.amsdu_size_8K) + ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; + + ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; +@@ -159,6 +136,7 @@ + struct ieee80211_channel *geo_ch; + struct ieee80211_rate *rates; + int i = 0; ++ s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN; + + if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || + priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { +@@ -232,8 +210,8 @@ + + geo_ch->flags |= ch->ht40_extension_channel; + +- if (ch->max_power_avg > priv->tx_power_device_lmt) +- priv->tx_power_device_lmt = ch->max_power_avg; ++ if (ch->max_power_avg > max_tx_power) ++ max_tx_power = ch->max_power_avg; + } else { + geo_ch->flags |= IEEE80211_CHAN_DISABLED; + } +@@ -246,6 +224,10 @@ + geo_ch->flags); + } + ++ priv->tx_power_device_lmt = max_tx_power; ++ priv->tx_power_user_lmt = max_tx_power; ++ priv->tx_power_next = max_tx_power; ++ + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && + priv->cfg->sku & IWL_SKU_A) { + IWL_INFO(priv, "Incorrectly detected BG card as ABG. " +@@ -434,72 +416,72 @@ + int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx) + { + struct iwl_rxon_cmd *rxon = &ctx->staging; +- bool error = false; ++ u32 errors = 0; + + if (rxon->flags & RXON_FLG_BAND_24G_MSK) { + if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) { + IWL_WARN(priv, "check 2.4G: wrong narrow\n"); +- error = true; ++ errors |= BIT(0); + } + if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) { + IWL_WARN(priv, "check 2.4G: wrong radar\n"); +- error = true; ++ errors |= BIT(1); + } + } else { + if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) { + IWL_WARN(priv, "check 5.2G: not short slot!\n"); +- error = true; ++ errors |= BIT(2); + } + if (rxon->flags & RXON_FLG_CCK_MSK) { + IWL_WARN(priv, "check 5.2G: CCK!\n"); +- error = true; ++ errors |= BIT(3); + } + } + if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) { + IWL_WARN(priv, "mac/bssid mcast!\n"); +- error = true; ++ errors |= BIT(4); + } + + /* make sure basic rates 6Mbps and 1Mbps are supported */ + if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 && + (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) { + IWL_WARN(priv, "neither 1 nor 6 are basic\n"); +- error = true; ++ errors |= BIT(5); + } + + if (le16_to_cpu(rxon->assoc_id) > 2007) { + IWL_WARN(priv, "aid > 2007\n"); +- error = true; ++ errors |= BIT(6); + } + + if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) { + IWL_WARN(priv, "CCK and short slot\n"); +- error = true; ++ errors |= BIT(7); + } + + if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) { + IWL_WARN(priv, "CCK and auto detect"); +- error = true; ++ errors |= BIT(8); + } + + if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | + RXON_FLG_TGG_PROTECT_MSK)) == + RXON_FLG_TGG_PROTECT_MSK) { + IWL_WARN(priv, "TGg but no auto-detect\n"); +- error = true; ++ errors |= BIT(9); + } + +- if (error) +- IWL_WARN(priv, "Tuning to channel %d\n", +- le16_to_cpu(rxon->channel)); +- +- if (error) { +- IWL_ERR(priv, "Invalid RXON\n"); +- return -EINVAL; ++ if (rxon->channel == 0) { ++ IWL_WARN(priv, "zero channel is invalid\n"); ++ errors |= BIT(10); + } +- return 0; ++ ++ WARN(errors, "Invalid RXON (%#x), channel %d", ++ errors, le16_to_cpu(rxon->channel)); ++ ++ return errors ? -EINVAL : 0; + } + + /** +@@ -890,10 +872,21 @@ + IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); + } + #endif +-/** +- * iwl_irq_handle_error - called for HW or SW error interrupt from card +- */ +-void iwl_irq_handle_error(struct iwl_priv *priv) ++ ++static void iwlagn_abort_notification_waits(struct iwl_priv *priv) ++{ ++ unsigned long flags; ++ struct iwl_notification_wait *wait_entry; ++ ++ spin_lock_irqsave(&priv->_agn.notif_wait_lock, flags); ++ list_for_each_entry(wait_entry, &priv->_agn.notif_waits, list) ++ wait_entry->aborted = true; ++ spin_unlock_irqrestore(&priv->_agn.notif_wait_lock, flags); ++ ++ wake_up_all(&priv->_agn.notif_waitq); ++} ++ ++void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) + { + unsigned int reload_msec; + unsigned long reload_jiffies; +@@ -904,18 +897,64 @@ + /* Cancel currently queued command. */ + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + ++ iwlagn_abort_notification_waits(priv); ++ ++ /* Keep the restart process from trying to send host ++ * commands by clearing the ready bit */ ++ clear_bit(STATUS_READY, &priv->status); ++ ++ wake_up_interruptible(&priv->wait_command_queue); ++ ++ if (!ondemand) { ++ /* ++ * If firmware keep reloading, then it indicate something ++ * serious wrong and firmware having problem to recover ++ * from it. Instead of keep trying which will fill the syslog ++ * and hang the system, let's just stop it ++ */ ++ reload_jiffies = jiffies; ++ reload_msec = jiffies_to_msecs((long) reload_jiffies - ++ (long) priv->reload_jiffies); ++ priv->reload_jiffies = reload_jiffies; ++ if (reload_msec <= IWL_MIN_RELOAD_DURATION) { ++ priv->reload_count++; ++ if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) { ++ IWL_ERR(priv, "BUG_ON, Stop restarting\n"); ++ return; ++ } ++ } else ++ priv->reload_count = 0; ++ } ++ ++ if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { ++ if (iwlagn_mod_params.restart_fw) { ++ IWL_DEBUG(priv, IWL_DL_FW_ERRORS, ++ "Restarting adapter due to uCode error.\n"); ++ queue_work(priv->workqueue, &priv->restart); ++ } else ++ IWL_DEBUG(priv, IWL_DL_FW_ERRORS, ++ "Detected FW error, but not restarting\n"); ++ } ++} ++ ++/** ++ * iwl_irq_handle_error - called for HW or SW error interrupt from card ++ */ ++void iwl_irq_handle_error(struct iwl_priv *priv) ++{ + /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ + if (priv->cfg->internal_wimax_coex && + (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) & + APMS_CLK_VAL_MRB_FUNC_MODE) || + (iwl_read_prph(priv, APMG_PS_CTRL_REG) & + APMG_PS_CTRL_VAL_RESET_REQ))) { +- wake_up_interruptible(&priv->wait_command_queue); + /* +- *Keep the restart process from trying to send host +- * commands by clearing the INIT status bit ++ * Keep the restart process from trying to send host ++ * commands by clearing the ready bit. + */ + clear_bit(STATUS_READY, &priv->status); ++ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); ++ wake_up_interruptible(&priv->wait_command_queue); + IWL_ERR(priv, "RF is used by WiMAX\n"); + return; + } +@@ -923,50 +962,17 @@ + IWL_ERR(priv, "Loaded firmware version: %s\n", + priv->hw->wiphy->fw_version); + +- priv->cfg->ops->lib->dump_nic_error_log(priv); +- if (priv->cfg->ops->lib->dump_csr) +- priv->cfg->ops->lib->dump_csr(priv); +- if (priv->cfg->ops->lib->dump_fh) +- priv->cfg->ops->lib->dump_fh(priv, NULL, false); +- priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false); ++ iwl_dump_nic_error_log(priv); ++ iwl_dump_csr(priv); ++ iwl_dump_fh(priv, NULL, false); ++ iwl_dump_nic_event_log(priv, false, NULL, false); + #ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) + iwl_print_rx_config_cmd(priv, + &priv->contexts[IWL_RXON_CTX_BSS]); + #endif + +- wake_up_interruptible(&priv->wait_command_queue); +- +- /* Keep the restart process from trying to send host +- * commands by clearing the INIT status bit */ +- clear_bit(STATUS_READY, &priv->status); +- +- /* +- * If firmware keep reloading, then it indicate something +- * serious wrong and firmware having problem to recover +- * from it. Instead of keep trying which will fill the syslog +- * and hang the system, let's just stop it +- */ +- reload_jiffies = jiffies; +- reload_msec = jiffies_to_msecs((long) reload_jiffies - +- (long) priv->reload_jiffies); +- priv->reload_jiffies = reload_jiffies; +- if (reload_msec <= IWL_MIN_RELOAD_DURATION) { +- priv->reload_count++; +- if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) { +- IWL_ERR(priv, "BUG_ON, Stop restarting\n"); +- return; +- } +- } else +- priv->reload_count = 0; +- +- if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { +- IWL_DEBUG(priv, IWL_DL_FW_ERRORS, +- "Restarting adapter due to uCode error.\n"); +- +- if (priv->cfg->mod_params->restart_fw) +- queue_work(priv->workqueue, &priv->restart); +- } ++ iwlagn_fw_error(priv, false); + } + + static int iwl_apm_stop_master(struct iwl_priv *priv) +@@ -990,6 +996,8 @@ + { + IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n"); + ++ clear_bit(STATUS_DEVICE_ENABLED, &priv->status); ++ + /* Stop device's DMA activity */ + iwl_apm_stop_master(priv); + +@@ -1040,7 +1048,6 @@ + /* + * Enable HAP INTA (interrupt from management bus) to + * wake device's PCI Express link L1a -> L0s +- * NOTE: This is no-op for 3945 (non-existent bit) + */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); +@@ -1053,20 +1060,18 @@ + * If not (unlikely), enable L0S, so there is at least some + * power savings, even without L1. + */ +- if (priv->cfg->base_params->set_l0s) { +- lctl = iwl_pcie_link_ctl(priv); +- if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == +- PCI_CFG_LINK_CTRL_VAL_L1_EN) { +- /* L1-ASPM enabled; disable(!) L0S */ +- iwl_set_bit(priv, CSR_GIO_REG, +- CSR_GIO_REG_VAL_L0S_ENABLED); +- IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n"); +- } else { +- /* L1-ASPM disabled; enable(!) L0S */ +- iwl_clear_bit(priv, CSR_GIO_REG, +- CSR_GIO_REG_VAL_L0S_ENABLED); +- IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n"); +- } ++ lctl = iwl_pcie_link_ctl(priv); ++ if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == ++ PCI_CFG_LINK_CTRL_VAL_L1_EN) { ++ /* L1-ASPM enabled; disable(!) L0S */ ++ iwl_set_bit(priv, CSR_GIO_REG, ++ CSR_GIO_REG_VAL_L0S_ENABLED); ++ IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n"); ++ } else { ++ /* L1-ASPM disabled; enable(!) L0S */ ++ iwl_clear_bit(priv, CSR_GIO_REG, ++ CSR_GIO_REG_VAL_L0S_ENABLED); ++ IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n"); + } + + /* Configure analog phase-lock-loop before activating to D0A */ +@@ -1094,27 +1099,21 @@ + } + + /* +- * Enable DMA and BSM (if used) clocks, wait for them to stabilize. +- * BSM (Boostrap State Machine) is only in 3945 and 4965; +- * later devices (i.e. 5000 and later) have non-volatile SRAM, +- * and don't need BSM to restore data after power-saving sleep. ++ * Enable DMA clock and wait for it to stabilize. + * + * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits + * do not disable clocks. This preserves any hardware bits already + * set by default in "CLK_CTRL_REG" after reset. + */ +- if (priv->cfg->base_params->use_bsm) +- iwl_write_prph(priv, APMG_CLK_EN_REG, +- APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); +- else +- iwl_write_prph(priv, APMG_CLK_EN_REG, +- APMG_CLK_VAL_DMA_CLK_RQT); ++ iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); + udelay(20); + + /* Disable L1-Active */ + iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + ++ set_bit(STATUS_DEVICE_ENABLED, &priv->status); ++ + out: + return ret; + } +@@ -1430,7 +1429,6 @@ + + iwl_teardown_interface(priv, vif, false); + +- memset(priv->bssid, 0, ETH_ALEN); + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211(priv, "leave\n"); +@@ -1750,21 +1748,13 @@ + * detect failure), then fw_restart module parameter + * need to be check before performing firmware reload + */ +- if (!external && !priv->cfg->mod_params->restart_fw) { ++ if (!external && !iwlagn_mod_params.restart_fw) { + IWL_DEBUG_INFO(priv, "Cancel firmware reload based on " + "module parameter setting\n"); + break; + } + IWL_ERR(priv, "On demand firmware reload\n"); +- /* Set the FW error flag -- cleared on iwl_down */ +- set_bit(STATUS_FW_ERROR, &priv->status); +- wake_up_interruptible(&priv->wait_command_queue); +- /* +- * Keep the restart process from trying to send host +- * commands by clearing the INIT status bit +- */ +- clear_bit(STATUS_READY, &priv->status); +- queue_work(priv->workqueue, &priv->restart); ++ iwlagn_fw_error(priv, true); + break; + } + return 0; +@@ -1775,6 +1765,7 @@ + { + struct iwl_priv *priv = hw->priv; + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); ++ struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct iwl_rxon_context *tmp; + u32 interface_modes; + int err; +@@ -1783,6 +1774,15 @@ + + mutex_lock(&priv->mutex); + ++ if (!ctx->vif || !iwl_is_ready_rf(priv)) { ++ /* ++ * Huh? But wait ... this can maybe happen when ++ * we're in the middle of a firmware restart! ++ */ ++ err = -EBUSY; ++ goto out; ++ } ++ + interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; + + if (!(interface_modes & BIT(newtype))) { +@@ -1790,6 +1790,19 @@ + goto out; + } + ++ /* ++ * Refuse a change that should be done by moving from the PAN ++ * context to the BSS context instead, if the BSS context is ++ * available and can support the new interface type. ++ */ ++ if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif && ++ (bss_ctx->interface_modes & BIT(newtype) || ++ bss_ctx->exclusive_interface_modes & BIT(newtype))) { ++ BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); ++ err = -EBUSY; ++ goto out; ++ } ++ + if (ctx->exclusive_interface_modes & BIT(newtype)) { + for_each_context(priv, tmp) { + if (ctx == tmp) +@@ -1810,6 +1823,7 @@ + /* success */ + iwl_teardown_interface(priv, vif, true); + vif->type = newtype; ++ vif->p2p = newp2p; + err = iwl_setup_interface(priv, ctx); + WARN_ON(err); + /* +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-core.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-core.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-core.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-core.h 2011-05-05 23:29:45.416441031 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +@@ -73,7 +73,7 @@ + + + #define IWLWIFI_VERSION "in-tree:" +-#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation" ++#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation" + #define DRV_AUTHOR "" + + #define IWL_PCI_DEVICE(dev, subdev, cfg) \ +@@ -90,7 +90,6 @@ + #define IWL_CMD(x) case x: return #x + + struct iwl_hcmd_ops { +- int (*rxon_assoc)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); + int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); + void (*set_rxon_chain)(struct iwl_priv *priv, + struct iwl_rxon_context *ctx); +@@ -122,37 +121,10 @@ + void (*config)(struct iwl_priv *priv); + }; + +-struct iwl_isr_ops { +- irqreturn_t (*isr) (int irq, void *data); +- void (*free)(struct iwl_priv *priv); +- int (*alloc)(struct iwl_priv *priv); +- int (*reset)(struct iwl_priv *priv); +- void (*disable)(struct iwl_priv *priv); +-}; +- +-struct iwl_debugfs_ops { +- ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos); +- ssize_t (*tx_stats_read)(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos); +- ssize_t (*general_stats_read)(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos); +- ssize_t (*bt_stats_read)(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos); +- ssize_t (*reply_tx_error)(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos); +-}; +- + struct iwl_temp_ops { + void (*temperature)(struct iwl_priv *priv); + }; + +-struct iwl_tt_ops { +- bool (*lower_power_detection)(struct iwl_priv *priv); +- u8 (*tt_power_mode)(struct iwl_priv *priv); +- bool (*ct_kill_check)(struct iwl_priv *priv); +-}; +- + struct iwl_lib_ops { + /* set hw dependent parameters */ + int (*set_hw_params)(struct iwl_priv *priv); +@@ -171,30 +143,14 @@ + struct iwl_tx_queue *txq); + int (*txq_init)(struct iwl_priv *priv, + struct iwl_tx_queue *txq); +- /* aggregations */ +- int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo, +- int sta_id, int tid, u16 ssn_idx); +- int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, +- u8 tx_fifo); + /* setup Rx handler */ + void (*rx_handler_setup)(struct iwl_priv *priv); + /* setup deferred work */ + void (*setup_deferred_work)(struct iwl_priv *priv); + /* cancel deferred work */ + void (*cancel_deferred_work)(struct iwl_priv *priv); +- /* alive notification after init uCode load */ +- void (*init_alive_start)(struct iwl_priv *priv); +- /* alive notification */ +- int (*alive_notify)(struct iwl_priv *priv); + /* check validity of rtc data address */ + int (*is_valid_rtc_data_addr)(u32 addr); +- /* 1st ucode load */ +- int (*load_ucode)(struct iwl_priv *priv); +- int (*dump_nic_event_log)(struct iwl_priv *priv, +- bool full_log, char **buf, bool display); +- void (*dump_nic_error_log)(struct iwl_priv *priv); +- void (*dump_csr)(struct iwl_priv *priv); +- int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display); + int (*set_channel_switch)(struct iwl_priv *priv, + struct ieee80211_channel_switch *ch_switch); + /* power management */ +@@ -204,9 +160,6 @@ + int (*send_tx_power) (struct iwl_priv *priv); + void (*update_chain_flags)(struct iwl_priv *priv); + +- /* isr */ +- struct iwl_isr_ops isr_ops; +- + /* eeprom operations (as defined in iwl-eeprom.h) */ + struct iwl_eeprom_ops eeprom_ops; + +@@ -216,14 +169,6 @@ + int (*txfifo_flush)(struct iwl_priv *priv, u16 flush_control); + void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control); + +- struct iwl_debugfs_ops debugfs_ops; +- +- /* thermal throttling */ +- struct iwl_tt_ops tt_ops; +-}; +- +-struct iwl_led_ops { +- int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd); + }; + + /* NIC specific ops */ +@@ -231,28 +176,15 @@ + void (*additional_nic_config)(struct iwl_priv *priv); + }; + +-struct iwl_legacy_ops { +- void (*post_associate)(struct iwl_priv *priv); +- void (*config_ap)(struct iwl_priv *priv); +- /* station management */ +- int (*update_bcast_stations)(struct iwl_priv *priv); +- int (*manage_ibss_station)(struct iwl_priv *priv, +- struct ieee80211_vif *vif, bool add); +-}; +- + struct iwl_ops { + const struct iwl_lib_ops *lib; + const struct iwl_hcmd_ops *hcmd; + const struct iwl_hcmd_utils_ops *utils; +- const struct iwl_led_ops *led; + const struct iwl_nic_ops *nic; +- const struct iwl_legacy_ops *legacy; +- const struct ieee80211_ops *ieee80211_ops; + }; + + struct iwl_mod_params { + int sw_crypto; /* def: 0 = using hardware encryption */ +- int disable_hw_scan; /* def: 0 = use h/w scan */ + int num_of_queues; /* def: HW dependent */ + int disable_11n; /* def: 0 = 11n capabilities enabled */ + int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ +@@ -278,16 +210,7 @@ + * @wd_timeout: TX queues watchdog timeout + * @temperature_kelvin: temperature report by uCode in kelvin + * @max_event_log_size: size of event log buffer size for ucode event logging +- * @tx_power_by_driver: tx power calibration performed by driver +- * instead of uCode +- * @ucode_tracing: support ucode continuous tracing +- * @sensitivity_calib_by_driver: driver has the capability to perform +- * sensitivity calibration operation +- * @chain_noise_calib_by_driver: driver has the capability to perform +- * chain noise calibration operation + * @shadow_reg_enable: HW shadhow register bit +- * @no_agg_framecnt_info: uCode do not provide aggregation frame count +- * information + */ + struct iwl_base_params { + int eeprom_size; +@@ -295,14 +218,10 @@ + int num_of_ampdu_queues;/* def: HW dependent */ + /* for iwl_apm_init() */ + u32 pll_cfg_val; +- bool set_l0s; +- bool use_bsm; + +- bool use_isr_legacy; + const u16 max_ll_items; + const bool shadow_ram_support; + u16 led_compensation; +- const bool broken_powersave; + int chain_noise_num_beacons; + bool adv_thermal_throttle; + bool support_ct_kill_exit; +@@ -312,18 +231,12 @@ + unsigned int wd_timeout; + bool temperature_kelvin; + u32 max_event_log_size; +- const bool tx_power_by_driver; +- const bool ucode_tracing; +- const bool sensitivity_calib_by_driver; +- const bool chain_noise_calib_by_driver; + const bool shadow_reg_enable; +- const bool no_agg_framecnt_info; + }; + /* + * @advanced_bt_coexist: support advanced bt coexist + * @bt_init_traffic_load: specify initial bt traffic load + * @bt_prio_boost: default bt priority boost value +- * @bt_statistics: use BT version of statistics notification + * @agg_time_limit: maximum number of uSec in aggregation + * @ampdu_factor: Maximum A-MPDU length factor + * @ampdu_density: Minimum A-MPDU spacing +@@ -333,7 +246,6 @@ + bool advanced_bt_coexist; + u8 bt_init_traffic_load; + u8 bt_prio_boost; +- const bool bt_statistics; + u16 agg_time_limit; + u8 ampdu_factor; + u8 ampdu_density; +@@ -364,6 +276,7 @@ + * @rx_with_siso_diversity: 1x1 device with rx antenna diversity + * @internal_wimax_coex: internal wifi/wimax combo device + * @iq_invert: I/Q inversion ++ * @disable_otp_refresh: disable OTP refresh current limit + * + * We enable the driver to be backward compatible wrt API version. The + * driver specifies which APIs it supports (with @ucode_api_max being the +@@ -398,8 +311,6 @@ + u16 eeprom_ver; + u16 eeprom_calib_ver; + const struct iwl_ops *ops; +- /* module based parameters which can be set from modprobe cmd */ +- const struct iwl_mod_params *mod_params; + /* params not likely to change within a device family */ + struct iwl_base_params *base_params; + /* params likely to change within a device family */ +@@ -414,13 +325,13 @@ + const bool rx_with_siso_diversity; + const bool internal_wimax_coex; + const bool iq_invert; ++ const bool disable_otp_refresh; + }; + + /*************************** + * L i b * + ***************************/ + +-struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg); + int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params); + int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); +@@ -625,6 +536,8 @@ + void iwl_dump_nic_error_log(struct iwl_priv *priv); + int iwl_dump_nic_event_log(struct iwl_priv *priv, + bool full_log, char **buf, bool display); ++void iwl_dump_csr(struct iwl_priv *priv); ++int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); + #ifdef CONFIG_IWLWIFI_DEBUG + void iwl_print_rx_config_cmd(struct iwl_priv *priv, + struct iwl_rxon_context *ctx); +@@ -662,6 +575,7 @@ + #define STATUS_SCAN_HW 15 + #define STATUS_POWER_PMI 16 + #define STATUS_FW_ERROR 17 ++#define STATUS_DEVICE_ENABLED 18 + + + static inline int iwl_is_ready(struct iwl_priv *priv) +@@ -714,11 +628,6 @@ + int iwl_apm_init(struct iwl_priv *priv); + + int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx); +-static inline int iwl_send_rxon_assoc(struct iwl_priv *priv, +- struct iwl_rxon_context *ctx) +-{ +- return priv->cfg->ops->hcmd->rxon_assoc(priv, ctx); +-} + static inline int iwlcore_commit_rxon(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) + { +@@ -736,12 +645,10 @@ + priv->cfg->bt_params->advanced_bt_coexist; + } + +-static inline bool iwl_bt_statistics(struct iwl_priv *priv) +-{ +- return priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics; +-} +- + extern bool bt_coex_active; + extern bool bt_siso_mode; + ++ ++void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); ++ + #endif /* __iwl_core_h__ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-csr.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-csr.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-csr.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-csr.h 2011-05-05 23:29:45.282439411 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +@@ -155,18 +155,10 @@ + #define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250) + + /* Bits for CSR_HW_IF_CONFIG_REG */ +-#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) + #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) + #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) + #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) + +-#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100) +-#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200) +-#define CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) +-#define CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) +-#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) +-#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) +- + #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) + #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) + #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ +@@ -186,7 +178,7 @@ + #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ + #define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ + #define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ +-#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ ++#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses */ + #define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ + #define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ + +@@ -202,29 +194,17 @@ + /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ + #define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ + #define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ +-#define CSR39_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */ + #define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ + #define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ +-#define CSR39_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */ + #define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ + #define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ + +-#define CSR39_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ +- CSR39_FH_INT_BIT_RX_CHNL2 | \ +- CSR_FH_INT_BIT_RX_CHNL1 | \ +- CSR_FH_INT_BIT_RX_CHNL0) +- +- +-#define CSR39_FH_INT_TX_MASK (CSR39_FH_INT_BIT_TX_CHNL6 | \ +- CSR_FH_INT_BIT_TX_CHNL1 | \ +- CSR_FH_INT_BIT_TX_CHNL0) +- +-#define CSR49_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ +- CSR_FH_INT_BIT_RX_CHNL1 | \ +- CSR_FH_INT_BIT_RX_CHNL0) ++#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ ++ CSR_FH_INT_BIT_RX_CHNL1 | \ ++ CSR_FH_INT_BIT_RX_CHNL0) + +-#define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ +- CSR_FH_INT_BIT_TX_CHNL0) ++#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ ++ CSR_FH_INT_BIT_TX_CHNL0) + + /* GPIO */ + #define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) +@@ -268,7 +248,7 @@ + * Indicates MAC (ucode processor, etc.) is powered up and can run. + * Internal resources are accessible. + * NOTE: This does not indicate that the processor is actually running. +- * NOTE: This does not indicate that 4965 or 3945 has completed ++ * NOTE: This does not indicate that device has completed + * init or post-power-down restore of internal SRAM memory. + * Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that + * SRAM is restored and uCode is in normal operation mode. +@@ -291,8 +271,6 @@ + + /* HW REV */ + #define CSR_HW_REV_TYPE_MSK (0x00001F0) +-#define CSR_HW_REV_TYPE_3945 (0x00000D0) +-#define CSR_HW_REV_TYPE_4965 (0x0000000) + #define CSR_HW_REV_TYPE_5300 (0x0000020) + #define CSR_HW_REV_TYPE_5350 (0x0000030) + #define CSR_HW_REV_TYPE_5100 (0x0000050) +@@ -363,7 +341,7 @@ + * 0: MAC_SLEEP + * uCode sets this when preparing a power-saving power-down. + * uCode resets this when power-up is complete and SRAM is sane. +- * NOTE: 3945/4965 saves internal SRAM data to host when powering down, ++ * NOTE: device saves internal SRAM data to host when powering down, + * and must restore this data after powering back up. + * MAC_SLEEP is the best indication that restore is complete. + * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and +@@ -394,7 +372,6 @@ + #define CSR_LED_REG_TRUN_OFF (0x38) + + /* ANA_PLL */ +-#define CSR39_ANA_PLL_CFG_VAL (0x01000000) + #define CSR50_ANA_PLL_CFG_VAL (0x00880300) + + /* HPET MEM debug */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-debugfs.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-debugfs.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-debugfs.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-debugfs.c 2011-05-05 23:29:45.388440693 +0200 +@@ -2,7 +2,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -39,6 +39,7 @@ + #include "iwl-debug.h" + #include "iwl-core.h" + #include "iwl-io.h" ++#include "iwl-agn.h" + + /* create and remove of files */ + #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ +@@ -226,10 +227,10 @@ + /* default is to dump the entire data segment */ + if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { + priv->dbgfs_sram_offset = 0x800000; +- if (priv->ucode_type == UCODE_INIT) +- priv->dbgfs_sram_len = priv->ucode_init_data.len; ++ if (priv->ucode_type == UCODE_SUBTYPE_INIT) ++ priv->dbgfs_sram_len = priv->ucode_init.data.len; + else +- priv->dbgfs_sram_len = priv->ucode_data.len; ++ priv->dbgfs_sram_len = priv->ucode_rt.data.len; + } + len = priv->dbgfs_sram_len; + +@@ -437,8 +438,7 @@ + int pos = 0; + ssize_t ret = -ENOMEM; + +- ret = pos = priv->cfg->ops->lib->dump_nic_event_log( +- priv, true, &buf, true); ++ ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true); + if (buf) { + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); +@@ -462,8 +462,7 @@ + if (sscanf(buf, "%d", &event_log_flag) != 1) + return -EFAULT; + if (event_log_flag == 1) +- priv->cfg->ops->lib->dump_nic_event_log(priv, true, +- NULL, false); ++ iwl_dump_nic_event_log(priv, true, NULL, false); + + return count; + } +@@ -1039,13 +1038,463 @@ + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + } + ++static const char *fmt_value = " %-30s %10u\n"; ++static const char *fmt_hex = " %-30s 0x%02X\n"; ++static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; ++static const char *fmt_header = ++ "%-32s current cumulative delta max\n"; ++ ++static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) ++{ ++ int p = 0; ++ u32 flag; ++ ++ flag = le32_to_cpu(priv->statistics.flag); ++ ++ p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag); ++ if (flag & UCODE_STATISTICS_CLEAR_MSK) ++ p += scnprintf(buf + p, bufsz - p, ++ "\tStatistics have been cleared\n"); ++ p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", ++ (flag & UCODE_STATISTICS_FREQUENCY_MSK) ++ ? "2.4 GHz" : "5.2 GHz"); ++ p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", ++ (flag & UCODE_STATISTICS_NARROW_BAND_MSK) ++ ? "enabled" : "disabled"); ++ ++ return p; ++} ++ + static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) + { + struct iwl_priv *priv = file->private_data; +- return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file, +- user_buf, count, ppos); ++ int pos = 0; ++ char *buf; ++ int bufsz = sizeof(struct statistics_rx_phy) * 40 + ++ sizeof(struct statistics_rx_non_phy) * 40 + ++ sizeof(struct statistics_rx_ht_phy) * 40 + 400; ++ ssize_t ret; ++ struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; ++ struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; ++ struct statistics_rx_non_phy *general, *accum_general; ++ struct statistics_rx_non_phy *delta_general, *max_general; ++ struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; ++ ++ if (!iwl_is_alive(priv)) ++ return -EAGAIN; ++ ++ buf = kzalloc(bufsz, GFP_KERNEL); ++ if (!buf) { ++ IWL_ERR(priv, "Can not allocate Buffer\n"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * the statistic information display here is based on ++ * the last statistics notification from uCode ++ * might not reflect the current uCode activity ++ */ ++ ofdm = &priv->statistics.rx_ofdm; ++ cck = &priv->statistics.rx_cck; ++ general = &priv->statistics.rx_non_phy; ++ ht = &priv->statistics.rx_ofdm_ht; ++ accum_ofdm = &priv->accum_stats.rx_ofdm; ++ accum_cck = &priv->accum_stats.rx_cck; ++ accum_general = &priv->accum_stats.rx_non_phy; ++ accum_ht = &priv->accum_stats.rx_ofdm_ht; ++ delta_ofdm = &priv->delta_stats.rx_ofdm; ++ delta_cck = &priv->delta_stats.rx_cck; ++ delta_general = &priv->delta_stats.rx_non_phy; ++ delta_ht = &priv->delta_stats.rx_ofdm_ht; ++ max_ofdm = &priv->max_delta_stats.rx_ofdm; ++ max_cck = &priv->max_delta_stats.rx_cck; ++ max_general = &priv->max_delta_stats.rx_non_phy; ++ max_ht = &priv->max_delta_stats.rx_ofdm_ht; ++ ++ pos += iwl_statistics_flag(priv, buf, bufsz); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_header, "Statistics_Rx - OFDM:"); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "ina_cnt:", ++ le32_to_cpu(ofdm->ina_cnt), ++ accum_ofdm->ina_cnt, ++ delta_ofdm->ina_cnt, max_ofdm->ina_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "fina_cnt:", ++ le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, ++ delta_ofdm->fina_cnt, max_ofdm->fina_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "plcp_err:", ++ le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, ++ delta_ofdm->plcp_err, max_ofdm->plcp_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "crc32_err:", ++ le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, ++ delta_ofdm->crc32_err, max_ofdm->crc32_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "overrun_err:", ++ le32_to_cpu(ofdm->overrun_err), ++ accum_ofdm->overrun_err, delta_ofdm->overrun_err, ++ max_ofdm->overrun_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "early_overrun_err:", ++ le32_to_cpu(ofdm->early_overrun_err), ++ accum_ofdm->early_overrun_err, ++ delta_ofdm->early_overrun_err, ++ max_ofdm->early_overrun_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "crc32_good:", ++ le32_to_cpu(ofdm->crc32_good), ++ accum_ofdm->crc32_good, delta_ofdm->crc32_good, ++ max_ofdm->crc32_good); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "false_alarm_cnt:", ++ le32_to_cpu(ofdm->false_alarm_cnt), ++ accum_ofdm->false_alarm_cnt, ++ delta_ofdm->false_alarm_cnt, ++ max_ofdm->false_alarm_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "fina_sync_err_cnt:", ++ le32_to_cpu(ofdm->fina_sync_err_cnt), ++ accum_ofdm->fina_sync_err_cnt, ++ delta_ofdm->fina_sync_err_cnt, ++ max_ofdm->fina_sync_err_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "sfd_timeout:", ++ le32_to_cpu(ofdm->sfd_timeout), ++ accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout, ++ max_ofdm->sfd_timeout); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "fina_timeout:", ++ le32_to_cpu(ofdm->fina_timeout), ++ accum_ofdm->fina_timeout, delta_ofdm->fina_timeout, ++ max_ofdm->fina_timeout); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "unresponded_rts:", ++ le32_to_cpu(ofdm->unresponded_rts), ++ accum_ofdm->unresponded_rts, ++ delta_ofdm->unresponded_rts, ++ max_ofdm->unresponded_rts); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "rxe_frame_lmt_ovrun:", ++ le32_to_cpu(ofdm->rxe_frame_limit_overrun), ++ accum_ofdm->rxe_frame_limit_overrun, ++ delta_ofdm->rxe_frame_limit_overrun, ++ max_ofdm->rxe_frame_limit_overrun); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "sent_ack_cnt:", ++ le32_to_cpu(ofdm->sent_ack_cnt), ++ accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt, ++ max_ofdm->sent_ack_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "sent_cts_cnt:", ++ le32_to_cpu(ofdm->sent_cts_cnt), ++ accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt, ++ max_ofdm->sent_cts_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "sent_ba_rsp_cnt:", ++ le32_to_cpu(ofdm->sent_ba_rsp_cnt), ++ accum_ofdm->sent_ba_rsp_cnt, ++ delta_ofdm->sent_ba_rsp_cnt, ++ max_ofdm->sent_ba_rsp_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "dsp_self_kill:", ++ le32_to_cpu(ofdm->dsp_self_kill), ++ accum_ofdm->dsp_self_kill, ++ delta_ofdm->dsp_self_kill, ++ max_ofdm->dsp_self_kill); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "mh_format_err:", ++ le32_to_cpu(ofdm->mh_format_err), ++ accum_ofdm->mh_format_err, ++ delta_ofdm->mh_format_err, ++ max_ofdm->mh_format_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "re_acq_main_rssi_sum:", ++ le32_to_cpu(ofdm->re_acq_main_rssi_sum), ++ accum_ofdm->re_acq_main_rssi_sum, ++ delta_ofdm->re_acq_main_rssi_sum, ++ max_ofdm->re_acq_main_rssi_sum); ++ ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_header, "Statistics_Rx - CCK:"); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "ina_cnt:", ++ le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, ++ delta_cck->ina_cnt, max_cck->ina_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "fina_cnt:", ++ le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, ++ delta_cck->fina_cnt, max_cck->fina_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "plcp_err:", ++ le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, ++ delta_cck->plcp_err, max_cck->plcp_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "crc32_err:", ++ le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, ++ delta_cck->crc32_err, max_cck->crc32_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "overrun_err:", ++ le32_to_cpu(cck->overrun_err), ++ accum_cck->overrun_err, delta_cck->overrun_err, ++ max_cck->overrun_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "early_overrun_err:", ++ le32_to_cpu(cck->early_overrun_err), ++ accum_cck->early_overrun_err, ++ delta_cck->early_overrun_err, ++ max_cck->early_overrun_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "crc32_good:", ++ le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, ++ delta_cck->crc32_good, max_cck->crc32_good); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "false_alarm_cnt:", ++ le32_to_cpu(cck->false_alarm_cnt), ++ accum_cck->false_alarm_cnt, ++ delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "fina_sync_err_cnt:", ++ le32_to_cpu(cck->fina_sync_err_cnt), ++ accum_cck->fina_sync_err_cnt, ++ delta_cck->fina_sync_err_cnt, ++ max_cck->fina_sync_err_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "sfd_timeout:", ++ le32_to_cpu(cck->sfd_timeout), ++ accum_cck->sfd_timeout, delta_cck->sfd_timeout, ++ max_cck->sfd_timeout); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "fina_timeout:", ++ le32_to_cpu(cck->fina_timeout), ++ accum_cck->fina_timeout, delta_cck->fina_timeout, ++ max_cck->fina_timeout); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "unresponded_rts:", ++ le32_to_cpu(cck->unresponded_rts), ++ accum_cck->unresponded_rts, delta_cck->unresponded_rts, ++ max_cck->unresponded_rts); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "rxe_frame_lmt_ovrun:", ++ le32_to_cpu(cck->rxe_frame_limit_overrun), ++ accum_cck->rxe_frame_limit_overrun, ++ delta_cck->rxe_frame_limit_overrun, ++ max_cck->rxe_frame_limit_overrun); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "sent_ack_cnt:", ++ le32_to_cpu(cck->sent_ack_cnt), ++ accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt, ++ max_cck->sent_ack_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "sent_cts_cnt:", ++ le32_to_cpu(cck->sent_cts_cnt), ++ accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt, ++ max_cck->sent_cts_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "sent_ba_rsp_cnt:", ++ le32_to_cpu(cck->sent_ba_rsp_cnt), ++ accum_cck->sent_ba_rsp_cnt, ++ delta_cck->sent_ba_rsp_cnt, ++ max_cck->sent_ba_rsp_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "dsp_self_kill:", ++ le32_to_cpu(cck->dsp_self_kill), ++ accum_cck->dsp_self_kill, delta_cck->dsp_self_kill, ++ max_cck->dsp_self_kill); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "mh_format_err:", ++ le32_to_cpu(cck->mh_format_err), ++ accum_cck->mh_format_err, delta_cck->mh_format_err, ++ max_cck->mh_format_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "re_acq_main_rssi_sum:", ++ le32_to_cpu(cck->re_acq_main_rssi_sum), ++ accum_cck->re_acq_main_rssi_sum, ++ delta_cck->re_acq_main_rssi_sum, ++ max_cck->re_acq_main_rssi_sum); ++ ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_header, "Statistics_Rx - GENERAL:"); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "bogus_cts:", ++ le32_to_cpu(general->bogus_cts), ++ accum_general->bogus_cts, delta_general->bogus_cts, ++ max_general->bogus_cts); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "bogus_ack:", ++ le32_to_cpu(general->bogus_ack), ++ accum_general->bogus_ack, delta_general->bogus_ack, ++ max_general->bogus_ack); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "non_bssid_frames:", ++ le32_to_cpu(general->non_bssid_frames), ++ accum_general->non_bssid_frames, ++ delta_general->non_bssid_frames, ++ max_general->non_bssid_frames); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "filtered_frames:", ++ le32_to_cpu(general->filtered_frames), ++ accum_general->filtered_frames, ++ delta_general->filtered_frames, ++ max_general->filtered_frames); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "non_channel_beacons:", ++ le32_to_cpu(general->non_channel_beacons), ++ accum_general->non_channel_beacons, ++ delta_general->non_channel_beacons, ++ max_general->non_channel_beacons); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "channel_beacons:", ++ le32_to_cpu(general->channel_beacons), ++ accum_general->channel_beacons, ++ delta_general->channel_beacons, ++ max_general->channel_beacons); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "num_missed_bcon:", ++ le32_to_cpu(general->num_missed_bcon), ++ accum_general->num_missed_bcon, ++ delta_general->num_missed_bcon, ++ max_general->num_missed_bcon); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "adc_rx_saturation_time:", ++ le32_to_cpu(general->adc_rx_saturation_time), ++ accum_general->adc_rx_saturation_time, ++ delta_general->adc_rx_saturation_time, ++ max_general->adc_rx_saturation_time); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "ina_detect_search_tm:", ++ le32_to_cpu(general->ina_detection_search_time), ++ accum_general->ina_detection_search_time, ++ delta_general->ina_detection_search_time, ++ max_general->ina_detection_search_time); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "beacon_silence_rssi_a:", ++ le32_to_cpu(general->beacon_silence_rssi_a), ++ accum_general->beacon_silence_rssi_a, ++ delta_general->beacon_silence_rssi_a, ++ max_general->beacon_silence_rssi_a); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "beacon_silence_rssi_b:", ++ le32_to_cpu(general->beacon_silence_rssi_b), ++ accum_general->beacon_silence_rssi_b, ++ delta_general->beacon_silence_rssi_b, ++ max_general->beacon_silence_rssi_b); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "beacon_silence_rssi_c:", ++ le32_to_cpu(general->beacon_silence_rssi_c), ++ accum_general->beacon_silence_rssi_c, ++ delta_general->beacon_silence_rssi_c, ++ max_general->beacon_silence_rssi_c); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "interference_data_flag:", ++ le32_to_cpu(general->interference_data_flag), ++ accum_general->interference_data_flag, ++ delta_general->interference_data_flag, ++ max_general->interference_data_flag); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "channel_load:", ++ le32_to_cpu(general->channel_load), ++ accum_general->channel_load, ++ delta_general->channel_load, ++ max_general->channel_load); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "dsp_false_alarms:", ++ le32_to_cpu(general->dsp_false_alarms), ++ accum_general->dsp_false_alarms, ++ delta_general->dsp_false_alarms, ++ max_general->dsp_false_alarms); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "beacon_rssi_a:", ++ le32_to_cpu(general->beacon_rssi_a), ++ accum_general->beacon_rssi_a, ++ delta_general->beacon_rssi_a, ++ max_general->beacon_rssi_a); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "beacon_rssi_b:", ++ le32_to_cpu(general->beacon_rssi_b), ++ accum_general->beacon_rssi_b, ++ delta_general->beacon_rssi_b, ++ max_general->beacon_rssi_b); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "beacon_rssi_c:", ++ le32_to_cpu(general->beacon_rssi_c), ++ accum_general->beacon_rssi_c, ++ delta_general->beacon_rssi_c, ++ max_general->beacon_rssi_c); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "beacon_energy_a:", ++ le32_to_cpu(general->beacon_energy_a), ++ accum_general->beacon_energy_a, ++ delta_general->beacon_energy_a, ++ max_general->beacon_energy_a); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "beacon_energy_b:", ++ le32_to_cpu(general->beacon_energy_b), ++ accum_general->beacon_energy_b, ++ delta_general->beacon_energy_b, ++ max_general->beacon_energy_b); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "beacon_energy_c:", ++ le32_to_cpu(general->beacon_energy_c), ++ accum_general->beacon_energy_c, ++ delta_general->beacon_energy_c, ++ max_general->beacon_energy_c); ++ ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_header, "Statistics_Rx - OFDM_HT:"); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "plcp_err:", ++ le32_to_cpu(ht->plcp_err), accum_ht->plcp_err, ++ delta_ht->plcp_err, max_ht->plcp_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "overrun_err:", ++ le32_to_cpu(ht->overrun_err), accum_ht->overrun_err, ++ delta_ht->overrun_err, max_ht->overrun_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "early_overrun_err:", ++ le32_to_cpu(ht->early_overrun_err), ++ accum_ht->early_overrun_err, ++ delta_ht->early_overrun_err, ++ max_ht->early_overrun_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "crc32_good:", ++ le32_to_cpu(ht->crc32_good), accum_ht->crc32_good, ++ delta_ht->crc32_good, max_ht->crc32_good); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "crc32_err:", ++ le32_to_cpu(ht->crc32_err), accum_ht->crc32_err, ++ delta_ht->crc32_err, max_ht->crc32_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "mh_format_err:", ++ le32_to_cpu(ht->mh_format_err), ++ accum_ht->mh_format_err, ++ delta_ht->mh_format_err, max_ht->mh_format_err); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg_crc32_good:", ++ le32_to_cpu(ht->agg_crc32_good), ++ accum_ht->agg_crc32_good, ++ delta_ht->agg_crc32_good, max_ht->agg_crc32_good); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg_mpdu_cnt:", ++ le32_to_cpu(ht->agg_mpdu_cnt), ++ accum_ht->agg_mpdu_cnt, ++ delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg_cnt:", ++ le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt, ++ delta_ht->agg_cnt, max_ht->agg_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "unsupport_mcs:", ++ le32_to_cpu(ht->unsupport_mcs), ++ accum_ht->unsupport_mcs, ++ delta_ht->unsupport_mcs, max_ht->unsupport_mcs); ++ ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); ++ kfree(buf); ++ return ret; + } + + static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, +@@ -1053,8 +1502,190 @@ + size_t count, loff_t *ppos) + { + struct iwl_priv *priv = file->private_data; +- return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file, +- user_buf, count, ppos); ++ int pos = 0; ++ char *buf; ++ int bufsz = (sizeof(struct statistics_tx) * 48) + 250; ++ ssize_t ret; ++ struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; ++ ++ if (!iwl_is_alive(priv)) ++ return -EAGAIN; ++ ++ buf = kzalloc(bufsz, GFP_KERNEL); ++ if (!buf) { ++ IWL_ERR(priv, "Can not allocate Buffer\n"); ++ return -ENOMEM; ++ } ++ ++ /* the statistic information display here is based on ++ * the last statistics notification from uCode ++ * might not reflect the current uCode activity ++ */ ++ tx = &priv->statistics.tx; ++ accum_tx = &priv->accum_stats.tx; ++ delta_tx = &priv->delta_stats.tx; ++ max_tx = &priv->max_delta_stats.tx; ++ ++ pos += iwl_statistics_flag(priv, buf, bufsz); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_header, "Statistics_Tx:"); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "preamble:", ++ le32_to_cpu(tx->preamble_cnt), ++ accum_tx->preamble_cnt, ++ delta_tx->preamble_cnt, max_tx->preamble_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "rx_detected_cnt:", ++ le32_to_cpu(tx->rx_detected_cnt), ++ accum_tx->rx_detected_cnt, ++ delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "bt_prio_defer_cnt:", ++ le32_to_cpu(tx->bt_prio_defer_cnt), ++ accum_tx->bt_prio_defer_cnt, ++ delta_tx->bt_prio_defer_cnt, ++ max_tx->bt_prio_defer_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "bt_prio_kill_cnt:", ++ le32_to_cpu(tx->bt_prio_kill_cnt), ++ accum_tx->bt_prio_kill_cnt, ++ delta_tx->bt_prio_kill_cnt, ++ max_tx->bt_prio_kill_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "few_bytes_cnt:", ++ le32_to_cpu(tx->few_bytes_cnt), ++ accum_tx->few_bytes_cnt, ++ delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "cts_timeout:", ++ le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, ++ delta_tx->cts_timeout, max_tx->cts_timeout); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "ack_timeout:", ++ le32_to_cpu(tx->ack_timeout), ++ accum_tx->ack_timeout, ++ delta_tx->ack_timeout, max_tx->ack_timeout); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "expected_ack_cnt:", ++ le32_to_cpu(tx->expected_ack_cnt), ++ accum_tx->expected_ack_cnt, ++ delta_tx->expected_ack_cnt, ++ max_tx->expected_ack_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "actual_ack_cnt:", ++ le32_to_cpu(tx->actual_ack_cnt), ++ accum_tx->actual_ack_cnt, ++ delta_tx->actual_ack_cnt, ++ max_tx->actual_ack_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "dump_msdu_cnt:", ++ le32_to_cpu(tx->dump_msdu_cnt), ++ accum_tx->dump_msdu_cnt, ++ delta_tx->dump_msdu_cnt, ++ max_tx->dump_msdu_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "abort_nxt_frame_mismatch:", ++ le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), ++ accum_tx->burst_abort_next_frame_mismatch_cnt, ++ delta_tx->burst_abort_next_frame_mismatch_cnt, ++ max_tx->burst_abort_next_frame_mismatch_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "abort_missing_nxt_frame:", ++ le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), ++ accum_tx->burst_abort_missing_next_frame_cnt, ++ delta_tx->burst_abort_missing_next_frame_cnt, ++ max_tx->burst_abort_missing_next_frame_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "cts_timeout_collision:", ++ le32_to_cpu(tx->cts_timeout_collision), ++ accum_tx->cts_timeout_collision, ++ delta_tx->cts_timeout_collision, ++ max_tx->cts_timeout_collision); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "ack_ba_timeout_collision:", ++ le32_to_cpu(tx->ack_or_ba_timeout_collision), ++ accum_tx->ack_or_ba_timeout_collision, ++ delta_tx->ack_or_ba_timeout_collision, ++ max_tx->ack_or_ba_timeout_collision); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg ba_timeout:", ++ le32_to_cpu(tx->agg.ba_timeout), ++ accum_tx->agg.ba_timeout, ++ delta_tx->agg.ba_timeout, ++ max_tx->agg.ba_timeout); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg ba_resched_frames:", ++ le32_to_cpu(tx->agg.ba_reschedule_frames), ++ accum_tx->agg.ba_reschedule_frames, ++ delta_tx->agg.ba_reschedule_frames, ++ max_tx->agg.ba_reschedule_frames); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg scd_query_agg_frame:", ++ le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), ++ accum_tx->agg.scd_query_agg_frame_cnt, ++ delta_tx->agg.scd_query_agg_frame_cnt, ++ max_tx->agg.scd_query_agg_frame_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg scd_query_no_agg:", ++ le32_to_cpu(tx->agg.scd_query_no_agg), ++ accum_tx->agg.scd_query_no_agg, ++ delta_tx->agg.scd_query_no_agg, ++ max_tx->agg.scd_query_no_agg); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg scd_query_agg:", ++ le32_to_cpu(tx->agg.scd_query_agg), ++ accum_tx->agg.scd_query_agg, ++ delta_tx->agg.scd_query_agg, ++ max_tx->agg.scd_query_agg); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg scd_query_mismatch:", ++ le32_to_cpu(tx->agg.scd_query_mismatch), ++ accum_tx->agg.scd_query_mismatch, ++ delta_tx->agg.scd_query_mismatch, ++ max_tx->agg.scd_query_mismatch); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg frame_not_ready:", ++ le32_to_cpu(tx->agg.frame_not_ready), ++ accum_tx->agg.frame_not_ready, ++ delta_tx->agg.frame_not_ready, ++ max_tx->agg.frame_not_ready); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg underrun:", ++ le32_to_cpu(tx->agg.underrun), ++ accum_tx->agg.underrun, ++ delta_tx->agg.underrun, max_tx->agg.underrun); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg bt_prio_kill:", ++ le32_to_cpu(tx->agg.bt_prio_kill), ++ accum_tx->agg.bt_prio_kill, ++ delta_tx->agg.bt_prio_kill, ++ max_tx->agg.bt_prio_kill); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "agg rx_ba_rsp_cnt:", ++ le32_to_cpu(tx->agg.rx_ba_rsp_cnt), ++ accum_tx->agg.rx_ba_rsp_cnt, ++ delta_tx->agg.rx_ba_rsp_cnt, ++ max_tx->agg.rx_ba_rsp_cnt); ++ ++ if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) { ++ pos += scnprintf(buf + pos, bufsz - pos, ++ "tx power: (1/2 dB step)\n"); ++ if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a) ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_hex, "antenna A:", ++ tx->tx_power.ant_a); ++ if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b) ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_hex, "antenna B:", ++ tx->tx_power.ant_b); ++ if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c) ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_hex, "antenna C:", ++ tx->tx_power.ant_c); ++ } ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); ++ kfree(buf); ++ return ret; + } + + static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, +@@ -1062,8 +1693,347 @@ + size_t count, loff_t *ppos) + { + struct iwl_priv *priv = file->private_data; +- return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file, +- user_buf, count, ppos); ++ int pos = 0; ++ char *buf; ++ int bufsz = sizeof(struct statistics_general) * 10 + 300; ++ ssize_t ret; ++ struct statistics_general_common *general, *accum_general; ++ struct statistics_general_common *delta_general, *max_general; ++ struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; ++ struct statistics_div *div, *accum_div, *delta_div, *max_div; ++ ++ if (!iwl_is_alive(priv)) ++ return -EAGAIN; ++ ++ buf = kzalloc(bufsz, GFP_KERNEL); ++ if (!buf) { ++ IWL_ERR(priv, "Can not allocate Buffer\n"); ++ return -ENOMEM; ++ } ++ ++ /* the statistic information display here is based on ++ * the last statistics notification from uCode ++ * might not reflect the current uCode activity ++ */ ++ general = &priv->statistics.common; ++ dbg = &priv->statistics.common.dbg; ++ div = &priv->statistics.common.div; ++ accum_general = &priv->accum_stats.common; ++ accum_dbg = &priv->accum_stats.common.dbg; ++ accum_div = &priv->accum_stats.common.div; ++ delta_general = &priv->delta_stats.common; ++ max_general = &priv->max_delta_stats.common; ++ delta_dbg = &priv->delta_stats.common.dbg; ++ max_dbg = &priv->max_delta_stats.common.dbg; ++ delta_div = &priv->delta_stats.common.div; ++ max_div = &priv->max_delta_stats.common.div; ++ ++ pos += iwl_statistics_flag(priv, buf, bufsz); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_header, "Statistics_General:"); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_value, "temperature:", ++ le32_to_cpu(general->temperature)); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_value, "temperature_m:", ++ le32_to_cpu(general->temperature_m)); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_value, "ttl_timestamp:", ++ le32_to_cpu(general->ttl_timestamp)); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "burst_check:", ++ le32_to_cpu(dbg->burst_check), ++ accum_dbg->burst_check, ++ delta_dbg->burst_check, max_dbg->burst_check); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "burst_count:", ++ le32_to_cpu(dbg->burst_count), ++ accum_dbg->burst_count, ++ delta_dbg->burst_count, max_dbg->burst_count); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "wait_for_silence_timeout_count:", ++ le32_to_cpu(dbg->wait_for_silence_timeout_cnt), ++ accum_dbg->wait_for_silence_timeout_cnt, ++ delta_dbg->wait_for_silence_timeout_cnt, ++ max_dbg->wait_for_silence_timeout_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "sleep_time:", ++ le32_to_cpu(general->sleep_time), ++ accum_general->sleep_time, ++ delta_general->sleep_time, max_general->sleep_time); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "slots_out:", ++ le32_to_cpu(general->slots_out), ++ accum_general->slots_out, ++ delta_general->slots_out, max_general->slots_out); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "slots_idle:", ++ le32_to_cpu(general->slots_idle), ++ accum_general->slots_idle, ++ delta_general->slots_idle, max_general->slots_idle); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "tx_on_a:", ++ le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, ++ delta_div->tx_on_a, max_div->tx_on_a); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "tx_on_b:", ++ le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, ++ delta_div->tx_on_b, max_div->tx_on_b); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "exec_time:", ++ le32_to_cpu(div->exec_time), accum_div->exec_time, ++ delta_div->exec_time, max_div->exec_time); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "probe_time:", ++ le32_to_cpu(div->probe_time), accum_div->probe_time, ++ delta_div->probe_time, max_div->probe_time); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "rx_enable_counter:", ++ le32_to_cpu(general->rx_enable_counter), ++ accum_general->rx_enable_counter, ++ delta_general->rx_enable_counter, ++ max_general->rx_enable_counter); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ fmt_table, "num_of_sos_states:", ++ le32_to_cpu(general->num_of_sos_states), ++ accum_general->num_of_sos_states, ++ delta_general->num_of_sos_states, ++ max_general->num_of_sos_states); ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); ++ kfree(buf); ++ return ret; ++} ++ ++static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct iwl_priv *priv = (struct iwl_priv *)file->private_data; ++ int pos = 0; ++ char *buf; ++ int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200; ++ ssize_t ret; ++ struct statistics_bt_activity *bt, *accum_bt; ++ ++ if (!iwl_is_alive(priv)) ++ return -EAGAIN; ++ ++ if (!priv->bt_enable_flag) ++ return -EINVAL; ++ ++ /* make request to uCode to retrieve statistics information */ ++ mutex_lock(&priv->mutex); ++ ret = iwl_send_statistics_request(priv, CMD_SYNC, false); ++ mutex_unlock(&priv->mutex); ++ ++ if (ret) { ++ IWL_ERR(priv, ++ "Error sending statistics request: %zd\n", ret); ++ return -EAGAIN; ++ } ++ buf = kzalloc(bufsz, GFP_KERNEL); ++ if (!buf) { ++ IWL_ERR(priv, "Can not allocate Buffer\n"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * the statistic information display here is based on ++ * the last statistics notification from uCode ++ * might not reflect the current uCode activity ++ */ ++ bt = &priv->statistics.bt_activity; ++ accum_bt = &priv->accum_stats.bt_activity; ++ ++ pos += iwl_statistics_flag(priv, buf, bufsz); ++ pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n"); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ "\t\t\tcurrent\t\t\taccumulative\n"); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", ++ le32_to_cpu(bt->hi_priority_tx_req_cnt), ++ accum_bt->hi_priority_tx_req_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n", ++ le32_to_cpu(bt->hi_priority_tx_denied_cnt), ++ accum_bt->hi_priority_tx_denied_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", ++ le32_to_cpu(bt->lo_priority_tx_req_cnt), ++ accum_bt->lo_priority_tx_req_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n", ++ le32_to_cpu(bt->lo_priority_tx_denied_cnt), ++ accum_bt->lo_priority_tx_denied_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", ++ le32_to_cpu(bt->hi_priority_rx_req_cnt), ++ accum_bt->hi_priority_rx_req_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n", ++ le32_to_cpu(bt->hi_priority_rx_denied_cnt), ++ accum_bt->hi_priority_rx_denied_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", ++ le32_to_cpu(bt->lo_priority_rx_req_cnt), ++ accum_bt->lo_priority_rx_req_cnt); ++ pos += scnprintf(buf + pos, bufsz - pos, ++ "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n", ++ le32_to_cpu(bt->lo_priority_rx_denied_cnt), ++ accum_bt->lo_priority_rx_denied_cnt); ++ ++ pos += scnprintf(buf + pos, bufsz - pos, ++ "(rx)num_bt_kills:\t\t%u\t\t\t%u\n", ++ le32_to_cpu(priv->statistics.num_bt_kills), ++ priv->statistics.accum_num_bt_kills); ++ ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); ++ kfree(buf); ++ return ret; ++} ++ ++static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct iwl_priv *priv = (struct iwl_priv *)file->private_data; ++ int pos = 0; ++ char *buf; ++ int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) + ++ (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200; ++ ssize_t ret; ++ ++ if (!iwl_is_alive(priv)) ++ return -EAGAIN; ++ ++ buf = kzalloc(bufsz, GFP_KERNEL); ++ if (!buf) { ++ IWL_ERR(priv, "Can not allocate Buffer\n"); ++ return -ENOMEM; ++ } ++ ++ pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n"); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY), ++ priv->_agn.reply_tx_stats.pp_delay); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES), ++ priv->_agn.reply_tx_stats.pp_few_bytes); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO), ++ priv->_agn.reply_tx_stats.pp_bt_prio); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD), ++ priv->_agn.reply_tx_stats.pp_quiet_period); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK), ++ priv->_agn.reply_tx_stats.pp_calc_ttak); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", ++ iwl_get_tx_fail_reason( ++ TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY), ++ priv->_agn.reply_tx_stats.int_crossed_retry); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT), ++ priv->_agn.reply_tx_stats.short_limit); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT), ++ priv->_agn.reply_tx_stats.long_limit); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN), ++ priv->_agn.reply_tx_stats.fifo_underrun); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW), ++ priv->_agn.reply_tx_stats.drain_flow); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH), ++ priv->_agn.reply_tx_stats.rfkill_flush); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE), ++ priv->_agn.reply_tx_stats.life_expire); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS), ++ priv->_agn.reply_tx_stats.dest_ps); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED), ++ priv->_agn.reply_tx_stats.host_abort); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY), ++ priv->_agn.reply_tx_stats.pp_delay); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID), ++ priv->_agn.reply_tx_stats.sta_invalid); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED), ++ priv->_agn.reply_tx_stats.frag_drop); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE), ++ priv->_agn.reply_tx_stats.tid_disable); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED), ++ priv->_agn.reply_tx_stats.fifo_flush); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", ++ iwl_get_tx_fail_reason( ++ TX_STATUS_FAIL_INSUFFICIENT_CF_POLL), ++ priv->_agn.reply_tx_stats.insuff_cf_poll); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX), ++ priv->_agn.reply_tx_stats.fail_hw_drop); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", ++ iwl_get_tx_fail_reason( ++ TX_STATUS_FAIL_NO_BEACON_ON_RADAR), ++ priv->_agn.reply_tx_stats.sta_color_mismatch); ++ pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", ++ priv->_agn.reply_tx_stats.unknown); ++ ++ pos += scnprintf(buf + pos, bufsz - pos, ++ "\nStatistics_Agg_TX_Error:\n"); ++ ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK), ++ priv->_agn.reply_agg_tx_stats.underrun); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK), ++ priv->_agn.reply_agg_tx_stats.bt_prio); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK), ++ priv->_agn.reply_agg_tx_stats.few_bytes); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK), ++ priv->_agn.reply_agg_tx_stats.abort); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", ++ iwl_get_agg_tx_fail_reason( ++ AGG_TX_STATE_LAST_SENT_TTL_MSK), ++ priv->_agn.reply_agg_tx_stats.last_sent_ttl); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", ++ iwl_get_agg_tx_fail_reason( ++ AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK), ++ priv->_agn.reply_agg_tx_stats.last_sent_try); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", ++ iwl_get_agg_tx_fail_reason( ++ AGG_TX_STATE_LAST_SENT_BT_KILL_MSK), ++ priv->_agn.reply_agg_tx_stats.last_sent_bt_kill); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK), ++ priv->_agn.reply_agg_tx_stats.scd_query); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", ++ iwl_get_agg_tx_fail_reason( ++ AGG_TX_STATE_TEST_BAD_CRC32_MSK), ++ priv->_agn.reply_agg_tx_stats.bad_crc32); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK), ++ priv->_agn.reply_agg_tx_stats.response); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK), ++ priv->_agn.reply_agg_tx_stats.dump_tx); ++ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", ++ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK), ++ priv->_agn.reply_agg_tx_stats.delay_tx); ++ pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", ++ priv->_agn.reply_agg_tx_stats.unknown); ++ ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); ++ kfree(buf); ++ return ret; + } + + static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, +@@ -1268,8 +2238,7 @@ + if (sscanf(buf, "%d", &csr) != 1) + return -EFAULT; + +- if (priv->cfg->ops->lib->dump_csr) +- priv->cfg->ops->lib->dump_csr(priv); ++ iwl_dump_csr(priv); + + return count; + } +@@ -1359,13 +2328,11 @@ + int pos = 0; + ssize_t ret = -EFAULT; + +- if (priv->cfg->ops->lib->dump_fh) { +- ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true); +- if (buf) { +- ret = simple_read_from_buffer(user_buf, +- count, ppos, buf, pos); +- kfree(buf); +- } ++ ret = pos = iwl_dump_fh(priv, &buf, true); ++ if (buf) { ++ ret = simple_read_from_buffer(user_buf, ++ count, ppos, buf, pos); ++ kfree(buf); + } + + return ret; +@@ -1531,16 +2498,6 @@ + return count; + } + +-static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file, +- char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- struct iwl_priv *priv = (struct iwl_priv *)file->private_data; +- +- return priv->cfg->ops->lib->debugfs_ops.bt_stats_read(file, +- user_buf, count, ppos); +-} +- + static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) { +@@ -1572,12 +2529,10 @@ + int pos = 0; + char buf[200]; + const size_t bufsz = sizeof(buf); +- ssize_t ret; + + if (!priv->bt_enable_flag) { + pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n"); +- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); +- return ret; ++ return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + } + pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n", + priv->bt_enable_flag); +@@ -1608,8 +2563,7 @@ + break; + } + +- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); +- return ret; ++ return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + } + + static ssize_t iwl_dbgfs_protection_mode_read(struct file *file, +@@ -1658,18 +2612,6 @@ + return count; + } + +-static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file, +- char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- struct iwl_priv *priv = file->private_data; +- +- if (priv->cfg->ops->lib->debugfs_ops.reply_tx_error) +- return priv->cfg->ops->lib->debugfs_ops.reply_tx_error( +- file, user_buf, count, ppos); +- else +- return -ENODATA; +-} + DEBUGFS_READ_FILE_OPS(rx_statistics); + DEBUGFS_READ_FILE_OPS(tx_statistics); + DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); +@@ -1731,11 +2673,8 @@ + DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR); + DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR); +- if (!priv->cfg->base_params->broken_powersave) { +- DEBUGFS_ADD_FILE(sleep_level_override, dir_data, +- S_IWUSR | S_IRUSR); +- DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); +- } ++ DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR); ++ DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); + DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR); + DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR); +@@ -1758,29 +2697,20 @@ + DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR); + DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR); + +- if (priv->cfg->base_params->sensitivity_calib_by_driver) +- DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); +- if (priv->cfg->base_params->chain_noise_calib_by_driver) +- DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); +- if (priv->cfg->base_params->ucode_tracing) +- DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); +- if (iwl_bt_statistics(priv)) +- DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR); ++ DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); ++ DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); ++ DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); ++ DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); + DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR); + DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR); + if (iwl_advanced_bt_coexist(priv)) + DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR); +- if (priv->cfg->base_params->sensitivity_calib_by_driver) +- DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, +- &priv->disable_sens_cal); +- if (priv->cfg->base_params->chain_noise_calib_by_driver) +- DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, +- &priv->disable_chain_noise_cal); +- if (priv->cfg->base_params->tx_power_by_driver) +- DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf, +- &priv->disable_tx_power_cal); ++ DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, ++ &priv->disable_sens_cal); ++ DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, ++ &priv->disable_chain_noise_cal); + return 0; + + err: +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-debug.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-debug.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-debug.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-debug.h 2011-05-05 23:29:45.348440209 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * +@@ -146,7 +146,6 @@ + #define IWL_DL_RX (1 << 24) + #define IWL_DL_ISR (1 << 25) + #define IWL_DL_HT (1 << 26) +-#define IWL_DL_IO (1 << 27) + /* 0xF0000000 - 0x10000000 */ + #define IWL_DL_11H (1 << 28) + #define IWL_DL_STATS (1 << 29) +@@ -174,7 +173,6 @@ + IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a) + #define IWL_DEBUG_AP(p, f, a...) IWL_DEBUG(p, IWL_DL_AP, f, ## a) + #define IWL_DEBUG_TXPOWER(p, f, a...) IWL_DEBUG(p, IWL_DL_TXPOWER, f, ## a) +-#define IWL_DEBUG_IO(p, f, a...) IWL_DEBUG(p, IWL_DL_IO, f, ## a) + #define IWL_DEBUG_RATE(p, f, a...) IWL_DEBUG(p, IWL_DL_RATE, f, ## a) + #define IWL_DEBUG_RATE_LIMIT(p, f, a...) \ + IWL_DEBUG_LIMIT(p, IWL_DL_RATE, f, ## a) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-dev.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-dev.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-dev.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-dev.h 2011-05-05 23:29:45.360440353 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 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 +@@ -26,7 +26,6 @@ + /* + * Please use this file (iwl-dev.h) for driver implementation definitions. + * Please use iwl-commands.h for uCode API definitions. +- * Please use iwl-4965-hw.h for hardware-related definitions. + */ + + #ifndef __iwl_dev_h__ +@@ -179,53 +178,12 @@ + + #define IWL_NUM_SCAN_RATES (2) + +-struct iwl4965_channel_tgd_info { +- u8 type; +- s8 max_power; +-}; +- +-struct iwl4965_channel_tgh_info { +- s64 last_radar_time; +-}; +- +-#define IWL4965_MAX_RATE (33) +- +-struct iwl3945_clip_group { +- /* maximum power level to prevent clipping for each rate, derived by +- * us from this band's saturation power in EEPROM */ +- const s8 clip_powers[IWL_MAX_RATES]; +-}; +- +-/* current Tx power values to use, one for each rate for each channel. +- * requested power is limited by: +- * -- regulatory EEPROM limits for this channel +- * -- hardware capabilities (clip-powers) +- * -- spectrum management +- * -- user preference (e.g. iwconfig) +- * when requested power is set, base power index must also be set. */ +-struct iwl3945_channel_power_info { +- struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ +- s8 power_table_index; /* actual (compenst'd) index into gain table */ +- s8 base_power_index; /* gain index for power at factory temp. */ +- s8 requested_power; /* power (dBm) requested for this chnl/rate */ +-}; +- +-/* current scan Tx power values to use, one for each scan rate for each +- * channel. */ +-struct iwl3945_scan_power_info { +- struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ +- s8 power_table_index; /* actual (compenst'd) index into gain table */ +- s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ +-}; +- + /* + * One for each channel, holds all channel setup data + * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant + * with one another! + */ + struct iwl_channel_info { +- struct iwl4965_channel_tgd_info tgd; +- struct iwl4965_channel_tgh_info tgh; + struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ + struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for + * HT40 channel */ +@@ -245,14 +203,6 @@ + s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ + u8 ht40_flags; /* flags copied from EEPROM */ + u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ +- +- /* Radio/DSP gain settings for each "normal" data Tx rate. +- * These include, in addition to RF and DSP gain, a few fields for +- * remembering/modifying gain settings (indexes). */ +- struct iwl3945_channel_power_info power_info[IWL4965_MAX_RATE]; +- +- /* Radio/DSP gain settings for each scan rate, for directed scans. */ +- struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; + }; + + #define IWL_TX_FIFO_BK 0 /* shared */ +@@ -309,6 +259,7 @@ + CMD_SIZE_HUGE = (1 << 0), + CMD_ASYNC = (1 << 1), + CMD_WANT_SKB = (1 << 2), ++ CMD_MAPPED = (1 << 3), + }; + + #define DEF_CMD_PAYLOAD_SIZE 320 +@@ -416,6 +367,7 @@ + #define IWL_EMPTYING_HW_QUEUE_ADDBA 2 + #define IWL_EMPTYING_HW_QUEUE_DELBA 3 + u8 state; ++ u8 tx_fifo; + }; + + +@@ -499,9 +451,6 @@ + * When mac80211 creates a station it reserves some space (hw->sta_data_size) + * in the structure for use by driver. This structure is places in that + * space. +- * +- * The common struct MUST be first because it is shared between +- * 3945 and agn! + */ + struct iwl_station_priv { + struct iwl_station_priv_common common; +@@ -530,6 +479,10 @@ + u32 len; /* bytes */ + }; + ++struct fw_img { ++ struct fw_desc code, data; ++}; ++ + /* v1/v2 uCode file layout */ + struct iwl_ucode_header { + __le32 ver; /* major/minor/API/serial */ +@@ -586,6 +539,22 @@ + IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, + IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, + IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, ++ /* 16 and 17 reserved for future use */ ++ IWL_UCODE_TLV_FLAGS = 18, ++}; ++ ++/** ++ * enum iwl_ucode_tlv_flag - ucode API flags ++ * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously ++ * was a separate TLV but moved here to save space. ++ * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, ++ * treats good CRC threshold as a boolean ++ * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). ++ */ ++enum iwl_ucode_tlv_flag { ++ IWL_UCODE_TLV_FLAGS_PAN = BIT(0), ++ IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), ++ IWL_UCODE_TLV_FLAGS_MFP = BIT(2), + }; + + struct iwl_ucode_tlv { +@@ -619,14 +588,6 @@ + u8 data[0]; + }; + +-struct iwl4965_ibss_seq { +- u8 mac[ETH_ALEN]; +- u16 seq_num; +- u16 frag_num; +- unsigned long packet_time; +- struct list_head list; +-}; +- + struct iwl_sensitivity_ranges { + u16 min_nrg_cck; + u16 max_nrg_cck; +@@ -700,7 +661,6 @@ + u8 max_beacon_itrvl; /* in 1024 ms */ + u32 max_inst_size; + u32 max_data_size; +- u32 max_bsm_size; + u32 ct_kill_threshold; /* value in hw-dependent units */ + u32 ct_kill_exit_threshold; /* value in hw-dependent units */ + /* for 1000, 6000 series and up */ +@@ -722,8 +682,6 @@ + * Naming convention -- + * iwl_ <-- Is part of iwlwifi + * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) +- * iwl4965_bg_ <-- Called from work queue context +- * iwl4965_mac_ <-- mac80211 callback + * + ****************************************************************************/ + extern void iwl_update_chain_flags(struct iwl_priv *priv); +@@ -772,7 +730,6 @@ + + /* Sensitivity and chain noise calibration */ + #define INITIALIZATION_VALUE 0xFFFF +-#define IWL4965_CAL_NUM_BEACONS 20 + #define IWL_CAL_NUM_BEACONS 16 + #define MAXIMUM_ALLOWED_PATHLOSS 15 + +@@ -806,24 +763,19 @@ + #define NRG_NUM_PREV_STAT_L 20 + #define NUM_RX_CHAINS 3 + +-enum iwl4965_false_alarm_state { ++enum iwlagn_false_alarm_state { + IWL_FA_TOO_MANY = 0, + IWL_FA_TOO_FEW = 1, + IWL_FA_GOOD_RANGE = 2, + }; + +-enum iwl4965_chain_noise_state { ++enum iwlagn_chain_noise_state { + IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ + IWL_CHAIN_NOISE_ACCUMULATE, + IWL_CHAIN_NOISE_CALIBRATED, + IWL_CHAIN_NOISE_DONE, + }; + +-enum iwl4965_calib_enabled_state { +- IWL_CALIB_DISABLED = 0, /* must be 0 */ +- IWL_CALIB_ENABLED = 1, +-}; +- + + /* + * enum iwl_calib +@@ -847,12 +799,6 @@ + size_t buf_len; + }; + +-enum ucode_type { +- UCODE_NONE = 0, +- UCODE_INIT, +- UCODE_RT +-}; +- + /* Sensitivity calib data */ + struct iwl_sensitivity_data { + u32 auto_corr_ofdm; +@@ -1131,12 +1077,6 @@ + + /* extend beacon time format bit shifting */ + /* +- * for _3945 devices +- * bits 31:24 - extended +- * bits 23:0 - interval +- */ +-#define IWL3945_EXT_BEACON_TIME_POS 24 +-/* + * for _agn devices + * bits 31:22 - extended + * bits 21:0 - interval +@@ -1164,10 +1104,12 @@ + struct iwl_notification_wait { + struct list_head list; + +- void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt); ++ void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt, ++ void *data); ++ void *fn_data; + + u8 cmd; +- bool triggered; ++ bool triggered, aborted; + }; + + enum iwl_rxon_context_id { +@@ -1228,6 +1170,8 @@ + bool enabled, is_40mhz; + u8 extension_chan_offset; + } ht; ++ ++ bool last_tx_rejected; + }; + + enum iwl_scan_type { +@@ -1249,7 +1193,6 @@ + int frames_count; + + enum ieee80211_band band; +- int alloc_rxb_page; + + void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); +@@ -1305,16 +1248,12 @@ + spinlock_t hcmd_lock; /* protect hcmd */ + spinlock_t reg_lock; /* protect hw register access */ + struct mutex mutex; +- struct mutex sync_cmd_mutex; /* enable serialization of sync commands */ + + /* basic pci-network driver stuff */ + struct pci_dev *pci_dev; + + /* pci hardware address support */ + void __iomem *hw_base; +- u32 hw_rev; +- u32 hw_wa_rev; +- u8 rev_id; + + /* microcode/device supports multiple contexts */ + u8 valid_contexts; +@@ -1325,6 +1264,8 @@ + /* max number of station keys */ + u8 sta_key_max_num; + ++ bool new_scan_threshold_behaviour; ++ + /* EEPROM MAC addresses */ + struct mac_address addresses[2]; + +@@ -1332,13 +1273,10 @@ + int fw_index; /* firmware we're trying to load */ + u32 ucode_ver; /* version of ucode, copy of + iwl_ucode.ver */ +- struct fw_desc ucode_code; /* runtime inst */ +- struct fw_desc ucode_data; /* runtime data original */ +- struct fw_desc ucode_data_backup; /* runtime data save/restore */ +- struct fw_desc ucode_init; /* initialization inst */ +- struct fw_desc ucode_init_data; /* initialization data */ +- struct fw_desc ucode_boot; /* bootstrap inst */ +- enum ucode_type ucode_type; ++ struct fw_img ucode_rt; ++ struct fw_img ucode_init; ++ ++ enum iwlagn_ucode_subtype ucode_type; + u8 ucode_write_complete; /* the image write is complete */ + char firmware_name[25]; + +@@ -1346,10 +1284,10 @@ + + struct iwl_switch_rxon switch_rxon; + +- /* 1st responses from initialize and runtime uCode images. +- * _agn's initialize alive response contains some calibration data. */ +- struct iwl_init_alive_resp card_alive_init; +- struct iwl_alive_resp card_alive; ++ struct { ++ u32 error_event_table; ++ u32 log_event_table; ++ } device_pointers; + + u16 active_rate; + +@@ -1390,15 +1328,12 @@ + struct iwl_power_mgr power_data; + struct iwl_tt_mgmt thermal_throttle; + +- /* context information */ +- u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */ +- + /* station table variables */ + + /* Note: if lock and sta_lock are needed, lock must be acquired first */ + spinlock_t sta_lock; + int num_stations; +- struct iwl_station_entry stations[IWL_STATION_COUNT]; ++ struct iwl_station_entry stations[IWLAGN_STATION_COUNT]; + unsigned long ucode_key_table; + + /* queue refcounts */ +@@ -1422,101 +1357,81 @@ + /* Last Rx'd beacon timestamp */ + u64 timestamp; + +- union { +-#if defined(CONFIG_IWL3945) || defined(CONFIG_IWL3945_MODULE) +- struct { +- void *shared_virt; +- dma_addr_t shared_phys; +- +- struct delayed_work thermal_periodic; +- struct delayed_work rfkill_poll; +- +- struct iwl3945_notif_statistics statistics; ++ struct { ++ __le32 flag; ++ struct statistics_general_common common; ++ struct statistics_rx_non_phy rx_non_phy; ++ struct statistics_rx_phy rx_ofdm; ++ struct statistics_rx_ht_phy rx_ofdm_ht; ++ struct statistics_rx_phy rx_cck; ++ struct statistics_tx tx; + #ifdef CONFIG_IWLWIFI_DEBUGFS +- struct iwl3945_notif_statistics accum_statistics; +- struct iwl3945_notif_statistics delta_statistics; +- struct iwl3945_notif_statistics max_delta; ++ struct statistics_bt_activity bt_activity; ++ __le32 num_bt_kills, accum_num_bt_kills; + #endif +- +- u32 sta_supp_rates; +- int last_rx_rssi; /* From Rx packet statistics */ +- +- /* Rx'd packet timing information */ +- u32 last_beacon_time; +- u64 last_tsf; +- +- /* +- * each calibration channel group in the +- * EEPROM has a derived clip setting for +- * each rate. +- */ +- const struct iwl3945_clip_group clip_groups[5]; +- +- } _3945; +-#endif +-#if defined(CONFIG_IWLAGN) || defined(CONFIG_IWLAGN_MODULE) +- struct { +- /* INT ICT Table */ +- __le32 *ict_tbl; +- void *ict_tbl_vir; +- dma_addr_t ict_tbl_dma; +- dma_addr_t aligned_ict_tbl_dma; +- int ict_index; +- u32 inta; +- bool use_ict; +- /* +- * reporting the number of tids has AGG on. 0 means +- * no AGGREGATION +- */ +- u8 agg_tids_count; +- +- struct iwl_rx_phy_res last_phy_res; +- bool last_phy_res_valid; +- +- struct completion firmware_loading_complete; +- +- u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; +- u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; +- +- /* +- * chain noise reset and gain commands are the +- * two extra calibration commands follows the standard +- * phy calibration commands +- */ +- u8 phy_calib_chain_noise_reset_cmd; +- u8 phy_calib_chain_noise_gain_cmd; +- +- struct iwl_notif_statistics statistics; +- struct iwl_bt_notif_statistics statistics_bt; +- /* counts reply_tx error */ +- struct reply_tx_error_statistics reply_tx_stats; +- struct reply_agg_tx_error_statistics reply_agg_tx_stats; ++ } statistics; + #ifdef CONFIG_IWLWIFI_DEBUGFS +- struct iwl_notif_statistics accum_statistics; +- struct iwl_notif_statistics delta_statistics; +- struct iwl_notif_statistics max_delta; +- struct iwl_bt_notif_statistics accum_statistics_bt; +- struct iwl_bt_notif_statistics delta_statistics_bt; +- struct iwl_bt_notif_statistics max_delta_bt; ++ struct { ++ struct statistics_general_common common; ++ struct statistics_rx_non_phy rx_non_phy; ++ struct statistics_rx_phy rx_ofdm; ++ struct statistics_rx_ht_phy rx_ofdm_ht; ++ struct statistics_rx_phy rx_cck; ++ struct statistics_tx tx; ++ struct statistics_bt_activity bt_activity; ++ } accum_stats, delta_stats, max_delta_stats; + #endif + +- /* notification wait support */ +- struct list_head notif_waits; +- spinlock_t notif_wait_lock; +- wait_queue_head_t notif_waitq; +- +- /* remain-on-channel offload support */ +- struct ieee80211_channel *hw_roc_channel; +- struct delayed_work hw_roc_work; +- enum nl80211_channel_type hw_roc_chantype; +- int hw_roc_duration; +- +- struct sk_buff *offchan_tx_skb; +- int offchan_tx_timeout; +- struct ieee80211_channel *offchan_tx_chan; +- } _agn; +-#endif +- }; ++ struct { ++ /* INT ICT Table */ ++ __le32 *ict_tbl; ++ void *ict_tbl_vir; ++ dma_addr_t ict_tbl_dma; ++ dma_addr_t aligned_ict_tbl_dma; ++ int ict_index; ++ u32 inta; ++ bool use_ict; ++ /* ++ * reporting the number of tids has AGG on. 0 means ++ * no AGGREGATION ++ */ ++ u8 agg_tids_count; ++ ++ struct iwl_rx_phy_res last_phy_res; ++ bool last_phy_res_valid; ++ ++ struct completion firmware_loading_complete; ++ ++ u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; ++ u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; ++ ++ /* ++ * chain noise reset and gain commands are the ++ * two extra calibration commands follows the standard ++ * phy calibration commands ++ */ ++ u8 phy_calib_chain_noise_reset_cmd; ++ u8 phy_calib_chain_noise_gain_cmd; ++ ++ /* counts reply_tx error */ ++ struct reply_tx_error_statistics reply_tx_stats; ++ struct reply_agg_tx_error_statistics reply_agg_tx_stats; ++ /* notification wait support */ ++ struct list_head notif_waits; ++ spinlock_t notif_wait_lock; ++ wait_queue_head_t notif_waitq; ++ ++ /* remain-on-channel offload support */ ++ struct ieee80211_channel *hw_roc_channel; ++ struct delayed_work hw_roc_work; ++ enum nl80211_channel_type hw_roc_chantype; ++ int hw_roc_duration; ++ bool hw_roc_setup; ++ ++ struct sk_buff *offchan_tx_skb; ++ int offchan_tx_timeout; ++ struct ieee80211_channel *offchan_tx_chan; ++ } _agn; + + /* bt coex */ + u8 bt_enable_flag; +@@ -1559,8 +1474,6 @@ + + struct tasklet_struct irq_tasklet; + +- struct delayed_work init_alive_start; +- struct delayed_work alive_start; + struct delayed_work scan_check; + + /* TX Power */ +@@ -1589,12 +1502,10 @@ + struct work_struct txpower_work; + u32 disable_sens_cal; + u32 disable_chain_noise_cal; +- u32 disable_tx_power_cal; + struct work_struct run_time_calib_work; + struct timer_list statistics_periodic; + struct timer_list ucode_trace; + struct timer_list watchdog; +- bool hw_ready; + + struct iwl_event_log event_log; + +@@ -1710,12 +1621,10 @@ + static inline void __iwl_free_pages(struct iwl_priv *priv, struct page *page) + { + __free_pages(page, priv->hw_params.rx_page_order); +- priv->alloc_rxb_page--; + } + + static inline void iwl_free_pages(struct iwl_priv *priv, unsigned long page) + { + free_pages(page, priv->hw_params.rx_page_order); +- priv->alloc_rxb_page--; + } + #endif /* __iwl_dev_h__ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-devtrace.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-devtrace.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-devtrace.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-devtrace.c 2011-05-05 23:29:45.349440221 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2009 - 2011 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 +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-devtrace.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-devtrace.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-devtrace.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-devtrace.h 2011-05-05 23:29:45.348440209 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2009 - 2011 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 +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-eeprom.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-eeprom.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-eeprom.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-eeprom.c 2011-05-05 23:29:45.340440113 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +@@ -142,6 +142,45 @@ + * + ******************************************************************************/ + ++/* ++ * The device's EEPROM semaphore prevents conflicts between driver and uCode ++ * when accessing the EEPROM; each access is a series of pulses to/from the ++ * EEPROM chip, not a single event, so even reads could conflict if they ++ * weren't arbitrated by the semaphore. ++ */ ++static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv) ++{ ++ u16 count; ++ int ret; ++ ++ for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { ++ /* Request semaphore */ ++ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, ++ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); ++ ++ /* See if we got it */ ++ ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, ++ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, ++ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, ++ EEPROM_SEM_TIMEOUT); ++ if (ret >= 0) { ++ IWL_DEBUG_EEPROM(priv, ++ "Acquired semaphore after %d tries.\n", ++ count+1); ++ return ret; ++ } ++ } ++ ++ return ret; ++} ++ ++static void iwl_eeprom_release_semaphore(struct iwl_priv *priv) ++{ ++ iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, ++ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); ++ ++} ++ + static int iwl_eeprom_verify_signature(struct iwl_priv *priv) + { + u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; +@@ -188,18 +227,16 @@ + CSR_OTP_GP_REG_OTP_ACCESS_MODE); + } + +-static int iwlcore_get_nvm_type(struct iwl_priv *priv) ++static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) + { + u32 otpgp; + int nvm_type; + + /* OTP only valid for CP/PP and after */ +- switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { ++ switch (hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_NONE: + IWL_ERR(priv, "Unknown hardware type\n"); + return -ENOENT; +- case CSR_HW_REV_TYPE_3945: +- case CSR_HW_REV_TYPE_4965: + case CSR_HW_REV_TYPE_5300: + case CSR_HW_REV_TYPE_5350: + case CSR_HW_REV_TYPE_5100: +@@ -217,26 +254,20 @@ + return nvm_type; + } + +-const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) +-{ +- BUG_ON(offset >= priv->cfg->base_params->eeprom_size); +- return &priv->eeprom[offset]; +-} +- + static int iwl_init_otp_access(struct iwl_priv *priv) + { + int ret; + + /* Enable 40MHz radio clock */ +- _iwl_write32(priv, CSR_GP_CNTRL, +- _iwl_read32(priv, CSR_GP_CNTRL) | +- CSR_GP_CNTRL_REG_FLAG_INIT_DONE); ++ iwl_write32(priv, CSR_GP_CNTRL, ++ iwl_read32(priv, CSR_GP_CNTRL) | ++ CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* wait for clock to be ready */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, +- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, +- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, +- 25000); ++ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, ++ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, ++ 25000); + if (ret < 0) + IWL_ERR(priv, "Time out access OTP\n"); + else { +@@ -263,17 +294,17 @@ + u32 r; + u32 otpgp; + +- _iwl_write32(priv, CSR_EEPROM_REG, +- CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); ++ iwl_write32(priv, CSR_EEPROM_REG, ++ CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + ret = iwl_poll_bit(priv, CSR_EEPROM_REG, +- CSR_EEPROM_REG_READ_VALID_MSK, +- CSR_EEPROM_REG_READ_VALID_MSK, +- IWL_EEPROM_ACCESS_TIMEOUT); ++ CSR_EEPROM_REG_READ_VALID_MSK, ++ CSR_EEPROM_REG_READ_VALID_MSK, ++ IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { + IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); + return ret; + } +- r = _iwl_read_direct32(priv, CSR_EEPROM_REG); ++ r = iwl_read32(priv, CSR_EEPROM_REG); + /* check for ECC errors: */ + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { +@@ -396,7 +427,7 @@ + * + * NOTE: This routine uses the non-debug IO access functions. + */ +-int iwl_eeprom_init(struct iwl_priv *priv) ++int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) + { + __le16 *e; + u32 gp = iwl_read32(priv, CSR_EEPROM_GP); +@@ -406,7 +437,7 @@ + u16 validblockaddr = 0; + u16 cache_addr = 0; + +- priv->nvm_device_type = iwlcore_get_nvm_type(priv); ++ priv->nvm_device_type = iwlcore_get_nvm_type(priv, hw_rev); + if (priv->nvm_device_type == -ENOENT) + return -ENOENT; + /* allocate eeprom */ +@@ -429,7 +460,7 @@ + } + + /* Make sure driver (instead of uCode) is allowed to read EEPROM */ +- ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv); ++ ret = iwl_eeprom_acquire_semaphore(priv); + if (ret < 0) { + IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n"); + ret = -ENOENT; +@@ -444,9 +475,9 @@ + ret = -ENOENT; + goto done; + } +- _iwl_write32(priv, CSR_EEPROM_GP, +- iwl_read32(priv, CSR_EEPROM_GP) & +- ~CSR_EEPROM_GP_IF_OWNER_MSK); ++ iwl_write32(priv, CSR_EEPROM_GP, ++ iwl_read32(priv, CSR_EEPROM_GP) & ++ ~CSR_EEPROM_GP_IF_OWNER_MSK); + + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | +@@ -473,8 +504,8 @@ + for (addr = 0; addr < sz; addr += sizeof(u16)) { + u32 r; + +- _iwl_write32(priv, CSR_EEPROM_REG, +- CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); ++ iwl_write32(priv, CSR_EEPROM_REG, ++ CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + + ret = iwl_poll_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, +@@ -484,7 +515,7 @@ + IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); + goto done; + } +- r = _iwl_read_direct32(priv, CSR_EEPROM_REG); ++ r = iwl_read32(priv, CSR_EEPROM_REG); + e[addr / 2] = cpu_to_le16(r >> 16); + } + } +@@ -496,7 +527,7 @@ + + ret = 0; + done: +- priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); ++ iwl_eeprom_release_semaphore(priv); + + err: + if (ret) +@@ -719,13 +750,6 @@ + flags & EEPROM_CHANNEL_RADAR)) + ? "" : "not "); + +- /* Set the tx_power_user_lmt to the highest power +- * supported by any channel */ +- if (eeprom_ch_info[ch].max_power_avg > +- priv->tx_power_user_lmt) +- priv->tx_power_user_lmt = +- eeprom_ch_info[ch].max_power_avg; +- + ch_info++; + } + } +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-eeprom.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-eeprom.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-eeprom.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-eeprom.h 2011-05-05 23:29:45.245438965 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +@@ -110,10 +110,6 @@ + }; + + /* SKU Capabilities */ +-/* 3945 only */ +-#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) +-#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) +- + /* 5000 and up */ + #define EEPROM_SKU_CAP_BAND_POS (4) + #define EEPROM_SKU_CAP_BAND_SELECTION \ +@@ -168,28 +164,6 @@ + s8 mimo3_max; + } __packed; + +-/* 3945 Specific */ +-#define EEPROM_3945_EEPROM_VERSION (0x2f) +- +-/* 4965 has two radio transmitters (and 3 radio receivers) */ +-#define EEPROM_TX_POWER_TX_CHAINS (2) +- +-/* 4965 has room for up to 8 sets of txpower calibration data */ +-#define EEPROM_TX_POWER_BANDS (8) +- +-/* 4965 factory calibration measures txpower gain settings for +- * each of 3 target output levels */ +-#define EEPROM_TX_POWER_MEASUREMENTS (3) +- +-/* 4965 Specific */ +-/* 4965 driver does not work with txpower calibration version < 5 */ +-#define EEPROM_4965_TX_POWER_VERSION (5) +-#define EEPROM_4965_EEPROM_VERSION (0x2f) +-#define EEPROM_4965_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ +-#define EEPROM_4965_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ +-#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ +-#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ +- + /* 5000 Specific */ + #define EEPROM_5000_TX_POWER_VERSION (4) + #define EEPROM_5000_EEPROM_VERSION (0x11A) +@@ -282,90 +256,6 @@ + /* 2.4 GHz */ + extern const u8 iwl_eeprom_band_1[14]; + +-/* +- * factory calibration data for one txpower level, on one channel, +- * measured on one of the 2 tx chains (radio transmitter and associated +- * antenna). EEPROM contains: +- * +- * 1) Temperature (degrees Celsius) of device when measurement was made. +- * +- * 2) Gain table index used to achieve the target measurement power. +- * This refers to the "well-known" gain tables (see iwl-4965-hw.h). +- * +- * 3) Actual measured output power, in half-dBm ("34" = 17 dBm). +- * +- * 4) RF power amplifier detector level measurement (not used). +- */ +-struct iwl_eeprom_calib_measure { +- u8 temperature; /* Device temperature (Celsius) */ +- u8 gain_idx; /* Index into gain table */ +- u8 actual_pow; /* Measured RF output power, half-dBm */ +- s8 pa_det; /* Power amp detector level (not used) */ +-} __packed; +- +- +-/* +- * measurement set for one channel. EEPROM contains: +- * +- * 1) Channel number measured +- * +- * 2) Measurements for each of 3 power levels for each of 2 radio transmitters +- * (a.k.a. "tx chains") (6 measurements altogether) +- */ +-struct iwl_eeprom_calib_ch_info { +- u8 ch_num; +- struct iwl_eeprom_calib_measure +- measurements[EEPROM_TX_POWER_TX_CHAINS] +- [EEPROM_TX_POWER_MEASUREMENTS]; +-} __packed; +- +-/* +- * txpower subband info. +- * +- * For each frequency subband, EEPROM contains the following: +- * +- * 1) First and last channels within range of the subband. "0" values +- * indicate that this sample set is not being used. +- * +- * 2) Sample measurement sets for 2 channels close to the range endpoints. +- */ +-struct iwl_eeprom_calib_subband_info { +- u8 ch_from; /* channel number of lowest channel in subband */ +- u8 ch_to; /* channel number of highest channel in subband */ +- struct iwl_eeprom_calib_ch_info ch1; +- struct iwl_eeprom_calib_ch_info ch2; +-} __packed; +- +- +-/* +- * txpower calibration info. EEPROM contains: +- * +- * 1) Factory-measured saturation power levels (maximum levels at which +- * tx power amplifier can output a signal without too much distortion). +- * There is one level for 2.4 GHz band and one for 5 GHz band. These +- * values apply to all channels within each of the bands. +- * +- * 2) Factory-measured power supply voltage level. This is assumed to be +- * constant (i.e. same value applies to all channels/bands) while the +- * factory measurements are being made. +- * +- * 3) Up to 8 sets of factory-measured txpower calibration values. +- * These are for different frequency ranges, since txpower gain +- * characteristics of the analog radio circuitry vary with frequency. +- * +- * Not all sets need to be filled with data; +- * struct iwl_eeprom_calib_subband_info contains range of channels +- * (0 if unused) for each set of data. +- */ +-struct iwl_eeprom_calib_info { +- u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ +- u8 saturation_power52; /* half-dBm */ +- __le16 voltage; /* signed */ +- struct iwl_eeprom_calib_subband_info +- band_info[EEPROM_TX_POWER_BANDS]; +-} __packed; +- +- + #define ADDRESS_MSK 0x0000FFFF + #define INDIRECT_TYPE_MSK 0x000F0000 + #define INDIRECT_HOST 0x00010000 +@@ -398,103 +288,24 @@ + #define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ + #define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ + +-#define EEPROM_3945_RF_CFG_TYPE_MAX 0x0 +-#define EEPROM_4965_RF_CFG_TYPE_MAX 0x1 +- +-/* Radio Config for 5000 and up */ +-#define EEPROM_RF_CONFIG_TYPE_R3x3 0x0 +-#define EEPROM_RF_CONFIG_TYPE_R2x2 0x1 +-#define EEPROM_RF_CONFIG_TYPE_R1x2 0x2 + #define EEPROM_RF_CONFIG_TYPE_MAX 0x3 + +-/* +- * Per-channel regulatory data. +- * +- * Each channel that *might* be supported by iwl has a fixed location +- * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory +- * txpower (MSB). +- * +- * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) +- * channels (only for 4965, not supported by 3945) appear later in the EEPROM. +- * +- * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 +- */ +-#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ +-#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ +-#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ +- +-/* +- * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, +- * 5.0 GHz channels 7, 8, 11, 12, 16 +- * (4915-5080MHz) (none of these is ever supported) +- */ +-#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ +-#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ +- +-/* +- * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 +- * (5170-5320MHz) +- */ +-#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ +-#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ +- +-/* +- * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 +- * (5500-5700MHz) +- */ +-#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ +-#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ +- +-/* +- * 5.7 GHz channels 145, 149, 153, 157, 161, 165 +- * (5725-5825MHz) +- */ +-#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ +-#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ +- +-/* +- * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) +- * +- * The channel listed is the center of the lower 20 MHz half of the channel. +- * The overall center frequency is actually 2 channels (10 MHz) above that, +- * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away +- * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5, +- * and the overall HT40 channel width centers on channel 3. +- * +- * NOTE: The RXON command uses 20 MHz channel numbers to specify the +- * control channel to which to tune. RXON also specifies whether the +- * control channel is the upper or lower half of a HT40 channel. +- * +- * NOTE: 4965 does not support HT40 channels on 2.4 GHz. +- */ +-#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */ +- +-/* +- * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64), +- * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) +- */ +-#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */ +- + #define EEPROM_REGULATORY_BAND_NO_HT40 (0) + + struct iwl_eeprom_ops { + const u32 regulatory_bands[7]; +- int (*acquire_semaphore) (struct iwl_priv *priv); +- void (*release_semaphore) (struct iwl_priv *priv); +- u16 (*calib_version) (struct iwl_priv *priv); + const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); + void (*update_enhanced_txpower) (struct iwl_priv *priv); + }; + + +-int iwl_eeprom_init(struct iwl_priv *priv); ++int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev); + void iwl_eeprom_free(struct iwl_priv *priv); + int iwl_eeprom_check_version(struct iwl_priv *priv); + int iwl_eeprom_check_sku(struct iwl_priv *priv); + const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); + int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); + u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset); +-const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); + int iwl_init_channel_map(struct iwl_priv *priv); + void iwl_free_channel_map(struct iwl_priv *priv); + const struct iwl_channel_info *iwl_get_channel_info( +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-fh.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-fh.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-fh.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-fh.h 2011-05-05 23:29:45.360440353 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +@@ -77,14 +77,14 @@ + /** + * Keep-Warm (KW) buffer base address. + * +- * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the ++ * Driver must allocate a 4KByte buffer that is for keeping the + * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency +- * DRAM access when 4965 is Txing or Rxing. The dummy accesses prevent host ++ * DRAM access when doing Txing or Rxing. The dummy accesses prevent host + * from going into a power-savings mode that would cause higher DRAM latency, + * and possible data over/under-runs, before all Tx/Rx is complete. + * + * Driver loads FH_KW_MEM_ADDR_REG with the physical address (bits 35:4) +- * of the buffer, which must be 4K aligned. Once this is set up, the 4965 ++ * of the buffer, which must be 4K aligned. Once this is set up, the device + * automatically invokes keep-warm accesses when normal accesses might not + * be sufficient to maintain fast DRAM response. + * +@@ -97,7 +97,7 @@ + /** + * TFD Circular Buffers Base (CBBC) addresses + * +- * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident ++ * Device has 16 base pointer registers, one for each of 16 host-DRAM-resident + * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs) + * (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04 + * bytes from one another. Each TFD circular buffer in DRAM must be 256-byte +@@ -116,16 +116,16 @@ + /** + * Rx SRAM Control and Status Registers (RSCSR) + * +- * These registers provide handshake between driver and 4965 for the Rx queue ++ * These registers provide handshake between driver and device for the Rx queue + * (this queue handles *all* command responses, notifications, Rx data, etc. +- * sent from 4965 uCode to host driver). Unlike Tx, there is only one Rx ++ * sent from uCode to host driver). Unlike Tx, there is only one Rx + * queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can + * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer + * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1 + * mapping between RBDs and RBs. + * + * Driver must allocate host DRAM memory for the following, and set the +- * physical address of each into 4965 registers: ++ * physical address of each into device registers: + * + * 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256 + * entries (although any power of 2, up to 4096, is selectable by driver). +@@ -140,20 +140,20 @@ + * Driver sets physical address [35:8] of base of RBD circular buffer + * into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0]. + * +- * 2) Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers ++ * 2) Rx status buffer, 8 bytes, in which uCode indicates which Rx Buffers + * (RBs) have been filled, via a "write pointer", actually the index of + * the RB's corresponding RBD within the circular buffer. Driver sets + * physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0]. + * + * Bit fields in lower dword of Rx status buffer (upper dword not used +- * by driver; see struct iwl4965_shared, val0): ++ * by driver: + * 31-12: Not used by driver + * 11- 0: Index of last filled Rx buffer descriptor +- * (4965 writes, driver reads this value) ++ * (device writes, driver reads this value) + * +- * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must ++ * As the driver prepares Receive Buffers (RBs) for device to fill, driver must + * enter pointers to these RBs into contiguous RBD circular buffer entries, +- * and update the 4965's "write" index register, ++ * and update the device's "write" index register, + * FH_RSCSR_CHNL0_RBDCB_WPTR_REG. + * + * This "write" index corresponds to the *next* RBD that the driver will make +@@ -162,12 +162,12 @@ + * RBs), should be 8 after preparing the first 8 RBs (for example), and must + * wrap back to 0 at the end of the circular buffer (but don't wrap before + * "read" index has advanced past 1! See below). +- * NOTE: 4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. ++ * NOTE: DEVICE EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. + * +- * As the 4965 fills RBs (referenced from contiguous RBDs within the circular ++ * As the device fills RBs (referenced from contiguous RBDs within the circular + * buffer), it updates the Rx status buffer in host DRAM, 2) described above, + * to tell the driver the index of the latest filled RBD. The driver must +- * read this "read" index from DRAM after receiving an Rx interrupt from 4965. ++ * read this "read" index from DRAM after receiving an Rx interrupt from device + * + * The driver must also internally keep track of a third index, which is the + * next RBD to process. When receiving an Rx interrupt, driver should process +@@ -176,7 +176,7 @@ + * driver may process the RB pointed to by RBD 0. Depending on volume of + * traffic, there may be many RBs to process. + * +- * If read index == write index, 4965 thinks there is no room to put new data. ++ * If read index == write index, device thinks there is no room to put new data. + * Due to this, the maximum number of filled RBs is 255, instead of 256. To + * be safe, make sure that there is a gap of at least 2 RBDs between "write" + * and "read" indexes; that is, make sure that there are no more than 254 +@@ -303,7 +303,7 @@ + /** + * Transmit DMA Channel Control/Status Registers (TCSR) + * +- * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels ++ * Device has one configuration register for each of 8 Tx DMA/FIFO channels + * supported in hardware (don't confuse these with the 16 Tx queues in DRAM, + * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes. + * +@@ -326,7 +326,6 @@ + #define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) + + /* Find Control/Status reg for given Tx DMA/FIFO channel */ +-#define FH49_TCSR_CHNL_NUM (7) + #define FH50_TCSR_CHNL_NUM (8) + + /* TCSR: tx_config register values */ +@@ -424,7 +423,6 @@ + #define RX_LOW_WATERMARK 8 + + /* Size of one Rx buffer in host DRAM */ +-#define IWL_RX_BUF_SIZE_3K (3 * 1000) /* 3945 only */ + #define IWL_RX_BUF_SIZE_4K (4 * 1024) + #define IWL_RX_BUF_SIZE_8K (8 * 1024) + +@@ -443,7 +441,7 @@ + __le16 closed_fr_num; + __le16 finished_rb_num; + __le16 finished_fr_nam; +- __le32 __unused; /* 3945 only */ ++ __le32 __unused; + } __packed; + + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-hcmd.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-hcmd.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-hcmd.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-hcmd.c 2011-05-05 23:29:45.340440113 +0200 +@@ -2,7 +2,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +@@ -51,9 +51,7 @@ + IWL_CMD(REPLY_REMOVE_ALL_STA); + IWL_CMD(REPLY_TXFIFO_FLUSH); + IWL_CMD(REPLY_WEPKEY); +- IWL_CMD(REPLY_3945_RX); + IWL_CMD(REPLY_TX); +- IWL_CMD(REPLY_RATE_SCALE); + IWL_CMD(REPLY_LEDS_CMD); + IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); + IWL_CMD(COEX_PRIORITY_TABLE_CMD); +@@ -145,10 +143,12 @@ + { + int ret; + +- BUG_ON(!(cmd->flags & CMD_ASYNC)); ++ if (WARN_ON(!(cmd->flags & CMD_ASYNC))) ++ return -EINVAL; + + /* An asynchronous command can not expect an SKB to be set. */ +- BUG_ON(cmd->flags & CMD_WANT_SKB); ++ if (WARN_ON(cmd->flags & CMD_WANT_SKB)) ++ return -EINVAL; + + /* Assign a generic callback if one is not provided */ + if (!cmd->callback) +@@ -171,14 +171,15 @@ + int cmd_idx; + int ret; + +- BUG_ON(cmd->flags & CMD_ASYNC); ++ if (WARN_ON(cmd->flags & CMD_ASYNC)) ++ return -EINVAL; + + /* A synchronous command can not have a callback set. */ +- BUG_ON(cmd->callback); ++ if (WARN_ON(cmd->callback)) ++ return -EINVAL; + + IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", + get_cmd_string(cmd->id)); +- mutex_lock(&priv->sync_cmd_mutex); + + set_bit(STATUS_HCMD_ACTIVE, &priv->status); + IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", +@@ -189,7 +190,7 @@ + ret = cmd_idx; + IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); +- goto out; ++ return ret; + } + + ret = wait_event_interruptible_timeout(priv->wait_command_queue, +@@ -229,8 +230,7 @@ + goto cancel; + } + +- ret = 0; +- goto out; ++ return 0; + + cancel: + if (cmd->flags & CMD_WANT_SKB) { +@@ -248,8 +248,7 @@ + iwl_free_pages(priv, cmd->reply_page); + cmd->reply_page = 0; + } +-out: +- mutex_unlock(&priv->sync_cmd_mutex); ++ + return ret; + } + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-helpers.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-helpers.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-helpers.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-helpers.h 2011-05-05 23:29:45.349440221 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. +@@ -64,30 +64,6 @@ + return --index & (n_bd - 1); + } + +-/* TODO: Move fw_desc functions to iwl-pci.ko */ +-static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, +- struct fw_desc *desc) +-{ +- if (desc->v_addr) +- dma_free_coherent(&pci_dev->dev, desc->len, +- desc->v_addr, desc->p_addr); +- desc->v_addr = NULL; +- desc->len = 0; +-} +- +-static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev, +- struct fw_desc *desc) +-{ +- if (!desc->len) { +- desc->v_addr = NULL; +- return -EINVAL; +- } +- +- desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len, +- &desc->p_addr, GFP_KERNEL); +- return (desc->v_addr != NULL) ? 0 : -ENOMEM; +-} +- + /* + * we have 8 bits used like this: + * +@@ -131,6 +107,19 @@ + ieee80211_stop_queue(priv->hw, ac); + } + ++static inline void iwl_wake_any_queue(struct iwl_priv *priv, ++ struct iwl_rxon_context *ctx) ++{ ++ u8 ac; ++ ++ for (ac = 0; ac < AC_NUM; ac++) { ++ IWL_DEBUG_INFO(priv, "Queue Status: Q[%d] %s\n", ++ ac, (atomic_read(&priv->queue_stop_count[ac]) > 0) ++ ? "stopped" : "awake"); ++ iwl_wake_queue(priv, &priv->txq[ctx->ac_to_queue[ac]]); ++ } ++} ++ + #define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue + #define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-io.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-io.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-io.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-io.c 2011-05-05 23:29:45.375440535 +0200 +@@ -0,0 +1,294 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. ++ * ++ * Portions of this file are derived from the ipw3945 project. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * Intel Linux Wireless ++ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ * ++ *****************************************************************************/ ++ ++#include "iwl-io.h" ++ ++#define IWL_POLL_INTERVAL 10 /* microseconds */ ++ ++static inline void __iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) ++{ ++ iwl_write32(priv, reg, iwl_read32(priv, reg) | mask); ++} ++ ++static inline void __iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) ++{ ++ iwl_write32(priv, reg, iwl_read32(priv, reg) & ~mask); ++} ++ ++void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->reg_lock, flags); ++ __iwl_set_bit(priv, reg, mask); ++ spin_unlock_irqrestore(&priv->reg_lock, flags); ++} ++ ++void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->reg_lock, flags); ++ __iwl_clear_bit(priv, reg, mask); ++ spin_unlock_irqrestore(&priv->reg_lock, flags); ++} ++ ++int iwl_poll_bit(struct iwl_priv *priv, u32 addr, ++ u32 bits, u32 mask, int timeout) ++{ ++ int t = 0; ++ ++ do { ++ if ((iwl_read32(priv, addr) & mask) == (bits & mask)) ++ return t; ++ udelay(IWL_POLL_INTERVAL); ++ t += IWL_POLL_INTERVAL; ++ } while (t < timeout); ++ ++ return -ETIMEDOUT; ++} ++ ++int iwl_grab_nic_access_silent(struct iwl_priv *priv) ++{ ++ int ret; ++ ++ lockdep_assert_held(&priv->reg_lock); ++ ++ /* this bit wakes up the NIC */ ++ __iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); ++ ++ /* ++ * These bits say the device is running, and should keep running for ++ * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), ++ * but they do not indicate that embedded SRAM is restored yet; ++ * 3945 and 4965 have volatile SRAM, and must save/restore contents ++ * to/from host DRAM when sleeping/waking for power-saving. ++ * Each direction takes approximately 1/4 millisecond; with this ++ * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a ++ * series of register accesses are expected (e.g. reading Event Log), ++ * to keep device from sleeping. ++ * ++ * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that ++ * SRAM is okay/restored. We don't check that here because this call ++ * is just for hardware register access; but GP1 MAC_SLEEP check is a ++ * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). ++ * ++ * 5000 series and later (including 1000 series) have non-volatile SRAM, ++ * and do not save/restore SRAM when power cycling. ++ */ ++ ret = iwl_poll_bit(priv, CSR_GP_CNTRL, ++ CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, ++ (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | ++ CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); ++ if (ret < 0) { ++ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++int iwl_grab_nic_access(struct iwl_priv *priv) ++{ ++ int ret = iwl_grab_nic_access_silent(priv); ++ if (ret) { ++ u32 val = iwl_read32(priv, CSR_GP_CNTRL); ++ IWL_ERR(priv, ++ "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); ++ } ++ ++ return ret; ++} ++ ++void iwl_release_nic_access(struct iwl_priv *priv) ++{ ++ lockdep_assert_held(&priv->reg_lock); ++ __iwl_clear_bit(priv, CSR_GP_CNTRL, ++ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); ++} ++ ++u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) ++{ ++ u32 value; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->reg_lock, flags); ++ iwl_grab_nic_access(priv); ++ value = iwl_read32(priv, reg); ++ iwl_release_nic_access(priv); ++ spin_unlock_irqrestore(&priv->reg_lock, flags); ++ ++ return value; ++} ++ ++void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->reg_lock, flags); ++ if (!iwl_grab_nic_access(priv)) { ++ iwl_write32(priv, reg, value); ++ iwl_release_nic_access(priv); ++ } ++ spin_unlock_irqrestore(&priv->reg_lock, flags); ++} ++ ++int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, ++ int timeout) ++{ ++ int t = 0; ++ ++ do { ++ if ((iwl_read_direct32(priv, addr) & mask) == mask) ++ return t; ++ udelay(IWL_POLL_INTERVAL); ++ t += IWL_POLL_INTERVAL; ++ } while (t < timeout); ++ ++ return -ETIMEDOUT; ++} ++ ++static inline u32 __iwl_read_prph(struct iwl_priv *priv, u32 reg) ++{ ++ iwl_write32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); ++ rmb(); ++ return iwl_read32(priv, HBUS_TARG_PRPH_RDAT); ++} ++ ++static inline void __iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) ++{ ++ iwl_write32(priv, HBUS_TARG_PRPH_WADDR, ++ ((addr & 0x0000FFFF) | (3 << 24))); ++ wmb(); ++ iwl_write32(priv, HBUS_TARG_PRPH_WDAT, val); ++} ++ ++u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) ++{ ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(&priv->reg_lock, flags); ++ iwl_grab_nic_access(priv); ++ val = __iwl_read_prph(priv, reg); ++ iwl_release_nic_access(priv); ++ spin_unlock_irqrestore(&priv->reg_lock, flags); ++ return val; ++} ++ ++void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->reg_lock, flags); ++ if (!iwl_grab_nic_access(priv)) { ++ __iwl_write_prph(priv, addr, val); ++ iwl_release_nic_access(priv); ++ } ++ spin_unlock_irqrestore(&priv->reg_lock, flags); ++} ++ ++void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->reg_lock, flags); ++ iwl_grab_nic_access(priv); ++ __iwl_write_prph(priv, reg, __iwl_read_prph(priv, reg) | mask); ++ iwl_release_nic_access(priv); ++ spin_unlock_irqrestore(&priv->reg_lock, flags); ++} ++ ++void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, ++ u32 bits, u32 mask) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->reg_lock, flags); ++ iwl_grab_nic_access(priv); ++ __iwl_write_prph(priv, reg, ++ (__iwl_read_prph(priv, reg) & mask) | bits); ++ iwl_release_nic_access(priv); ++ spin_unlock_irqrestore(&priv->reg_lock, flags); ++} ++ ++void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) ++{ ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(&priv->reg_lock, flags); ++ iwl_grab_nic_access(priv); ++ val = __iwl_read_prph(priv, reg); ++ __iwl_write_prph(priv, reg, (val & ~mask)); ++ iwl_release_nic_access(priv); ++ spin_unlock_irqrestore(&priv->reg_lock, flags); ++} ++ ++void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr, ++ void *buf, int words) ++{ ++ unsigned long flags; ++ int offs; ++ u32 *vals = buf; ++ ++ spin_lock_irqsave(&priv->reg_lock, flags); ++ iwl_grab_nic_access(priv); ++ ++ iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr); ++ rmb(); ++ ++ for (offs = 0; offs < words; offs++) ++ vals[offs] = iwl_read32(priv, HBUS_TARG_MEM_RDAT); ++ ++ iwl_release_nic_access(priv); ++ spin_unlock_irqrestore(&priv->reg_lock, flags); ++} ++ ++u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) ++{ ++ u32 value; ++ ++ _iwl_read_targ_mem_words(priv, addr, &value, 1); ++ ++ return value; ++} ++ ++void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->reg_lock, flags); ++ if (!iwl_grab_nic_access(priv)) { ++ iwl_write32(priv, HBUS_TARG_MEM_WADDR, addr); ++ wmb(); ++ iwl_write32(priv, HBUS_TARG_MEM_WDAT, val); ++ iwl_release_nic_access(priv); ++ } ++ spin_unlock_irqrestore(&priv->reg_lock, flags); ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-io.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-io.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-io.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-io.h 2011-05-05 23:29:45.320439871 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * +@@ -35,494 +35,58 @@ + #include "iwl-debug.h" + #include "iwl-devtrace.h" + +-/* +- * IO, register, and NIC memory access functions +- * +- * NOTE on naming convention and macro usage for these +- * +- * A single _ prefix before a an access function means that no state +- * check or debug information is printed when that function is called. +- * +- * A double __ prefix before an access function means that state is checked +- * and the current line number and caller function name are printed in addition +- * to any other debug output. +- * +- * The non-prefixed name is the #define that maps the caller into a +- * #define that provides the caller's name and __LINE__ to the double +- * prefix version. +- * +- * If you wish to call the function without any debug or state checking, +- * you should use the single _ prefix version (as is used by dependent IO +- * routines, for example _iwl_read_direct32 calls the non-check version of +- * _iwl_read32.) +- * +- * These declarations are *extremely* useful in quickly isolating code deltas +- * which result in misconfiguration of the hardware I/O. In combination with +- * git-bisect and the IO debug level you can quickly determine the specific +- * commit which breaks the IO sequence to the hardware. +- * +- */ +- +-static inline void _iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) ++static inline void iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) + { + trace_iwlwifi_dev_iowrite8(priv, ofs, val); + iowrite8(val, priv->hw_base + ofs); + } + +-#ifdef CONFIG_IWLWIFI_DEBUG +-static inline void __iwl_write8(const char *f, u32 l, struct iwl_priv *priv, +- u32 ofs, u8 val) +-{ +- IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l); +- _iwl_write8(priv, ofs, val); +-} +-#define iwl_write8(priv, ofs, val) \ +- __iwl_write8(__FILE__, __LINE__, priv, ofs, val) +-#else +-#define iwl_write8(priv, ofs, val) _iwl_write8(priv, ofs, val) +-#endif +- +- +-static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) ++static inline void iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) + { + trace_iwlwifi_dev_iowrite32(priv, ofs, val); + iowrite32(val, priv->hw_base + ofs); + } + +-#ifdef CONFIG_IWLWIFI_DEBUG +-static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, +- u32 ofs, u32 val) +-{ +- IWL_DEBUG_IO(priv, "write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l); +- _iwl_write32(priv, ofs, val); +-} +-#define iwl_write32(priv, ofs, val) \ +- __iwl_write32(__FILE__, __LINE__, priv, ofs, val) +-#else +-#define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val) +-#endif +- +-static inline u32 _iwl_read32(struct iwl_priv *priv, u32 ofs) ++static inline u32 iwl_read32(struct iwl_priv *priv, u32 ofs) + { + u32 val = ioread32(priv->hw_base + ofs); + trace_iwlwifi_dev_ioread32(priv, ofs, val); + return val; + } + +-#ifdef CONFIG_IWLWIFI_DEBUG +-static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) +-{ +- IWL_DEBUG_IO(priv, "read_direct32(0x%08X) - %s %d\n", ofs, f, l); +- return _iwl_read32(priv, ofs); +-} +-#define iwl_read32(priv, ofs) __iwl_read32(__FILE__, __LINE__, priv, ofs) +-#else +-#define iwl_read32(p, o) _iwl_read32(p, o) +-#endif +- +-#define IWL_POLL_INTERVAL 10 /* microseconds */ +-static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, +- u32 bits, u32 mask, int timeout) +-{ +- int t = 0; +- +- do { +- if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) +- return t; +- udelay(IWL_POLL_INTERVAL); +- t += IWL_POLL_INTERVAL; +- } while (t < timeout); +- +- return -ETIMEDOUT; +-} +-#ifdef CONFIG_IWLWIFI_DEBUG +-static inline int __iwl_poll_bit(const char *f, u32 l, +- struct iwl_priv *priv, u32 addr, +- u32 bits, u32 mask, int timeout) +-{ +- int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout); +- IWL_DEBUG_IO(priv, "poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", +- addr, bits, mask, +- unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l); +- return ret; +-} +-#define iwl_poll_bit(priv, addr, bits, mask, timeout) \ +- __iwl_poll_bit(__FILE__, __LINE__, priv, addr, bits, mask, timeout) +-#else +-#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t) +-#endif +- +-static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +-{ +- _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask); +-} +-#ifdef CONFIG_IWLWIFI_DEBUG +-static inline void __iwl_set_bit(const char *f, u32 l, +- struct iwl_priv *priv, u32 reg, u32 mask) +-{ +- u32 val = _iwl_read32(priv, reg) | mask; +- IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); +- _iwl_write32(priv, reg, val); +-} +-static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) +-{ +- unsigned long reg_flags; +- +- spin_lock_irqsave(&p->reg_lock, reg_flags); +- __iwl_set_bit(__FILE__, __LINE__, p, r, m); +- spin_unlock_irqrestore(&p->reg_lock, reg_flags); +-} +-#else +-static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) +-{ +- unsigned long reg_flags; +- +- spin_lock_irqsave(&p->reg_lock, reg_flags); +- _iwl_set_bit(p, r, m); +- spin_unlock_irqrestore(&p->reg_lock, reg_flags); +-} +-#endif +- +-static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +-{ +- _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask); +-} +-#ifdef CONFIG_IWLWIFI_DEBUG +-static inline void __iwl_clear_bit(const char *f, u32 l, +- struct iwl_priv *priv, u32 reg, u32 mask) +-{ +- u32 val = _iwl_read32(priv, reg) & ~mask; +- IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); +- _iwl_write32(priv, reg, val); +-} +-static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) +-{ +- unsigned long reg_flags; +- +- spin_lock_irqsave(&p->reg_lock, reg_flags); +- __iwl_clear_bit(__FILE__, __LINE__, p, r, m); +- spin_unlock_irqrestore(&p->reg_lock, reg_flags); +-} +-#else +-static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) +-{ +- unsigned long reg_flags; +- +- spin_lock_irqsave(&p->reg_lock, reg_flags); +- _iwl_clear_bit(p, r, m); +- spin_unlock_irqrestore(&p->reg_lock, reg_flags); +-} +-#endif +- +-static inline int _iwl_grab_nic_access(struct iwl_priv *priv) +-{ +- int ret; +- u32 val; +- +- /* this bit wakes up the NIC */ +- _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +- +- /* +- * These bits say the device is running, and should keep running for +- * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), +- * but they do not indicate that embedded SRAM is restored yet; +- * 3945 and 4965 have volatile SRAM, and must save/restore contents +- * to/from host DRAM when sleeping/waking for power-saving. +- * Each direction takes approximately 1/4 millisecond; with this +- * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a +- * series of register accesses are expected (e.g. reading Event Log), +- * to keep device from sleeping. +- * +- * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that +- * SRAM is okay/restored. We don't check that here because this call +- * is just for hardware register access; but GP1 MAC_SLEEP check is a +- * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). +- * +- * 5000 series and later (including 1000 series) have non-volatile SRAM, +- * and do not save/restore SRAM when power cycling. +- */ +- ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, +- CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, +- (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | +- CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); +- if (ret < 0) { +- val = _iwl_read32(priv, CSR_GP_CNTRL); +- IWL_ERR(priv, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); +- _iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); +- return -EIO; +- } +- +- return 0; +-} +- +-#ifdef CONFIG_IWLWIFI_DEBUG +-static inline int __iwl_grab_nic_access(const char *f, u32 l, +- struct iwl_priv *priv) +-{ +- IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l); +- return _iwl_grab_nic_access(priv); +-} +-#define iwl_grab_nic_access(priv) \ +- __iwl_grab_nic_access(__FILE__, __LINE__, priv) +-#else +-#define iwl_grab_nic_access(priv) \ +- _iwl_grab_nic_access(priv) +-#endif +- +-static inline void _iwl_release_nic_access(struct iwl_priv *priv) +-{ +- _iwl_clear_bit(priv, CSR_GP_CNTRL, +- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +-} +-#ifdef CONFIG_IWLWIFI_DEBUG +-static inline void __iwl_release_nic_access(const char *f, u32 l, +- struct iwl_priv *priv) +-{ +- +- IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l); +- _iwl_release_nic_access(priv); +-} +-#define iwl_release_nic_access(priv) \ +- __iwl_release_nic_access(__FILE__, __LINE__, priv) +-#else +-#define iwl_release_nic_access(priv) \ +- _iwl_release_nic_access(priv) +-#endif +- +-static inline u32 _iwl_read_direct32(struct iwl_priv *priv, u32 reg) +-{ +- return _iwl_read32(priv, reg); +-} +-#ifdef CONFIG_IWLWIFI_DEBUG +-static inline u32 __iwl_read_direct32(const char *f, u32 l, +- struct iwl_priv *priv, u32 reg) +-{ +- u32 value = _iwl_read_direct32(priv, reg); +- IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d\n", reg, value, +- f, l); +- return value; +-} +-static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) +-{ +- u32 value; +- unsigned long reg_flags; +- +- spin_lock_irqsave(&priv->reg_lock, reg_flags); +- iwl_grab_nic_access(priv); +- value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg); +- iwl_release_nic_access(priv); +- spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +- return value; +-} +- +-#else +-static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) +-{ +- u32 value; +- unsigned long reg_flags; +- +- spin_lock_irqsave(&priv->reg_lock, reg_flags); +- iwl_grab_nic_access(priv); +- value = _iwl_read_direct32(priv, reg); +- iwl_release_nic_access(priv); +- spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +- return value; +- +-} +-#endif +- +-static inline void _iwl_write_direct32(struct iwl_priv *priv, +- u32 reg, u32 value) +-{ +- _iwl_write32(priv, reg, value); +-} +-static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) +-{ +- unsigned long reg_flags; +- +- spin_lock_irqsave(&priv->reg_lock, reg_flags); +- if (!iwl_grab_nic_access(priv)) { +- _iwl_write_direct32(priv, reg, value); +- iwl_release_nic_access(priv); +- } +- spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +-} +- +-static inline void iwl_write_reg_buf(struct iwl_priv *priv, +- u32 reg, u32 len, u32 *values) +-{ +- u32 count = sizeof(u32); +- +- if ((priv != NULL) && (values != NULL)) { +- for (; 0 < len; len -= count, reg += count, values++) +- iwl_write_direct32(priv, reg, *values); +- } +-} +- +-static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, +- u32 mask, int timeout) +-{ +- int t = 0; +- +- do { +- if ((iwl_read_direct32(priv, addr) & mask) == mask) +- return t; +- udelay(IWL_POLL_INTERVAL); +- t += IWL_POLL_INTERVAL; +- } while (t < timeout); +- +- return -ETIMEDOUT; +-} +- +-#ifdef CONFIG_IWLWIFI_DEBUG +-static inline int __iwl_poll_direct_bit(const char *f, u32 l, +- struct iwl_priv *priv, +- u32 addr, u32 mask, int timeout) +-{ +- int ret = _iwl_poll_direct_bit(priv, addr, mask, timeout); +- +- if (unlikely(ret == -ETIMEDOUT)) +- IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) - " +- "timedout - %s %d\n", addr, mask, f, l); +- else +- IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) = 0x%08X " +- "- %s %d\n", addr, mask, ret, f, l); +- return ret; +-} +-#define iwl_poll_direct_bit(priv, addr, mask, timeout) \ +- __iwl_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout) +-#else +-#define iwl_poll_direct_bit _iwl_poll_direct_bit +-#endif +- +-static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) +-{ +- _iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); +- rmb(); +- return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); +-} +-static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) +-{ +- unsigned long reg_flags; +- u32 val; +- +- spin_lock_irqsave(&priv->reg_lock, reg_flags); +- iwl_grab_nic_access(priv); +- val = _iwl_read_prph(priv, reg); +- iwl_release_nic_access(priv); +- spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +- return val; +-} +- +-static inline void _iwl_write_prph(struct iwl_priv *priv, +- u32 addr, u32 val) +-{ +- _iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR, +- ((addr & 0x0000FFFF) | (3 << 24))); +- wmb(); +- _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); +-} +- +-static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) +-{ +- unsigned long reg_flags; +- +- spin_lock_irqsave(&priv->reg_lock, reg_flags); +- if (!iwl_grab_nic_access(priv)) { +- _iwl_write_prph(priv, addr, val); +- iwl_release_nic_access(priv); +- } +- spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +-} +- +-#define _iwl_set_bits_prph(priv, reg, mask) \ +- _iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask)) ++void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask); ++void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask); + +-static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) +-{ +- unsigned long reg_flags; +- +- spin_lock_irqsave(&priv->reg_lock, reg_flags); +- iwl_grab_nic_access(priv); +- _iwl_set_bits_prph(priv, reg, mask); +- iwl_release_nic_access(priv); +- spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +-} ++int iwl_poll_bit(struct iwl_priv *priv, u32 addr, ++ u32 bits, u32 mask, int timeout); ++int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, ++ int timeout); ++ ++int iwl_grab_nic_access_silent(struct iwl_priv *priv); ++int iwl_grab_nic_access(struct iwl_priv *priv); ++void iwl_release_nic_access(struct iwl_priv *priv); ++ ++u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg); ++void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value); ++ ++ ++u32 iwl_read_prph(struct iwl_priv *priv, u32 reg); ++void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val); ++void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); ++void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, ++ u32 bits, u32 mask); ++void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); ++ ++void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr, ++ void *buf, int words); ++ ++#define iwl_read_targ_mem_words(priv, addr, buf, bufsize) \ ++ do { \ ++ BUILD_BUG_ON((bufsize) % sizeof(u32)); \ ++ _iwl_read_targ_mem_words(priv, addr, buf, \ ++ (bufsize) / sizeof(u32));\ ++ } while (0) + +-#define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \ +- _iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits)) +- +-static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, +- u32 bits, u32 mask) +-{ +- unsigned long reg_flags; +- +- spin_lock_irqsave(&priv->reg_lock, reg_flags); +- iwl_grab_nic_access(priv); +- _iwl_set_bits_mask_prph(priv, reg, bits, mask); +- iwl_release_nic_access(priv); +- spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +-} +- +-static inline void iwl_clear_bits_prph(struct iwl_priv +- *priv, u32 reg, u32 mask) +-{ +- unsigned long reg_flags; +- u32 val; +- +- spin_lock_irqsave(&priv->reg_lock, reg_flags); +- iwl_grab_nic_access(priv); +- val = _iwl_read_prph(priv, reg); +- _iwl_write_prph(priv, reg, (val & ~mask)); +- iwl_release_nic_access(priv); +- spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +-} +- +-static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) +-{ +- unsigned long reg_flags; +- u32 value; +- +- spin_lock_irqsave(&priv->reg_lock, reg_flags); +- iwl_grab_nic_access(priv); +- +- _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); +- rmb(); +- value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); +- +- iwl_release_nic_access(priv); +- spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +- return value; +-} +- +-static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) +-{ +- unsigned long reg_flags; +- +- spin_lock_irqsave(&priv->reg_lock, reg_flags); +- if (!iwl_grab_nic_access(priv)) { +- _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); +- wmb(); +- _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); +- iwl_release_nic_access(priv); +- } +- spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +-} +- +-static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, +- u32 len, u32 *values) +-{ +- unsigned long reg_flags; +- +- spin_lock_irqsave(&priv->reg_lock, reg_flags); +- if (!iwl_grab_nic_access(priv)) { +- _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); +- wmb(); +- for (; 0 < len; len -= sizeof(u32), values++) +- _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); +- +- iwl_release_nic_access(priv); +- } +- spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +-} ++u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr); ++void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val); + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-led.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-led.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-led.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-led.c 2011-05-05 23:29:45.325439931 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 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 +@@ -61,10 +61,16 @@ + { .throughput = 300 * 1024 - 1, .blink_time = 50 }, + }; + ++/* Set led register off */ ++void iwlagn_led_enable(struct iwl_priv *priv) ++{ ++ iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); ++} ++ + /* + * Adjust led blink rate to compensate on a MAC Clock difference on every HW +- * Led blink rate analysis showed an average deviation of 0% on 3945, +- * 5% on 4965 HW and 20% on 5000 series and up. ++ * Led blink rate analysis showed an average deviation of 20% on 5000 series ++ * and up. + * Need to compensate on the led on/off time per HW according to the deviation + * to achieve the desired led frequency + * The calculation is: (100-averageDeviation)/100 * blinkTime +@@ -84,6 +90,24 @@ + return (u8)((time * compensation) >> 6); + } + ++static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) ++{ ++ struct iwl_host_cmd cmd = { ++ .id = REPLY_LEDS_CMD, ++ .len = sizeof(struct iwl_led_cmd), ++ .data = led_cmd, ++ .flags = CMD_ASYNC, ++ .callback = NULL, ++ }; ++ u32 reg; ++ ++ reg = iwl_read32(priv, CSR_LED_REG); ++ if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) ++ iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); ++ ++ return iwl_send_cmd(priv, &cmd); ++} ++ + /* Set led pattern command */ + static int iwl_led_cmd(struct iwl_priv *priv, + unsigned long on, +@@ -108,7 +132,7 @@ + led_cmd.off = iwl_blink_compensation(priv, off, + priv->cfg->base_params->led_compensation); + +- ret = priv->cfg->ops->led->cmd(priv, &led_cmd); ++ ret = iwl_send_led_cmd(priv, &led_cmd); + if (!ret) { + priv->blink_on = on; + priv->blink_off = off; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-led.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-led.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-led.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-led.h 2011-05-05 23:29:45.406440909 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 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 +@@ -50,6 +50,7 @@ + IWL_LED_BLINK, + }; + ++void iwlagn_led_enable(struct iwl_priv *priv); + void iwl_leds_init(struct iwl_priv *priv); + void iwl_leds_exit(struct iwl_priv *priv); + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-power.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-power.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-power.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-power.c 2011-05-05 23:29:45.282439411 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. +@@ -188,9 +188,10 @@ + table = range_0; + } + +- BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); +- +- *cmd = table[lvl].cmd; ++ if (WARN_ON(lvl < 0 || lvl >= IWL_POWER_NUM)) ++ memset(cmd, 0, sizeof(*cmd)); ++ else ++ *cmd = table[lvl].cmd; + + if (period == 0) { + skip = 0; +@@ -354,16 +355,12 @@ + + dtimper = priv->hw->conf.ps_dtim_period ?: 1; + +- if (priv->cfg->base_params->broken_powersave) +- iwl_power_sleep_cam_cmd(priv, cmd); +- else if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) ++ if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) + iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); +- else if (priv->cfg->ops->lib->tt_ops.lower_power_detection && +- priv->cfg->ops->lib->tt_ops.tt_power_mode && +- priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) { ++ else if (iwl_tt_is_low_power_state(priv)) { + /* in thermal throttling low power state */ + iwl_static_sleep_cmd(priv, cmd, +- priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper); ++ iwl_tt_current_power_mode(priv), dtimper); + } else if (!enabled) + iwl_power_sleep_cam_cmd(priv, cmd); + else if (priv->power_data.debug_sleep_level_override >= 0) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-power.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-power.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-power.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-power.h 2011-05-05 23:29:45.389440705 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-prph.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-prph.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-prph.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-prph.h 2011-05-05 23:29:45.347440197 +0200 +@@ -5,7 +5,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 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 +@@ -30,7 +30,7 @@ + * + * BSD LICENSE + * +- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without +@@ -91,7 +91,6 @@ + #define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) + #define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) + #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) +-#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */ + #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) + #define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ + #define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) +@@ -99,152 +98,6 @@ + #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) + + /** +- * BSM (Bootstrap State Machine) +- * +- * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program +- * in special SRAM that does not power down when the embedded control +- * processor is sleeping (e.g. for periodic power-saving shutdowns of radio). +- * +- * When powering back up after sleeps (or during initial uCode load), the BSM +- * internally loads the short bootstrap program from the special SRAM into the +- * embedded processor's instruction SRAM, and starts the processor so it runs +- * the bootstrap program. +- * +- * This bootstrap program loads (via PCI busmaster DMA) instructions and data +- * images for a uCode program from host DRAM locations. The host driver +- * indicates DRAM locations and sizes for instruction and data images via the +- * four BSM_DRAM_* registers. Once the bootstrap program loads the new program, +- * the new program starts automatically. +- * +- * The uCode used for open-source drivers includes two programs: +- * +- * 1) Initialization -- performs hardware calibration and sets up some +- * internal data, then notifies host via "initialize alive" notification +- * (struct iwl_init_alive_resp) that it has completed all of its work. +- * After signal from host, it then loads and starts the runtime program. +- * The initialization program must be used when initially setting up the +- * NIC after loading the driver. +- * +- * 2) Runtime/Protocol -- performs all normal runtime operations. This +- * notifies host via "alive" notification (struct iwl_alive_resp) that it +- * is ready to be used. +- * +- * When initializing the NIC, the host driver does the following procedure: +- * +- * 1) Load bootstrap program (instructions only, no data image for bootstrap) +- * into bootstrap memory. Use dword writes starting at BSM_SRAM_LOWER_BOUND +- * +- * 2) Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction +- * images in host DRAM. +- * +- * 3) Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked: +- * BSM_WR_MEM_SRC_REG = 0 +- * BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND +- * BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image +- * +- * 4) Load bootstrap into instruction SRAM: +- * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START +- * +- * 5) Wait for load completion: +- * Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0 +- * +- * 6) Enable future boot loads whenever NIC's power management triggers it: +- * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN +- * +- * 7) Start the NIC by removing all reset bits: +- * CSR_RESET = 0 +- * +- * The bootstrap uCode (already in instruction SRAM) loads initialization +- * uCode. Initialization uCode performs data initialization, sends +- * "initialize alive" notification to host, and waits for a signal from +- * host to load runtime code. +- * +- * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction +- * images in host DRAM. The last register loaded must be the instruction +- * byte count register ("1" in MSbit tells initialization uCode to load +- * the runtime uCode): +- * BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD +- * +- * 5) Wait for "alive" notification, then issue normal runtime commands. +- * +- * Data caching during power-downs: +- * +- * Just before the embedded controller powers down (e.g for automatic +- * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA) +- * a current snapshot of the embedded processor's data SRAM into host DRAM. +- * This caches the data while the embedded processor's memory is powered down. +- * Location and size are controlled by BSM_DRAM_DATA_* registers. +- * +- * NOTE: Instruction SRAM does not need to be saved, since that doesn't +- * change during operation; the original image (from uCode distribution +- * file) can be used for reload. +- * +- * When powering back up, the BSM loads the bootstrap program. Bootstrap looks +- * at the BSM_DRAM_* registers, which now point to the runtime instruction +- * image and the cached (modified) runtime data (*not* the initialization +- * uCode). Bootstrap reloads these runtime images into SRAM, and restarts the +- * uCode from where it left off before the power-down. +- * +- * NOTE: Initialization uCode does *not* run as part of the save/restore +- * procedure. +- * +- * This save/restore method is mostly for autonomous power management during +- * normal operation (result of POWER_TABLE_CMD). Platform suspend/resume and +- * RFKILL should use complete restarts (with total re-initialization) of uCode, +- * allowing total shutdown (including BSM memory). +- * +- * Note that, during normal operation, the host DRAM that held the initial +- * startup data for the runtime code is now being used as a backup data cache +- * for modified data! If you need to completely re-initialize the NIC, make +- * sure that you use the runtime data image from the uCode distribution file, +- * not the modified/saved runtime data. You may want to store a separate +- * "clean" runtime data image in DRAM to avoid disk reads of distribution file. +- */ +- +-/* BSM bit fields */ +-#define BSM_WR_CTRL_REG_BIT_START (0x80000000) /* start boot load now */ +-#define BSM_WR_CTRL_REG_BIT_START_EN (0x40000000) /* enable boot after pwrup*/ +-#define BSM_DRAM_INST_LOAD (0x80000000) /* start program load now */ +- +-/* BSM addresses */ +-#define BSM_BASE (PRPH_BASE + 0x3400) +-#define BSM_END (PRPH_BASE + 0x3800) +- +-#define BSM_WR_CTRL_REG (BSM_BASE + 0x000) /* ctl and status */ +-#define BSM_WR_MEM_SRC_REG (BSM_BASE + 0x004) /* source in BSM mem */ +-#define BSM_WR_MEM_DST_REG (BSM_BASE + 0x008) /* dest in SRAM mem */ +-#define BSM_WR_DWCOUNT_REG (BSM_BASE + 0x00C) /* bytes */ +-#define BSM_WR_STATUS_REG (BSM_BASE + 0x010) /* bit 0: 1 == done */ +- +-/* +- * Pointers and size regs for bootstrap load and data SRAM save/restore. +- * NOTE: 3945 pointers use bits 31:0 of DRAM address. +- * 4965 pointers use bits 35:4 of DRAM address. +- */ +-#define BSM_DRAM_INST_PTR_REG (BSM_BASE + 0x090) +-#define BSM_DRAM_INST_BYTECOUNT_REG (BSM_BASE + 0x094) +-#define BSM_DRAM_DATA_PTR_REG (BSM_BASE + 0x098) +-#define BSM_DRAM_DATA_BYTECOUNT_REG (BSM_BASE + 0x09C) +- +-/* +- * BSM special memory, stays powered on during power-save sleeps. +- * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1) +- */ +-#define BSM_SRAM_LOWER_BOUND (PRPH_BASE + 0x3800) +-#define BSM_SRAM_SIZE (1024) /* bytes */ +- +- +-/* 3945 Tx scheduler registers */ +-#define ALM_SCD_BASE (PRPH_BASE + 0x2E00) +-#define ALM_SCD_MODE_REG (ALM_SCD_BASE + 0x000) +-#define ALM_SCD_ARASTAT_REG (ALM_SCD_BASE + 0x004) +-#define ALM_SCD_TXFACT_REG (ALM_SCD_BASE + 0x010) +-#define ALM_SCD_TXF4MF_REG (ALM_SCD_BASE + 0x014) +-#define ALM_SCD_TXF5MF_REG (ALM_SCD_BASE + 0x020) +-#define ALM_SCD_SBYP_MODE_1_REG (ALM_SCD_BASE + 0x02C) +-#define ALM_SCD_SBYP_MODE_2_REG (ALM_SCD_BASE + 0x030) +- +-/** + * Tx Scheduler + * + * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs +@@ -254,17 +107,7 @@ + * device. A queue maps to only one (selectable by driver) Tx DMA channel, + * but one DMA channel may take input from several queues. + * +- * Tx DMA FIFOs have dedicated purposes. For 4965, they are used as follows +- * (cf. default_queue_to_tx_fifo in iwl-4965.c): +- * +- * 0 -- EDCA BK (background) frames, lowest priority +- * 1 -- EDCA BE (best effort) frames, normal priority +- * 2 -- EDCA VI (video) frames, higher priority +- * 3 -- EDCA VO (voice) and management frames, highest priority +- * 4 -- Commands (e.g. RXON, etc.) +- * 5 -- unused (HCCA) +- * 6 -- unused (HCCA) +- * 7 -- not used by driver (device-internal only) ++ * Tx DMA FIFOs have dedicated purposes. + * + * For 5000 series and up, they are used differently + * (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c): +@@ -298,7 +141,7 @@ + * Tx completion may end up being out-of-order). + * + * The driver must maintain the queue's Byte Count table in host DRAM +- * (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode. ++ * for this mode. + * This mode does not support fragmentation. + * + * 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order. +@@ -311,7 +154,7 @@ + * + * Driver controls scheduler operation via 3 means: + * 1) Scheduler registers +- * 2) Shared scheduler data base in internal 4956 SRAM ++ * 2) Shared scheduler data base in internal SRAM + * 3) Shared data in host DRAM + * + * Initialization: +@@ -330,201 +173,10 @@ + * Max Tx window size is the max number of contiguous TFDs that the scheduler + * can keep track of at one time when creating block-ack chains of frames. + * Note that "64" matches the number of ack bits in a block-ack packet. +- * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize +- * IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) values. + */ + #define SCD_WIN_SIZE 64 + #define SCD_FRAME_LIMIT 64 + +-/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */ +-#define IWL49_SCD_START_OFFSET 0xa02c00 +- +-/* +- * 4965 tells driver SRAM address for internal scheduler structs via this reg. +- * Value is valid only after "Alive" response from uCode. +- */ +-#define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x0) +- +-/* +- * Driver may need to update queue-empty bits after changing queue's +- * write and read pointers (indexes) during (re-)initialization (i.e. when +- * scheduler is not tracking what's happening). +- * Bit fields: +- * 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit +- * 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty +- * NOTE: This register is not used by Linux driver. +- */ +-#define IWL49_SCD_EMPTY_BITS (IWL49_SCD_START_OFFSET + 0x4) +- +-/* +- * Physical base address of array of byte count (BC) circular buffers (CBs). +- * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode. +- * This register points to BC CB for queue 0, must be on 1024-byte boundary. +- * Others are spaced by 1024 bytes. +- * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad. +- * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff). +- * Bit fields: +- * 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned. +- */ +-#define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x10) +- +-/* +- * Enables any/all Tx DMA/FIFO channels. +- * Scheduler generates requests for only the active channels. +- * Set this to 0xff to enable all 8 channels (normal usage). +- * Bit fields: +- * 7- 0: Enable (1), disable (0), one bit for each channel 0-7 +- */ +-#define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c) +-/* +- * Queue (x) Write Pointers (indexes, really!), one for each Tx queue. +- * Initialized and updated by driver as new TFDs are added to queue. +- * NOTE: If using Block Ack, index must correspond to frame's +- * Start Sequence Number; index = (SSN & 0xff) +- * NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses? +- */ +-#define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_START_OFFSET + 0x24 + (x) * 4) +- +-/* +- * Queue (x) Read Pointers (indexes, really!), one for each Tx queue. +- * For FIFO mode, index indicates next frame to transmit. +- * For Scheduler-ACK mode, index indicates first frame in Tx window. +- * Initialized by driver, updated by scheduler. +- */ +-#define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_START_OFFSET + 0x64 + (x) * 4) +- +-/* +- * Select which queues work in chain mode (1) vs. not (0). +- * Use chain mode to build chains of aggregated frames. +- * Bit fields: +- * 31-16: Reserved +- * 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time +- * NOTE: If driver sets up queue for chain mode, it should be also set up +- * Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x). +- */ +-#define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_START_OFFSET + 0xd0) +- +-/* +- * Select which queues interrupt driver when scheduler increments +- * a queue's read pointer (index). +- * Bit fields: +- * 31-16: Reserved +- * 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled +- * NOTE: This functionality is apparently a no-op; driver relies on interrupts +- * from Rx queue to read Tx command responses and update Tx queues. +- */ +-#define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_START_OFFSET + 0xe4) +- +-/* +- * Queue search status registers. One for each queue. +- * Sets up queue mode and assigns queue to Tx DMA channel. +- * Bit fields: +- * 19-10: Write mask/enable bits for bits 0-9 +- * 9: Driver should init to "0" +- * 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0). +- * Driver should init to "1" for aggregation mode, or "0" otherwise. +- * 7-6: Driver should init to "0" +- * 5: Window Size Left; indicates whether scheduler can request +- * another TFD, based on window size, etc. Driver should init +- * this bit to "1" for aggregation mode, or "0" for non-agg. +- * 4-1: Tx FIFO to use (range 0-7). +- * 0: Queue is active (1), not active (0). +- * Other bits should be written as "0" +- * +- * NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled +- * via SCD_QUEUECHAIN_SEL. +- */ +-#define IWL49_SCD_QUEUE_STATUS_BITS(x)\ +- (IWL49_SCD_START_OFFSET + 0x104 + (x) * 4) +- +-/* Bit field positions */ +-#define IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE (0) +-#define IWL49_SCD_QUEUE_STTS_REG_POS_TXF (1) +-#define IWL49_SCD_QUEUE_STTS_REG_POS_WSL (5) +-#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) +- +-/* Write masks */ +-#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) +-#define IWL49_SCD_QUEUE_STTS_REG_MSK (0x0007FC00) +- +-/** +- * 4965 internal SRAM structures for scheduler, shared with driver ... +- * +- * Driver should clear and initialize the following areas after receiving +- * "Alive" response from 4965 uCode, i.e. after initial +- * uCode load, or after a uCode load done for error recovery: +- * +- * SCD_CONTEXT_DATA_OFFSET (size 128 bytes) +- * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes) +- * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes) +- * +- * Driver accesses SRAM via HBUS_TARG_MEM_* registers. +- * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR. +- * All OFFSET values must be added to this base address. +- */ +- +-/* +- * Queue context. One 8-byte entry for each of 16 queues. +- * +- * Driver should clear this entire area (size 0x80) to 0 after receiving +- * "Alive" notification from uCode. Additionally, driver should init +- * each queue's entry as follows: +- * +- * LS Dword bit fields: +- * 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64. +- * +- * MS Dword bit fields: +- * 16-22: Frame limit. Driver should init to 10 (0xa). +- * +- * Driver should init all other bits to 0. +- * +- * Init must be done after driver receives "Alive" response from 4965 uCode, +- * and when setting up queue for aggregation. +- */ +-#define IWL49_SCD_CONTEXT_DATA_OFFSET 0x380 +-#define IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) \ +- (IWL49_SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) +- +-#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) +-#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) +-#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) +-#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) +- +-/* +- * Tx Status Bitmap +- * +- * Driver should clear this entire area (size 0x100) to 0 after receiving +- * "Alive" notification from uCode. Area is used only by device itself; +- * no other support (besides clearing) is required from driver. +- */ +-#define IWL49_SCD_TX_STTS_BITMAP_OFFSET 0x400 +- +-/* +- * RAxTID to queue translation mapping. +- * +- * When queue is in Scheduler-ACK mode, frames placed in a that queue must be +- * for only one combination of receiver address (RA) and traffic ID (TID), i.e. +- * one QOS priority level destined for one station (for this wireless link, +- * not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit +- * mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK +- * mode, the device ignores the mapping value. +- * +- * Bit fields, for each 16-bit map: +- * 15-9: Reserved, set to 0 +- * 8-4: Index into device's station table for recipient station +- * 3-0: Traffic ID (tid), range 0-15 +- * +- * Driver should clear this entire area (size 32 bytes) to 0 after receiving +- * "Alive" notification from uCode. To update a 16-bit map value, driver +- * must read a dword-aligned value from device SRAM, replace the 16-bit map +- * value of interest, and write the dword value back into device SRAM. +- */ +-#define IWL49_SCD_TRANSLATE_TBL_OFFSET 0x500 +- +-/* Find translation table dword to read/write for given queue */ +-#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ +- ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) +- + #define IWL_SCD_TXFIFO_POS_TID (0) + #define IWL_SCD_TXFIFO_POS_RA (4) + #define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-rx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-rx.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-rx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-rx.c 2011-05-05 23:29:45.373440511 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. +@@ -225,55 +225,6 @@ + * + ******************************************************************************/ + +-static void iwl_rx_reply_alive(struct iwl_priv *priv, +- struct iwl_rx_mem_buffer *rxb) +-{ +- struct iwl_rx_packet *pkt = rxb_addr(rxb); +- struct iwl_alive_resp *palive; +- struct delayed_work *pwork; +- +- palive = &pkt->u.alive_frame; +- +- IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " +- "0x%01X 0x%01X\n", +- palive->is_valid, palive->ver_type, +- palive->ver_subtype); +- +- if (palive->ver_subtype == INITIALIZE_SUBTYPE) { +- IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); +- memcpy(&priv->card_alive_init, +- &pkt->u.alive_frame, +- sizeof(struct iwl_init_alive_resp)); +- pwork = &priv->init_alive_start; +- } else { +- IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); +- memcpy(&priv->card_alive, &pkt->u.alive_frame, +- sizeof(struct iwl_alive_resp)); +- pwork = &priv->alive_start; +- } +- +- /* We delay the ALIVE response by 5ms to +- * give the HW RF Kill time to activate... */ +- if (palive->is_valid == UCODE_VALID_OK) +- queue_delayed_work(priv->workqueue, pwork, +- msecs_to_jiffies(5)); +- else { +- IWL_WARN(priv, "%s uCode did not respond OK.\n", +- (palive->ver_subtype == INITIALIZE_SUBTYPE) ? +- "init" : "runtime"); +- /* +- * If fail to load init uCode, +- * let's try to load the init uCode again. +- * We should not get into this situation, but if it +- * does happen, we should not move on and loading "runtime" +- * without proper calibrate the device. +- */ +- if (palive->ver_subtype == INITIALIZE_SUBTYPE) +- priv->ucode_type = UCODE_NONE; +- queue_work(priv->workqueue, &priv->restart); +- } +-} +- + static void iwl_rx_reply_error(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) + { +@@ -390,21 +341,16 @@ + * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal + * operation state. + */ +-static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt) ++static bool iwl_good_ack_health(struct iwl_priv *priv, ++ struct statistics_tx *cur) + { + int actual_delta, expected_delta, ba_timeout_delta; +- struct statistics_tx *cur, *old; ++ struct statistics_tx *old; + + if (priv->_agn.agg_tids_count) + return true; + +- if (iwl_bt_statistics(priv)) { +- cur = &pkt->u.stats_bt.tx; +- old = &priv->_agn.statistics_bt.tx; +- } else { +- cur = &pkt->u.stats.tx; +- old = &priv->_agn.statistics.tx; +- } ++ old = &priv->statistics.tx; + + actual_delta = le32_to_cpu(cur->actual_ack_cnt) - + le32_to_cpu(old->actual_ack_cnt); +@@ -430,10 +376,10 @@ + * DEBUG is not, these will just compile out. + */ + IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n", +- priv->_agn.delta_statistics.tx.rx_detected_cnt); ++ priv->delta_stats.tx.rx_detected_cnt); + IWL_DEBUG_RADIO(priv, + "ack_or_ba_timeout_collision delta %d\n", +- priv->_agn.delta_statistics.tx.ack_or_ba_timeout_collision); ++ priv->delta_stats.tx.ack_or_ba_timeout_collision); + #endif + + if (ba_timeout_delta >= BA_TIMEOUT_MAX) +@@ -450,7 +396,9 @@ + * to improve the throughput. + */ + static bool iwl_good_plcp_health(struct iwl_priv *priv, +- struct iwl_rx_packet *pkt, unsigned int msecs) ++ struct statistics_rx_phy *cur_ofdm, ++ struct statistics_rx_ht_phy *cur_ofdm_ht, ++ unsigned int msecs) + { + int delta; + int threshold = priv->cfg->base_params->plcp_delta_threshold; +@@ -460,29 +408,12 @@ + return true; + } + +- if (iwl_bt_statistics(priv)) { +- struct statistics_rx_bt *cur, *old; ++ delta = le32_to_cpu(cur_ofdm->plcp_err) - ++ le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) + ++ le32_to_cpu(cur_ofdm_ht->plcp_err) - ++ le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err); + +- cur = &pkt->u.stats_bt.rx; +- old = &priv->_agn.statistics_bt.rx; +- +- delta = le32_to_cpu(cur->ofdm.plcp_err) - +- le32_to_cpu(old->ofdm.plcp_err) + +- le32_to_cpu(cur->ofdm_ht.plcp_err) - +- le32_to_cpu(old->ofdm_ht.plcp_err); +- } else { +- struct statistics_rx *cur, *old; +- +- cur = &pkt->u.stats.rx; +- old = &priv->_agn.statistics.rx; +- +- delta = le32_to_cpu(cur->ofdm.plcp_err) - +- le32_to_cpu(old->ofdm.plcp_err) + +- le32_to_cpu(cur->ofdm_ht.plcp_err) - +- le32_to_cpu(old->ofdm_ht.plcp_err); +- } +- +- /* Can be negative if firmware reseted statistics */ ++ /* Can be negative if firmware reset statistics */ + if (delta <= 0) + return true; + +@@ -497,44 +428,35 @@ + } + + static void iwl_recover_from_statistics(struct iwl_priv *priv, +- struct iwl_rx_packet *pkt) ++ struct statistics_rx_phy *cur_ofdm, ++ struct statistics_rx_ht_phy *cur_ofdm_ht, ++ struct statistics_tx *tx, ++ unsigned long stamp) + { +- const struct iwl_mod_params *mod_params = priv->cfg->mod_params; + unsigned int msecs; +- unsigned long stamp; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + +- stamp = jiffies; + msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies); + + /* Only gather statistics and update time stamp when not associated */ + if (!iwl_is_any_associated(priv)) +- goto out; ++ return; + + /* Do not check/recover when do not have enough statistics data */ + if (msecs < 99) + return; + +- if (mod_params->ack_check && !iwl_good_ack_health(priv, pkt)) { ++ if (iwlagn_mod_params.ack_check && !iwl_good_ack_health(priv, tx)) { + IWL_ERR(priv, "low ack count detected, restart firmware\n"); + if (!iwl_force_reset(priv, IWL_FW_RESET, false)) + return; + } + +- if (mod_params->plcp_check && !iwl_good_plcp_health(priv, pkt, msecs)) ++ if (iwlagn_mod_params.plcp_check && ++ !iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs)) + iwl_force_reset(priv, IWL_RF_RESET, false); +- +-out: +- if (iwl_bt_statistics(priv)) +- memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt, +- sizeof(priv->_agn.statistics_bt)); +- else +- memcpy(&priv->_agn.statistics, &pkt->u.stats, +- sizeof(priv->_agn.statistics)); +- +- priv->rx_statistics_jiffies = stamp; + } + + /* Calculate noise level, based on measurements during network silence just +@@ -548,10 +470,8 @@ + int bcn_silence_a, bcn_silence_b, bcn_silence_c; + int last_rx_noise; + +- if (iwl_bt_statistics(priv)) +- rx_info = &(priv->_agn.statistics_bt.rx.general.common); +- else +- rx_info = &(priv->_agn.statistics.rx.general); ++ rx_info = &priv->statistics.rx_non_phy; ++ + bcn_silence_a = + le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; + bcn_silence_b = +@@ -583,105 +503,153 @@ + last_rx_noise); + } + ++#ifdef CONFIG_IWLWIFI_DEBUGFS + /* + * based on the assumption of all statistics counter are in DWORD + * FIXME: This function is for debugging, do not deal with + * the case of counters roll-over. + */ +-static void iwl_accumulative_statistics(struct iwl_priv *priv, +- __le32 *stats) ++static void accum_stats(__le32 *prev, __le32 *cur, __le32 *delta, ++ __le32 *max_delta, __le32 *accum, int size) + { +-#ifdef CONFIG_IWLWIFI_DEBUGFS +- int i, size; +- __le32 *prev_stats; +- u32 *accum_stats; +- u32 *delta, *max_delta; +- struct statistics_general_common *general, *accum_general; +- struct statistics_tx *tx, *accum_tx; +- +- if (iwl_bt_statistics(priv)) { +- prev_stats = (__le32 *)&priv->_agn.statistics_bt; +- accum_stats = (u32 *)&priv->_agn.accum_statistics_bt; +- size = sizeof(struct iwl_bt_notif_statistics); +- general = &priv->_agn.statistics_bt.general.common; +- accum_general = &priv->_agn.accum_statistics_bt.general.common; +- tx = &priv->_agn.statistics_bt.tx; +- accum_tx = &priv->_agn.accum_statistics_bt.tx; +- delta = (u32 *)&priv->_agn.delta_statistics_bt; +- max_delta = (u32 *)&priv->_agn.max_delta_bt; +- } else { +- prev_stats = (__le32 *)&priv->_agn.statistics; +- accum_stats = (u32 *)&priv->_agn.accum_statistics; +- size = sizeof(struct iwl_notif_statistics); +- general = &priv->_agn.statistics.general.common; +- accum_general = &priv->_agn.accum_statistics.general.common; +- tx = &priv->_agn.statistics.tx; +- accum_tx = &priv->_agn.accum_statistics.tx; +- delta = (u32 *)&priv->_agn.delta_statistics; +- max_delta = (u32 *)&priv->_agn.max_delta; +- } +- for (i = sizeof(__le32); i < size; +- i += sizeof(__le32), stats++, prev_stats++, delta++, +- max_delta++, accum_stats++) { +- if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) { +- *delta = (le32_to_cpu(*stats) - +- le32_to_cpu(*prev_stats)); +- *accum_stats += *delta; +- if (*delta > *max_delta) ++ int i; ++ ++ for (i = 0; ++ i < size / sizeof(__le32); ++ i++, prev++, cur++, delta++, max_delta++, accum++) { ++ if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) { ++ *delta = cpu_to_le32( ++ le32_to_cpu(*cur) - le32_to_cpu(*prev)); ++ le32_add_cpu(accum, le32_to_cpu(*delta)); ++ if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta)) + *max_delta = *delta; + } + } ++} + +- /* reset accumulative statistics for "no-counter" type statistics */ +- accum_general->temperature = general->temperature; +- accum_general->temperature_m = general->temperature_m; +- accum_general->ttl_timestamp = general->ttl_timestamp; +- accum_tx->tx_power.ant_a = tx->tx_power.ant_a; +- accum_tx->tx_power.ant_b = tx->tx_power.ant_b; +- accum_tx->tx_power.ant_c = tx->tx_power.ant_c; +-#endif ++static void ++iwl_accumulative_statistics(struct iwl_priv *priv, ++ struct statistics_general_common *common, ++ struct statistics_rx_non_phy *rx_non_phy, ++ struct statistics_rx_phy *rx_ofdm, ++ struct statistics_rx_ht_phy *rx_ofdm_ht, ++ struct statistics_rx_phy *rx_cck, ++ struct statistics_tx *tx, ++ struct statistics_bt_activity *bt_activity) ++{ ++#define ACCUM(_name) \ ++ accum_stats((__le32 *)&priv->statistics._name, \ ++ (__le32 *)_name, \ ++ (__le32 *)&priv->delta_stats._name, \ ++ (__le32 *)&priv->max_delta_stats._name, \ ++ (__le32 *)&priv->accum_stats._name, \ ++ sizeof(*_name)); ++ ++ ACCUM(common); ++ ACCUM(rx_non_phy); ++ ACCUM(rx_ofdm); ++ ACCUM(rx_ofdm_ht); ++ ACCUM(rx_cck); ++ ACCUM(tx); ++ if (bt_activity) ++ ACCUM(bt_activity); ++#undef ACCUM ++} ++#else ++static inline void ++iwl_accumulative_statistics(struct iwl_priv *priv, ++ struct statistics_general_common *common, ++ struct statistics_rx_non_phy *rx_non_phy, ++ struct statistics_rx_phy *rx_ofdm, ++ struct statistics_rx_ht_phy *rx_ofdm_ht, ++ struct statistics_rx_phy *rx_cck, ++ struct statistics_tx *tx, ++ struct statistics_bt_activity *bt_activity) ++{ + } ++#endif + + static void iwl_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) + { ++ unsigned long stamp = jiffies; + const int reg_recalib_period = 60; + int change; + struct iwl_rx_packet *pkt = rxb_addr(rxb); ++ u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; ++ __le32 *flag; ++ struct statistics_general_common *common; ++ struct statistics_rx_non_phy *rx_non_phy; ++ struct statistics_rx_phy *rx_ofdm; ++ struct statistics_rx_ht_phy *rx_ofdm_ht; ++ struct statistics_rx_phy *rx_cck; ++ struct statistics_tx *tx; ++ struct statistics_bt_activity *bt_activity; ++ ++ len -= sizeof(struct iwl_cmd_header); /* skip header */ ++ ++ IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n", ++ len); ++ ++ if (len == sizeof(struct iwl_bt_notif_statistics)) { ++ struct iwl_bt_notif_statistics *stats; ++ stats = &pkt->u.stats_bt; ++ flag = &stats->flag; ++ common = &stats->general.common; ++ rx_non_phy = &stats->rx.general.common; ++ rx_ofdm = &stats->rx.ofdm; ++ rx_ofdm_ht = &stats->rx.ofdm_ht; ++ rx_cck = &stats->rx.cck; ++ tx = &stats->tx; ++ bt_activity = &stats->general.activity; + +- if (iwl_bt_statistics(priv)) { +- IWL_DEBUG_RX(priv, +- "Statistics notification received (%d vs %d).\n", +- (int)sizeof(struct iwl_bt_notif_statistics), +- le32_to_cpu(pkt->len_n_flags) & +- FH_RSCSR_FRAME_SIZE_MSK); +- +- change = ((priv->_agn.statistics_bt.general.common.temperature != +- pkt->u.stats_bt.general.common.temperature) || +- ((priv->_agn.statistics_bt.flag & +- STATISTICS_REPLY_FLG_HT40_MODE_MSK) != +- (pkt->u.stats_bt.flag & +- STATISTICS_REPLY_FLG_HT40_MODE_MSK))); +- +- iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt); ++#ifdef CONFIG_IWLWIFI_DEBUGFS ++ /* handle this exception directly */ ++ priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills; ++ le32_add_cpu(&priv->statistics.accum_num_bt_kills, ++ le32_to_cpu(stats->rx.general.num_bt_kills)); ++#endif ++ } else if (len == sizeof(struct iwl_notif_statistics)) { ++ struct iwl_notif_statistics *stats; ++ stats = &pkt->u.stats; ++ flag = &stats->flag; ++ common = &stats->general.common; ++ rx_non_phy = &stats->rx.general; ++ rx_ofdm = &stats->rx.ofdm; ++ rx_ofdm_ht = &stats->rx.ofdm_ht; ++ rx_cck = &stats->rx.cck; ++ tx = &stats->tx; ++ bt_activity = NULL; + } else { +- IWL_DEBUG_RX(priv, +- "Statistics notification received (%d vs %d).\n", +- (int)sizeof(struct iwl_notif_statistics), +- le32_to_cpu(pkt->len_n_flags) & +- FH_RSCSR_FRAME_SIZE_MSK); +- +- change = ((priv->_agn.statistics.general.common.temperature != +- pkt->u.stats.general.common.temperature) || +- ((priv->_agn.statistics.flag & +- STATISTICS_REPLY_FLG_HT40_MODE_MSK) != +- (pkt->u.stats.flag & +- STATISTICS_REPLY_FLG_HT40_MODE_MSK))); +- +- iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); ++ WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n", ++ len, sizeof(struct iwl_bt_notif_statistics), ++ sizeof(struct iwl_notif_statistics)); ++ return; + } + +- iwl_recover_from_statistics(priv, pkt); ++ change = common->temperature != priv->statistics.common.temperature || ++ (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) != ++ (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK); ++ ++ iwl_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm, ++ rx_ofdm_ht, rx_cck, tx, bt_activity); ++ ++ iwl_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp); ++ ++ priv->statistics.flag = *flag; ++ memcpy(&priv->statistics.common, common, sizeof(*common)); ++ memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy)); ++ memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm)); ++ memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht)); ++ memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck)); ++ memcpy(&priv->statistics.tx, tx, sizeof(*tx)); ++#ifdef CONFIG_IWLWIFI_DEBUGFS ++ if (bt_activity) ++ memcpy(&priv->statistics.bt_activity, bt_activity, ++ sizeof(*bt_activity)); ++#endif ++ ++ priv->rx_statistics_jiffies = stamp; + + set_bit(STATUS_STATISTICS, &priv->status); + +@@ -708,18 +676,12 @@ + + if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { + #ifdef CONFIG_IWLWIFI_DEBUGFS +- memset(&priv->_agn.accum_statistics, 0, +- sizeof(struct iwl_notif_statistics)); +- memset(&priv->_agn.delta_statistics, 0, +- sizeof(struct iwl_notif_statistics)); +- memset(&priv->_agn.max_delta, 0, +- sizeof(struct iwl_notif_statistics)); +- memset(&priv->_agn.accum_statistics_bt, 0, +- sizeof(struct iwl_bt_notif_statistics)); +- memset(&priv->_agn.delta_statistics_bt, 0, +- sizeof(struct iwl_bt_notif_statistics)); +- memset(&priv->_agn.max_delta_bt, 0, +- sizeof(struct iwl_bt_notif_statistics)); ++ memset(&priv->accum_stats, 0, ++ sizeof(priv->accum_stats)); ++ memset(&priv->delta_stats, 0, ++ sizeof(priv->delta_stats)); ++ memset(&priv->max_delta_stats, 0, ++ sizeof(priv->max_delta_stats)); + #endif + IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); + } +@@ -873,6 +835,7 @@ + { + struct sk_buff *skb; + __le16 fc = hdr->frame_control; ++ struct iwl_rxon_context *ctx; + + /* We only process data packets if the interface is open */ + if (unlikely(!priv->is_open)) { +@@ -882,7 +845,7 @@ + } + + /* In case of HW accelerated crypto and bad decryption, drop */ +- if (!priv->cfg->mod_params->sw_crypto && ++ if (!iwlagn_mod_params.sw_crypto && + iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) + return; + +@@ -895,10 +858,29 @@ + skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); + + iwl_update_stats(priv, false, fc, len); ++ ++ /* ++ * Wake any queues that were stopped due to a passive channel tx ++ * failure. This can happen because the regulatory enforcement in ++ * the device waits for a beacon before allowing transmission, ++ * sometimes even after already having transmitted frames for the ++ * association because the new RXON may reset the information. ++ */ ++ if (unlikely(ieee80211_is_beacon(fc))) { ++ for_each_context(priv, ctx) { ++ if (!ctx->last_tx_rejected) ++ continue; ++ if (compare_ether_addr(hdr->addr3, ++ ctx->active.bssid_addr)) ++ continue; ++ ctx->last_tx_rejected = false; ++ iwl_wake_any_queue(priv, ctx); ++ } ++ } ++ + memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); + + ieee80211_rx(priv->hw, skb); +- priv->alloc_rxb_page--; + rxb->page = NULL; + } + +@@ -1093,7 +1075,6 @@ + + handlers = priv->rx_handlers; + +- handlers[REPLY_ALIVE] = iwl_rx_reply_alive; + handlers[REPLY_ERROR] = iwl_rx_reply_error; + handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + handlers[SPECTRUM_MEASURE_NOTIFICATION] = iwl_rx_spectrum_measure_notif; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-scan.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-scan.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-scan.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-scan.c 2011-05-05 23:29:45.237438867 +0200 +@@ -2,7 +2,7 @@ + * + * GPL LICENSE SUMMARY + * +- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 - 2011 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 +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-spectrum.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-spectrum.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-spectrum.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-spectrum.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,92 +0,0 @@ +-/****************************************************************************** +- * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. +- * +- * Portions of this file are derived from the ieee80211 subsystem header files. +- * +- * 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., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +- * +- * The full GNU General Public License is included in this distribution in the +- * file called LICENSE. +- * +- * Contact Information: +- * Intel Linux Wireless +- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +- * +- *****************************************************************************/ +- +-#ifndef __iwl_spectrum_h__ +-#define __iwl_spectrum_h__ +-enum { /* ieee80211_basic_report.map */ +- IEEE80211_BASIC_MAP_BSS = (1 << 0), +- IEEE80211_BASIC_MAP_OFDM = (1 << 1), +- IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2), +- IEEE80211_BASIC_MAP_RADAR = (1 << 3), +- IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4), +- /* Bits 5-7 are reserved */ +- +-}; +-struct ieee80211_basic_report { +- u8 channel; +- __le64 start_time; +- __le16 duration; +- u8 map; +-} __packed; +- +-enum { /* ieee80211_measurement_request.mode */ +- /* Bit 0 is reserved */ +- IEEE80211_MEASUREMENT_ENABLE = (1 << 1), +- IEEE80211_MEASUREMENT_REQUEST = (1 << 2), +- IEEE80211_MEASUREMENT_REPORT = (1 << 3), +- /* Bits 4-7 are reserved */ +-}; +- +-enum { +- IEEE80211_REPORT_BASIC = 0, /* required */ +- IEEE80211_REPORT_CCA = 1, /* optional */ +- IEEE80211_REPORT_RPI = 2, /* optional */ +- /* 3-255 reserved */ +-}; +- +-struct ieee80211_measurement_params { +- u8 channel; +- __le64 start_time; +- __le16 duration; +-} __packed; +- +-struct ieee80211_info_element { +- u8 id; +- u8 len; +- u8 data[0]; +-} __packed; +- +-struct ieee80211_measurement_request { +- struct ieee80211_info_element ie; +- u8 token; +- u8 mode; +- u8 type; +- struct ieee80211_measurement_params params[0]; +-} __packed; +- +-struct ieee80211_measurement_report { +- struct ieee80211_info_element ie; +- u8 token; +- u8 mode; +- u8 type; +- union { +- struct ieee80211_basic_report basic[0]; +- } u; +-} __packed; +- +-#endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-sta.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-sta.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-sta.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-sta.c 2011-05-05 23:29:45.267439231 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. +@@ -233,7 +233,6 @@ + struct iwl_station_entry *station; + int i; + u8 sta_id = IWL_INVALID_STATION; +- u16 rate; + + if (is_ap) + sta_id = ctx->ap_sta_id; +@@ -306,12 +305,6 @@ + */ + iwl_set_ht_add_station(priv, sta_id, sta, ctx); + +- /* 3945 only */ +- rate = (priv->band == IEEE80211_BAND_5GHZ) ? +- IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP; +- /* Turn on both antennas for the station... */ +- station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); +- + return sta_id; + + } +@@ -501,7 +494,8 @@ + + priv->num_stations--; + +- BUG_ON(priv->num_stations < 0); ++ if (WARN_ON(priv->num_stations < 0)) ++ priv->num_stations = 0; + + spin_unlock_irqrestore(&priv->sta_lock, flags); + +@@ -686,7 +680,8 @@ + + priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; + priv->num_stations--; +- BUG_ON(priv->num_stations < 0); ++ if (WARN_ON(priv->num_stations < 0)) ++ priv->num_stations = 0; + kfree(priv->stations[i].lq); + priv->stations[i].lq = NULL; + } +@@ -782,7 +777,8 @@ + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + + iwl_dump_lq_cmd(priv, lq); +- BUG_ON(init && (cmd.flags & CMD_ASYNC)); ++ if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) ++ return -EINVAL; + + if (is_lq_table_valid(priv, ctx, lq)) + ret = iwl_send_cmd(priv, &cmd); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-sta.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-sta.h +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-sta.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-sta.h 2011-05-05 23:29:45.374440523 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-tx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-tx.c +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/iwl-tx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/iwl-tx.c 2011-05-05 23:29:45.257439109 +0200 +@@ -1,6 +1,6 @@ + /****************************************************************************** + * +- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. ++ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. +@@ -149,32 +149,31 @@ + struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; + struct iwl_queue *q = &txq->q; + int i; +- bool huge = false; + + if (q->n_bd == 0) + return; + + while (q->read_ptr != q->write_ptr) { +- /* we have no way to tell if it is a huge cmd ATM */ + i = get_cmd_index(q, q->read_ptr, 0); + +- if (txq->meta[i].flags & CMD_SIZE_HUGE) +- huge = true; +- else ++ if (txq->meta[i].flags & CMD_MAPPED) { + pci_unmap_single(priv->pci_dev, + dma_unmap_addr(&txq->meta[i], mapping), + dma_unmap_len(&txq->meta[i], len), + PCI_DMA_BIDIRECTIONAL); ++ txq->meta[i].flags = 0; ++ } + +- q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); ++ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); + } + +- if (huge) { +- i = q->n_window; ++ i = q->n_window; ++ if (txq->meta[i].flags & CMD_MAPPED) { + pci_unmap_single(priv->pci_dev, + dma_unmap_addr(&txq->meta[i], mapping), + dma_unmap_len(&txq->meta[i], len), + PCI_DMA_BIDIRECTIONAL); ++ txq->meta[i].flags = 0; + } + } + +@@ -233,7 +232,6 @@ + * reclaiming packets (on 'tx done IRQ), if free space become > high mark, + * Tx queue resumed. + * +- * See more detailed info in iwl-4965-hw.h. + ***************************************************/ + + int iwl_queue_space(const struct iwl_queue *q) +@@ -265,11 +263,13 @@ + + /* count must be power-of-two size, otherwise iwl_queue_inc_wrap + * and iwl_queue_dec_wrap are broken. */ +- BUG_ON(!is_power_of_2(count)); ++ if (WARN_ON(!is_power_of_2(count))) ++ return -EINVAL; + + /* slots_num must be power-of-two size, otherwise + * get_cmd_index is broken. */ +- BUG_ON(!is_power_of_2(slots_num)); ++ if (WARN_ON(!is_power_of_2(slots_num))) ++ return -EINVAL; + + q->low_mark = q->n_window / 4; + if (q->low_mark < 4) +@@ -386,7 +386,9 @@ + BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); + + /* Initialize queue's high/low-water marks, and head/tail indexes */ +- iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); ++ ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); ++ if (ret) ++ return ret; + + /* Tell device where to find queue */ + priv->cfg->ops->lib->txq_init(priv, txq); +@@ -448,14 +450,19 @@ + cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); + fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); + +- /* If any of the command structures end up being larger than ++ /* ++ * If any of the command structures end up being larger than + * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then + * we will need to increase the size of the TFD entries + * Also, check to see if command buffer should not exceed the size +- * of device_cmd and max_cmd_size. */ +- BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && +- !(cmd->flags & CMD_SIZE_HUGE)); +- BUG_ON(fix_size > IWL_MAX_CMD_SIZE); ++ * of device_cmd and max_cmd_size. ++ */ ++ if (WARN_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && ++ !(cmd->flags & CMD_SIZE_HUGE))) ++ return -EINVAL; ++ ++ if (WARN_ON(fix_size > IWL_MAX_CMD_SIZE)) ++ return -EINVAL; + + if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) { + IWL_WARN(priv, "Not sending command - %s KILL\n", +@@ -463,35 +470,39 @@ + return -EIO; + } + ++ /* ++ * As we only have a single huge buffer, check that the command ++ * is synchronous (otherwise buffers could end up being reused). ++ */ ++ ++ if (WARN_ON((cmd->flags & CMD_ASYNC) && (cmd->flags & CMD_SIZE_HUGE))) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&priv->hcmd_lock, flags); ++ + if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { ++ spin_unlock_irqrestore(&priv->hcmd_lock, flags); ++ + IWL_ERR(priv, "No space in command queue\n"); +- if (priv->cfg->ops->lib->tt_ops.ct_kill_check) { +- is_ct_kill = +- priv->cfg->ops->lib->tt_ops.ct_kill_check(priv); +- } ++ is_ct_kill = iwl_check_for_ct_kill(priv); + if (!is_ct_kill) { + IWL_ERR(priv, "Restarting adapter due to queue full\n"); +- queue_work(priv->workqueue, &priv->restart); ++ iwlagn_fw_error(priv, false); + } + return -ENOSPC; + } + +- spin_lock_irqsave(&priv->hcmd_lock, flags); +- +- /* If this is a huge cmd, mark the huge flag also on the meta.flags +- * of the _original_ cmd. This is used for DMA mapping clean up. +- */ +- if (cmd->flags & CMD_SIZE_HUGE) { +- idx = get_cmd_index(q, q->write_ptr, 0); +- txq->meta[idx].flags = CMD_SIZE_HUGE; +- } +- + idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); + out_cmd = txq->cmd[idx]; + out_meta = &txq->meta[idx]; + ++ if (WARN_ON(out_meta->flags & CMD_MAPPED)) { ++ spin_unlock_irqrestore(&priv->hcmd_lock, flags); ++ return -ENOSPC; ++ } ++ + memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ +- out_meta->flags = cmd->flags; ++ out_meta->flags = cmd->flags | CMD_MAPPED; + if (cmd->flags & CMD_WANT_SKB) + out_meta->source = cmd; + if (cmd->flags & CMD_ASYNC) +@@ -584,7 +595,7 @@ + if (nfreed++ > 0) { + IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx, + q->write_ptr, q->read_ptr); +- queue_work(priv->workqueue, &priv->restart); ++ iwlagn_fw_error(priv, false); + } + + } +@@ -609,6 +620,7 @@ + struct iwl_device_cmd *cmd; + struct iwl_cmd_meta *meta; + struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; ++ unsigned long flags; + + /* If a Tx command is being handled and it isn't in the actual + * command queue then there a command routing bug has been introduced +@@ -622,14 +634,6 @@ + return; + } + +- /* If this is a huge cmd, clear the huge flag on the meta.flags +- * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap +- * the DMA buffer for the scan (huge) command. +- */ +- if (huge) { +- cmd_index = get_cmd_index(&txq->q, index, 0); +- txq->meta[cmd_index].flags = 0; +- } + cmd_index = get_cmd_index(&txq->q, index, huge); + cmd = txq->cmd[cmd_index]; + meta = &txq->meta[cmd_index]; +@@ -646,6 +650,8 @@ + } else if (meta->callback) + meta->callback(priv, cmd, pkt); + ++ spin_lock_irqsave(&priv->hcmd_lock, flags); ++ + iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); + + if (!(meta->flags & CMD_ASYNC)) { +@@ -654,5 +660,9 @@ + get_cmd_string(cmd->hdr.cmd)); + wake_up_interruptible(&priv->wait_command_queue); + } ++ ++ /* Mark as unmapped */ + meta->flags = 0; ++ ++ spin_unlock_irqrestore(&priv->hcmd_lock, flags); + } +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/Makefile linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/Makefile +--- linux-2.6.39-rc6/drivers/net/wireless/iwlwifi/Makefile 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/iwlwifi/Makefile 2011-05-05 23:29:45.339440101 +0200 +@@ -1,8 +1,8 @@ + # AGN + obj-$(CONFIG_IWLAGN) += iwlagn.o +-iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o ++iwlagn-objs := iwl-agn.o iwl-agn-rs.o + iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o +-iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o ++iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o + iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o + + iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o +@@ -14,7 +14,6 @@ + iwlagn-objs += iwl-1000.o + iwlagn-objs += iwl-2000.o + +-iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o + iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o + iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/Kconfig linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/Kconfig +--- linux-2.6.39-rc6/drivers/net/wireless/Kconfig 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/Kconfig 2011-05-05 23:29:49.211486883 +0200 +@@ -284,5 +284,6 @@ + source "drivers/net/wireless/wl1251/Kconfig" + source "drivers/net/wireless/wl12xx/Kconfig" + source "drivers/net/wireless/zd1211rw/Kconfig" ++source "drivers/net/wireless/mwifiex/Kconfig" + + endif # WLAN +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/cfg.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/cfg.c +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/cfg.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/cfg.c 2011-05-05 23:29:46.522454393 +0200 +@@ -122,8 +122,10 @@ + } + + +-/* Various firmware commands need the list of supported rates, but with +- the hight-bit set for basic rates */ ++/* ++ * Various firmware commands need the list of supported rates, but with ++ * the hight-bit set for basic rates ++ */ + static int lbs_add_rates(u8 *rates) + { + size_t i; +@@ -425,7 +427,7 @@ + return ie_len + 2; + } + +-/*************************************************************************** ++/* + * Set Channel + */ + +@@ -452,7 +454,7 @@ + + + +-/*************************************************************************** ++/* + * Scanning + */ + +@@ -538,8 +540,10 @@ + goto done; + } + +- /* Validity check: the TLV holds TSF values with 8 bytes each, so +- * the size in the TLV must match the nr_sets value */ ++ /* ++ * Validity check: the TLV holds TSF values with 8 bytes each, so ++ * the size in the TLV must match the nr_sets value ++ */ + i = get_unaligned_le16(tsfdesc); + tsfdesc += 2; + if (i / 8 != scanresp->nr_sets) { +@@ -581,8 +585,10 @@ + + /* To find out the channel, we must parse the IEs */ + ie = pos; +- /* 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon +- interval, capabilities */ ++ /* ++ * 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon ++ * interval, capabilities ++ */ + ielen = left = len - (6 + 1 + 8 + 2 + 2); + while (left >= 2) { + u8 id, elen; +@@ -790,7 +796,7 @@ + + + +-/*************************************************************************** ++/* + * Events + */ + +@@ -825,7 +831,7 @@ + + + +-/*************************************************************************** ++/* + * Connect/disconnect + */ + +@@ -950,8 +956,10 @@ + * Set WPA/WPA key material + */ + +-/* like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we +- * get rid of WEXT, this should go into host.h */ ++/* ++ * like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we ++ * get rid of WEXT, this should go into host.h ++ */ + + struct cmd_key_material { + struct cmd_header hdr; +@@ -1536,7 +1544,7 @@ + } + + +-/*************************************************************************** ++/* + * Get station + */ + +@@ -1581,7 +1589,7 @@ + + + +-/*************************************************************************** ++/* + * "Site survey", here just current channel and noise level + */ + +@@ -1614,7 +1622,7 @@ + + + +-/*************************************************************************** ++/* + * Change interface + */ + +@@ -1656,11 +1664,12 @@ + + + +-/*************************************************************************** ++/* + * IBSS (Ad-Hoc) + */ + +-/* The firmware needs the following bits masked out of the beacon-derived ++/* ++ * The firmware needs the following bits masked out of the beacon-derived + * capability field when associating/joining to a BSS: + * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused) + */ +@@ -1999,7 +2008,7 @@ + + + +-/*************************************************************************** ++/* + * Initialization + */ + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/cmd.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/cmd.c +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/cmd.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/cmd.c 2011-05-05 23:29:46.547454696 +0200 +@@ -1,7 +1,7 @@ +-/** +- * This file contains the handling of command. +- * It prepares command and sends it to firmware when it is ready. +- */ ++/* ++ * This file contains the handling of command. ++ * It prepares command and sends it to firmware when it is ready. ++ */ + + #include + #include +@@ -16,14 +16,14 @@ + #define CAL_RSSI(snr, nf) ((s32)((s32)(snr) + CAL_NF(nf))) + + /** +- * @brief Simple callback that copies response back into command ++ * lbs_cmd_copyback - Simple callback that copies response back into command + * +- * @param priv A pointer to struct lbs_private structure +- * @param extra A pointer to the original command structure for which +- * 'resp' is a response +- * @param resp A pointer to the command response ++ * @priv: A pointer to &struct lbs_private structure ++ * @extra: A pointer to the original command structure for which ++ * 'resp' is a response ++ * @resp: A pointer to the command response + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, + struct cmd_header *resp) +@@ -38,15 +38,15 @@ + EXPORT_SYMBOL_GPL(lbs_cmd_copyback); + + /** +- * @brief Simple callback that ignores the result. Use this if +- * you just want to send a command to the hardware, but don't ++ * lbs_cmd_async_callback - Simple callback that ignores the result. ++ * Use this if you just want to send a command to the hardware, but don't + * care for the result. + * +- * @param priv ignored +- * @param extra ignored +- * @param resp ignored ++ * @priv: ignored ++ * @extra: ignored ++ * @resp: ignored + * +- * @return 0 for success ++ * returns: 0 for success + */ + static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra, + struct cmd_header *resp) +@@ -56,10 +56,11 @@ + + + /** +- * @brief Checks whether a command is allowed in Power Save mode ++ * is_command_allowed_in_ps - tests if a command is allowed in Power Save mode ++ * ++ * @cmd: the command ID + * +- * @param command the command ID +- * @return 1 if allowed, 0 if not allowed ++ * returns: 1 if allowed, 0 if not allowed + */ + static u8 is_command_allowed_in_ps(u16 cmd) + { +@@ -75,11 +76,12 @@ + } + + /** +- * @brief Updates the hardware details like MAC address and regulatory region ++ * lbs_update_hw_spec - Updates the hardware details like MAC address ++ * and regulatory region + * +- * @param priv A pointer to struct lbs_private structure ++ * @priv: A pointer to &struct lbs_private structure + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_update_hw_spec(struct lbs_private *priv) + { +@@ -217,14 +219,14 @@ + EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg); + + /** +- * @brief Sets the Power Save mode ++ * lbs_set_ps_mode - Sets the Power Save mode + * +- * @param priv A pointer to struct lbs_private structure +- * @param cmd_action The Power Save operation (PS_MODE_ACTION_ENTER_PS or ++ * @priv: A pointer to &struct lbs_private structure ++ * @cmd_action: The Power Save operation (PS_MODE_ACTION_ENTER_PS or + * PS_MODE_ACTION_EXIT_PS) +- * @param block Whether to block on a response or not ++ * @block: Whether to block on a response or not + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block) + { +@@ -417,13 +419,13 @@ + } + + /** +- * @brief Set an SNMP MIB value ++ * lbs_set_snmp_mib - Set an SNMP MIB value + * +- * @param priv A pointer to struct lbs_private structure +- * @param oid The OID to set in the firmware +- * @param val Value to set the OID to ++ * @priv: A pointer to &struct lbs_private structure ++ * @oid: The OID to set in the firmware ++ * @val: Value to set the OID to + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val) + { +@@ -467,13 +469,13 @@ + } + + /** +- * @brief Get an SNMP MIB value ++ * lbs_get_snmp_mib - Get an SNMP MIB value + * +- * @param priv A pointer to struct lbs_private structure +- * @param oid The OID to retrieve from the firmware +- * @param out_val Location for the returned value ++ * @priv: A pointer to &struct lbs_private structure ++ * @oid: The OID to retrieve from the firmware ++ * @out_val: Location for the returned value + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val) + { +@@ -510,14 +512,14 @@ + } + + /** +- * @brief Get the min, max, and current TX power ++ * lbs_get_tx_power - Get the min, max, and current TX power + * +- * @param priv A pointer to struct lbs_private structure +- * @param curlevel Current power level in dBm +- * @param minlevel Minimum supported power level in dBm (optional) +- * @param maxlevel Maximum supported power level in dBm (optional) ++ * @priv: A pointer to &struct lbs_private structure ++ * @curlevel: Current power level in dBm ++ * @minlevel: Minimum supported power level in dBm (optional) ++ * @maxlevel: Maximum supported power level in dBm (optional) + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, + s16 *maxlevel) +@@ -545,12 +547,12 @@ + } + + /** +- * @brief Set the TX power ++ * lbs_set_tx_power - Set the TX power + * +- * @param priv A pointer to struct lbs_private structure +- * @param dbm The desired power level in dBm ++ * @priv: A pointer to &struct lbs_private structure ++ * @dbm: The desired power level in dBm + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) + { +@@ -573,12 +575,13 @@ + } + + /** +- * @brief Enable or disable monitor mode (only implemented on OLPC usb8388 FW) ++ * lbs_set_monitor_mode - Enable or disable monitor mode ++ * (only implemented on OLPC usb8388 FW) + * +- * @param priv A pointer to struct lbs_private structure +- * @param enable 1 to enable monitor mode, 0 to disable ++ * @priv: A pointer to &struct lbs_private structure ++ * @enable: 1 to enable monitor mode, 0 to disable + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_set_monitor_mode(struct lbs_private *priv, int enable) + { +@@ -604,11 +607,11 @@ + } + + /** +- * @brief Get the radio channel ++ * lbs_get_channel - Get the radio channel + * +- * @param priv A pointer to struct lbs_private structure ++ * @priv: A pointer to &struct lbs_private structure + * +- * @return The channel on success, error on failure ++ * returns: The channel on success, error on failure + */ + static int lbs_get_channel(struct lbs_private *priv) + { +@@ -650,12 +653,12 @@ + } + + /** +- * @brief Set the radio channel ++ * lbs_set_channel - Set the radio channel + * +- * @param priv A pointer to struct lbs_private structure +- * @param channel The desired channel, or 0 to clear a locked channel ++ * @priv: A pointer to &struct lbs_private structure ++ * @channel: The desired channel, or 0 to clear a locked channel + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_set_channel(struct lbs_private *priv, u8 channel) + { +@@ -686,12 +689,13 @@ + } + + /** +- * @brief Get current RSSI and noise floor ++ * lbs_get_rssi - Get current RSSI and noise floor + * +- * @param priv A pointer to struct lbs_private structure +- * @param rssi On successful return, signal level in mBm ++ * @priv: A pointer to &struct lbs_private structure ++ * @rssi: On successful return, signal level in mBm ++ * @nf: On successful return, Noise floor + * +- * @return The channel on success, error on failure ++ * returns: The channel on success, error on failure + */ + int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf) + { +@@ -719,13 +723,14 @@ + } + + /** +- * @brief Send regulatory and 802.11d domain information to the firmware ++ * lbs_set_11d_domain_info - Send regulatory and 802.11d domain information ++ * to the firmware + * +- * @param priv pointer to struct lbs_private +- * @param request cfg80211 regulatory request structure +- * @param bands the device's supported bands and channels ++ * @priv: pointer to &struct lbs_private ++ * @request: cfg80211 regulatory request structure ++ * @bands: the device's supported bands and channels + * +- * @return 0 on success, error code on failure ++ * returns: 0 on success, error code on failure + */ + int lbs_set_11d_domain_info(struct lbs_private *priv, + struct regulatory_request *request, +@@ -842,15 +847,15 @@ + } + + /** +- * @brief Read a MAC, Baseband, or RF register ++ * lbs_get_reg - Read a MAC, Baseband, or RF register + * +- * @param priv pointer to struct lbs_private +- * @param cmd register command, one of CMD_MAC_REG_ACCESS, +- * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS +- * @param offset byte offset of the register to get +- * @param value on success, the value of the register at 'offset' ++ * @priv: pointer to &struct lbs_private ++ * @reg: register command, one of CMD_MAC_REG_ACCESS, ++ * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS ++ * @offset: byte offset of the register to get ++ * @value: on success, the value of the register at 'offset' + * +- * @return 0 on success, error code on failure ++ * returns: 0 on success, error code on failure + */ + int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value) + { +@@ -886,15 +891,15 @@ + } + + /** +- * @brief Write a MAC, Baseband, or RF register ++ * lbs_set_reg - Write a MAC, Baseband, or RF register + * +- * @param priv pointer to struct lbs_private +- * @param cmd register command, one of CMD_MAC_REG_ACCESS, +- * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS +- * @param offset byte offset of the register to set +- * @param value the value to write to the register at 'offset' ++ * @priv: pointer to &struct lbs_private ++ * @reg: register command, one of CMD_MAC_REG_ACCESS, ++ * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS ++ * @offset: byte offset of the register to set ++ * @value: the value to write to the register at 'offset' + * +- * @return 0 on success, error code on failure ++ * returns: 0 on success, error code on failure + */ + int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value) + { +@@ -1023,7 +1028,7 @@ + lbs_deb_leave(LBS_DEB_HOST); + } + +-/** ++/* + * This function inserts command node to cmdfreeq + * after cleans it. Requires priv->driver_lock held. + */ +@@ -1125,11 +1130,12 @@ + } + + /** +- * @brief This function allocates the command buffer and link +- * it to command free queue. ++ * lbs_allocate_cmd_buffer - allocates the command buffer and links ++ * it to command free queue ++ * ++ * @priv: A pointer to &struct lbs_private structure + * +- * @param priv A pointer to struct lbs_private structure +- * @return 0 or -1 ++ * returns: 0 for success or -1 on error + */ + int lbs_allocate_cmd_buffer(struct lbs_private *priv) + { +@@ -1171,10 +1177,11 @@ + } + + /** +- * @brief This function frees the command buffer. ++ * lbs_free_cmd_buffer - free the command buffer + * +- * @param priv A pointer to struct lbs_private structure +- * @return 0 or -1 ++ * @priv: A pointer to &struct lbs_private structure ++ * ++ * returns: 0 for success + */ + int lbs_free_cmd_buffer(struct lbs_private *priv) + { +@@ -1211,11 +1218,13 @@ + } + + /** +- * @brief This function gets a free command node if available in +- * command free queue. ++ * lbs_get_free_cmd_node - gets a free command node if available in ++ * command free queue ++ * ++ * @priv: A pointer to &struct lbs_private structure + * +- * @param priv A pointer to struct lbs_private structure +- * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL ++ * returns: A pointer to &cmd_ctrl_node structure on success ++ * or %NULL on error + */ + static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv) + { +@@ -1245,12 +1254,12 @@ + } + + /** +- * @brief This function executes next command in command +- * pending queue. It will put firmware back to PS mode +- * if applicable. ++ * lbs_execute_next_command - execute next command in command ++ * pending queue. Will put firmware back to PS mode if applicable. + * +- * @param priv A pointer to struct lbs_private structure +- * @return 0 or -1 ++ * @priv: A pointer to &struct lbs_private structure ++ * ++ * returns: 0 on success or -1 on error + */ + int lbs_execute_next_command(struct lbs_private *priv) + { +@@ -1454,12 +1463,12 @@ + } + + /** +- * @brief This function checks condition and prepares to +- * send sleep confirm command to firmware if ok. ++ * lbs_ps_confirm_sleep - checks condition and prepares to ++ * send sleep confirm command to firmware if ok ++ * ++ * @priv: A pointer to &struct lbs_private structure + * +- * @param priv A pointer to struct lbs_private structure +- * @param psmode Power Saving mode +- * @return n/a ++ * returns: n/a + */ + void lbs_ps_confirm_sleep(struct lbs_private *priv) + { +@@ -1499,16 +1508,16 @@ + + + /** +- * @brief Configures the transmission power control functionality. ++ * lbs_set_tpc_cfg - Configures the transmission power control functionality + * +- * @param priv A pointer to struct lbs_private structure +- * @param enable Transmission power control enable +- * @param p0 Power level when link quality is good (dBm). +- * @param p1 Power level when link quality is fair (dBm). +- * @param p2 Power level when link quality is poor (dBm). +- * @param usesnr Use Signal to Noise Ratio in TPC ++ * @priv: A pointer to &struct lbs_private structure ++ * @enable: Transmission power control enable ++ * @p0: Power level when link quality is good (dBm). ++ * @p1: Power level when link quality is fair (dBm). ++ * @p2: Power level when link quality is poor (dBm). ++ * @usesnr: Use Signal to Noise Ratio in TPC + * +- * @return 0 on success ++ * returns: 0 on success + */ + int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, + int8_t p2, int usesnr) +@@ -1531,15 +1540,15 @@ + } + + /** +- * @brief Configures the power adaptation settings. ++ * lbs_set_power_adapt_cfg - Configures the power adaptation settings + * +- * @param priv A pointer to struct lbs_private structure +- * @param enable Power adaptation enable +- * @param p0 Power level for 1, 2, 5.5 and 11 Mbps (dBm). +- * @param p1 Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm). +- * @param p2 Power level for 48 and 54 Mbps (dBm). ++ * @priv: A pointer to &struct lbs_private structure ++ * @enable: Power adaptation enable ++ * @p0: Power level for 1, 2, 5.5 and 11 Mbps (dBm). ++ * @p1: Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm). ++ * @p2: Power level for 48 and 54 Mbps (dBm). + * +- * @return 0 on Success ++ * returns: 0 on Success + */ + + int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/cmdresp.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/cmdresp.c +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/cmdresp.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/cmdresp.c 2011-05-05 23:29:46.554454781 +0200 +@@ -1,7 +1,7 @@ +-/** +- * This file contains the handling of command +- * responses as well as events generated by firmware. +- */ ++/* ++ * This file contains the handling of command ++ * responses as well as events generated by firmware. ++ */ + #include + #include + #include +@@ -12,12 +12,13 @@ + #include "cmd.h" + + /** +- * @brief This function handles disconnect event. it +- * reports disconnect to upper layer, clean tx/rx packets, +- * reset link state etc. ++ * lbs_mac_event_disconnected - handles disconnect event. It ++ * reports disconnect to upper layer, clean tx/rx packets, ++ * reset link state etc. ++ * ++ * @priv: A pointer to struct lbs_private structure + * +- * @param priv A pointer to struct lbs_private structure +- * @return n/a ++ * returns: n/a + */ + void lbs_mac_event_disconnected(struct lbs_private *priv) + { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/debugfs.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/debugfs.c +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/debugfs.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/debugfs.c 2011-05-05 23:29:46.555454793 +0200 +@@ -849,15 +849,14 @@ + static int num_of_items = ARRAY_SIZE(items); + + /** +- * @brief proc read function ++ * lbs_debugfs_read - proc read function + * +- * @param page pointer to buffer +- * @param s read data starting position +- * @param off offset +- * @param cnt counter +- * @param eof end of file flag +- * @param data data to output +- * @return number of output data ++ * @file: file to read ++ * @userbuf: pointer to buffer ++ * @count: number of bytes to read ++ * @ppos: read data starting position ++ * ++ * returns: amount of data read or negative error code + */ + static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +@@ -897,13 +896,14 @@ + } + + /** +- * @brief proc write function ++ * lbs_debugfs_write - proc write function ++ * ++ * @f: file pointer ++ * @buf: pointer to data buffer ++ * @cnt: data number to write ++ * @ppos: file position + * +- * @param f file pointer +- * @param buf pointer to data buffer +- * @param cnt data number to write +- * @param data data to write +- * @return number of data ++ * returns: amount of data written + */ + static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf, + size_t cnt, loff_t *ppos) +@@ -966,11 +966,11 @@ + }; + + /** +- * @brief create debug proc file ++ * lbs_debug_init - create debug proc file ++ * ++ * @priv: pointer to &struct lbs_private + * +- * @param priv pointer struct lbs_private +- * @param dev pointer net_device +- * @return N/A ++ * returns: N/A + */ + static void lbs_debug_init(struct lbs_private *priv) + { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/decl.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/decl.h +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/decl.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/decl.h 2011-05-05 23:29:46.553454769 +0200 +@@ -1,8 +1,8 @@ + +-/** +- * This file contains declaration referring to +- * functions defined in other source files +- */ ++/* ++ * This file contains declaration referring to ++ * functions defined in other source files ++ */ + + #ifndef _LBS_DECL_H_ + #define _LBS_DECL_H_ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/defs.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/defs.h +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/defs.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/defs.h 2011-05-05 23:29:46.556454805 +0200 +@@ -1,7 +1,7 @@ +-/** +- * This header file contains global constant/enum definitions, +- * global variable declaration. +- */ ++/* ++ * This header file contains global constant/enum definitions, ++ * global variable declaration. ++ */ + #ifndef _LBS_DEFS_H_ + #define _LBS_DEFS_H_ + +@@ -123,19 +123,19 @@ + + + +-/** Buffer Constants */ ++/* Buffer Constants */ + + /* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical +-* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas +-* driver has more local TxPDs. Each TxPD on the host memory is associated +-* with a Tx control node. The driver maintains 8 RxPD descriptors for +-* station firmware to store Rx packet information. +-* +-* Current version of MAC has a 32x6 multicast address buffer. +-* +-* 802.11b can have up to 14 channels, the driver keeps the +-* BSSID(MAC address) of each APs or Ad hoc stations it has sensed. +-*/ ++ * addresses of TxPD buffers. Station has only 8 TxPD available, Whereas ++ * driver has more local TxPDs. Each TxPD on the host memory is associated ++ * with a Tx control node. The driver maintains 8 RxPD descriptors for ++ * station firmware to store Rx packet information. ++ * ++ * Current version of MAC has a 32x6 multicast address buffer. ++ * ++ * 802.11b can have up to 14 channels, the driver keeps the ++ * BSSID(MAC address) of each APs or Ad hoc stations it has sensed. ++ */ + + #define MRVDRV_MAX_MULTICAST_LIST_SIZE 32 + #define LBS_NUM_CMD_BUFFERS 10 +@@ -166,7 +166,7 @@ + #define WOL_RESULT_NOSPC_ERR 1 + #define WOL_RESULT_EEXIST_ERR 2 + +-/** Misc constants */ ++/* Misc constants */ + /* This section defines 802.11 specific contants */ + + #define MRVDRV_MAX_BSS_DESCRIPTS 16 +@@ -183,7 +183,8 @@ + + #define MARVELL_MESH_IE_LENGTH 9 + +-/* Values used to populate the struct mrvl_mesh_ie. The only time you need this ++/* ++ * Values used to populate the struct mrvl_mesh_ie. The only time you need this + * is when enabling the mesh using CMD_MESH_CONFIG. + */ + #define MARVELL_MESH_IE_TYPE 4 +@@ -193,7 +194,7 @@ + #define MARVELL_MESH_METRIC_ID 0 + #define MARVELL_MESH_CAPABILITY 0 + +-/** INT status Bit Definition*/ ++/* INT status Bit Definition */ + #define MRVDRV_TX_DNLD_RDY 0x0001 + #define MRVDRV_RX_UPLD_RDY 0x0002 + #define MRVDRV_CMD_DNLD_RDY 0x0004 +@@ -208,59 +209,63 @@ + #define TPC_DEFAULT_P1 10 + #define TPC_DEFAULT_P2 13 + +-/** TxPD status */ ++/* TxPD status */ + +-/* Station firmware use TxPD status field to report final Tx transmit +-* result, Bit masks are used to present combined situations. +-*/ ++/* ++ * Station firmware use TxPD status field to report final Tx transmit ++ * result, Bit masks are used to present combined situations. ++ */ + + #define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01 + #define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08 + +-/** Tx mesh flag */ +-/* Currently we are using normal WDS flag as mesh flag. ++/* Tx mesh flag */ ++/* ++ * Currently we are using normal WDS flag as mesh flag. + * TODO: change to proper mesh flag when MAC understands it. + */ + #define TxPD_CONTROL_WDS_FRAME (1<<17) + #define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME + +-/** Mesh interface ID */ ++/* Mesh interface ID */ + #define MESH_IFACE_ID 0x0001 +-/** Mesh id should be in bits 14-13-12 */ ++/* Mesh id should be in bits 14-13-12 */ + #define MESH_IFACE_BIT_OFFSET 0x000c +-/** Mesh enable bit in FW capability */ ++/* Mesh enable bit in FW capability */ + #define MESH_CAPINFO_ENABLE_MASK (1<<16) + +-/** FW definition from Marvell v4 */ ++/* FW definition from Marvell v4 */ + #define MRVL_FW_V4 (0x04) +-/** FW definition from Marvell v5 */ ++/* FW definition from Marvell v5 */ + #define MRVL_FW_V5 (0x05) +-/** FW definition from Marvell v10 */ ++/* FW definition from Marvell v10 */ + #define MRVL_FW_V10 (0x0a) +-/** FW major revision definition */ ++/* FW major revision definition */ + #define MRVL_FW_MAJOR_REV(x) ((x)>>24) + +-/** RxPD status */ ++/* RxPD status */ + + #define MRVDRV_RXPD_STATUS_OK 0x0001 + +-/** RxPD status - Received packet types */ +-/** Rx mesh flag */ +-/* Currently we are using normal WDS flag as mesh flag. ++/* RxPD status - Received packet types */ ++/* Rx mesh flag */ ++/* ++ * Currently we are using normal WDS flag as mesh flag. + * TODO: change to proper mesh flag when MAC understands it. + */ + #define RxPD_CONTROL_WDS_FRAME (0x40) + #define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME + +-/** RSSI-related defines */ +-/* RSSI constants are used to implement 802.11 RSSI threshold +-* indication. if the Rx packet signal got too weak for 5 consecutive +-* times, miniport driver (driver) will report this event to wrapper +-*/ ++/* RSSI-related defines */ ++/* ++ * RSSI constants are used to implement 802.11 RSSI threshold ++ * indication. if the Rx packet signal got too weak for 5 consecutive ++ * times, miniport driver (driver) will report this event to wrapper ++ */ + + #define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96) + +-/** RTS/FRAG related defines */ ++/* RTS/FRAG related defines */ + #define MRVDRV_RTS_MIN_VALUE 0 + #define MRVDRV_RTS_MAX_VALUE 2347 + #define MRVDRV_FRAG_MIN_VALUE 256 +@@ -300,36 +305,36 @@ + + #define MAX_LEDS 8 + +-/** Global Variable Declaration */ ++/* Global Variable Declaration */ + extern const char lbs_driver_version[]; + extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE]; + + +-/** ENUM definition*/ +-/** SNRNF_TYPE */ ++/* ENUM definition */ ++/* SNRNF_TYPE */ + enum SNRNF_TYPE { + TYPE_BEACON = 0, + TYPE_RXPD, + MAX_TYPE_B + }; + +-/** SNRNF_DATA*/ ++/* SNRNF_DATA */ + enum SNRNF_DATA { + TYPE_NOAVG = 0, + TYPE_AVG, + MAX_TYPE_AVG + }; + +-/** LBS_802_11_POWER_MODE */ ++/* LBS_802_11_POWER_MODE */ + enum LBS_802_11_POWER_MODE { + LBS802_11POWERMODECAM, + LBS802_11POWERMODEMAX_PSP, + LBS802_11POWERMODEFAST_PSP, +- /*not a real mode, defined as an upper bound */ ++ /* not a real mode, defined as an upper bound */ + LBS802_11POWEMODEMAX + }; + +-/** PS_STATE */ ++/* PS_STATE */ + enum PS_STATE { + PS_STATE_FULL_POWER, + PS_STATE_AWAKE, +@@ -337,7 +342,7 @@ + PS_STATE_SLEEP + }; + +-/** DNLD_STATE */ ++/* DNLD_STATE */ + enum DNLD_STATE { + DNLD_RES_RECEIVED, + DNLD_DATA_SENT, +@@ -345,19 +350,19 @@ + DNLD_BOOTCMD_SENT, + }; + +-/** LBS_MEDIA_STATE */ ++/* LBS_MEDIA_STATE */ + enum LBS_MEDIA_STATE { + LBS_CONNECTED, + LBS_DISCONNECTED + }; + +-/** LBS_802_11_PRIVACY_FILTER */ ++/* LBS_802_11_PRIVACY_FILTER */ + enum LBS_802_11_PRIVACY_FILTER { + LBS802_11PRIVFILTERACCEPTALL, + LBS802_11PRIVFILTER8021XWEP + }; + +-/** mv_ms_type */ ++/* mv_ms_type */ + enum mv_ms_type { + MVMS_DAT = 0, + MVMS_CMD = 1, +@@ -365,14 +370,14 @@ + MVMS_EVENT + }; + +-/** KEY_TYPE_ID */ ++/* KEY_TYPE_ID */ + enum KEY_TYPE_ID { + KEY_TYPE_ID_WEP = 0, + KEY_TYPE_ID_TKIP, + KEY_TYPE_ID_AES + }; + +-/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */ ++/* KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */ + enum KEY_INFO_WPA { + KEY_INFO_WPA_MCAST = 0x01, + KEY_INFO_WPA_UNICAST = 0x02, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/dev.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/dev.h +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/dev.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/dev.h 2011-05-05 23:29:46.551454745 +0200 +@@ -1,8 +1,8 @@ +-/** +- * This file contains definitions and data structures specific +- * to Marvell 802.11 NIC. It contains the Device Information +- * structure struct lbs_private.. +- */ ++/* ++ * This file contains definitions and data structures specific ++ * to Marvell 802.11 NIC. It contains the Device Information ++ * structure struct lbs_private.. ++ */ + #ifndef _LBS_DEV_H_ + #define _LBS_DEV_H_ + +@@ -12,7 +12,7 @@ + + #include + +-/** sleep_params */ ++/* sleep_params */ + struct sleep_params { + uint16_t sp_error; + uint16_t sp_offset; +@@ -23,7 +23,7 @@ + }; + + +-/** Private structure for the MV device */ ++/* Private structure for the MV device */ + struct lbs_private { + + /* Basic networking */ +@@ -125,12 +125,12 @@ + /* Events sent from hardware to driver */ + struct kfifo event_fifo; + +- /** thread to service interrupts */ ++ /* thread to service interrupts */ + struct task_struct *main_thread; + wait_queue_head_t waitq; + struct workqueue_struct *work_thread; + +- /** Encryption stuff */ ++ /* Encryption stuff */ + u8 authtype_auto; + u8 wep_tx_key; + u8 wep_key[4][WLAN_KEY_LEN_WEP104]; +@@ -162,7 +162,7 @@ + s16 txpower_min; + s16 txpower_max; + +- /** Scanning */ ++ /* Scanning */ + struct delayed_work scan_work; + int scan_channel; + /* Queue of things waiting for scan completion */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/ethtool.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/ethtool.c +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/ethtool.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/ethtool.c 2011-05-05 23:29:46.548454709 +0200 +@@ -20,7 +20,8 @@ + strcpy(info->version, lbs_driver_version); + } + +-/* All 8388 parts have 16KiB EEPROM size at the time of writing. ++/* ++ * All 8388 parts have 16KiB EEPROM size at the time of writing. + * In case that changes this needs fixing. + */ + #define LBS_EEPROM_LEN 16384 +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/host.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/host.h +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/host.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/host.h 2011-05-05 23:29:46.545454671 +0200 +@@ -1,7 +1,7 @@ +-/** +- * This file function prototypes, data structure +- * and definitions for all the host/station commands +- */ ++/* ++ * This file function prototypes, data structure ++ * and definitions for all the host/station commands ++ */ + + #ifndef _LBS_HOST_H_ + #define _LBS_HOST_H_ +@@ -13,9 +13,10 @@ + + #define CMD_OPTION_WAITFORRSP 0x0002 + +-/** Host command IDs */ ++/* Host command IDs */ + +-/* Return command are almost always the same as the host command, but with ++/* ++ * Return command are almost always the same as the host command, but with + * bit 15 set high. There are a few exceptions, though... + */ + #define CMD_RET(cmd) (0x8000 | cmd) +@@ -251,7 +252,7 @@ + CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */ + }; + +-/** Card Event definition */ ++/* Card Event definition */ + #define MACREG_INT_CODE_TX_PPA_FREE 0 + #define MACREG_INT_CODE_TX_DMA_DONE 1 + #define MACREG_INT_CODE_LINK_LOST_W_SCAN 2 +@@ -624,12 +625,14 @@ + struct cmd_ds_802_11_rssi { + struct cmd_header hdr; + +- /* request: number of beacons (N) to average the SNR and NF over ++ /* ++ * request: number of beacons (N) to average the SNR and NF over + * response: SNR of most recent beacon + */ + __le16 n_or_snr; + +- /* The following fields are only set in the response. ++ /* ++ * The following fields are only set in the response. + * In the request these are reserved and should be set to 0. + */ + __le16 nf; /* most recent beacon noise floor */ +@@ -680,14 +683,16 @@ + + __le16 action; + +- /* Interval for keepalive in PS mode: ++ /* ++ * Interval for keepalive in PS mode: + * 0x0000 = don't change + * 0x001E = firmware default + * 0xFFFF = disable + */ + __le16 nullpktinterval; + +- /* Number of DTIM intervals to wake up for: ++ /* ++ * Number of DTIM intervals to wake up for: + * 0 = don't change + * 1 = firmware default + * 5 = max +@@ -697,7 +702,8 @@ + __le16 reserved; + __le16 locallisteninterval; + +- /* AdHoc awake period (FW v9+ only): ++ /* ++ * AdHoc awake period (FW v9+ only): + * 0 = don't change + * 1 = always awake (IEEE standard behavior) + * 2 - 31 = sleep for (n - 1) periods and awake for 1 period +@@ -771,7 +777,8 @@ + __le16 capability; + u8 rates[MAX_RATES]; + +- /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the ++ /* ++ * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the + * Adhoc join command and will cause a binary layout mismatch with + * the firmware + */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/if_cs.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/if_cs.c +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/if_cs.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/if_cs.c 2011-05-05 23:29:46.637455783 +0200 +@@ -312,7 +312,8 @@ + #define CF8385_MANFID 0x02df + #define CF8385_CARDID 0x8103 + +-/* FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when ++/* ++ * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when + * that gets fixed. Currently there's no way to access it from the probe hook. + */ + static inline u32 get_model(u16 manf_id, u16 card_id) +@@ -621,8 +622,10 @@ + if (remain < count) + count = remain; + +- /* "write the number of bytes to be sent to the I/O Command +- * write length register" */ ++ /* ++ * "write the number of bytes to be sent to the I/O Command ++ * write length register" ++ */ + if_cs_write16(card, IF_CS_CMD_LEN, count); + + /* "write this to I/O Command port register as 16 bit writes */ +@@ -631,16 +634,22 @@ + &fw->data[sent], + count >> 1); + +- /* "Assert the download over interrupt command in the Host +- * status register" */ ++ /* ++ * "Assert the download over interrupt command in the Host ++ * status register" ++ */ + if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); + +- /* "Assert the download over interrupt command in the Card +- * interrupt case register" */ ++ /* ++ * "Assert the download over interrupt command in the Card ++ * interrupt case register" ++ */ + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); + +- /* "The host polls the Card Status register ... for 50 ms before +- declaring a failure */ ++ /* ++ * "The host polls the Card Status register ... for 50 ms before ++ * declaring a failure" ++ */ + ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, + IF_CS_BIT_COMMAND); + if (ret < 0) { +@@ -841,7 +850,7 @@ + + /* + * Most of the libertas cards can do unaligned register access, but some +- * weird ones can not. That's especially true for the CF8305 card. ++ * weird ones cannot. That's especially true for the CF8305 card. + */ + card->align_regs = 0; + +@@ -913,8 +922,10 @@ + goto out3; + } + +- /* Clear any interrupt cause that happened while sending +- * firmware/initializing card */ ++ /* ++ * Clear any interrupt cause that happened while sending ++ * firmware/initializing card ++ */ + if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK); + if_cs_enable_ints(card); + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/if_spi.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/if_spi.c +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/if_spi.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/if_spi.c 2011-05-05 23:29:46.552454757 +0200 +@@ -57,6 +57,7 @@ + /* Handles all SPI communication (except for FW load) */ + struct workqueue_struct *workqueue; + struct work_struct packet_work; ++ struct work_struct resume_work; + + u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE]; + +@@ -68,6 +69,9 @@ + + /* Protects cmd_packet_list and data_packet_list */ + spinlock_t buffer_lock; ++ ++ /* True is card suspended */ ++ u8 suspended; + }; + + static void free_if_spi_card(struct if_spi_card *card) +@@ -139,8 +143,10 @@ + card->prev_xfer_time = jiffies; + } + +-/* Write out a byte buffer to an SPI register, +- * using a series of 16-bit transfers. */ ++/* ++ * Write out a byte buffer to an SPI register, ++ * using a series of 16-bit transfers. ++ */ + static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) + { + int err = 0; +@@ -204,8 +210,10 @@ + struct spi_transfer dummy_trans; + struct spi_transfer data_trans; + +- /* You must take an even number of bytes from the SPU, even if you +- * don't care about the last one. */ ++ /* ++ * You must take an even number of bytes from the SPU, even if you ++ * don't care about the last one. ++ */ + BUG_ON(len & 0x1); + + spu_transaction_init(card); +@@ -254,8 +262,10 @@ + return ret; + } + +-/* Read 32 bits from an SPI register. +- * The low 16 bits are read first. */ ++/* ++ * Read 32 bits from an SPI register. ++ * The low 16 bits are read first. ++ */ + static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val) + { + __le32 buf; +@@ -267,13 +277,15 @@ + return err; + } + +-/* Keep reading 16 bits from an SPI register until you get the correct result. ++/* ++ * Keep reading 16 bits from an SPI register until you get the correct result. + * + * If mask = 0, the correct result is any non-zero number. + * If mask != 0, the correct result is any number where + * number & target_mask == target + * +- * Returns -ETIMEDOUT if a second passes without the correct result. */ ++ * Returns -ETIMEDOUT if a second passes without the correct result. ++ */ + static int spu_wait_for_u16(struct if_spi_card *card, u16 reg, + u16 target_mask, u16 target) + { +@@ -301,8 +313,10 @@ + } + } + +-/* Read 16 bits from an SPI register until you receive a specific value. +- * Returns -ETIMEDOUT if a 4 tries pass without success. */ ++/* ++ * Read 16 bits from an SPI register until you receive a specific value. ++ * Returns -ETIMEDOUT if a 4 tries pass without success. ++ */ + static int spu_wait_for_u32(struct if_spi_card *card, u32 reg, u32 target) + { + int err, try; +@@ -324,8 +338,10 @@ + { + int err = 0; + +- /* We can suppress a host interrupt by clearing the appropriate +- * bit in the "host interrupt status mask" register */ ++ /* ++ * We can suppress a host interrupt by clearing the appropriate ++ * bit in the "host interrupt status mask" register ++ */ + if (suppress_host_int) { + err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0); + if (err) +@@ -341,10 +357,12 @@ + return err; + } + +- /* If auto-interrupts are on, the completion of certain transactions ++ /* ++ * If auto-interrupts are on, the completion of certain transactions + * will trigger an interrupt automatically. If auto-interrupts + * are off, we need to set the "Card Interrupt Cause" register to +- * trigger a card interrupt. */ ++ * trigger a card interrupt. ++ */ + if (auto_int) { + err = spu_write_u16(card, IF_SPI_HOST_INT_CTRL_REG, + IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO | +@@ -398,8 +416,10 @@ + int err = 0; + u32 delay; + +- /* We have to start up in timed delay mode so that we can safely +- * read the Delay Read Register. */ ++ /* ++ * We have to start up in timed delay mode so that we can safely ++ * read the Delay Read Register. ++ */ + card->use_dummy_writes = 0; + err = spu_set_bus_mode(card, + IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING | +@@ -455,8 +475,10 @@ + + /* Load helper firmware image */ + while (bytes_remaining > 0) { +- /* Scratch pad 1 should contain the number of bytes we +- * want to download to the firmware */ ++ /* ++ * Scratch pad 1 should contain the number of bytes we ++ * want to download to the firmware ++ */ + err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, + HELPER_FW_LOAD_CHUNK_SZ); + if (err) +@@ -468,8 +490,10 @@ + if (err) + goto out; + +- /* Feed the data into the command read/write port reg +- * in chunks of 64 bytes */ ++ /* ++ * Feed the data into the command read/write port reg ++ * in chunks of 64 bytes ++ */ + memset(temp, 0, sizeof(temp)); + memcpy(temp, fw, + min(bytes_remaining, HELPER_FW_LOAD_CHUNK_SZ)); +@@ -491,9 +515,11 @@ + fw += HELPER_FW_LOAD_CHUNK_SZ; + } + +- /* Once the helper / single stage firmware download is complete, ++ /* ++ * Once the helper / single stage firmware download is complete, + * write 0 to scratch pad 1 and interrupt the +- * bootloader. This completes the helper download. */ ++ * bootloader. This completes the helper download. ++ */ + err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK); + if (err) + goto out; +@@ -513,16 +539,20 @@ + return err; + } + +-/* Returns the length of the next packet the firmware expects us to send +- * Sets crc_err if the previous transfer had a CRC error. */ ++/* ++ * Returns the length of the next packet the firmware expects us to send. ++ * Sets crc_err if the previous transfer had a CRC error. ++ */ + static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card, + int *crc_err) + { + u16 len; + int err = 0; + +- /* wait until the host interrupt status register indicates +- * that we are ready to download */ ++ /* ++ * wait until the host interrupt status register indicates ++ * that we are ready to download ++ */ + err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG, + IF_SPI_HIST_CMD_DOWNLOAD_RDY, + IF_SPI_HIST_CMD_DOWNLOAD_RDY); +@@ -583,8 +613,10 @@ + goto out; + } + if (bytes < 0) { +- /* If there are no more bytes left, we would normally +- * expect to have terminated with len = 0 */ ++ /* ++ * If there are no more bytes left, we would normally ++ * expect to have terminated with len = 0 ++ */ + lbs_pr_err("Firmware load wants more bytes " + "than we have to offer.\n"); + break; +@@ -656,14 +688,18 @@ + u16 len; + u8 i; + +- /* We need a buffer big enough to handle whatever people send to +- * hw_host_to_card */ ++ /* ++ * We need a buffer big enough to handle whatever people send to ++ * hw_host_to_card ++ */ + BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_CMD_BUFFER_SIZE); + BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_UPLD_SIZE); + +- /* It's just annoying if the buffer size isn't a multiple of 4, because +- * then we might have len < IF_SPI_CMD_BUF_SIZE but +- * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE */ ++ /* ++ * It's just annoying if the buffer size isn't a multiple of 4, because ++ * then we might have len < IF_SPI_CMD_BUF_SIZE but ++ * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE ++ */ + BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0); + + lbs_deb_enter(LBS_DEB_SPI); +@@ -834,8 +870,10 @@ + + lbs_deb_enter(LBS_DEB_SPI); + +- /* Read the host interrupt status register to see what we +- * can do. */ ++ /* ++ * Read the host interrupt status register to see what we ++ * can do. ++ */ + err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG, + &hiStatus); + if (err) { +@@ -854,12 +892,15 @@ + goto err; + } + +- /* workaround: in PS mode, the card does not set the Command +- * Download Ready bit, but it sets TX Download Ready. */ ++ /* ++ * workaround: in PS mode, the card does not set the Command ++ * Download Ready bit, but it sets TX Download Ready. ++ */ + if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY || + (card->priv->psstate != PS_STATE_FULL_POWER && + (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) { +- /* This means two things. First of all, ++ /* ++ * This means two things. First of all, + * if there was a previous command sent, the card has + * successfully received it. + * Secondly, it is now ready to download another +@@ -867,8 +908,7 @@ + */ + lbs_host_to_card_done(card->priv); + +- /* Do we have any command packets from the host to +- * send? */ ++ /* Do we have any command packets from the host to send? */ + packet = NULL; + spin_lock_irqsave(&card->buffer_lock, flags); + if (!list_empty(&card->cmd_packet_list)) { +@@ -882,8 +922,7 @@ + if_spi_h2c(card, packet, MVMS_CMD); + } + if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) { +- /* Do we have any data packets from the host to +- * send? */ ++ /* Do we have any data packets from the host to send? */ + packet = NULL; + spin_lock_irqsave(&card->buffer_lock, flags); + if (!list_empty(&card->data_packet_list)) { +@@ -910,7 +949,8 @@ + * Host to Card + * + * Called from Libertas to transfer some data to the WLAN device +- * We can't sleep here. */ ++ * We can't sleep here. ++ */ + static int if_spi_host_to_card(struct lbs_private *priv, + u8 type, u8 *buf, u16 nb) + { +@@ -1057,6 +1097,28 @@ + return err; + } + ++static void if_spi_resume_worker(struct work_struct *work) ++{ ++ struct if_spi_card *card; ++ ++ card = container_of(work, struct if_spi_card, resume_work); ++ ++ if (card->suspended) { ++ if (card->pdata->setup) ++ card->pdata->setup(card->spi); ++ ++ /* Init card ... */ ++ if_spi_init_card(card); ++ ++ enable_irq(card->spi->irq); ++ ++ /* And resume it ... */ ++ lbs_resume(card->priv); ++ ++ card->suspended = 0; ++ } ++} ++ + static int __devinit if_spi_probe(struct spi_device *spi) + { + struct if_spi_card *card; +@@ -1099,14 +1161,17 @@ + if (err) + goto free_card; + +- /* Register our card with libertas. +- * This will call alloc_etherdev */ ++ /* ++ * Register our card with libertas. ++ * This will call alloc_etherdev. ++ */ + priv = lbs_add_card(card, &spi->dev); + if (!priv) { + err = -ENOMEM; + goto free_card; + } + card->priv = priv; ++ priv->setup_fw_on_resume = 1; + priv->card = card; + priv->hw_host_to_card = if_spi_host_to_card; + priv->enter_deep_sleep = NULL; +@@ -1117,6 +1182,7 @@ + /* Initialize interrupt handling stuff. */ + card->workqueue = create_workqueue("libertas_spi"); + INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); ++ INIT_WORK(&card->resume_work, if_spi_resume_worker); + + err = request_irq(spi->irq, if_spi_host_interrupt, + IRQF_TRIGGER_FALLING, "libertas_spi", card); +@@ -1125,9 +1191,11 @@ + goto terminate_workqueue; + } + +- /* Start the card. ++ /* ++ * Start the card. + * This will call register_netdev, and we'll start +- * getting interrupts... */ ++ * getting interrupts... ++ */ + err = lbs_start_card(priv); + if (err) + goto release_irq; +@@ -1161,6 +1229,8 @@ + lbs_deb_spi("libertas_spi_remove\n"); + lbs_deb_enter(LBS_DEB_SPI); + ++ cancel_work_sync(&card->resume_work); ++ + lbs_stop_card(priv); + lbs_remove_card(priv); /* will call free_netdev */ + +@@ -1174,6 +1244,40 @@ + return 0; + } + ++static int if_spi_suspend(struct device *dev) ++{ ++ struct spi_device *spi = to_spi_device(dev); ++ struct if_spi_card *card = spi_get_drvdata(spi); ++ ++ if (!card->suspended) { ++ lbs_suspend(card->priv); ++ flush_workqueue(card->workqueue); ++ disable_irq(spi->irq); ++ ++ if (card->pdata->teardown) ++ card->pdata->teardown(spi); ++ card->suspended = 1; ++ } ++ ++ return 0; ++} ++ ++static int if_spi_resume(struct device *dev) ++{ ++ struct spi_device *spi = to_spi_device(dev); ++ struct if_spi_card *card = spi_get_drvdata(spi); ++ ++ /* Schedule delayed work */ ++ schedule_work(&card->resume_work); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops if_spi_pm_ops = { ++ .suspend = if_spi_suspend, ++ .resume = if_spi_resume, ++}; ++ + static struct spi_driver libertas_spi_driver = { + .probe = if_spi_probe, + .remove = __devexit_p(libertas_spi_remove), +@@ -1181,6 +1285,7 @@ + .name = "libertas_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, ++ .pm = &if_spi_pm_ops, + }, + }; + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/if_spi.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/if_spi.h +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/if_spi.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/if_spi.h 2011-05-05 23:29:46.548454709 +0200 +@@ -86,34 +86,34 @@ + #define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dc) (dc & 0x000000ff) + + /***************** IF_SPI_HOST_INT_CTRL_REG *****************/ +-/** Host Interrupt Control bit : Wake up */ ++/* Host Interrupt Control bit : Wake up */ + #define IF_SPI_HICT_WAKE_UP (1<<0) +-/** Host Interrupt Control bit : WLAN ready */ ++/* Host Interrupt Control bit : WLAN ready */ + #define IF_SPI_HICT_WLAN_READY (1<<1) + /*#define IF_SPI_HICT_FIFO_FIRST_HALF_EMPTY (1<<2) */ + /*#define IF_SPI_HICT_FIFO_SECOND_HALF_EMPTY (1<<3) */ + /*#define IF_SPI_HICT_IRQSRC_WLAN (1<<4) */ +-/** Host Interrupt Control bit : Tx auto download */ ++/* Host Interrupt Control bit : Tx auto download */ + #define IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO (1<<5) +-/** Host Interrupt Control bit : Rx auto upload */ ++/* Host Interrupt Control bit : Rx auto upload */ + #define IF_SPI_HICT_RX_UPLOAD_OVER_AUTO (1<<6) +-/** Host Interrupt Control bit : Command auto download */ ++/* Host Interrupt Control bit : Command auto download */ + #define IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO (1<<7) +-/** Host Interrupt Control bit : Command auto upload */ ++/* Host Interrupt Control bit : Command auto upload */ + #define IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO (1<<8) + + /***************** IF_SPI_CARD_INT_CAUSE_REG *****************/ +-/** Card Interrupt Case bit : Tx download over */ ++/* Card Interrupt Case bit : Tx download over */ + #define IF_SPI_CIC_TX_DOWNLOAD_OVER (1<<0) +-/** Card Interrupt Case bit : Rx upload over */ ++/* Card Interrupt Case bit : Rx upload over */ + #define IF_SPI_CIC_RX_UPLOAD_OVER (1<<1) +-/** Card Interrupt Case bit : Command download over */ ++/* Card Interrupt Case bit : Command download over */ + #define IF_SPI_CIC_CMD_DOWNLOAD_OVER (1<<2) +-/** Card Interrupt Case bit : Host event */ ++/* Card Interrupt Case bit : Host event */ + #define IF_SPI_CIC_HOST_EVENT (1<<3) +-/** Card Interrupt Case bit : Command upload over */ ++/* Card Interrupt Case bit : Command upload over */ + #define IF_SPI_CIC_CMD_UPLOAD_OVER (1<<4) +-/** Card Interrupt Case bit : Power down */ ++/* Card Interrupt Case bit : Power down */ + #define IF_SPI_CIC_POWER_DOWN (1<<5) + + /***************** IF_SPI_CARD_INT_STATUS_REG *****************/ +@@ -138,51 +138,51 @@ + #define IF_SPI_HICU_CMD_RD_FIFO_UNDERFLOW (1<<10) + + /***************** IF_SPI_HOST_INT_STATUS_REG *****************/ +-/** Host Interrupt Status bit : Tx download ready */ ++/* Host Interrupt Status bit : Tx download ready */ + #define IF_SPI_HIST_TX_DOWNLOAD_RDY (1<<0) +-/** Host Interrupt Status bit : Rx upload ready */ ++/* Host Interrupt Status bit : Rx upload ready */ + #define IF_SPI_HIST_RX_UPLOAD_RDY (1<<1) +-/** Host Interrupt Status bit : Command download ready */ ++/* Host Interrupt Status bit : Command download ready */ + #define IF_SPI_HIST_CMD_DOWNLOAD_RDY (1<<2) +-/** Host Interrupt Status bit : Card event */ ++/* Host Interrupt Status bit : Card event */ + #define IF_SPI_HIST_CARD_EVENT (1<<3) +-/** Host Interrupt Status bit : Command upload ready */ ++/* Host Interrupt Status bit : Command upload ready */ + #define IF_SPI_HIST_CMD_UPLOAD_RDY (1<<4) +-/** Host Interrupt Status bit : I/O write FIFO overflow */ ++/* Host Interrupt Status bit : I/O write FIFO overflow */ + #define IF_SPI_HIST_IO_WR_FIFO_OVERFLOW (1<<5) +-/** Host Interrupt Status bit : I/O read FIFO underflow */ ++/* Host Interrupt Status bit : I/O read FIFO underflow */ + #define IF_SPI_HIST_IO_RD_FIFO_UNDRFLOW (1<<6) +-/** Host Interrupt Status bit : Data write FIFO overflow */ ++/* Host Interrupt Status bit : Data write FIFO overflow */ + #define IF_SPI_HIST_DATA_WR_FIFO_OVERFLOW (1<<7) +-/** Host Interrupt Status bit : Data read FIFO underflow */ ++/* Host Interrupt Status bit : Data read FIFO underflow */ + #define IF_SPI_HIST_DATA_RD_FIFO_UNDERFLOW (1<<8) +-/** Host Interrupt Status bit : Command write FIFO overflow */ ++/* Host Interrupt Status bit : Command write FIFO overflow */ + #define IF_SPI_HIST_CMD_WR_FIFO_OVERFLOW (1<<9) +-/** Host Interrupt Status bit : Command read FIFO underflow */ ++/* Host Interrupt Status bit : Command read FIFO underflow */ + #define IF_SPI_HIST_CMD_RD_FIFO_UNDERFLOW (1<<10) + + /***************** IF_SPI_HOST_INT_STATUS_MASK_REG *****************/ +-/** Host Interrupt Status Mask bit : Tx download ready */ ++/* Host Interrupt Status Mask bit : Tx download ready */ + #define IF_SPI_HISM_TX_DOWNLOAD_RDY (1<<0) +-/** Host Interrupt Status Mask bit : Rx upload ready */ ++/* Host Interrupt Status Mask bit : Rx upload ready */ + #define IF_SPI_HISM_RX_UPLOAD_RDY (1<<1) +-/** Host Interrupt Status Mask bit : Command download ready */ ++/* Host Interrupt Status Mask bit : Command download ready */ + #define IF_SPI_HISM_CMD_DOWNLOAD_RDY (1<<2) +-/** Host Interrupt Status Mask bit : Card event */ ++/* Host Interrupt Status Mask bit : Card event */ + #define IF_SPI_HISM_CARDEVENT (1<<3) +-/** Host Interrupt Status Mask bit : Command upload ready */ ++/* Host Interrupt Status Mask bit : Command upload ready */ + #define IF_SPI_HISM_CMD_UPLOAD_RDY (1<<4) +-/** Host Interrupt Status Mask bit : I/O write FIFO overflow */ ++/* Host Interrupt Status Mask bit : I/O write FIFO overflow */ + #define IF_SPI_HISM_IO_WR_FIFO_OVERFLOW (1<<5) +-/** Host Interrupt Status Mask bit : I/O read FIFO underflow */ ++/* Host Interrupt Status Mask bit : I/O read FIFO underflow */ + #define IF_SPI_HISM_IO_RD_FIFO_UNDERFLOW (1<<6) +-/** Host Interrupt Status Mask bit : Data write FIFO overflow */ ++/* Host Interrupt Status Mask bit : Data write FIFO overflow */ + #define IF_SPI_HISM_DATA_WR_FIFO_OVERFLOW (1<<7) +-/** Host Interrupt Status Mask bit : Data write FIFO underflow */ ++/* Host Interrupt Status Mask bit : Data write FIFO underflow */ + #define IF_SPI_HISM_DATA_RD_FIFO_UNDERFLOW (1<<8) +-/** Host Interrupt Status Mask bit : Command write FIFO overflow */ ++/* Host Interrupt Status Mask bit : Command write FIFO overflow */ + #define IF_SPI_HISM_CMD_WR_FIFO_OVERFLOW (1<<9) +-/** Host Interrupt Status Mask bit : Command write FIFO underflow */ ++/* Host Interrupt Status Mask bit : Command write FIFO underflow */ + #define IF_SPI_HISM_CMD_RD_FIFO_UNDERFLOW (1<<10) + + /***************** IF_SPI_SPU_BUS_MODE_REG *****************/ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/if_usb.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/if_usb.c +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/if_usb.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/if_usb.c 2011-05-05 23:29:46.556454805 +0200 +@@ -1,6 +1,6 @@ +-/** +- * This file contains functions used in USB interface module. +- */ ++/* ++ * This file contains functions used in USB interface module. ++ */ + #include + #include + #include +@@ -66,7 +66,7 @@ + + /* sysfs hooks */ + +-/** ++/* + * Set function to write firmware to device's persistent memory + */ + static ssize_t if_usb_firmware_set(struct device *dev, +@@ -85,7 +85,7 @@ + return ret; + } + +-/** ++/* + * lbs_flash_fw attribute to be exported per ethX interface through sysfs + * (/sys/class/net/ethX/lbs_flash_fw). Use this like so to write firmware to + * the device's persistent memory: +@@ -94,7 +94,14 @@ + static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set); + + /** +- * Set function to write firmware to device's persistent memory ++ * if_usb_boot2_set - write firmware to device's persistent memory ++ * ++ * @dev: target device ++ * @attr: device attributes ++ * @buf: firmware buffer to write ++ * @count: number of bytes to write ++ * ++ * returns: number of bytes written or negative error code + */ + static ssize_t if_usb_boot2_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +@@ -112,7 +119,7 @@ + return ret; + } + +-/** ++/* + * lbs_flash_boot2 attribute to be exported per ethX interface through sysfs + * (/sys/class/net/ethX/lbs_flash_boot2). Use this like so to write firmware + * to the device's persistent memory: +@@ -121,9 +128,10 @@ + static DEVICE_ATTR(lbs_flash_boot2, 0200, NULL, if_usb_boot2_set); + + /** +- * @brief call back function to handle the status of the URB +- * @param urb pointer to urb structure +- * @return N/A ++ * if_usb_write_bulk_callback - callback function to handle the status ++ * of the URB ++ * @urb: pointer to &urb structure ++ * returns: N/A + */ + static void if_usb_write_bulk_callback(struct urb *urb) + { +@@ -150,9 +158,9 @@ + } + + /** +- * @brief free tx/rx urb, skb and rx buffer +- * @param cardp pointer if_usb_card +- * @return N/A ++ * if_usb_free - free tx/rx urb, skb and rx buffer ++ * @cardp: pointer to &if_usb_card ++ * returns: N/A + */ + static void if_usb_free(struct if_usb_card *cardp) + { +@@ -231,10 +239,10 @@ + #endif + + /** +- * @brief sets the configuration values +- * @param ifnum interface number +- * @param id pointer to usb_device_id +- * @return 0 on success, error code on failure ++ * if_usb_probe - sets the configuration values ++ * @intf: &usb_interface pointer ++ * @id: pointer to usb_device_id ++ * returns: 0 on success, error code on failure + */ + static int if_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +@@ -366,9 +374,9 @@ + } + + /** +- * @brief free resource and cleanup +- * @param intf USB interface structure +- * @return N/A ++ * if_usb_disconnect - free resource and cleanup ++ * @intf: USB interface structure ++ * returns: N/A + */ + static void if_usb_disconnect(struct usb_interface *intf) + { +@@ -398,9 +406,9 @@ + } + + /** +- * @brief This function download FW +- * @param priv pointer to struct lbs_private +- * @return 0 ++ * if_usb_send_fw_pkt - download FW ++ * @cardp: pointer to &struct if_usb_card ++ * returns: 0 + */ + static int if_usb_send_fw_pkt(struct if_usb_card *cardp) + { +@@ -486,11 +494,11 @@ + } + + /** +- * @brief This function transfer the data to the device. +- * @param priv pointer to struct lbs_private +- * @param payload pointer to payload data +- * @param nb data length +- * @return 0 or -1 ++ * usb_tx_block - transfer the data to the device ++ * @cardp: pointer to &struct if_usb_card ++ * @payload: pointer to payload data ++ * @nb: data length ++ * returns: 0 for success or negative error code + */ + static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb) + { +@@ -727,11 +735,11 @@ + } + + /** +- * @brief This function reads of the packet into the upload buff, +- * wake up the main thread and initialise the Rx callack. ++ * if_usb_receive - read the packet into the upload buffer, ++ * wake up the main thread and initialise the Rx callack + * +- * @param urb pointer to struct urb +- * @return N/A ++ * @urb: pointer to &struct urb ++ * returns: N/A + */ + static void if_usb_receive(struct urb *urb) + { +@@ -802,12 +810,12 @@ + } + + /** +- * @brief This function downloads data to FW +- * @param priv pointer to struct lbs_private structure +- * @param type type of data +- * @param buf pointer to data buffer +- * @param len number of bytes +- * @return 0 or -1 ++ * if_usb_host_to_card - downloads data to FW ++ * @priv: pointer to &struct lbs_private structure ++ * @type: type of data ++ * @payload: pointer to data buffer ++ * @nb: number of bytes ++ * returns: 0 for success or negative error code + */ + static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, + uint8_t *payload, uint16_t nb) +@@ -831,10 +839,11 @@ + } + + /** +- * @brief This function issues Boot command to the Boot2 code +- * @param ivalue 1:Boot from FW by USB-Download +- * 2:Boot from FW in EEPROM +- * @return 0 ++ * if_usb_issue_boot_command - issues Boot command to the Boot2 code ++ * @cardp: pointer to &if_usb_card ++ * @ivalue: 1:Boot from FW by USB-Download ++ * 2:Boot from FW in EEPROM ++ * returns: 0 for success or negative error code + */ + static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue) + { +@@ -853,11 +862,11 @@ + + + /** +- * @brief This function checks the validity of Boot2/FW image. ++ * check_fwfile_format - check the validity of Boot2/FW image + * +- * @param data pointer to image +- * len image length +- * @return 0 or -1 ++ * @data: pointer to image ++ * @totlen: image length ++ * returns: 0 (good) or 1 (failure) + */ + static int check_fwfile_format(const uint8_t *data, uint32_t totlen) + { +@@ -901,13 +910,13 @@ + + + /** +-* @brief This function programs the firmware subject to cmd ++* if_usb_prog_firmware - programs the firmware subject to cmd + * +-* @param cardp the if_usb_card descriptor +-* fwname firmware or boot2 image file name +-* cmd either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW, +-* or BOOT_CMD_UPDATE_BOOT2. +-* @return 0 or error code ++* @cardp: the if_usb_card descriptor ++* @fwname: firmware or boot2 image file name ++* @cmd: either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW, ++* or BOOT_CMD_UPDATE_BOOT2. ++* returns: 0 or error code + */ + static int if_usb_prog_firmware(struct if_usb_card *cardp, + const char *fwname, int cmd) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/if_usb.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/if_usb.h +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/if_usb.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/if_usb.h 2011-05-05 23:29:46.546454683 +0200 +@@ -6,9 +6,9 @@ + + struct lbs_private; + +-/** +- * This file contains definition for USB interface. +- */ ++/* ++ * This file contains definition for USB interface. ++ */ + #define CMD_TYPE_REQUEST 0xF00DFACE + #define CMD_TYPE_DATA 0xBEADC0DE + #define CMD_TYPE_INDICATION 0xBEEFFACE +@@ -40,7 +40,7 @@ + uint8_t pad[2]; + }; + +-/** USB card description structure*/ ++/* USB card description structure*/ + struct if_usb_card { + struct usb_device *udev; + uint32_t model; /* MODEL_* */ +@@ -77,7 +77,7 @@ + __le16 boot2_version; + }; + +-/** fwheader */ ++/* fwheader */ + struct fwheader { + __le32 dnldcmd; + __le32 baseaddr; +@@ -86,14 +86,14 @@ + }; + + #define FW_MAX_DATA_BLK_SIZE 600 +-/** FWData */ ++/* FWData */ + struct fwdata { + struct fwheader hdr; + __le32 seqnum; + uint8_t data[0]; + }; + +-/** fwsyncheader */ ++/* fwsyncheader */ + struct fwsyncheader { + __le32 cmd; + __le32 seqnum; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/main.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/main.c +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/main.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/main.c 2011-05-05 23:29:46.555454793 +0200 +@@ -1,8 +1,8 @@ +-/** +- * This file contains the major functions in WLAN +- * driver. It includes init, exit, open, close and main +- * thread etc.. +- */ ++/* ++ * This file contains the major functions in WLAN ++ * driver. It includes init, exit, open, close and main ++ * thread etc.. ++ */ + + #include + #include +@@ -35,18 +35,20 @@ + module_param_named(libertas_debug, lbs_debug, int, 0644); + + +-/* This global structure is used to send the confirm_sleep command as +- * fast as possible down to the firmware. */ ++/* ++ * This global structure is used to send the confirm_sleep command as ++ * fast as possible down to the firmware. ++ */ + struct cmd_confirm_sleep confirm_sleep; + + +-/** ++/* + * the table to keep region code + */ + u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] = + { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; + +-/** ++/* + * FW rate table. FW refers to rates by their index in this table, not by the + * rate value itself. Values of 0x00 are + * reserved positions. +@@ -57,10 +59,10 @@ + }; + + /** +- * @brief use index to get the data rate ++ * lbs_fw_index_to_data_rate - use index to get the data rate + * +- * @param idx The index of data rate +- * @return data rate or 0 ++ * @idx: The index of data rate ++ * returns: data rate or 0 + */ + u32 lbs_fw_index_to_data_rate(u8 idx) + { +@@ -70,10 +72,10 @@ + } + + /** +- * @brief use rate to get the index ++ * lbs_data_rate_to_fw_index - use rate to get the index + * +- * @param rate data rate +- * @return index or 0 ++ * @rate: data rate ++ * returns: index or 0 + */ + u8 lbs_data_rate_to_fw_index(u32 rate) + { +@@ -91,10 +93,10 @@ + + + /** +- * @brief This function opens the ethX interface ++ * lbs_dev_open - open the ethX interface + * +- * @param dev A pointer to net_device structure +- * @return 0 or -EBUSY if monitor mode active ++ * @dev: A pointer to &net_device structure ++ * returns: 0 or -EBUSY if monitor mode active + */ + static int lbs_dev_open(struct net_device *dev) + { +@@ -120,10 +122,10 @@ + } + + /** +- * @brief This function closes the ethX interface ++ * lbs_eth_stop - close the ethX interface + * +- * @param dev A pointer to net_device structure +- * @return 0 ++ * @dev: A pointer to &net_device structure ++ * returns: 0 + */ + static int lbs_eth_stop(struct net_device *dev) + { +@@ -336,12 +338,12 @@ + } + + /** +- * @brief This function handles the major jobs in the LBS driver. ++ * lbs_thread - handles the major jobs in the LBS driver. + * It handles all events generated by firmware, RX data received + * from firmware and TX data sent from kernel. + * +- * @param data A pointer to lbs_thread structure +- * @return 0 ++ * @data: A pointer to &lbs_thread structure ++ * returns: 0 + */ + static int lbs_thread(void *data) + { +@@ -540,11 +542,11 @@ + } + + /** +- * @brief This function gets the HW spec from the firmware and sets +- * some basic parameters. ++ * lbs_setup_firmware - gets the HW spec from the firmware and sets ++ * some basic parameters + * +- * @param priv A pointer to struct lbs_private structure +- * @return 0 or -1 ++ * @priv: A pointer to &struct lbs_private structure ++ * returns: 0 or -1 + */ + static int lbs_setup_firmware(struct lbs_private *priv) + { +@@ -630,8 +632,10 @@ + EXPORT_SYMBOL_GPL(lbs_resume); + + /** +- * This function handles the timeout of command sending. +- * It will re-send the same command again. ++ * lbs_cmd_timeout_handler - handles the timeout of command sending. ++ * It will re-send the same command again. ++ * ++ * @data: &struct lbs_private pointer + */ + static void lbs_cmd_timeout_handler(unsigned long data) + { +@@ -655,8 +659,10 @@ + } + + /** +- * This function put the device back to deep sleep mode when timer expires +- * and no activity (command, event, data etc.) is detected. ++ * auto_deepsleep_timer_fn - put the device back to deep sleep mode when ++ * timer expires and no activity (command, event, data etc.) is detected. ++ * @data: &struct lbs_private pointer ++ * returns: N/A + */ + static void auto_deepsleep_timer_fn(unsigned long data) + { +@@ -792,11 +798,12 @@ + }; + + /** +- * @brief This function adds the card. it will probe the ++ * lbs_add_card - adds the card. It will probe the + * card, allocate the lbs_priv and initialize the device. + * +- * @param card A pointer to card +- * @return A pointer to struct lbs_private structure ++ * @card: A pointer to card ++ * @dmdev: A pointer to &struct device ++ * returns: A pointer to &struct lbs_private structure + */ + struct lbs_private *lbs_add_card(void *card, struct device *dmdev) + { +@@ -1057,19 +1064,19 @@ + EXPORT_SYMBOL_GPL(lbs_notify_command_response); + + /** +- * @brief Retrieves two-stage firmware ++ * lbs_get_firmware - Retrieves two-stage firmware + * +- * @param dev A pointer to device structure +- * @param user_helper User-defined helper firmware file +- * @param user_mainfw User-defined main firmware file +- * @param card_model Bus-specific card model ID used to filter firmware table +- * elements +- * @param fw_table Table of firmware file names and device model numbers +- * terminated by an entry with a NULL helper name +- * @param helper On success, the helper firmware; caller must free +- * @param mainfw On success, the main firmware; caller must free ++ * @dev: A pointer to &device structure ++ * @user_helper: User-defined helper firmware file ++ * @user_mainfw: User-defined main firmware file ++ * @card_model: Bus-specific card model ID used to filter firmware table ++ * elements ++ * @fw_table: Table of firmware file names and device model numbers ++ * terminated by an entry with a NULL helper name ++ * @helper: On success, the helper firmware; caller must free ++ * @mainfw: On success, the main firmware; caller must free + * +- * @return 0 on success, non-zero on failure ++ * returns: 0 on success, non-zero on failure + */ + int lbs_get_firmware(struct device *dev, const char *user_helper, + const char *user_mainfw, u32 card_model, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/mesh.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/mesh.c +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/mesh.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/mesh.c 2011-05-05 23:29:46.546454683 +0200 +@@ -16,12 +16,15 @@ + * Mesh sysfs support + */ + +-/** ++/* + * Attributes exported through sysfs + */ + + /** +- * @brief Get function for sysfs attribute anycast_mask ++ * lbs_anycast_get - Get function for sysfs attribute anycast_mask ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer where data will be returned + */ + static ssize_t lbs_anycast_get(struct device *dev, + struct device_attribute *attr, char * buf) +@@ -40,7 +43,11 @@ + } + + /** +- * @brief Set function for sysfs attribute anycast_mask ++ * lbs_anycast_set - Set function for sysfs attribute anycast_mask ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer that contains new attribute value ++ * @count: size of buffer + */ + static ssize_t lbs_anycast_set(struct device *dev, + struct device_attribute *attr, const char * buf, size_t count) +@@ -62,7 +69,10 @@ + } + + /** +- * @brief Get function for sysfs attribute prb_rsp_limit ++ * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer where data will be returned + */ + static ssize_t lbs_prb_rsp_limit_get(struct device *dev, + struct device_attribute *attr, char *buf) +@@ -85,7 +95,11 @@ + } + + /** +- * @brief Set function for sysfs attribute prb_rsp_limit ++ * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer that contains new attribute value ++ * @count: size of buffer + */ + static ssize_t lbs_prb_rsp_limit_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +@@ -114,7 +128,10 @@ + } + + /** +- * Get function for sysfs attribute mesh ++ * lbs_mesh_get - Get function for sysfs attribute mesh ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer where data will be returned + */ + static ssize_t lbs_mesh_get(struct device *dev, + struct device_attribute *attr, char * buf) +@@ -124,7 +141,11 @@ + } + + /** +- * Set function for sysfs attribute mesh ++ * lbs_mesh_set - Set function for sysfs attribute mesh ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer that contains new attribute value ++ * @count: size of buffer + */ + static ssize_t lbs_mesh_set(struct device *dev, + struct device_attribute *attr, const char * buf, size_t count) +@@ -151,19 +172,19 @@ + return count; + } + +-/** ++/* + * lbs_mesh attribute to be exported per ethX interface + * through sysfs (/sys/class/net/ethX/lbs_mesh) + */ + static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set); + +-/** ++/* + * anycast_mask attribute to be exported per mshX interface + * through sysfs (/sys/class/net/mshX/anycast_mask) + */ + static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set); + +-/** ++/* + * prb_rsp_limit attribute to be exported per mshX interface + * through sysfs (/sys/class/net/mshX/prb_rsp_limit) + */ +@@ -274,10 +295,10 @@ + + + /** +- * @brief This function closes the mshX interface ++ * lbs_mesh_stop - close the mshX interface + * +- * @param dev A pointer to net_device structure +- * @return 0 ++ * @dev: A pointer to &net_device structure ++ * returns: 0 + */ + static int lbs_mesh_stop(struct net_device *dev) + { +@@ -301,10 +322,10 @@ + } + + /** +- * @brief This function opens the mshX interface ++ * lbs_mesh_dev_open - open the mshX interface + * +- * @param dev A pointer to net_device structure +- * @return 0 or -EBUSY if monitor mode active ++ * @dev: A pointer to &net_device structure ++ * returns: 0 or -EBUSY if monitor mode active + */ + static int lbs_mesh_dev_open(struct net_device *dev) + { +@@ -342,10 +363,10 @@ + }; + + /** +- * @brief This function adds mshX interface ++ * lbs_add_mesh - add mshX interface + * +- * @param priv A pointer to the struct lbs_private structure +- * @return 0 if successful, -X otherwise ++ * @priv: A pointer to the &struct lbs_private structure ++ * returns: 0 if successful, -X otherwise + */ + int lbs_add_mesh(struct lbs_private *priv) + { +@@ -456,13 +477,13 @@ + */ + + /** +- * @brief Add or delete Mesh Blinding Table entries ++ * lbs_mesh_bt_add_del - Add or delete Mesh Blinding Table entries + * +- * @param priv A pointer to struct lbs_private structure +- * @param add TRUE to add the entry, FALSE to delete it +- * @param addr1 Destination address to blind or unblind ++ * @priv: A pointer to &struct lbs_private structure ++ * @add: TRUE to add the entry, FALSE to delete it ++ * @addr1: Destination address to blind or unblind + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1) + { +@@ -493,11 +514,11 @@ + } + + /** +- * @brief Reset/clear the mesh blinding table ++ * lbs_mesh_bt_reset - Reset/clear the mesh blinding table + * +- * @param priv A pointer to struct lbs_private structure ++ * @priv: A pointer to &struct lbs_private structure + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_mesh_bt_reset(struct lbs_private *priv) + { +@@ -517,17 +538,18 @@ + } + + /** +- * @brief Gets the inverted status of the mesh blinding table ++ * lbs_mesh_bt_get_inverted - Gets the inverted status of the mesh ++ * blinding table + * +- * Normally the firmware "blinds" or ignores traffic from mesh nodes in the +- * table, but an inverted table allows *only* traffic from nodes listed in +- * the table. ++ * Normally the firmware "blinds" or ignores traffic from mesh nodes in the ++ * table, but an inverted table allows *only* traffic from nodes listed in ++ * the table. + * +- * @param priv A pointer to struct lbs_private structure +- * @param invert On success, TRUE if the blinding table is inverted, +- * FALSE if it is not inverted ++ * @priv: A pointer to &struct lbs_private structure ++ * @inverted: On success, TRUE if the blinding table is inverted, ++ * FALSE if it is not inverted + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted) + { +@@ -551,18 +573,19 @@ + } + + /** +- * @brief Sets the inverted status of the mesh blinding table ++ * lbs_mesh_bt_set_inverted - Sets the inverted status of the mesh ++ * blinding table + * +- * Normally the firmware "blinds" or ignores traffic from mesh nodes in the +- * table, but an inverted table allows *only* traffic from nodes listed in +- * the table. ++ * Normally the firmware "blinds" or ignores traffic from mesh nodes in the ++ * table, but an inverted table allows *only* traffic from nodes listed in ++ * the table. + * +- * @param priv A pointer to struct lbs_private structure +- * @param invert TRUE to invert the blinding table (only traffic from +- * listed nodes allowed), FALSE to return it +- * to normal state (listed nodes ignored) ++ * @priv: A pointer to &struct lbs_private structure ++ * @inverted: TRUE to invert the blinding table (only traffic from ++ * listed nodes allowed), FALSE to return it ++ * to normal state (listed nodes ignored) + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted) + { +@@ -583,13 +606,13 @@ + } + + /** +- * @brief List an entry in the mesh blinding table ++ * lbs_mesh_bt_get_entry - List an entry in the mesh blinding table + * +- * @param priv A pointer to struct lbs_private structure +- * @param id The ID of the entry to list +- * @param addr1 MAC address associated with the table entry ++ * @priv: A pointer to &struct lbs_private structure ++ * @id: The ID of the entry to list ++ * @addr1: MAC address associated with the table entry + * +- * @return 0 on success, error on failure ++ * returns: 0 on success, error on failure + */ + int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1) + { +@@ -614,14 +637,14 @@ + } + + /** +- * @brief Access the mesh forwarding table ++ * lbs_cmd_fwt_access - Access the mesh forwarding table + * +- * @param priv A pointer to struct lbs_private structure +- * @param cmd_action The forwarding table action to perform +- * @param cmd The pre-filled FWT_ACCESS command ++ * @priv: A pointer to &struct lbs_private structure ++ * @cmd_action: The forwarding table action to perform ++ * @cmd: The pre-filled FWT_ACCESS command + * +- * @return 0 on success and 'cmd' will be filled with the +- * firmware's response ++ * returns: 0 on success and 'cmd' will be filled with the ++ * firmware's response + */ + int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action, + struct cmd_ds_fwt_access *cmd) +@@ -774,7 +797,10 @@ + } + + /** +- * @brief Get function for sysfs attribute bootflag ++ * bootflag_get - Get function for sysfs attribute bootflag ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer where data will be returned + */ + static ssize_t bootflag_get(struct device *dev, + struct device_attribute *attr, char *buf) +@@ -791,7 +817,11 @@ + } + + /** +- * @brief Set function for sysfs attribute bootflag ++ * bootflag_set - Set function for sysfs attribute bootflag ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer that contains new attribute value ++ * @count: size of buffer + */ + static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +@@ -817,7 +847,10 @@ + } + + /** +- * @brief Get function for sysfs attribute boottime ++ * boottime_get - Get function for sysfs attribute boottime ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer where data will be returned + */ + static ssize_t boottime_get(struct device *dev, + struct device_attribute *attr, char *buf) +@@ -834,7 +867,11 @@ + } + + /** +- * @brief Set function for sysfs attribute boottime ++ * boottime_set - Set function for sysfs attribute boottime ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer that contains new attribute value ++ * @count: size of buffer + */ + static ssize_t boottime_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +@@ -869,7 +906,10 @@ + } + + /** +- * @brief Get function for sysfs attribute channel ++ * channel_get - Get function for sysfs attribute channel ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer where data will be returned + */ + static ssize_t channel_get(struct device *dev, + struct device_attribute *attr, char *buf) +@@ -886,7 +926,11 @@ + } + + /** +- * @brief Set function for sysfs attribute channel ++ * channel_set - Set function for sysfs attribute channel ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer that contains new attribute value ++ * @count: size of buffer + */ + static ssize_t channel_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +@@ -912,7 +956,10 @@ + } + + /** +- * @brief Get function for sysfs attribute mesh_id ++ * mesh_id_get - Get function for sysfs attribute mesh_id ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer where data will be returned + */ + static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -938,7 +985,11 @@ + } + + /** +- * @brief Set function for sysfs attribute mesh_id ++ * mesh_id_set - Set function for sysfs attribute mesh_id ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer that contains new attribute value ++ * @count: size of buffer + */ + static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +@@ -980,7 +1031,10 @@ + } + + /** +- * @brief Get function for sysfs attribute protocol_id ++ * protocol_id_get - Get function for sysfs attribute protocol_id ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer where data will be returned + */ + static ssize_t protocol_id_get(struct device *dev, + struct device_attribute *attr, char *buf) +@@ -997,7 +1051,11 @@ + } + + /** +- * @brief Set function for sysfs attribute protocol_id ++ * protocol_id_set - Set function for sysfs attribute protocol_id ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer that contains new attribute value ++ * @count: size of buffer + */ + static ssize_t protocol_id_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +@@ -1034,7 +1092,10 @@ + } + + /** +- * @brief Get function for sysfs attribute metric_id ++ * metric_id_get - Get function for sysfs attribute metric_id ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer where data will be returned + */ + static ssize_t metric_id_get(struct device *dev, + struct device_attribute *attr, char *buf) +@@ -1051,7 +1112,11 @@ + } + + /** +- * @brief Set function for sysfs attribute metric_id ++ * metric_id_set - Set function for sysfs attribute metric_id ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer that contains new attribute value ++ * @count: size of buffer + */ + static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +@@ -1088,7 +1153,10 @@ + } + + /** +- * @brief Get function for sysfs attribute capability ++ * capability_get - Get function for sysfs attribute capability ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer where data will be returned + */ + static ssize_t capability_get(struct device *dev, + struct device_attribute *attr, char *buf) +@@ -1105,7 +1173,11 @@ + } + + /** +- * @brief Set function for sysfs attribute capability ++ * capability_set - Set function for sysfs attribute capability ++ * @dev: the &struct device ++ * @attr: device attributes ++ * @buf: buffer that contains new attribute value ++ * @count: size of buffer + */ + static ssize_t capability_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/mesh.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/mesh.h +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/mesh.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/mesh.h 2011-05-05 23:29:46.760457269 +0200 +@@ -1,6 +1,6 @@ +-/** +- * Contains all definitions needed for the Libertas' MESH implementation. +- */ ++/* ++ * Contains all definitions needed for the Libertas' MESH implementation. ++ */ + #ifndef _LBS_MESH_H_ + #define _LBS_MESH_H_ + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/rx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/rx.c +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/rx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/rx.c 2011-05-05 23:29:46.553454769 +0200 +@@ -1,6 +1,6 @@ +-/** +- * This file contains the handling of RX in wlan driver. +- */ ++/* ++ * This file contains the handling of RX in wlan driver. ++ */ + #include + #include + #include +@@ -40,12 +40,12 @@ + struct sk_buff *skb); + + /** +- * @brief This function processes received packet and forwards it +- * to kernel/upper layer ++ * lbs_process_rxed_packet - processes received packet and forwards it ++ * to kernel/upper layer + * +- * @param priv A pointer to struct lbs_private +- * @param skb A pointer to skb which includes the received packet +- * @return 0 or -1 ++ * @priv: A pointer to &struct lbs_private ++ * @skb: A pointer to skb which includes the received packet ++ * returns: 0 or -1 + */ + int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) + { +@@ -156,11 +156,11 @@ + EXPORT_SYMBOL_GPL(lbs_process_rxed_packet); + + /** +- * @brief This function converts Tx/Rx rates from the Marvell WLAN format +- * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) ++ * convert_mv_rate_to_radiotap - converts Tx/Rx rates from Marvell WLAN format ++ * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) + * +- * @param rate Input rate +- * @return Output Rate (0 if invalid) ++ * @rate: Input rate ++ * returns: Output Rate (0 if invalid) + */ + static u8 convert_mv_rate_to_radiotap(u8 rate) + { +@@ -196,12 +196,12 @@ + } + + /** +- * @brief This function processes a received 802.11 packet and forwards it +- * to kernel/upper layer ++ * process_rxed_802_11_packet - processes a received 802.11 packet and forwards ++ * it to kernel/upper layer + * +- * @param priv A pointer to struct lbs_private +- * @param skb A pointer to skb which includes the received packet +- * @return 0 or -1 ++ * @priv: A pointer to &struct lbs_private ++ * @skb: A pointer to skb which includes the received packet ++ * returns: 0 or -1 + */ + static int process_rxed_802_11_packet(struct lbs_private *priv, + struct sk_buff *skb) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/tx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/tx.c +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/tx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/tx.c 2011-05-05 23:29:46.514454297 +0200 +@@ -1,6 +1,6 @@ +-/** +- * This file contains the handling of TX in wlan driver. +- */ ++/* ++ * This file contains the handling of TX in wlan driver. ++ */ + #include + #include + #include +@@ -13,11 +13,11 @@ + #include "dev.h" + + /** +- * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE +- * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1) ++ * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE ++ * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1) + * +- * @param rate Input rate +- * @return Output Rate (0 if invalid) ++ * @rate: Input rate ++ * returns: Output Rate (0 if invalid) + */ + static u32 convert_radiotap_rate_to_mv(u8 rate) + { +@@ -51,12 +51,12 @@ + } + + /** +- * @brief This function checks the conditions and sends packet to IF +- * layer if everything is ok. ++ * lbs_hard_start_xmit - checks the conditions and sends packet to IF ++ * layer if everything is ok + * +- * @param priv A pointer to struct lbs_private structure +- * @param skb A pointer to skb which includes TX packet +- * @return 0 or -1 ++ * @skb: A pointer to skb which includes TX packet ++ * @dev: A pointer to the &struct net_device ++ * returns: 0 or -1 + */ + netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) + { +@@ -168,13 +168,13 @@ + } + + /** +- * @brief This function sends to the host the last transmitted packet, +- * filling the radiotap headers with transmission information. ++ * lbs_send_tx_feedback - sends to the host the last transmitted packet, ++ * filling the radiotap headers with transmission information. + * +- * @param priv A pointer to struct lbs_private structure +- * @param status A 32 bit value containing transmission status. ++ * @priv: A pointer to &struct lbs_private structure ++ * @try_count: A 32-bit value containing transmission retry status. + * +- * @returns void ++ * returns: void + */ + void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count) + { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/libertas/types.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/types.h +--- linux-2.6.39-rc6/drivers/net/wireless/libertas/types.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/libertas/types.h 2011-05-05 23:29:46.737456991 +0200 +@@ -1,6 +1,6 @@ +-/** +- * This header file contains definition for global types +- */ ++/* ++ * This header file contains definition for global types ++ */ + #ifndef _LBS_TYPES_H_ + #define _LBS_TYPES_H_ + +@@ -54,7 +54,7 @@ + struct ieee_ie_ds_param_set ds; + } __packed; + +-/** TLV type ID definition */ ++/* TLV type ID definition */ + #define PROPRIETARY_TLV_BASE_ID 0x0100 + + /* Terminating TLV type */ +@@ -96,7 +96,7 @@ + #define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37) + #define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291) + +-/** TLV related data structures*/ ++/* TLV related data structures */ + struct mrvl_ie_header { + __le16 type; + __le16 len; +@@ -177,7 +177,7 @@ + __le16 auth; + } __packed; + +-/** Local Power capability */ ++/* Local Power capability */ + struct mrvl_ie_power_capability { + struct mrvl_ie_header header; + s8 minpower; +@@ -235,9 +235,11 @@ + struct led_bhv ledbhv[1]; + } __packed; + +-/* Meant to be packed as the value member of a struct ieee80211_info_element. ++/* ++ * Meant to be packed as the value member of a struct ieee80211_info_element. + * Note that the len member of the ieee80211_info_element varies depending on +- * the mesh_id_len */ ++ * the mesh_id_len ++ */ + struct mrvl_meshie_val { + uint8_t oui[3]; + uint8_t type; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/Makefile linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/Makefile +--- linux-2.6.39-rc6/drivers/net/wireless/Makefile 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/Makefile 2011-05-05 23:29:45.782445453 +0200 +@@ -56,3 +56,5 @@ + obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ + + obj-$(CONFIG_IWM) += iwmc3200wifi/ ++ ++obj-$(CONFIG_MWIFIEX) += mwifiex/ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/11n_aggr.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/11n_aggr.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/11n_aggr.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/11n_aggr.c 2011-05-05 23:29:45.470441683 +0200 +@@ -0,0 +1,422 @@ ++/* ++ * Marvell Wireless LAN device driver: 802.11n Aggregation ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++#include "11n_aggr.h" ++ ++/* ++ * Creates an AMSDU subframe for aggregation into one AMSDU packet. ++ * ++ * The resultant AMSDU subframe format is - ++ * ++ * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+ ++ * | DA | SA | Length | SNAP header | MSDU | ++ * | data[0..5] | data[6..11] | | | data[14..] | ++ * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+ ++ * <--6-bytes--> <--6-bytes--> <--2-bytes--><--8-bytes--> <--n-bytes--> ++ * ++ * This function also computes the amount of padding required to make the ++ * buffer length multiple of 4 bytes. ++ * ++ * Data => |DA|SA|SNAP-TYPE|........ .| ++ * MSDU => |DA|SA|Length|SNAP|...... ..| ++ */ ++static int ++mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr, ++ struct sk_buff *skb_src, int *pad) ++ ++{ ++ int dt_offset; ++ struct rfc_1042_hdr snap = { ++ 0xaa, /* LLC DSAP */ ++ 0xaa, /* LLC SSAP */ ++ 0x03, /* LLC CTRL */ ++ {0x00, 0x00, 0x00}, /* SNAP OUI */ ++ 0x0000 /* SNAP type */ ++ /* ++ * This field will be overwritten ++ * later with ethertype ++ */ ++ }; ++ struct tx_packet_hdr *tx_header = NULL; ++ ++ skb_put(skb_aggr, sizeof(*tx_header)); ++ ++ tx_header = (struct tx_packet_hdr *) skb_aggr->data; ++ ++ /* Copy DA and SA */ ++ dt_offset = 2 * ETH_ALEN; ++ memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset); ++ ++ /* Copy SNAP header */ ++ snap.snap_type = *(u16 *) ((u8 *)skb_src->data + dt_offset); ++ dt_offset += sizeof(u16); ++ ++ memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr)); ++ ++ skb_pull(skb_src, dt_offset); ++ ++ /* Update Length field */ ++ tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN); ++ ++ /* Add payload */ ++ skb_put(skb_aggr, skb_src->len); ++ memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data, ++ skb_src->len); ++ *pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len + ++ LLC_SNAP_LEN)) & 3)) : 0; ++ skb_put(skb_aggr, *pad); ++ ++ return skb_aggr->len + *pad; ++} ++ ++/* ++ * Adds TxPD to AMSDU header. ++ * ++ * Each AMSDU packet will contain one TxPD at the beginning, ++ * followed by multiple AMSDU subframes. ++ */ ++static void ++mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, ++ struct sk_buff *skb) ++{ ++ struct txpd *local_tx_pd; ++ ++ skb_push(skb, sizeof(*local_tx_pd)); ++ ++ local_tx_pd = (struct txpd *) skb->data; ++ memset(local_tx_pd, 0, sizeof(struct txpd)); ++ ++ /* Original priority has been overwritten */ ++ local_tx_pd->priority = (u8) skb->priority; ++ local_tx_pd->pkt_delay_2ms = ++ mwifiex_wmm_compute_drv_pkt_delay(priv, skb); ++ local_tx_pd->bss_num = priv->bss_num; ++ local_tx_pd->bss_type = priv->bss_type; ++ /* Always zero as the data is followed by struct txpd */ ++ local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); ++ local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU); ++ local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len - ++ sizeof(*local_tx_pd)); ++ ++ if (local_tx_pd->tx_control == 0) ++ /* TxCtrl set by user or default */ ++ local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); ++ ++ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && ++ (priv->adapter->pps_uapsd_mode)) { ++ if (true == mwifiex_check_last_packet_indication(priv)) { ++ priv->adapter->tx_lock_flag = true; ++ local_tx_pd->flags = ++ MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; ++ } ++ } ++} ++ ++/* ++ * Counts the number of subframes in an aggregate packet. ++ * ++ * This function parses an aggregate packet buffer, looking for ++ * subframes and counting the number of such subframe found. The ++ * function automatically skips the DA/SA fields at the beginning ++ * of each subframe and padding at the end. ++ */ ++static int ++mwifiex_11n_get_num_aggr_pkts(u8 *data, int total_pkt_len) ++{ ++ int pkt_count = 0, pkt_len, pad; ++ ++ while (total_pkt_len > 0) { ++ /* Length will be in network format, change it to host */ ++ pkt_len = ntohs((*(__be16 *)(data + 2 * ETH_ALEN))); ++ pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ? ++ (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0; ++ data += pkt_len + pad + sizeof(struct ethhdr); ++ total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr); ++ ++pkt_count; ++ } ++ ++ return pkt_count; ++} ++ ++/* ++ * De-aggregate received packets. ++ * ++ * This function parses the received aggregate buffer, extracts each subframe, ++ * strips off the SNAP header from them and sends the data portion for further ++ * processing. ++ * ++ * Each subframe body is copied onto a separate buffer, which are freed by ++ * upper layer after processing. The function also performs sanity tests on ++ * the received buffer. ++ */ ++int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, ++ struct sk_buff *skb) ++{ ++ u16 pkt_len; ++ int total_pkt_len; ++ u8 *data; ++ int pad; ++ struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); ++ struct rxpd *local_rx_pd = (struct rxpd *) skb->data; ++ struct sk_buff *skb_daggr; ++ struct mwifiex_rxinfo *rx_info_daggr = NULL; ++ int ret = -1; ++ struct rx_packet_hdr *rx_pkt_hdr; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; ++ ++ data = (u8 *) (local_rx_pd + local_rx_pd->rx_pkt_offset); ++ total_pkt_len = local_rx_pd->rx_pkt_length; ++ ++ /* Sanity test */ ++ if (total_pkt_len > MWIFIEX_RX_DATA_BUF_SIZE) { ++ dev_err(adapter->dev, "total pkt len greater than buffer" ++ " size %d\n", total_pkt_len); ++ return -1; ++ } ++ ++ rx_info->use_count = mwifiex_11n_get_num_aggr_pkts(data, total_pkt_len); ++ ++ while (total_pkt_len > 0) { ++ rx_pkt_hdr = (struct rx_packet_hdr *) data; ++ /* Length will be in network format, change it to host */ ++ pkt_len = ntohs((*(__be16 *) (data + 2 * ETH_ALEN))); ++ if (pkt_len > total_pkt_len) { ++ dev_err(adapter->dev, "pkt_len %d > total_pkt_len %d\n", ++ total_pkt_len, pkt_len); ++ break; ++ } ++ ++ pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ? ++ (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0; ++ ++ total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr); ++ ++ if (memcmp(&rx_pkt_hdr->rfc1042_hdr, ++ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { ++ memmove(data + LLC_SNAP_LEN, data, 2 * ETH_ALEN); ++ data += LLC_SNAP_LEN; ++ pkt_len += sizeof(struct ethhdr) - LLC_SNAP_LEN; ++ } else { ++ *(u16 *) (data + 2 * ETH_ALEN) = (u16) 0; ++ pkt_len += sizeof(struct ethhdr); ++ } ++ ++ skb_daggr = dev_alloc_skb(pkt_len); ++ if (!skb_daggr) { ++ dev_err(adapter->dev, "%s: failed to alloc skb_daggr\n", ++ __func__); ++ return -1; ++ } ++ rx_info_daggr = MWIFIEX_SKB_RXCB(skb_daggr); ++ ++ rx_info_daggr->bss_index = rx_info->bss_index; ++ skb_daggr->tstamp = skb->tstamp; ++ rx_info_daggr->parent = skb; ++ skb_daggr->priority = skb->priority; ++ skb_put(skb_daggr, pkt_len); ++ memcpy(skb_daggr->data, data, pkt_len); ++ ++ ret = mwifiex_recv_packet(adapter, skb_daggr); ++ ++ switch (ret) { ++ case -EINPROGRESS: ++ break; ++ case -1: ++ dev_err(adapter->dev, "deaggr: host_to_card failed\n"); ++ case 0: ++ mwifiex_recv_packet_complete(adapter, skb_daggr, ret); ++ break; ++ default: ++ break; ++ } ++ ++ data += pkt_len + pad; ++ } ++ ++ return ret; ++} ++ ++/* ++ * Create aggregated packet. ++ * ++ * This function creates an aggregated MSDU packet, by combining buffers ++ * from the RA list. Each individual buffer is encapsulated as an AMSDU ++ * subframe and all such subframes are concatenated together to form the ++ * AMSDU packet. ++ * ++ * A TxPD is also added to the front of the resultant AMSDU packets for ++ * transmission. The resultant packets format is - ++ * ++ * +---- ~ ----+------ ~ ------+------ ~ ------+-..-+------ ~ ------+ ++ * | TxPD |AMSDU sub-frame|AMSDU sub-frame| .. |AMSDU sub-frame| ++ * | | 1 | 2 | .. | n | ++ * +---- ~ ----+------ ~ ------+------ ~ ------+ .. +------ ~ ------+ ++ */ ++int ++mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, ++ struct mwifiex_ra_list_tbl *pra_list, int headroom, ++ int ptrindex, unsigned long ra_list_flags) ++ __releases(&priv->wmm.ra_list_spinlock) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct sk_buff *skb_aggr, *skb_src; ++ struct mwifiex_txinfo *tx_info_aggr, *tx_info_src; ++ int pad = 0; ++ int ret = 0; ++ struct mwifiex_tx_param tx_param; ++ struct txpd *ptx_pd = NULL; ++ ++ if (skb_queue_empty(&pra_list->skb_head)) { ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ return 0; ++ } ++ skb_src = skb_peek(&pra_list->skb_head); ++ tx_info_src = MWIFIEX_SKB_TXCB(skb_src); ++ skb_aggr = dev_alloc_skb(adapter->tx_buf_size); ++ if (!skb_aggr) { ++ dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__); ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ return -1; ++ } ++ skb_reserve(skb_aggr, headroom + sizeof(struct txpd)); ++ tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr); ++ ++ tx_info_aggr->bss_index = tx_info_src->bss_index; ++ skb_aggr->priority = skb_src->priority; ++ ++ while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len ++ + LLC_SNAP_LEN) ++ <= adapter->tx_buf_size)) { ++ ++ if (!skb_queue_empty(&pra_list->skb_head)) ++ skb_src = skb_dequeue(&pra_list->skb_head); ++ else ++ skb_src = NULL; ++ ++ pra_list->total_pkts_size -= skb_src->len; ++ ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad); ++ ++ mwifiex_write_data_complete(adapter, skb_src, 0); ++ ++ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); ++ ++ if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ return -1; ++ } ++ ++ if (!skb_queue_empty(&pra_list->skb_head)) ++ skb_src = skb_peek(&pra_list->skb_head); ++ else ++ skb_src = NULL; ++ } ++ ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); ++ ++ /* Last AMSDU packet does not need padding */ ++ skb_trim(skb_aggr, skb_aggr->len - pad); ++ ++ /* Form AMSDU */ ++ mwifiex_11n_form_amsdu_txpd(priv, skb_aggr); ++ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) ++ ptx_pd = (struct txpd *)skb_aggr->data; ++ ++ skb_push(skb_aggr, headroom); ++ ++ tx_param.next_pkt_len = ((pra_list->total_pkts_size) ? ++ (((pra_list->total_pkts_size) > ++ adapter->tx_buf_size) ? adapter-> ++ tx_buf_size : pra_list->total_pkts_size + ++ LLC_SNAP_LEN + sizeof(struct txpd)) : 0); ++ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, ++ skb_aggr->data, ++ skb_aggr->len, &tx_param); ++ switch (ret) { ++ case -EBUSY: ++ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); ++ if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ mwifiex_write_data_complete(adapter, skb_aggr, -1); ++ return -1; ++ } ++ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && ++ (adapter->pps_uapsd_mode) && ++ (adapter->tx_lock_flag)) { ++ priv->adapter->tx_lock_flag = false; ++ ptx_pd->flags = 0; ++ } ++ ++ skb_queue_tail(&pra_list->skb_head, skb_aggr); ++ ++ pra_list->total_pkts_size += skb_aggr->len; ++ ++ tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); ++ break; ++ case -1: ++ adapter->data_sent = false; ++ dev_err(adapter->dev, "%s: host_to_card failed: %#x\n", ++ __func__, ret); ++ adapter->dbg.num_tx_host_to_card_failure++; ++ mwifiex_write_data_complete(adapter, skb_aggr, ret); ++ return 0; ++ case -EINPROGRESS: ++ adapter->data_sent = false; ++ break; ++ case 0: ++ mwifiex_write_data_complete(adapter, skb_aggr, ret); ++ break; ++ default: ++ break; ++ } ++ if (ret != -EBUSY) { ++ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); ++ if (mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { ++ priv->wmm.packets_out[ptrindex]++; ++ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list; ++ } ++ /* Now bss_prio_cur pointer points to next node */ ++ adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = ++ list_first_entry( ++ &adapter->bss_prio_tbl[priv->bss_priority] ++ .bss_prio_cur->list, ++ struct mwifiex_bss_prio_node, list); ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ } ++ ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/11n_aggr.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/11n_aggr.h +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/11n_aggr.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/11n_aggr.h 2011-05-05 23:29:45.488441901 +0200 +@@ -0,0 +1,32 @@ ++/* ++ * Marvell Wireless LAN device driver: 802.11n Aggregation ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#ifndef _MWIFIEX_11N_AGGR_H_ ++#define _MWIFIEX_11N_AGGR_H_ ++ ++#define PKT_TYPE_AMSDU 0xE6 ++ ++int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, ++ struct sk_buff *skb); ++int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, ++ struct mwifiex_ra_list_tbl *ptr, int headroom, ++ int ptr_index, unsigned long flags) ++ __releases(&priv->wmm.ra_list_spinlock); ++ ++#endif /* !_MWIFIEX_11N_AGGR_H_ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/11n.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/11n.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/11n.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/11n.c 2011-05-05 23:29:45.488441901 +0200 +@@ -0,0 +1,745 @@ ++/* ++ * Marvell Wireless LAN device driver: 802.11n ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++ ++/* ++ * Fills HT capability information field, AMPDU Parameters field, HT extended ++ * capability field, and supported MCS set fields. ++ * ++ * HT capability information field, AMPDU Parameters field, supported MCS set ++ * fields are retrieved from cfg80211 stack ++ * ++ * RD responder bit to set to clear in the extended capability header. ++ */ ++void ++mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type, ++ struct mwifiex_ie_types_htcap *ht_cap) ++{ ++ uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info); ++ struct ieee80211_supported_band *sband = ++ priv->wdev->wiphy->bands[radio_type]; ++ ++ ht_cap->ht_cap.ampdu_params_info = ++ (sband->ht_cap.ampdu_factor & ++ IEEE80211_HT_AMPDU_PARM_FACTOR)| ++ ((sband->ht_cap.ampdu_density << ++ IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT) & ++ IEEE80211_HT_AMPDU_PARM_DENSITY); ++ ++ memcpy((u8 *) &ht_cap->ht_cap.mcs, &sband->ht_cap.mcs, ++ sizeof(sband->ht_cap.mcs)); ++ ++ if (priv->bss_mode == NL80211_IFTYPE_STATION || ++ (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) ++ /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ ++ SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); ++ ++ /* Clear RD responder bit */ ++ ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER; ++ ++ ht_cap->ht_cap.cap_info = cpu_to_le16(sband->ht_cap.cap); ++ ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap); ++} ++ ++/* ++ * This function returns the pointer to an entry in BA Stream ++ * table which matches the requested BA status. ++ */ ++static struct mwifiex_tx_ba_stream_tbl * ++mwifiex_11n_get_tx_ba_stream_status(struct mwifiex_private *priv, ++ enum mwifiex_ba_status ba_status) ++{ ++ struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); ++ list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { ++ if (tx_ba_tsr_tbl->ba_status == ba_status) { ++ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, ++ flags); ++ return tx_ba_tsr_tbl; ++ } ++ } ++ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); ++ return NULL; ++} ++ ++/* ++ * This function handles the command response of delete a block ++ * ack request. ++ * ++ * The function checks the response success status and takes action ++ * accordingly (send an add BA request in case of success, or recreate ++ * the deleted stream in case of failure, if the add BA was also ++ * initiated by us). ++ */ ++int mwifiex_ret_11n_delba(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ int tid; ++ struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; ++ struct host_cmd_ds_11n_delba *del_ba = ++ (struct host_cmd_ds_11n_delba *) &resp->params.del_ba; ++ uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set); ++ ++ tid = del_ba_param_set >> DELBA_TID_POS; ++ if (del_ba->del_result == BA_RESULT_SUCCESS) { ++ mwifiex_11n_delete_ba_stream_tbl(priv, tid, ++ del_ba->peer_mac_addr, TYPE_DELBA_SENT, ++ INITIATOR_BIT(del_ba_param_set)); ++ ++ tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv, ++ BA_STREAM_SETUP_INPROGRESS); ++ if (tx_ba_tbl) ++ mwifiex_send_addba(priv, tx_ba_tbl->tid, ++ tx_ba_tbl->ra); ++ } else { /* ++ * In case of failure, recreate the deleted stream in case ++ * we initiated the ADDBA ++ */ ++ if (INITIATOR_BIT(del_ba_param_set)) { ++ mwifiex_11n_create_tx_ba_stream_tbl(priv, ++ del_ba->peer_mac_addr, tid, ++ BA_STREAM_SETUP_INPROGRESS); ++ ++ tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv, ++ BA_STREAM_SETUP_INPROGRESS); ++ if (tx_ba_tbl) ++ mwifiex_11n_delete_ba_stream_tbl(priv, ++ tx_ba_tbl->tid, tx_ba_tbl->ra, ++ TYPE_DELBA_SENT, true); ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of add a block ++ * ack request. ++ * ++ * Handling includes changing the header fields to CPU formats, checking ++ * the response success status and taking actions accordingly (delete the ++ * BA stream table in case of failure). ++ */ ++int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ int tid; ++ struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = ++ (struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp; ++ struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; ++ ++ add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) ++ & SSN_MASK); ++ ++ tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set) ++ & IEEE80211_ADDBA_PARAM_TID_MASK) ++ >> BLOCKACKPARAM_TID_POS; ++ if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { ++ tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ++ add_ba_rsp->peer_mac_addr); ++ if (tx_ba_tbl) { ++ dev_dbg(priv->adapter->dev, "info: BA stream complete\n"); ++ tx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE; ++ } else { ++ dev_err(priv->adapter->dev, "BA stream not created\n"); ++ } ++ } else { ++ mwifiex_11n_delete_ba_stream_tbl(priv, tid, ++ add_ba_rsp->peer_mac_addr, ++ TYPE_DELBA_SENT, true); ++ if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) ++ priv->aggr_prio_tbl[tid].ampdu_ap = ++ BA_STREAM_NOT_ALLOWED; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of 11n configuration request. ++ * ++ * Handling includes changing the header fields into CPU format. ++ */ ++int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, void *data_buf) ++{ ++ struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL; ++ struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg; ++ ++ if (data_buf) { ++ tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf; ++ tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap); ++ tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info); ++ } ++ return 0; ++} ++ ++/* ++ * This function prepares command of reconfigure Tx buffer. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting Tx buffer size (for SET only) ++ * - Ensuring correct endian-ness ++ */ ++int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, int cmd_action, ++ void *data_buf) ++{ ++ struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf; ++ u16 action = (u16) cmd_action; ++ u16 buf_size = *((u16 *) data_buf); ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF); ++ cmd->size = ++ cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN); ++ tx_buf->action = cpu_to_le16(action); ++ switch (action) { ++ case HostCmd_ACT_GEN_SET: ++ dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size); ++ tx_buf->buff_size = cpu_to_le16(buf_size); ++ break; ++ case HostCmd_ACT_GEN_GET: ++ default: ++ tx_buf->buff_size = 0; ++ break; ++ } ++ return 0; ++} ++ ++/* ++ * This function prepares command of AMSDU aggregation control. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting AMSDU control parameters (for SET only) ++ * - Ensuring correct endian-ness ++ */ ++int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, ++ int cmd_action, void *data_buf) ++{ ++ struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = ++ &cmd->params.amsdu_aggr_ctrl; ++ u16 action = (u16) cmd_action; ++ struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl = ++ (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL); ++ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl) ++ + S_DS_GEN); ++ amsdu_ctrl->action = cpu_to_le16(action); ++ switch (action) { ++ case HostCmd_ACT_GEN_SET: ++ amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable); ++ amsdu_ctrl->curr_buf_size = 0; ++ break; ++ case HostCmd_ACT_GEN_GET: ++ default: ++ amsdu_ctrl->curr_buf_size = 0; ++ break; ++ } ++ return 0; ++} ++ ++/* ++ * This function handles the command response of AMSDU aggregation ++ * control request. ++ * ++ * Handling includes changing the header fields into CPU format. ++ */ ++int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp, ++ void *data_buf) ++{ ++ struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL; ++ struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = ++ &resp->params.amsdu_aggr_ctrl; ++ ++ if (data_buf) { ++ amsdu_aggr_ctrl = ++ (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; ++ amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable); ++ amsdu_aggr_ctrl->curr_buf_size = ++ le16_to_cpu(amsdu_ctrl->curr_buf_size); ++ } ++ return 0; ++} ++ ++/* ++ * This function prepares 11n configuration command. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting HT Tx capability and HT Tx information fields ++ * - Ensuring correct endian-ness ++ */ ++int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, ++ u16 cmd_action, void *data_buf) ++{ ++ struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; ++ struct mwifiex_ds_11n_tx_cfg *txcfg = ++ (struct mwifiex_ds_11n_tx_cfg *) data_buf; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG); ++ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN); ++ htcfg->action = cpu_to_le16(cmd_action); ++ htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap); ++ htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo); ++ return 0; ++} ++ ++/* ++ * This function appends an 11n TLV to a buffer. ++ * ++ * Buffer allocation is responsibility of the calling ++ * function. No size validation is made here. ++ * ++ * The function fills up the following sections, if applicable - ++ * - HT capability IE ++ * - HT information IE (with channel list) ++ * - 20/40 BSS Coexistence IE ++ * - HT Extended Capabilities IE ++ */ ++int ++mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc, ++ u8 **buffer) ++{ ++ struct mwifiex_ie_types_htcap *ht_cap; ++ struct mwifiex_ie_types_htinfo *ht_info; ++ struct mwifiex_ie_types_chan_list_param_set *chan_list; ++ struct mwifiex_ie_types_2040bssco *bss_co_2040; ++ struct mwifiex_ie_types_extcap *ext_cap; ++ int ret_len = 0; ++ struct ieee80211_supported_band *sband; ++ u8 radio_type; ++ ++ if (!buffer || !*buffer) ++ return ret_len; ++ ++ radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); ++ sband = priv->wdev->wiphy->bands[radio_type]; ++ ++ if (bss_desc->bcn_ht_cap) { ++ ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; ++ memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); ++ ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); ++ ht_cap->header.len = ++ cpu_to_le16(sizeof(struct ieee80211_ht_cap)); ++ memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header), ++ (u8 *) bss_desc->bcn_ht_cap + ++ sizeof(struct ieee_types_header), ++ le16_to_cpu(ht_cap->header.len)); ++ ++ mwifiex_fill_cap_info(priv, radio_type, ht_cap); ++ ++ *buffer += sizeof(struct mwifiex_ie_types_htcap); ++ ret_len += sizeof(struct mwifiex_ie_types_htcap); ++ } ++ ++ if (bss_desc->bcn_ht_info) { ++ if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { ++ ht_info = (struct mwifiex_ie_types_htinfo *) *buffer; ++ memset(ht_info, 0, ++ sizeof(struct mwifiex_ie_types_htinfo)); ++ ht_info->header.type = ++ cpu_to_le16(WLAN_EID_HT_INFORMATION); ++ ht_info->header.len = ++ cpu_to_le16(sizeof(struct ieee80211_ht_info)); ++ ++ memcpy((u8 *) ht_info + ++ sizeof(struct mwifiex_ie_types_header), ++ (u8 *) bss_desc->bcn_ht_info + ++ sizeof(struct ieee_types_header), ++ le16_to_cpu(ht_info->header.len)); ++ ++ if (!(sband->ht_cap.cap & ++ IEEE80211_HT_CAP_SUP_WIDTH_20_40)) ++ ht_info->ht_info.ht_param &= ++ ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY | ++ IEEE80211_HT_PARAM_CHA_SEC_OFFSET); ++ ++ *buffer += sizeof(struct mwifiex_ie_types_htinfo); ++ ret_len += sizeof(struct mwifiex_ie_types_htinfo); ++ } ++ ++ chan_list = ++ (struct mwifiex_ie_types_chan_list_param_set *) *buffer; ++ memset(chan_list, 0, ++ sizeof(struct mwifiex_ie_types_chan_list_param_set)); ++ chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); ++ chan_list->header.len = cpu_to_le16( ++ sizeof(struct mwifiex_ie_types_chan_list_param_set) - ++ sizeof(struct mwifiex_ie_types_header)); ++ chan_list->chan_scan_param[0].chan_number = ++ bss_desc->bcn_ht_info->control_chan; ++ chan_list->chan_scan_param[0].radio_type = ++ mwifiex_band_to_radio_type((u8) bss_desc->bss_band); ++ ++ if ((sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ++ && (bss_desc->bcn_ht_info->ht_param & ++ IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) ++ SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. ++ radio_type, ++ (bss_desc->bcn_ht_info->ht_param & ++ IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); ++ ++ *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); ++ ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set); ++ } ++ ++ if (bss_desc->bcn_bss_co_2040) { ++ bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer; ++ memset(bss_co_2040, 0, ++ sizeof(struct mwifiex_ie_types_2040bssco)); ++ bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040); ++ bss_co_2040->header.len = ++ cpu_to_le16(sizeof(bss_co_2040->bss_co_2040)); ++ ++ memcpy((u8 *) bss_co_2040 + ++ sizeof(struct mwifiex_ie_types_header), ++ (u8 *) bss_desc->bcn_bss_co_2040 + ++ sizeof(struct ieee_types_header), ++ le16_to_cpu(bss_co_2040->header.len)); ++ ++ *buffer += sizeof(struct mwifiex_ie_types_2040bssco); ++ ret_len += sizeof(struct mwifiex_ie_types_2040bssco); ++ } ++ ++ if (bss_desc->bcn_ext_cap) { ++ ext_cap = (struct mwifiex_ie_types_extcap *) *buffer; ++ memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap)); ++ ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY); ++ ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap)); ++ ++ memcpy((u8 *) ext_cap + ++ sizeof(struct mwifiex_ie_types_header), ++ (u8 *) bss_desc->bcn_ext_cap + ++ sizeof(struct ieee_types_header), ++ le16_to_cpu(ext_cap->header.len)); ++ ++ *buffer += sizeof(struct mwifiex_ie_types_extcap); ++ ret_len += sizeof(struct mwifiex_ie_types_extcap); ++ } ++ ++ return ret_len; ++} ++ ++/* ++ * This function reconfigures the Tx buffer size in firmware. ++ * ++ * This function prepares a firmware command and issues it, if ++ * the current Tx buffer size is different from the one requested. ++ * Maximum configurable Tx buffer size is limited by the HT capability ++ * field value. ++ */ ++void ++mwifiex_cfg_tx_buf(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc) ++{ ++ u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K; ++ u16 tx_buf = 0; ++ u16 curr_tx_buf_size = 0; ++ ++ if (bss_desc->bcn_ht_cap) { ++ if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) & ++ IEEE80211_HT_CAP_MAX_AMSDU) ++ max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K; ++ else ++ max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K; ++ } ++ ++ tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu); ++ ++ dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n", ++ max_amsdu, priv->adapter->max_tx_buf_size); ++ ++ if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K) ++ curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; ++ else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K) ++ curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; ++ else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K) ++ curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K; ++ if (curr_tx_buf_size != tx_buf) ++ mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, ++ HostCmd_ACT_GEN_SET, 0, &tx_buf); ++} ++ ++/* ++ * This function checks if the given pointer is valid entry of ++ * Tx BA Stream table. ++ */ ++static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv, ++ struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr) ++{ ++ struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; ++ ++ list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { ++ if (tx_ba_tsr_tbl == tx_tbl_ptr) ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++ * This function deletes the given entry in Tx BA Stream table. ++ * ++ * The function also performs a validity check on the supplied ++ * pointer before trying to delete. ++ */ ++void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, ++ struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl) ++{ ++ if (!tx_ba_tsr_tbl && ++ mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl)) ++ return; ++ ++ dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl); ++ ++ list_del(&tx_ba_tsr_tbl->list); ++ ++ kfree(tx_ba_tsr_tbl); ++} ++ ++/* ++ * This function deletes all the entries in Tx BA Stream table. ++ */ ++void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv) ++{ ++ int i; ++ struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); ++ list_for_each_entry_safe(del_tbl_ptr, tmp_node, ++ &priv->tx_ba_stream_tbl_ptr, list) ++ mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr); ++ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); ++ ++ INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); ++ ++ for (i = 0; i < MAX_NUM_TID; ++i) ++ priv->aggr_prio_tbl[i].ampdu_ap = ++ priv->aggr_prio_tbl[i].ampdu_user; ++} ++ ++/* ++ * This function returns the pointer to an entry in BA Stream ++ * table which matches the given RA/TID pair. ++ */ ++struct mwifiex_tx_ba_stream_tbl * ++mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv, ++ int tid, u8 *ra) ++{ ++ struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); ++ list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { ++ if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN)) ++ && (tx_ba_tsr_tbl->tid == tid)) { ++ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, ++ flags); ++ return tx_ba_tsr_tbl; ++ } ++ } ++ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); ++ return NULL; ++} ++ ++/* ++ * This function creates an entry in Tx BA stream table for the ++ * given RA/TID pair. ++ */ ++void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, ++ u8 *ra, int tid, ++ enum mwifiex_ba_status ba_status) ++{ ++ struct mwifiex_tx_ba_stream_tbl *new_node; ++ unsigned long flags; ++ ++ if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) { ++ new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl), ++ GFP_ATOMIC); ++ if (!new_node) { ++ dev_err(priv->adapter->dev, ++ "%s: failed to alloc new_node\n", __func__); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&new_node->list); ++ ++ new_node->tid = tid; ++ new_node->ba_status = ba_status; ++ memcpy(new_node->ra, ra, ETH_ALEN); ++ ++ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); ++ list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr); ++ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); ++ } ++} ++ ++/* ++ * This function sends an add BA request to the given TID/RA pair. ++ */ ++int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) ++{ ++ struct host_cmd_ds_11n_addba_req add_ba_req; ++ static u8 dialog_tok; ++ int ret; ++ ++ dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid); ++ ++ add_ba_req.block_ack_param_set = cpu_to_le16( ++ (u16) ((tid << BLOCKACKPARAM_TID_POS) | ++ (priv->add_ba_param. ++ tx_win_size << BLOCKACKPARAM_WINSIZE_POS) | ++ IMMEDIATE_BLOCK_ACK)); ++ add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout); ++ ++ ++dialog_tok; ++ ++ if (dialog_tok == 0) ++ dialog_tok = 1; ++ ++ add_ba_req.dialog_token = dialog_tok; ++ memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN); ++ ++ /* We don't wait for the response of this command */ ++ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ, ++ 0, 0, &add_ba_req); ++ ++ return ret; ++} ++ ++/* ++ * This function sends a delete BA request to the given TID/RA pair. ++ */ ++int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, ++ int initiator) ++{ ++ struct host_cmd_ds_11n_delba delba; ++ int ret; ++ uint16_t del_ba_param_set; ++ ++ memset(&delba, 0, sizeof(delba)); ++ delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS); ++ ++ del_ba_param_set = le16_to_cpu(delba.del_ba_param_set); ++ if (initiator) ++ del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK; ++ else ++ del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK; ++ ++ memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); ++ ++ /* We don't wait for the response of this command */ ++ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, ++ HostCmd_ACT_GEN_SET, 0, &delba); ++ ++ return ret; ++} ++ ++/* ++ * This function handles the command response of a delete BA request. ++ */ ++void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba) ++{ ++ struct host_cmd_ds_11n_delba *cmd_del_ba = ++ (struct host_cmd_ds_11n_delba *) del_ba; ++ uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set); ++ int tid; ++ ++ tid = del_ba_param_set >> DELBA_TID_POS; ++ ++ mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr, ++ TYPE_DELBA_RECEIVE, ++ INITIATOR_BIT(del_ba_param_set)); ++} ++ ++/* ++ * This function retrieves the Rx reordering table. ++ */ ++int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, ++ struct mwifiex_ds_rx_reorder_tbl *buf) ++{ ++ int i; ++ struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf; ++ struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr; ++ int count = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); ++ list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr, ++ list) { ++ rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid; ++ memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN); ++ rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win; ++ rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size; ++ for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) { ++ if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) ++ rx_reo_tbl->buffer[i] = true; ++ else ++ rx_reo_tbl->buffer[i] = false; ++ } ++ rx_reo_tbl++; ++ count++; ++ ++ if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED) ++ break; ++ } ++ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); ++ ++ return count; ++} ++ ++/* ++ * This function retrieves the Tx BA stream table. ++ */ ++int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, ++ struct mwifiex_ds_tx_ba_stream_tbl *buf) ++{ ++ struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; ++ struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf; ++ int count = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); ++ list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { ++ rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid; ++ dev_dbg(priv->adapter->dev, "data: %s tid=%d\n", ++ __func__, rx_reo_tbl->tid); ++ memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN); ++ rx_reo_tbl++; ++ count++; ++ if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ++ break; ++ } ++ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); ++ ++ return count; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/11n.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/11n.h +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/11n.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/11n.h 2011-05-05 23:29:45.493441961 +0200 +@@ -0,0 +1,161 @@ ++/* ++ * Marvell Wireless LAN device driver: 802.11n ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#ifndef _MWIFIEX_11N_H_ ++#define _MWIFIEX_11N_H_ ++ ++#include "11n_aggr.h" ++#include "11n_rxreorder.h" ++#include "wmm.h" ++ ++int mwifiex_ret_11n_delba(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp); ++int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp); ++int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, ++ void *data_buf); ++int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, ++ u16 cmd_action, void *data_buf); ++ ++int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc, ++ u8 **buffer); ++void mwifiex_cfg_tx_buf(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc); ++void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type, ++ struct mwifiex_ie_types_htcap *); ++int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv, ++ u16 action, int *htcap_cfg); ++void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, ++ struct mwifiex_tx_ba_stream_tbl ++ *tx_tbl); ++void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv); ++struct mwifiex_tx_ba_stream_tbl *mwifiex_11n_get_tx_ba_stream_tbl(struct ++ mwifiex_private ++ *priv, int tid, ++ u8 *ra); ++void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, u8 *ra, ++ int tid, ++ enum mwifiex_ba_status ba_status); ++int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac); ++int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, ++ int initiator); ++void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba); ++int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, ++ struct mwifiex_ds_rx_reorder_tbl *buf); ++int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, ++ struct mwifiex_ds_tx_ba_stream_tbl *buf); ++int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp, ++ void *data_buf); ++int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ int cmd_action, void *data_buf); ++int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, ++ int cmd_action, void *data_buf); ++ ++/* ++ * This function checks whether AMPDU is allowed or not for a particular TID. ++ */ ++static inline u8 ++mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, int tid) ++{ ++ return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED) ++ ? true : false); ++} ++ ++/* ++ * This function checks whether AMSDU is allowed or not for a particular TID. ++ */ ++static inline u8 ++mwifiex_is_amsdu_allowed(struct mwifiex_private *priv, int tid) ++{ ++ return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED) ++ && ((priv->is_data_rate_auto) ++ || !((priv->bitmap_rates[2]) & 0x03))) ++ ? true : false); ++} ++ ++/* ++ * This function checks whether a space is available for new BA stream or not. ++ */ ++static inline u8 mwifiex_space_avail_for_new_ba_stream( ++ struct mwifiex_adapter *adapter) ++{ ++ struct mwifiex_private *priv; ++ u8 i; ++ u32 ba_stream_num = 0; ++ ++ for (i = 0; i < adapter->priv_num; i++) { ++ priv = adapter->priv[i]; ++ if (priv) ++ ba_stream_num += mwifiex_wmm_list_len( ++ (struct list_head *) ++ &priv->tx_ba_stream_tbl_ptr); ++ } ++ ++ return ((ba_stream_num < ++ MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false); ++} ++ ++/* ++ * This function finds the correct Tx BA stream to delete. ++ * ++ * Upon successfully locating, both the TID and the RA are returned. ++ */ ++static inline u8 ++mwifiex_find_stream_to_delete(struct mwifiex_private *priv, int ptr_tid, ++ int *ptid, u8 *ra) ++{ ++ int tid; ++ u8 ret = false; ++ struct mwifiex_tx_ba_stream_tbl *tx_tbl; ++ unsigned long flags; ++ ++ tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user; ++ ++ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); ++ list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) { ++ if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) { ++ tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user; ++ *ptid = tx_tbl->tid; ++ memcpy(ra, tx_tbl->ra, ETH_ALEN); ++ ret = true; ++ } ++ } ++ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); ++ ++ return ret; ++} ++ ++/* ++ * This function checks whether BA stream is set up or not. ++ */ ++static inline int ++mwifiex_is_ba_stream_setup(struct mwifiex_private *priv, ++ struct mwifiex_ra_list_tbl *ptr, int tid) ++{ ++ struct mwifiex_tx_ba_stream_tbl *tx_tbl; ++ ++ tx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ptr->ra); ++ if (tx_tbl && IS_BASTREAM_SETUP(tx_tbl)) ++ return true; ++ ++ return false; ++} ++#endif /* !_MWIFIEX_11N_H_ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/11n_rxreorder.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/11n_rxreorder.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/11n_rxreorder.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/11n_rxreorder.c 2011-05-05 23:29:45.473441719 +0200 +@@ -0,0 +1,617 @@ ++/* ++ * Marvell Wireless LAN device driver: 802.11n RX Re-ordering ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++#include "11n_rxreorder.h" ++ ++/* ++ * This function dispatches all packets in the Rx reorder table. ++ * ++ * There could be holes in the buffer, which are skipped by the function. ++ * Since the buffer is linear, the function uses rotation to simulate ++ * circular buffer. ++ */ ++static int ++mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, ++ struct mwifiex_rx_reorder_tbl ++ *rx_reor_tbl_ptr, int start_win) ++{ ++ int no_pkt_to_send, i; ++ void *rx_tmp_ptr = NULL; ++ unsigned long flags; ++ ++ no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ? ++ min((start_win - rx_reor_tbl_ptr->start_win), ++ rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size; ++ ++ for (i = 0; i < no_pkt_to_send; ++i) { ++ spin_lock_irqsave(&priv->rx_pkt_lock, flags); ++ rx_tmp_ptr = NULL; ++ if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) { ++ rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; ++ rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; ++ } ++ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); ++ if (rx_tmp_ptr) ++ mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr); ++ } ++ ++ spin_lock_irqsave(&priv->rx_pkt_lock, flags); ++ /* ++ * We don't have a circular buffer, hence use rotation to simulate ++ * circular buffer ++ */ ++ for (i = 0; i < rx_reor_tbl_ptr->win_size - no_pkt_to_send; ++i) { ++ rx_reor_tbl_ptr->rx_reorder_ptr[i] = ++ rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i]; ++ rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL; ++ } ++ ++ rx_reor_tbl_ptr->start_win = start_win; ++ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); ++ ++ return 0; ++} ++ ++/* ++ * This function dispatches all packets in the Rx reorder table until ++ * a hole is found. ++ * ++ * The start window is adjusted automatically when a hole is located. ++ * Since the buffer is linear, the function uses rotation to simulate ++ * circular buffer. ++ */ ++static int ++mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, ++ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr) ++{ ++ int i, j, xchg; ++ void *rx_tmp_ptr = NULL; ++ unsigned long flags; ++ ++ for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) { ++ spin_lock_irqsave(&priv->rx_pkt_lock, flags); ++ if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) { ++ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); ++ break; ++ } ++ rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; ++ rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; ++ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); ++ mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr); ++ } ++ ++ spin_lock_irqsave(&priv->rx_pkt_lock, flags); ++ /* ++ * We don't have a circular buffer, hence use rotation to simulate ++ * circular buffer ++ */ ++ if (i > 0) { ++ xchg = rx_reor_tbl_ptr->win_size - i; ++ for (j = 0; j < xchg; ++j) { ++ rx_reor_tbl_ptr->rx_reorder_ptr[j] = ++ rx_reor_tbl_ptr->rx_reorder_ptr[i + j]; ++ rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL; ++ } ++ } ++ rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i) ++ &(MAX_TID_VALUE - 1); ++ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); ++ return 0; ++} ++ ++/* ++ * This function deletes the Rx reorder table and frees the memory. ++ * ++ * The function stops the associated timer and dispatches all the ++ * pending packets in the Rx reorder table before deletion. ++ */ ++static void ++mwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv, ++ struct mwifiex_rx_reorder_tbl ++ *rx_reor_tbl_ptr) ++{ ++ unsigned long flags; ++ ++ if (!rx_reor_tbl_ptr) ++ return; ++ ++ mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, ++ (rx_reor_tbl_ptr->start_win + ++ rx_reor_tbl_ptr->win_size) ++ &(MAX_TID_VALUE - 1)); ++ ++ del_timer(&rx_reor_tbl_ptr->timer_context.timer); ++ ++ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); ++ list_del(&rx_reor_tbl_ptr->list); ++ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); ++ ++ kfree(rx_reor_tbl_ptr->rx_reorder_ptr); ++ kfree(rx_reor_tbl_ptr); ++} ++ ++/* ++ * This function returns the pointer to an entry in Rx reordering ++ * table which matches the given TA/TID pair. ++ */ ++static struct mwifiex_rx_reorder_tbl * ++mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta) ++{ ++ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); ++ list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { ++ if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN)) ++ && (rx_reor_tbl_ptr->tid == tid)) { ++ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, ++ flags); ++ return rx_reor_tbl_ptr; ++ } ++ } ++ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); ++ ++ return NULL; ++} ++ ++/* ++ * This function finds the last sequence number used in the packets ++ * buffered in Rx reordering table. ++ */ ++static int ++mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr) ++{ ++ int i; ++ ++ for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) ++ if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) ++ return i; ++ ++ return -1; ++} ++ ++/* ++ * This function flushes all the packets in Rx reordering table. ++ * ++ * The function checks if any packets are currently buffered in the ++ * table or not. In case there are packets available, it dispatches ++ * them and then dumps the Rx reordering table. ++ */ ++static void ++mwifiex_flush_data(unsigned long context) ++{ ++ struct reorder_tmr_cnxt *reorder_cnxt = ++ (struct reorder_tmr_cnxt *) context; ++ int start_win; ++ ++ start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr); ++ if (start_win >= 0) { ++ dev_dbg(reorder_cnxt->priv->adapter->dev, ++ "info: flush data %d\n", start_win); ++ mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv, ++ reorder_cnxt->ptr, ++ ((reorder_cnxt->ptr->start_win + ++ start_win + 1) & (MAX_TID_VALUE - 1))); ++ } ++} ++ ++/* ++ * This function creates an entry in Rx reordering table for the ++ * given TA/TID. ++ * ++ * The function also initializes the entry with sequence number, window ++ * size as well as initializes the timer. ++ * ++ * If the received TA/TID pair is already present, all the packets are ++ * dispatched and the window size is moved until the SSN. ++ */ ++static void ++mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, ++ int tid, int win_size, int seq_num) ++{ ++ int i; ++ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node; ++ u16 last_seq = 0; ++ unsigned long flags; ++ ++ /* ++ * If we get a TID, ta pair which is already present dispatch all the ++ * the packets and move the window size until the ssn ++ */ ++ rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); ++ if (rx_reor_tbl_ptr) { ++ mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, ++ seq_num); ++ return; ++ } ++ /* if !rx_reor_tbl_ptr then create one */ ++ new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL); ++ if (!new_node) { ++ dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n", ++ __func__); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&new_node->list); ++ new_node->tid = tid; ++ memcpy(new_node->ta, ta, ETH_ALEN); ++ new_node->start_win = seq_num; ++ if (mwifiex_queuing_ra_based(priv)) ++ /* TODO for adhoc */ ++ dev_dbg(priv->adapter->dev, ++ "info: ADHOC:last_seq=%d start_win=%d\n", ++ last_seq, new_node->start_win); ++ else ++ last_seq = priv->rx_seq[tid]; ++ ++ if (last_seq >= new_node->start_win) ++ new_node->start_win = last_seq + 1; ++ ++ new_node->win_size = win_size; ++ ++ new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size, ++ GFP_KERNEL); ++ if (!new_node->rx_reorder_ptr) { ++ kfree((u8 *) new_node); ++ dev_err(priv->adapter->dev, ++ "%s: failed to alloc reorder_ptr\n", __func__); ++ return; ++ } ++ ++ new_node->timer_context.ptr = new_node; ++ new_node->timer_context.priv = priv; ++ ++ init_timer(&new_node->timer_context.timer); ++ new_node->timer_context.timer.function = mwifiex_flush_data; ++ new_node->timer_context.timer.data = ++ (unsigned long) &new_node->timer_context; ++ ++ for (i = 0; i < win_size; ++i) ++ new_node->rx_reorder_ptr[i] = NULL; ++ ++ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); ++ list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr); ++ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); ++} ++ ++/* ++ * This function prepares command for adding a BA request. ++ * ++ * Preparation includes - ++ * - Setting command ID and proper size ++ * - Setting add BA request buffer ++ * - Ensuring correct endian-ness ++ */ ++int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf) ++{ ++ struct host_cmd_ds_11n_addba_req *add_ba_req = ++ (struct host_cmd_ds_11n_addba_req *) ++ &cmd->params.add_ba_req; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ); ++ cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN); ++ memcpy(add_ba_req, data_buf, sizeof(*add_ba_req)); ++ ++ return 0; ++} ++ ++/* ++ * This function prepares command for adding a BA response. ++ * ++ * Preparation includes - ++ * - Setting command ID and proper size ++ * - Setting add BA response buffer ++ * - Ensuring correct endian-ness ++ */ ++int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ void *data_buf) ++{ ++ struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = ++ (struct host_cmd_ds_11n_addba_rsp *) ++ &cmd->params.add_ba_rsp; ++ struct host_cmd_ds_11n_addba_req *cmd_addba_req = ++ (struct host_cmd_ds_11n_addba_req *) data_buf; ++ u8 tid = 0; ++ int win_size = 0; ++ uint16_t block_ack_param_set; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP); ++ cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN); ++ ++ memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr, ++ ETH_ALEN); ++ add_ba_rsp->dialog_token = cmd_addba_req->dialog_token; ++ add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo; ++ add_ba_rsp->ssn = cmd_addba_req->ssn; ++ ++ block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set); ++ tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) ++ >> BLOCKACKPARAM_TID_POS; ++ add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT); ++ block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; ++ /* We donot support AMSDU inside AMPDU, hence reset the bit */ ++ block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK; ++ block_ack_param_set |= (priv->add_ba_param.rx_win_size << ++ BLOCKACKPARAM_WINSIZE_POS); ++ add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set); ++ win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set) ++ & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) ++ >> BLOCKACKPARAM_WINSIZE_POS; ++ cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set); ++ ++ mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr, ++ tid, win_size, le16_to_cpu(cmd_addba_req->ssn)); ++ return 0; ++} ++ ++/* ++ * This function prepares command for deleting a BA request. ++ * ++ * Preparation includes - ++ * - Setting command ID and proper size ++ * - Setting del BA request buffer ++ * - Ensuring correct endian-ness ++ */ ++int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf) ++{ ++ struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *) ++ &cmd->params.del_ba; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA); ++ cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN); ++ memcpy(del_ba, data_buf, sizeof(*del_ba)); ++ ++ return 0; ++} ++ ++/* ++ * This function identifies if Rx reordering is needed for a received packet. ++ * ++ * In case reordering is required, the function will do the reordering ++ * before sending it to kernel. ++ * ++ * The Rx reorder table is checked first with the received TID/TA pair. If ++ * not found, the received packet is dispatched immediately. But if found, ++ * the packet is reordered and all the packets in the updated Rx reordering ++ * table is dispatched until a hole is found. ++ * ++ * For sequence number less than the starting window, the packet is dropped. ++ */ ++int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, ++ u16 seq_num, u16 tid, ++ u8 *ta, u8 pkt_type, void *payload) ++{ ++ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; ++ int start_win, end_win, win_size; ++ int ret = 0; ++ u16 pkt_index = 0; ++ ++ rx_reor_tbl_ptr = ++ mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv, ++ tid, ta); ++ if (!rx_reor_tbl_ptr) { ++ if (pkt_type != PKT_TYPE_BAR) ++ mwifiex_process_rx_packet(priv->adapter, payload); ++ return 0; ++ } ++ start_win = rx_reor_tbl_ptr->start_win; ++ win_size = rx_reor_tbl_ptr->win_size; ++ end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); ++ del_timer(&rx_reor_tbl_ptr->timer_context.timer); ++ mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies ++ + (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000); ++ ++ /* ++ * If seq_num is less then starting win then ignore and drop the ++ * packet ++ */ ++ if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */ ++ if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1)) ++ && (seq_num < start_win)) ++ return -1; ++ } else if ((seq_num < start_win) ++ || (seq_num > (start_win + (TWOPOW11)))) { ++ return -1; ++ } ++ ++ /* ++ * If this packet is a BAR we adjust seq_num as ++ * WinStart = seq_num ++ */ ++ if (pkt_type == PKT_TYPE_BAR) ++ seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1); ++ ++ if (((end_win < start_win) ++ && (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win))) ++ && (seq_num > end_win)) || ((end_win > start_win) ++ && ((seq_num > end_win) || (seq_num < start_win)))) { ++ end_win = seq_num; ++ if (((seq_num - win_size) + 1) >= 0) ++ start_win = (end_win - win_size) + 1; ++ else ++ start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1; ++ ret = mwifiex_11n_dispatch_pkt_until_start_win(priv, ++ rx_reor_tbl_ptr, start_win); ++ ++ if (ret) ++ return ret; ++ } ++ ++ if (pkt_type != PKT_TYPE_BAR) { ++ if (seq_num >= start_win) ++ pkt_index = seq_num - start_win; ++ else ++ pkt_index = (seq_num+MAX_TID_VALUE) - start_win; ++ ++ if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index]) ++ return -1; ++ ++ rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload; ++ } ++ ++ /* ++ * Dispatch all packets sequentially from start_win until a ++ * hole is found and adjust the start_win appropriately ++ */ ++ ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr); ++ ++ return ret; ++} ++ ++/* ++ * This function deletes an entry for a given TID/TA pair. ++ * ++ * The TID/TA are taken from del BA event body. ++ */ ++void ++mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int tid, ++ u8 *peer_mac, u8 type, int initiator) ++{ ++ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; ++ struct mwifiex_tx_ba_stream_tbl *ptx_tbl; ++ u8 cleanup_rx_reorder_tbl; ++ unsigned long flags; ++ ++ if (type == TYPE_DELBA_RECEIVE) ++ cleanup_rx_reorder_tbl = (initiator) ? true : false; ++ else ++ cleanup_rx_reorder_tbl = (initiator) ? false : true; ++ ++ dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, " ++ "initiator=%d\n", peer_mac, tid, initiator); ++ ++ if (cleanup_rx_reorder_tbl) { ++ rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ++ peer_mac); ++ if (!rx_reor_tbl_ptr) { ++ dev_dbg(priv->adapter->dev, ++ "event: TID, TA not found in table\n"); ++ return; ++ } ++ mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr); ++ } else { ++ ptx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, peer_mac); ++ if (!ptx_tbl) { ++ dev_dbg(priv->adapter->dev, ++ "event: TID, RA not found in table\n"); ++ return; ++ } ++ ++ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); ++ mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl); ++ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); ++ } ++} ++ ++/* ++ * This function handles the command response of an add BA response. ++ * ++ * Handling includes changing the header fields into CPU format and ++ * creating the stream, provided the add BA is accepted. ++ */ ++int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = ++ (struct host_cmd_ds_11n_addba_rsp *) ++ &resp->params.add_ba_rsp; ++ int tid, win_size; ++ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr = NULL; ++ uint16_t block_ack_param_set; ++ ++ block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); ++ ++ tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) ++ >> BLOCKACKPARAM_TID_POS; ++ /* ++ * Check if we had rejected the ADDBA, if yes then do not create ++ * the stream ++ */ ++ if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { ++ win_size = (block_ack_param_set & ++ IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) ++ >> BLOCKACKPARAM_WINSIZE_POS; ++ ++ dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM" ++ " tid=%d ssn=%d win_size=%d\n", ++ add_ba_rsp->peer_mac_addr, ++ tid, add_ba_rsp->ssn, win_size); ++ } else { ++ dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n", ++ add_ba_rsp->peer_mac_addr, tid); ++ ++ rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, ++ tid, add_ba_rsp->peer_mac_addr); ++ if (rx_reor_tbl_ptr) ++ mwifiex_11n_delete_rx_reorder_tbl_entry(priv, ++ rx_reor_tbl_ptr); ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function handles BA stream timeout event by preparing and sending ++ * a command to the firmware. ++ */ ++void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, ++ struct host_cmd_ds_11n_batimeout *event) ++{ ++ struct host_cmd_ds_11n_delba delba; ++ ++ memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba)); ++ memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN); ++ ++ delba.del_ba_param_set |= ++ cpu_to_le16((u16) event->tid << DELBA_TID_POS); ++ delba.del_ba_param_set |= cpu_to_le16( ++ (u16) event->origninator << DELBA_INITIATOR_POS); ++ delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); ++ mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba); ++} ++ ++/* ++ * This function cleans up the Rx reorder table by deleting all the entries ++ * and re-initializing. ++ */ ++void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv) ++{ ++ struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); ++ list_for_each_entry_safe(del_tbl_ptr, tmp_node, ++ &priv->rx_reorder_tbl_ptr, list) { ++ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); ++ mwifiex_11n_delete_rx_reorder_tbl_entry(priv, del_tbl_ptr); ++ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); ++ } ++ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); ++ ++ INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); ++ memset(priv->rx_seq, 0, sizeof(priv->rx_seq)); ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/11n_rxreorder.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/11n_rxreorder.h +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/11n_rxreorder.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/11n_rxreorder.h 2011-05-05 23:29:45.440441321 +0200 +@@ -0,0 +1,65 @@ ++/* ++ * Marvell Wireless LAN device driver: 802.11n RX Re-ordering ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#ifndef _MWIFIEX_11N_RXREORDER_H_ ++#define _MWIFIEX_11N_RXREORDER_H_ ++ ++#define MIN_FLUSH_TIMER_MS 50 ++ ++#define PKT_TYPE_BAR 0xE7 ++#define MAX_TID_VALUE (2 << 11) ++#define TWOPOW11 (2 << 10) ++ ++#define BLOCKACKPARAM_TID_POS 2 ++#define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1 ++#define BLOCKACKPARAM_WINSIZE_POS 6 ++#define DELBA_TID_POS 12 ++#define DELBA_INITIATOR_POS 11 ++#define TYPE_DELBA_SENT 1 ++#define TYPE_DELBA_RECEIVE 2 ++#define IMMEDIATE_BLOCK_ACK 0x2 ++ ++#define ADDBA_RSP_STATUS_ACCEPT 0 ++ ++int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *, ++ u16 seqNum, ++ u16 tid, u8 *ta, ++ u8 pkttype, void *payload); ++void mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int Tid, ++ u8 *PeerMACAddr, u8 type, ++ int initiator); ++void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, ++ struct host_cmd_ds_11n_batimeout *event); ++int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, ++ struct host_cmd_ds_command ++ *resp); ++int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, ++ void *data_buf); ++int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, ++ struct host_cmd_ds_command ++ *cmd, void *data_buf); ++int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, ++ void *data_buf); ++void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv); ++struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct ++ mwifiex_private ++ *priv, int tid, ++ u8 *ta); ++ ++#endif /* _MWIFIEX_11N_RXREORDER_H_ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/cfg80211.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/cfg80211.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/cfg80211.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/cfg80211.c 2011-05-05 23:29:45.476441755 +0200 +@@ -0,0 +1,1421 @@ ++/* ++ * Marvell Wireless LAN device driver: CFG80211 ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "cfg80211.h" ++#include "main.h" ++ ++/* ++ * This function maps the nl802.11 channel type into driver channel type. ++ * ++ * The mapping is as follows - ++ * NL80211_CHAN_NO_HT -> NO_SEC_CHANNEL ++ * NL80211_CHAN_HT20 -> NO_SEC_CHANNEL ++ * NL80211_CHAN_HT40PLUS -> SEC_CHANNEL_ABOVE ++ * NL80211_CHAN_HT40MINUS -> SEC_CHANNEL_BELOW ++ * Others -> NO_SEC_CHANNEL ++ */ ++static int ++mwifiex_cfg80211_channel_type_to_mwifiex_channels(enum nl80211_channel_type ++ channel_type) ++{ ++ switch (channel_type) { ++ case NL80211_CHAN_NO_HT: ++ case NL80211_CHAN_HT20: ++ return NO_SEC_CHANNEL; ++ case NL80211_CHAN_HT40PLUS: ++ return SEC_CHANNEL_ABOVE; ++ case NL80211_CHAN_HT40MINUS: ++ return SEC_CHANNEL_BELOW; ++ default: ++ return NO_SEC_CHANNEL; ++ } ++} ++ ++/* ++ * This function maps the driver channel type into nl802.11 channel type. ++ * ++ * The mapping is as follows - ++ * NO_SEC_CHANNEL -> NL80211_CHAN_HT20 ++ * SEC_CHANNEL_ABOVE -> NL80211_CHAN_HT40PLUS ++ * SEC_CHANNEL_BELOW -> NL80211_CHAN_HT40MINUS ++ * Others -> NL80211_CHAN_HT20 ++ */ ++static enum nl80211_channel_type ++mwifiex_channels_to_cfg80211_channel_type(int channel_type) ++{ ++ switch (channel_type) { ++ case NO_SEC_CHANNEL: ++ return NL80211_CHAN_HT20; ++ case SEC_CHANNEL_ABOVE: ++ return NL80211_CHAN_HT40PLUS; ++ case SEC_CHANNEL_BELOW: ++ return NL80211_CHAN_HT40MINUS; ++ default: ++ return NL80211_CHAN_HT20; ++ } ++} ++ ++/* ++ * This function checks whether WEP is set. ++ */ ++static int ++mwifiex_is_alg_wep(u32 cipher) ++{ ++ int alg = 0; ++ ++ switch (cipher) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ case WLAN_CIPHER_SUITE_WEP104: ++ alg = 1; ++ break; ++ default: ++ alg = 0; ++ break; ++ } ++ return alg; ++} ++ ++/* ++ * This function retrieves the private structure from kernel wiphy structure. ++ */ ++static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy) ++{ ++ return (void *) (*(unsigned long *) wiphy_priv(wiphy)); ++} ++ ++/* ++ * CFG802.11 operation handler to delete a network key. ++ */ ++static int ++mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, ++ u8 key_index, bool pairwise, const u8 *mac_addr) ++{ ++ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); ++ ++ if (mwifiex_set_encode(priv, NULL, 0, key_index, 1)) { ++ wiphy_err(wiphy, "deleting the crypto keys\n"); ++ return -EFAULT; ++ } ++ ++ wiphy_dbg(wiphy, "info: crypto keys deleted\n"); ++ return 0; ++} ++ ++/* ++ * CFG802.11 operation handler to set Tx power. ++ */ ++static int ++mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, ++ enum nl80211_tx_power_setting type, ++ int dbm) ++{ ++ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); ++ struct mwifiex_power_cfg power_cfg; ++ ++ if (type == NL80211_TX_POWER_FIXED) { ++ power_cfg.is_power_auto = 0; ++ power_cfg.power_level = dbm; ++ } else { ++ power_cfg.is_power_auto = 1; ++ } ++ ++ return mwifiex_set_tx_power(priv, &power_cfg); ++} ++ ++/* ++ * CFG802.11 operation handler to set Power Save option. ++ * ++ * The timeout value, if provided, is currently ignored. ++ */ ++static int ++mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, ++ struct net_device *dev, ++ bool enabled, int timeout) ++{ ++ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); ++ u32 ps_mode; ++ ++ if (timeout) ++ wiphy_dbg(wiphy, ++ "info: ignoring the timeout value" ++ " for IEEE power save\n"); ++ ++ ps_mode = enabled; ++ ++ return mwifiex_drv_set_power(priv, &ps_mode); ++} ++ ++/* ++ * CFG802.11 operation handler to set the default network key. ++ */ ++static int ++mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, ++ u8 key_index, bool unicast, ++ bool multicast) ++{ ++ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); ++ ++ /* Return if WEP key not configured */ ++ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED) ++ return 0; ++ ++ if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) { ++ wiphy_err(wiphy, "set default Tx key index\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/* ++ * CFG802.11 operation handler to add a network key. ++ */ ++static int ++mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, ++ u8 key_index, bool pairwise, const u8 *mac_addr, ++ struct key_params *params) ++{ ++ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); ++ ++ if (mwifiex_set_encode(priv, params->key, params->key_len, ++ key_index, 0)) { ++ wiphy_err(wiphy, "crypto keys added\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function sends domain information to the firmware. ++ * ++ * The following information are passed to the firmware - ++ * - Country codes ++ * - Sub bands (first channel, number of channels, maximum Tx power) ++ */ ++static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) ++{ ++ u8 no_of_triplet = 0; ++ struct ieee80211_country_ie_triplet *t; ++ u8 no_of_parsed_chan = 0; ++ u8 first_chan = 0, next_chan = 0, max_pwr = 0; ++ u8 i, flag = 0; ++ enum ieee80211_band band; ++ struct ieee80211_supported_band *sband; ++ struct ieee80211_channel *ch; ++ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg; ++ ++ /* Set country code */ ++ domain_info->country_code[0] = priv->country_code[0]; ++ domain_info->country_code[1] = priv->country_code[1]; ++ domain_info->country_code[2] = ' '; ++ ++ band = mwifiex_band_to_radio_type(adapter->config_bands); ++ if (!wiphy->bands[band]) { ++ wiphy_err(wiphy, "11D: setting domain info in FW\n"); ++ return -1; ++ } ++ ++ sband = wiphy->bands[band]; ++ ++ for (i = 0; i < sband->n_channels ; i++) { ++ ch = &sband->channels[i]; ++ if (ch->flags & IEEE80211_CHAN_DISABLED) ++ continue; ++ ++ if (!flag) { ++ flag = 1; ++ first_chan = (u32) ch->hw_value; ++ next_chan = first_chan; ++ max_pwr = ch->max_power; ++ no_of_parsed_chan = 1; ++ continue; ++ } ++ ++ if (ch->hw_value == next_chan + 1 && ++ ch->max_power == max_pwr) { ++ next_chan++; ++ no_of_parsed_chan++; ++ } else { ++ t = &domain_info->triplet[no_of_triplet]; ++ t->chans.first_channel = first_chan; ++ t->chans.num_channels = no_of_parsed_chan; ++ t->chans.max_power = max_pwr; ++ no_of_triplet++; ++ first_chan = (u32) ch->hw_value; ++ next_chan = first_chan; ++ max_pwr = ch->max_power; ++ no_of_parsed_chan = 1; ++ } ++ } ++ ++ if (flag) { ++ t = &domain_info->triplet[no_of_triplet]; ++ t->chans.first_channel = first_chan; ++ t->chans.num_channels = no_of_parsed_chan; ++ t->chans.max_power = max_pwr; ++ no_of_triplet++; ++ } ++ ++ domain_info->no_of_triplet = no_of_triplet; ++ ++ if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, ++ HostCmd_ACT_GEN_SET, 0, NULL)) { ++ wiphy_err(wiphy, "11D: setting domain info in FW\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * CFG802.11 regulatory domain callback function. ++ * ++ * This function is called when the regulatory domain is changed due to the ++ * following reasons - ++ * - Set by driver ++ * - Set by system core ++ * - Set by user ++ * - Set bt Country IE ++ */ ++static int mwifiex_reg_notifier(struct wiphy *wiphy, ++ struct regulatory_request *request) ++{ ++ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); ++ ++ wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain" ++ " %c%c\n", request->alpha2[0], request->alpha2[1]); ++ ++ memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2)); ++ ++ switch (request->initiator) { ++ case NL80211_REGDOM_SET_BY_DRIVER: ++ case NL80211_REGDOM_SET_BY_CORE: ++ case NL80211_REGDOM_SET_BY_USER: ++ break; ++ /* Todo: apply driver specific changes in channel flags based ++ on the request initiator if necessary. */ ++ case NL80211_REGDOM_SET_BY_COUNTRY_IE: ++ break; ++ } ++ mwifiex_send_domain_info_cmd_fw(wiphy); ++ ++ return 0; ++} ++ ++/* ++ * This function sets the RF channel. ++ * ++ * This function creates multiple IOCTL requests, populates them accordingly ++ * and issues them to set the band/channel and frequency. ++ */ ++static int ++mwifiex_set_rf_channel(struct mwifiex_private *priv, ++ struct ieee80211_channel *chan, ++ enum nl80211_channel_type channel_type) ++{ ++ struct mwifiex_chan_freq_power cfp; ++ struct mwifiex_ds_band_cfg band_cfg; ++ u32 config_bands = 0; ++ struct wiphy *wiphy = priv->wdev->wiphy; ++ ++ if (chan) { ++ memset(&band_cfg, 0, sizeof(band_cfg)); ++ /* Set appropriate bands */ ++ if (chan->band == IEEE80211_BAND_2GHZ) ++ config_bands = BAND_B | BAND_G | BAND_GN; ++ else ++ config_bands = BAND_AN | BAND_A; ++ if (priv->bss_mode == NL80211_IFTYPE_STATION ++ || priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) { ++ band_cfg.config_bands = config_bands; ++ } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { ++ band_cfg.config_bands = config_bands; ++ band_cfg.adhoc_start_band = config_bands; ++ } ++ ++ band_cfg.sec_chan_offset = ++ mwifiex_cfg80211_channel_type_to_mwifiex_channels ++ (channel_type); ++ ++ if (mwifiex_set_radio_band_cfg(priv, &band_cfg)) ++ return -EFAULT; ++ ++ mwifiex_send_domain_info_cmd_fw(wiphy); ++ } ++ ++ wiphy_dbg(wiphy, "info: setting band %d, channel offset %d and " ++ "mode %d\n", config_bands, band_cfg.sec_chan_offset, ++ priv->bss_mode); ++ if (!chan) ++ return 0; ++ ++ memset(&cfp, 0, sizeof(cfp)); ++ cfp.freq = chan->center_freq; ++ cfp.channel = ieee80211_frequency_to_channel(chan->center_freq); ++ ++ if (mwifiex_bss_set_channel(priv, &cfp)) ++ return -EFAULT; ++ ++ return mwifiex_drv_change_adhoc_chan(priv, cfp.channel); ++} ++ ++/* ++ * CFG802.11 operation handler to set channel. ++ * ++ * This function can only be used when station is not connected. ++ */ ++static int ++mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, ++ struct ieee80211_channel *chan, ++ enum nl80211_channel_type channel_type) ++{ ++ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); ++ ++ if (priv->media_connected) { ++ wiphy_err(wiphy, "This setting is valid only when station " ++ "is not connected\n"); ++ return -EINVAL; ++ } ++ ++ return mwifiex_set_rf_channel(priv, chan, channel_type); ++} ++ ++/* ++ * This function sets the fragmentation threshold. ++ * ++ * The fragmentation threshold value must lie between MWIFIEX_FRAG_MIN_VALUE ++ * and MWIFIEX_FRAG_MAX_VALUE. ++ */ ++static int ++mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr) ++{ ++ int ret = 0; ++ ++ if (frag_thr < MWIFIEX_FRAG_MIN_VALUE ++ || frag_thr > MWIFIEX_FRAG_MAX_VALUE) ++ return -EINVAL; ++ ++ /* Send request to firmware */ ++ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, ++ HostCmd_ACT_GEN_SET, FRAG_THRESH_I, ++ &frag_thr); ++ ++ return ret; ++} ++ ++/* ++ * This function sets the RTS threshold. ++ ++ * The rts value must lie between MWIFIEX_RTS_MIN_VALUE ++ * and MWIFIEX_RTS_MAX_VALUE. ++ */ ++static int ++mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr) ++{ ++ if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE) ++ rts_thr = MWIFIEX_RTS_MAX_VALUE; ++ ++ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, ++ HostCmd_ACT_GEN_SET, RTS_THRESH_I, ++ &rts_thr); ++} ++ ++/* ++ * CFG802.11 operation handler to set wiphy parameters. ++ * ++ * This function can be used to set the RTS threshold and the ++ * Fragmentation threshold of the driver. ++ */ ++static int ++mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) ++{ ++ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); ++ ++ int ret = 0; ++ ++ if (changed & WIPHY_PARAM_RTS_THRESHOLD) { ++ ret = mwifiex_set_rts(priv, wiphy->rts_threshold); ++ if (ret) ++ return ret; ++ } ++ ++ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) ++ ret = mwifiex_set_frag(priv, wiphy->frag_threshold); ++ ++ return ret; ++} ++ ++/* ++ * CFG802.11 operation handler to change interface type. ++ */ ++static int ++mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, ++ struct net_device *dev, ++ enum nl80211_iftype type, u32 *flags, ++ struct vif_params *params) ++{ ++ int ret = 0; ++ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); ++ ++ if (priv->bss_mode == type) { ++ wiphy_warn(wiphy, "already set to required type\n"); ++ return 0; ++ } ++ ++ priv->bss_mode = type; ++ ++ switch (type) { ++ case NL80211_IFTYPE_ADHOC: ++ dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC; ++ wiphy_dbg(wiphy, "info: setting interface type to adhoc\n"); ++ break; ++ case NL80211_IFTYPE_STATION: ++ dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; ++ wiphy_dbg(wiphy, "info: setting interface type to managed\n"); ++ break; ++ case NL80211_IFTYPE_UNSPECIFIED: ++ dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; ++ wiphy_dbg(wiphy, "info: setting interface type to auto\n"); ++ return 0; ++ default: ++ wiphy_err(wiphy, "unknown interface type: %d\n", type); ++ return -EINVAL; ++ } ++ ++ mwifiex_deauthenticate(priv, NULL); ++ ++ priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; ++ ++ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE, ++ HostCmd_ACT_GEN_SET, 0, NULL); ++ ++ return ret; ++} ++ ++/* ++ * This function dumps the station information on a buffer. ++ * ++ * The following information are shown - ++ * - Total bytes transmitted ++ * - Total bytes received ++ * - Total packets transmitted ++ * - Total packets received ++ * - Signal quality level ++ * - Transmission rate ++ */ ++static int ++mwifiex_dump_station_info(struct mwifiex_private *priv, ++ struct station_info *sinfo) ++{ ++ struct mwifiex_ds_get_signal signal; ++ struct mwifiex_rate_cfg rate; ++ int ret = 0; ++ ++ sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | ++ STATION_INFO_RX_PACKETS | ++ STATION_INFO_TX_PACKETS ++ | STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE; ++ ++ /* Get signal information from the firmware */ ++ memset(&signal, 0, sizeof(struct mwifiex_ds_get_signal)); ++ if (mwifiex_get_signal_info(priv, &signal)) { ++ dev_err(priv->adapter->dev, "getting signal information\n"); ++ ret = -EFAULT; ++ } ++ ++ if (mwifiex_drv_get_data_rate(priv, &rate)) { ++ dev_err(priv->adapter->dev, "getting data rate\n"); ++ ret = -EFAULT; ++ } ++ ++ sinfo->rx_bytes = priv->stats.rx_bytes; ++ sinfo->tx_bytes = priv->stats.tx_bytes; ++ sinfo->rx_packets = priv->stats.rx_packets; ++ sinfo->tx_packets = priv->stats.tx_packets; ++ sinfo->signal = priv->w_stats.qual.level; ++ sinfo->txrate.legacy = rate.rate; ++ ++ return ret; ++} ++ ++/* ++ * CFG802.11 operation handler to get station information. ++ * ++ * This function only works in connected mode, and dumps the ++ * requested station information, if available. ++ */ ++static int ++mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, ++ u8 *mac, struct station_info *sinfo) ++{ ++ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); ++ ++ mwifiex_dump_station_info(priv, sinfo); ++ ++ if (!priv->media_connected) ++ return -ENOENT; ++ if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) ++ return -ENOENT; ++ ++ return mwifiex_dump_station_info(priv, sinfo); ++} ++ ++/* Supported rates to be advertised to the cfg80211 */ ++ ++static struct ieee80211_rate mwifiex_rates[] = { ++ {.bitrate = 10, .hw_value = 2, }, ++ {.bitrate = 20, .hw_value = 4, }, ++ {.bitrate = 55, .hw_value = 11, }, ++ {.bitrate = 110, .hw_value = 22, }, ++ {.bitrate = 220, .hw_value = 44, }, ++ {.bitrate = 60, .hw_value = 12, }, ++ {.bitrate = 90, .hw_value = 18, }, ++ {.bitrate = 120, .hw_value = 24, }, ++ {.bitrate = 180, .hw_value = 36, }, ++ {.bitrate = 240, .hw_value = 48, }, ++ {.bitrate = 360, .hw_value = 72, }, ++ {.bitrate = 480, .hw_value = 96, }, ++ {.bitrate = 540, .hw_value = 108, }, ++ {.bitrate = 720, .hw_value = 144, }, ++}; ++ ++/* Channel definitions to be advertised to cfg80211 */ ++ ++static struct ieee80211_channel mwifiex_channels_2ghz[] = { ++ {.center_freq = 2412, .hw_value = 1, }, ++ {.center_freq = 2417, .hw_value = 2, }, ++ {.center_freq = 2422, .hw_value = 3, }, ++ {.center_freq = 2427, .hw_value = 4, }, ++ {.center_freq = 2432, .hw_value = 5, }, ++ {.center_freq = 2437, .hw_value = 6, }, ++ {.center_freq = 2442, .hw_value = 7, }, ++ {.center_freq = 2447, .hw_value = 8, }, ++ {.center_freq = 2452, .hw_value = 9, }, ++ {.center_freq = 2457, .hw_value = 10, }, ++ {.center_freq = 2462, .hw_value = 11, }, ++ {.center_freq = 2467, .hw_value = 12, }, ++ {.center_freq = 2472, .hw_value = 13, }, ++ {.center_freq = 2484, .hw_value = 14, }, ++}; ++ ++static struct ieee80211_supported_band mwifiex_band_2ghz = { ++ .channels = mwifiex_channels_2ghz, ++ .n_channels = ARRAY_SIZE(mwifiex_channels_2ghz), ++ .bitrates = mwifiex_rates, ++ .n_bitrates = 14, ++}; ++ ++static struct ieee80211_channel mwifiex_channels_5ghz[] = { ++ {.center_freq = 5040, .hw_value = 8, }, ++ {.center_freq = 5060, .hw_value = 12, }, ++ {.center_freq = 5080, .hw_value = 16, }, ++ {.center_freq = 5170, .hw_value = 34, }, ++ {.center_freq = 5190, .hw_value = 38, }, ++ {.center_freq = 5210, .hw_value = 42, }, ++ {.center_freq = 5230, .hw_value = 46, }, ++ {.center_freq = 5180, .hw_value = 36, }, ++ {.center_freq = 5200, .hw_value = 40, }, ++ {.center_freq = 5220, .hw_value = 44, }, ++ {.center_freq = 5240, .hw_value = 48, }, ++ {.center_freq = 5260, .hw_value = 52, }, ++ {.center_freq = 5280, .hw_value = 56, }, ++ {.center_freq = 5300, .hw_value = 60, }, ++ {.center_freq = 5320, .hw_value = 64, }, ++ {.center_freq = 5500, .hw_value = 100, }, ++ {.center_freq = 5520, .hw_value = 104, }, ++ {.center_freq = 5540, .hw_value = 108, }, ++ {.center_freq = 5560, .hw_value = 112, }, ++ {.center_freq = 5580, .hw_value = 116, }, ++ {.center_freq = 5600, .hw_value = 120, }, ++ {.center_freq = 5620, .hw_value = 124, }, ++ {.center_freq = 5640, .hw_value = 128, }, ++ {.center_freq = 5660, .hw_value = 132, }, ++ {.center_freq = 5680, .hw_value = 136, }, ++ {.center_freq = 5700, .hw_value = 140, }, ++ {.center_freq = 5745, .hw_value = 149, }, ++ {.center_freq = 5765, .hw_value = 153, }, ++ {.center_freq = 5785, .hw_value = 157, }, ++ {.center_freq = 5805, .hw_value = 161, }, ++ {.center_freq = 5825, .hw_value = 165, }, ++}; ++ ++static struct ieee80211_supported_band mwifiex_band_5ghz = { ++ .channels = mwifiex_channels_5ghz, ++ .n_channels = ARRAY_SIZE(mwifiex_channels_5ghz), ++ .bitrates = mwifiex_rates - 4, ++ .n_bitrates = ARRAY_SIZE(mwifiex_rates) + 4, ++}; ++ ++ ++/* Supported crypto cipher suits to be advertised to cfg80211 */ ++ ++static const u32 mwifiex_cipher_suites[] = { ++ WLAN_CIPHER_SUITE_WEP40, ++ WLAN_CIPHER_SUITE_WEP104, ++ WLAN_CIPHER_SUITE_TKIP, ++ WLAN_CIPHER_SUITE_CCMP, ++}; ++ ++/* ++ * CFG802.11 operation handler for disconnection request. ++ * ++ * This function does not work when there is already a disconnection ++ * procedure going on. ++ */ ++static int ++mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, ++ u16 reason_code) ++{ ++ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); ++ ++ if (priv->disconnect) ++ return -EBUSY; ++ ++ priv->disconnect = 1; ++ if (mwifiex_deauthenticate(priv, NULL)) ++ return -EFAULT; ++ ++ wiphy_dbg(wiphy, "info: successfully disconnected from %pM:" ++ " reason code %d\n", priv->cfg_bssid, reason_code); ++ ++ queue_work(priv->workqueue, &priv->cfg_workqueue); ++ ++ return 0; ++} ++ ++/* ++ * This function informs the CFG802.11 subsystem of a new IBSS. ++ * ++ * The following information are sent to the CFG802.11 subsystem ++ * to register the new IBSS. If we do not register the new IBSS, ++ * a kernel panic will result. ++ * - SSID ++ * - SSID length ++ * - BSSID ++ * - Channel ++ */ ++static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) ++{ ++ struct ieee80211_channel *chan; ++ struct mwifiex_bss_info bss_info; ++ int ie_len = 0; ++ u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; ++ ++ if (mwifiex_get_bss_info(priv, &bss_info)) ++ return -1; ++ ++ ie_buf[0] = WLAN_EID_SSID; ++ ie_buf[1] = bss_info.ssid.ssid_len; ++ ++ memcpy(&ie_buf[sizeof(struct ieee_types_header)], ++ &bss_info.ssid.ssid, ++ bss_info.ssid.ssid_len); ++ ie_len = ie_buf[1] + sizeof(struct ieee_types_header); ++ ++ chan = __ieee80211_get_channel(priv->wdev->wiphy, ++ ieee80211_channel_to_frequency(bss_info.bss_chan, ++ priv->curr_bss_params.band)); ++ ++ cfg80211_inform_bss(priv->wdev->wiphy, chan, ++ bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, ++ 0, ie_buf, ie_len, 0, GFP_KERNEL); ++ memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); ++ ++ return 0; ++} ++ ++/* ++ * This function informs the CFG802.11 subsystem of a new BSS connection. ++ * ++ * The following information are sent to the CFG802.11 subsystem ++ * to register the new BSS connection. If we do not register the new BSS, ++ * a kernel panic will result. ++ * - MAC address ++ * - Capabilities ++ * - Beacon period ++ * - RSSI value ++ * - Channel ++ * - Supported rates IE ++ * - Extended capabilities IE ++ * - DS parameter set IE ++ * - HT Capability IE ++ * - Vendor Specific IE (221) ++ * - WPA IE ++ * - RSN IE ++ */ ++static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, ++ struct mwifiex_802_11_ssid *ssid) ++{ ++ struct mwifiex_scan_resp scan_resp; ++ struct mwifiex_bssdescriptor *scan_table; ++ int i, j; ++ struct ieee80211_channel *chan; ++ u8 *ie, *ie_buf; ++ u32 ie_len; ++ u8 *beacon; ++ int beacon_size; ++ u8 element_id, element_len; ++ ++ memset(&scan_resp, 0, sizeof(scan_resp)); ++ scan_resp.scan_table = (u8 *) priv->adapter->scan_table; ++ scan_resp.num_in_scan_table = priv->adapter->num_in_scan_table; ++ ++#define MAX_IE_BUF 2048 ++ ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); ++ if (!ie_buf) { ++ dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n", ++ __func__); ++ return -ENOMEM; ++ } ++ ++ scan_table = (struct mwifiex_bssdescriptor *) scan_resp.scan_table; ++ for (i = 0; i < scan_resp.num_in_scan_table; i++) { ++ if (ssid) { ++ /* Inform specific BSS only */ ++ if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, ++ ssid->ssid_len)) ++ continue; ++ } ++ memset(ie_buf, 0, MAX_IE_BUF); ++ ie_buf[0] = WLAN_EID_SSID; ++ ie_buf[1] = scan_table[i].ssid.ssid_len; ++ memcpy(&ie_buf[sizeof(struct ieee_types_header)], ++ scan_table[i].ssid.ssid, ie_buf[1]); ++ ++ ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header); ++ ie_len = ie_buf[1] + sizeof(struct ieee_types_header); ++ ++ ie[0] = WLAN_EID_SUPP_RATES; ++ ++ for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { ++ if (!scan_table[i].supported_rates[j]) ++ break; ++ else ++ ie[j + sizeof(struct ieee_types_header)] = ++ scan_table[i].supported_rates[j]; ++ } ++ ++ ie[1] = j; ++ ie_len += ie[1] + sizeof(struct ieee_types_header); ++ ++ beacon = scan_table[i].beacon_buf; ++ beacon_size = scan_table[i].beacon_buf_size; ++ ++ /* Skip time stamp, beacon interval and capability */ ++ ++ if (beacon) { ++ beacon += sizeof(scan_table[i].beacon_period) ++ + sizeof(scan_table[i].time_stamp) + ++ +sizeof(scan_table[i].cap_info_bitmap); ++ ++ beacon_size -= sizeof(scan_table[i].beacon_period) ++ + sizeof(scan_table[i].time_stamp) ++ + sizeof(scan_table[i].cap_info_bitmap); ++ } ++ ++ while (beacon_size >= sizeof(struct ieee_types_header)) { ++ ie = ie_buf + ie_len; ++ element_id = *beacon; ++ element_len = *(beacon + 1); ++ if (beacon_size < (int) element_len + ++ sizeof(struct ieee_types_header)) { ++ dev_err(priv->adapter->dev, "%s: in processing" ++ " IE, bytes left < IE length\n", ++ __func__); ++ break; ++ } ++ switch (element_id) { ++ case WLAN_EID_EXT_CAPABILITY: ++ case WLAN_EID_DS_PARAMS: ++ case WLAN_EID_HT_CAPABILITY: ++ case WLAN_EID_VENDOR_SPECIFIC: ++ case WLAN_EID_RSN: ++ case WLAN_EID_BSS_AC_ACCESS_DELAY: ++ ie[0] = element_id; ++ ie[1] = element_len; ++ memcpy(&ie[sizeof(struct ieee_types_header)], ++ (u8 *) beacon ++ + sizeof(struct ieee_types_header), ++ element_len); ++ ie_len += ie[1] + ++ sizeof(struct ieee_types_header); ++ break; ++ default: ++ break; ++ } ++ beacon += element_len + ++ sizeof(struct ieee_types_header); ++ beacon_size -= element_len + ++ sizeof(struct ieee_types_header); ++ } ++ chan = ieee80211_get_channel(priv->wdev->wiphy, ++ scan_table[i].freq); ++ cfg80211_inform_bss(priv->wdev->wiphy, chan, ++ scan_table[i].mac_address, ++ 0, scan_table[i].cap_info_bitmap, ++ scan_table[i].beacon_period, ++ ie_buf, ie_len, ++ scan_table[i].rssi, GFP_KERNEL); ++ } ++ ++ kfree(ie_buf); ++ return 0; ++} ++ ++/* ++ * This function connects with a BSS. ++ * ++ * This function handles both Infra and Ad-Hoc modes. It also performs ++ * validity checking on the provided parameters, disconnects from the ++ * current BSS (if any), sets up the association/scan parameters, ++ * including security settings, and performs specific SSID scan before ++ * trying to connect. ++ * ++ * For Infra mode, the function returns failure if the specified SSID ++ * is not found in scan table. However, for Ad-Hoc mode, it can create ++ * the IBSS if it does not exist. On successful completion in either case, ++ * the function notifies the CFG802.11 subsystem of the new BSS connection, ++ * otherwise the kernel will panic. ++ */ ++static int ++mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, ++ u8 *bssid, int mode, struct ieee80211_channel *channel, ++ struct cfg80211_connect_params *sme, bool privacy) ++{ ++ struct mwifiex_802_11_ssid req_ssid; ++ struct mwifiex_ssid_bssid ssid_bssid; ++ int ret = 0; ++ int auth_type = 0; ++ ++ memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); ++ memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); ++ ++ req_ssid.ssid_len = ssid_len; ++ if (ssid_len > IEEE80211_MAX_SSID_LEN) { ++ dev_err(priv->adapter->dev, "invalid SSID - aborting\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(req_ssid.ssid, ssid, ssid_len); ++ if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) { ++ dev_err(priv->adapter->dev, "invalid SSID - aborting\n"); ++ return -EINVAL; ++ } ++ ++ /* disconnect before try to associate */ ++ mwifiex_deauthenticate(priv, NULL); ++ ++ if (channel) ++ ret = mwifiex_set_rf_channel(priv, channel, ++ mwifiex_channels_to_cfg80211_channel_type ++ (priv->adapter->chan_offset)); ++ ++ ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); /* Disable keys */ ++ ++ if (mode == NL80211_IFTYPE_ADHOC) { ++ /* "privacy" is set only for ad-hoc mode */ ++ if (privacy) { ++ /* ++ * Keep WLAN_CIPHER_SUITE_WEP104 for now so that ++ * the firmware can find a matching network from the ++ * scan. The cfg80211 does not give us the encryption ++ * mode at this stage so just setting it to WEP here. ++ */ ++ priv->sec_info.encryption_mode = ++ WLAN_CIPHER_SUITE_WEP104; ++ priv->sec_info.authentication_mode = ++ NL80211_AUTHTYPE_OPEN_SYSTEM; ++ } ++ ++ goto done; ++ } ++ ++ /* Now handle infra mode. "sme" is valid for infra mode only */ ++ if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC ++ || sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) ++ auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; ++ else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) ++ auth_type = NL80211_AUTHTYPE_SHARED_KEY; ++ ++ if (sme->crypto.n_ciphers_pairwise) { ++ priv->sec_info.encryption_mode = ++ sme->crypto.ciphers_pairwise[0]; ++ priv->sec_info.authentication_mode = auth_type; ++ } ++ ++ if (sme->crypto.cipher_group) { ++ priv->sec_info.encryption_mode = sme->crypto.cipher_group; ++ priv->sec_info.authentication_mode = auth_type; ++ } ++ if (sme->ie) ++ ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len); ++ ++ if (sme->key) { ++ if (mwifiex_is_alg_wep(0) | mwifiex_is_alg_wep(0)) { ++ dev_dbg(priv->adapter->dev, ++ "info: setting wep encryption" ++ " with key len %d\n", sme->key_len); ++ ret = mwifiex_set_encode(priv, sme->key, sme->key_len, ++ sme->key_idx, 0); ++ } ++ } ++done: ++ /* Do specific SSID scanning */ ++ if (mwifiex_request_scan(priv, &req_ssid)) { ++ dev_err(priv->adapter->dev, "scan error\n"); ++ return -EFAULT; ++ } ++ ++ ++ memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid)); ++ ++ if (mode != NL80211_IFTYPE_ADHOC) { ++ if (mwifiex_find_best_bss(priv, &ssid_bssid)) ++ return -EFAULT; ++ /* Inform the BSS information to kernel, otherwise ++ * kernel will give a panic after successful assoc */ ++ if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid)) ++ return -EFAULT; ++ } ++ ++ dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", ++ (char *) req_ssid.ssid, ssid_bssid.bssid); ++ ++ memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6); ++ ++ /* Connect to BSS by ESSID */ ++ memset(&ssid_bssid.bssid, 0, ETH_ALEN); ++ ++ if (!netif_queue_stopped(priv->netdev)) ++ netif_stop_queue(priv->netdev); ++ ++ if (mwifiex_bss_start(priv, &ssid_bssid)) ++ return -EFAULT; ++ ++ if (mode == NL80211_IFTYPE_ADHOC) { ++ /* Inform the BSS information to kernel, otherwise ++ * kernel will give a panic after successful assoc */ ++ if (mwifiex_cfg80211_inform_ibss_bss(priv)) ++ return -EFAULT; ++ } ++ ++ return ret; ++} ++ ++/* ++ * CFG802.11 operation handler for association request. ++ * ++ * This function does not work when the current mode is set to Ad-Hoc, or ++ * when there is already an association procedure going on. The given BSS ++ * information is used to associate. ++ */ ++static int ++mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_connect_params *sme) ++{ ++ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); ++ int ret = 0; ++ ++ if (priv->assoc_request) ++ return -EBUSY; ++ ++ if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { ++ wiphy_err(wiphy, "received infra assoc request " ++ "when station is in ibss mode\n"); ++ goto done; ++ } ++ ++ priv->assoc_request = 1; ++ ++ wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", ++ (char *) sme->ssid, sme->bssid); ++ ++ ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, ++ priv->bss_mode, sme->channel, sme, 0); ++ ++done: ++ priv->assoc_result = ret; ++ queue_work(priv->workqueue, &priv->cfg_workqueue); ++ return ret; ++} ++ ++/* ++ * CFG802.11 operation handler to join an IBSS. ++ * ++ * This function does not work in any mode other than Ad-Hoc, or if ++ * a join operation is already in progress. ++ */ ++static int ++mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_ibss_params *params) ++{ ++ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); ++ int ret = 0; ++ ++ if (priv->ibss_join_request) ++ return -EBUSY; ++ ++ if (priv->bss_mode != NL80211_IFTYPE_ADHOC) { ++ wiphy_err(wiphy, "request to join ibss received " ++ "when station is not in ibss mode\n"); ++ goto done; ++ } ++ ++ priv->ibss_join_request = 1; ++ ++ wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n", ++ (char *) params->ssid, params->bssid); ++ ++ ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, ++ params->bssid, priv->bss_mode, ++ params->channel, NULL, params->privacy); ++done: ++ priv->ibss_join_result = ret; ++ queue_work(priv->workqueue, &priv->cfg_workqueue); ++ return ret; ++} ++ ++/* ++ * CFG802.11 operation handler to leave an IBSS. ++ * ++ * This function does not work if a leave operation is ++ * already in progress. ++ */ ++static int ++mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) ++{ ++ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); ++ ++ if (priv->disconnect) ++ return -EBUSY; ++ ++ priv->disconnect = 1; ++ ++ wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n", ++ priv->cfg_bssid); ++ if (mwifiex_deauthenticate(priv, NULL)) ++ return -EFAULT; ++ ++ queue_work(priv->workqueue, &priv->cfg_workqueue); ++ ++ return 0; ++} ++ ++/* ++ * CFG802.11 operation handler for scan request. ++ * ++ * This function issues a scan request to the firmware based upon ++ * the user specified scan configuration. On successfull completion, ++ * it also informs the results. ++ */ ++static int ++mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_scan_request *request) ++{ ++ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); ++ ++ wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); ++ ++ if (priv->scan_request && priv->scan_request != request) ++ return -EBUSY; ++ ++ priv->scan_request = request; ++ ++ queue_work(priv->workqueue, &priv->cfg_workqueue); ++ return 0; ++} ++ ++/* ++ * This function sets up the CFG802.11 specific HT capability fields ++ * with default values. ++ * ++ * The following default values are set - ++ * - HT Supported = True ++ * - Maximum AMPDU length factor = IEEE80211_HT_MAX_AMPDU_64K ++ * - Minimum AMPDU spacing = IEEE80211_HT_MPDU_DENSITY_NONE ++ * - HT Capabilities supported by firmware ++ * - MCS information, Rx mask = 0xff ++ * - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01) ++ */ ++static void ++mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, ++ struct mwifiex_private *priv) ++{ ++ int rx_mcs_supp; ++ struct ieee80211_mcs_info mcs_set; ++ u8 *mcs = (u8 *)&mcs_set; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ ++ ht_info->ht_supported = true; ++ ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ++ ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; ++ ++ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); ++ ++ /* Fill HT capability information */ ++ if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) ++ ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; ++ else ++ ht_info->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; ++ ++ if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap)) ++ ht_info->cap |= IEEE80211_HT_CAP_SGI_20; ++ else ++ ht_info->cap &= ~IEEE80211_HT_CAP_SGI_20; ++ ++ if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap)) ++ ht_info->cap |= IEEE80211_HT_CAP_SGI_40; ++ else ++ ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40; ++ ++ if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)) ++ ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; ++ else ++ ht_info->cap &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT); ++ ++ if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) ++ ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; ++ else ++ ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC; ++ ++ ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; ++ ht_info->cap |= IEEE80211_HT_CAP_SM_PS; ++ ++ rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); ++ /* Set MCS for 1x1 */ ++ memset(mcs, 0xff, rx_mcs_supp); ++ /* Clear all the other values */ ++ memset(&mcs[rx_mcs_supp], 0, ++ sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); ++ if (priv->bss_mode == NL80211_IFTYPE_STATION || ++ ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) ++ /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ ++ SETHT_MCS32(mcs_set.rx_mask); ++ ++ memcpy((u8 *) &ht_info->mcs, mcs, sizeof(struct ieee80211_mcs_info)); ++ ++ ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; ++} ++ ++/* station cfg80211 operations */ ++static struct cfg80211_ops mwifiex_cfg80211_ops = { ++ .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf, ++ .scan = mwifiex_cfg80211_scan, ++ .connect = mwifiex_cfg80211_connect, ++ .disconnect = mwifiex_cfg80211_disconnect, ++ .get_station = mwifiex_cfg80211_get_station, ++ .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params, ++ .set_channel = mwifiex_cfg80211_set_channel, ++ .join_ibss = mwifiex_cfg80211_join_ibss, ++ .leave_ibss = mwifiex_cfg80211_leave_ibss, ++ .add_key = mwifiex_cfg80211_add_key, ++ .del_key = mwifiex_cfg80211_del_key, ++ .set_default_key = mwifiex_cfg80211_set_default_key, ++ .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt, ++ .set_tx_power = mwifiex_cfg80211_set_tx_power, ++}; ++ ++/* ++ * This function registers the device with CFG802.11 subsystem. ++ * ++ * The function creates the wireless device/wiphy, populates it with ++ * default parameters and handler function pointers, and finally ++ * registers the device. ++ */ ++int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, ++ struct mwifiex_private *priv) ++{ ++ int ret = 0; ++ void *wdev_priv = NULL; ++ struct wireless_dev *wdev; ++ ++ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); ++ if (!wdev) { ++ dev_err(priv->adapter->dev, "%s: allocating wireless device\n", ++ __func__); ++ return -ENOMEM; ++ } ++ wdev->wiphy = ++ wiphy_new(&mwifiex_cfg80211_ops, ++ sizeof(struct mwifiex_private *)); ++ if (!wdev->wiphy) ++ return -ENOMEM; ++ wdev->iftype = NL80211_IFTYPE_STATION; ++ wdev->wiphy->max_scan_ssids = 10; ++ wdev->wiphy->interface_modes = ++ BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); ++ ++ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz; ++ mwifiex_setup_ht_caps( ++ &wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv); ++ ++ if (priv->adapter->config_bands & BAND_A) { ++ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; ++ mwifiex_setup_ht_caps( ++ &wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv); ++ } else { ++ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; ++ } ++ ++ /* Initialize cipher suits */ ++ wdev->wiphy->cipher_suites = mwifiex_cipher_suites; ++ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); ++ ++ memcpy(wdev->wiphy->perm_addr, mac, 6); ++ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; ++ ++ /* We are using custom domains */ ++ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; ++ ++ wdev->wiphy->reg_notifier = mwifiex_reg_notifier; ++ ++ /* Set struct mwifiex_private pointer in wiphy_priv */ ++ wdev_priv = wiphy_priv(wdev->wiphy); ++ ++ *(unsigned long *) wdev_priv = (unsigned long) priv; ++ ++ ret = wiphy_register(wdev->wiphy); ++ if (ret < 0) { ++ dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n", ++ __func__); ++ wiphy_free(wdev->wiphy); ++ return ret; ++ } else { ++ dev_dbg(priv->adapter->dev, ++ "info: successfully registered wiphy device\n"); ++ } ++ ++ dev_net_set(dev, wiphy_net(wdev->wiphy)); ++ dev->ieee80211_ptr = wdev; ++ memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6); ++ memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6); ++ SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); ++ priv->wdev = wdev; ++ ++ dev->flags |= IFF_BROADCAST | IFF_MULTICAST; ++ dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT; ++ dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN; ++ ++ return ret; ++} ++ ++/* ++ * This function handles the result of different pending network operations. ++ * ++ * The following operations are handled and CFG802.11 subsystem is ++ * notified accordingly - ++ * - Scan request completion ++ * - Association request completion ++ * - IBSS join request completion ++ * - Disconnect request completion ++ */ ++void ++mwifiex_cfg80211_results(struct work_struct *work) ++{ ++ struct mwifiex_private *priv = ++ container_of(work, struct mwifiex_private, cfg_workqueue); ++ struct mwifiex_user_scan_cfg *scan_req; ++ int ret = 0, i; ++ struct ieee80211_channel *chan; ++ ++ if (priv->scan_request) { ++ scan_req = kzalloc(sizeof(struct mwifiex_user_scan_cfg), ++ GFP_KERNEL); ++ if (!scan_req) { ++ dev_err(priv->adapter->dev, "failed to alloc " ++ "scan_req\n"); ++ return; ++ } ++ for (i = 0; i < priv->scan_request->n_ssids; i++) { ++ memcpy(scan_req->ssid_list[i].ssid, ++ priv->scan_request->ssids[i].ssid, ++ priv->scan_request->ssids[i].ssid_len); ++ scan_req->ssid_list[i].max_len = ++ priv->scan_request->ssids[i].ssid_len; ++ } ++ for (i = 0; i < priv->scan_request->n_channels; i++) { ++ chan = priv->scan_request->channels[i]; ++ scan_req->chan_list[i].chan_number = chan->hw_value; ++ scan_req->chan_list[i].radio_type = chan->band; ++ if (chan->flags & IEEE80211_CHAN_DISABLED) ++ scan_req->chan_list[i].scan_type = ++ MWIFIEX_SCAN_TYPE_PASSIVE; ++ else ++ scan_req->chan_list[i].scan_type = ++ MWIFIEX_SCAN_TYPE_ACTIVE; ++ scan_req->chan_list[i].scan_time = 0; ++ } ++ if (mwifiex_set_user_scan_ioctl(priv, scan_req)) { ++ ret = -EFAULT; ++ goto done; ++ } ++ if (mwifiex_inform_bss_from_scan_result(priv, NULL)) ++ ret = -EFAULT; ++done: ++ priv->scan_result_status = ret; ++ dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", ++ __func__); ++ cfg80211_scan_done(priv->scan_request, ++ (priv->scan_result_status < 0)); ++ priv->scan_request = NULL; ++ kfree(scan_req); ++ } ++ ++ if (priv->assoc_request) { ++ if (!priv->assoc_result) { ++ cfg80211_connect_result(priv->netdev, priv->cfg_bssid, ++ NULL, 0, NULL, 0, ++ WLAN_STATUS_SUCCESS, ++ GFP_KERNEL); ++ dev_dbg(priv->adapter->dev, ++ "info: associated to bssid %pM successfully\n", ++ priv->cfg_bssid); ++ } else { ++ dev_dbg(priv->adapter->dev, ++ "info: association to bssid %pM failed\n", ++ priv->cfg_bssid); ++ memset(priv->cfg_bssid, 0, ETH_ALEN); ++ } ++ priv->assoc_request = 0; ++ priv->assoc_result = 0; ++ } ++ ++ if (priv->ibss_join_request) { ++ if (!priv->ibss_join_result) { ++ cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, ++ GFP_KERNEL); ++ dev_dbg(priv->adapter->dev, ++ "info: joined/created adhoc network with bssid" ++ " %pM successfully\n", priv->cfg_bssid); ++ } else { ++ dev_dbg(priv->adapter->dev, ++ "info: failed creating/joining adhoc network\n"); ++ } ++ priv->ibss_join_request = 0; ++ priv->ibss_join_result = 0; ++ } ++ ++ if (priv->disconnect) { ++ memset(priv->cfg_bssid, 0, ETH_ALEN); ++ priv->disconnect = 0; ++ } ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/cfg80211.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/cfg80211.h +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/cfg80211.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/cfg80211.h 2011-05-05 23:29:45.474441731 +0200 +@@ -0,0 +1,31 @@ ++/* ++ * Marvell Wireless LAN device driver: CFG80211 ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#ifndef __MWIFIEX_CFG80211__ ++#define __MWIFIEX_CFG80211__ ++ ++#include ++ ++#include "main.h" ++ ++int mwifiex_register_cfg80211(struct net_device *, u8 *, ++ struct mwifiex_private *); ++ ++void mwifiex_cfg80211_results(struct work_struct *work); ++#endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/cfp.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/cfp.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/cfp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/cfp.c 2011-05-05 23:29:45.477441767 +0200 +@@ -0,0 +1,360 @@ ++/* ++ * Marvell Wireless LAN device driver: Channel, Frequence and Power ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "cfg80211.h" ++ ++/* 100mW */ ++#define MWIFIEX_TX_PWR_DEFAULT 20 ++/* 100mW */ ++#define MWIFIEX_TX_PWR_US_DEFAULT 20 ++/* 50mW */ ++#define MWIFIEX_TX_PWR_JP_DEFAULT 16 ++/* 100mW */ ++#define MWIFIEX_TX_PWR_FR_100MW 20 ++/* 10mW */ ++#define MWIFIEX_TX_PWR_FR_10MW 10 ++/* 100mW */ ++#define MWIFIEX_TX_PWR_EMEA_DEFAULT 20 ++ ++static u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 }; ++ ++static u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24, ++ 0xb0, 0x48, 0x60, 0x6c, 0 }; ++ ++static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, ++ 0x0c, 0x12, 0x18, 0x24, ++ 0x30, 0x48, 0x60, 0x6c, 0 }; ++ ++static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24, ++ 0xb0, 0x48, 0x60, 0x6c, 0 }; ++u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, ++ 0xb0, 0x48, 0x60, 0x6c, 0 }; ++static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04, ++ 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18, ++ 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90, ++ 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68, ++ 0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51, ++ 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 }; ++ ++u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 }; ++ ++u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, ++ 0x30, 0x48, 0x60, 0x6c, 0 }; ++ ++u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c, ++ 0x12, 0x16, 0x18, 0x24, 0x30, 0x48, ++ 0x60, 0x6c, 0 }; ++ ++u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, ++ 0x32, 0x40, 0x41, 0xff }; ++ ++u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; ++ ++/* ++ * This function maps an index in supported rates table into ++ * the corresponding data rate. ++ */ ++u32 mwifiex_index_to_data_rate(u8 index, u8 ht_info) ++{ ++ u16 mcs_rate[4][8] = { ++ {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e} ++ , /* LG 40M */ ++ {0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c} ++ , /* SG 40M */ ++ {0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82} ++ , /* LG 20M */ ++ {0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90} ++ }; /* SG 20M */ ++ ++ u32 rate; ++ ++ if (ht_info & BIT(0)) { ++ if (index == MWIFIEX_RATE_BITMAP_MCS0) { ++ if (ht_info & BIT(2)) ++ rate = 0x0D; /* MCS 32 SGI rate */ ++ else ++ rate = 0x0C; /* MCS 32 LGI rate */ ++ } else if (index < 8) { ++ if (ht_info & BIT(1)) { ++ if (ht_info & BIT(2)) ++ /* SGI, 40M */ ++ rate = mcs_rate[1][index]; ++ else ++ /* LGI, 40M */ ++ rate = mcs_rate[0][index]; ++ } else { ++ if (ht_info & BIT(2)) ++ /* SGI, 20M */ ++ rate = mcs_rate[3][index]; ++ else ++ /* LGI, 20M */ ++ rate = mcs_rate[2][index]; ++ } ++ } else ++ rate = mwifiex_data_rates[0]; ++ } else { ++ if (index >= MWIFIEX_SUPPORTED_RATES_EXT) ++ index = 0; ++ rate = mwifiex_data_rates[index]; ++ } ++ return rate; ++} ++ ++/* ++ * This function maps a data rate value into corresponding index in supported ++ * rates table. ++ */ ++u8 mwifiex_data_rate_to_index(u32 rate) ++{ ++ u16 *ptr; ++ ++ if (rate) { ++ ptr = memchr(mwifiex_data_rates, rate, ++ sizeof(mwifiex_data_rates)); ++ if (ptr) ++ return (u8) (ptr - mwifiex_data_rates); ++ } ++ return 0; ++} ++ ++/* ++ * This function returns the current active data rates. ++ * ++ * The result may vary depending upon connection status. ++ */ ++u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates) ++{ ++ if (!priv->media_connected) ++ return mwifiex_get_supported_rates(priv, rates); ++ else ++ return mwifiex_copy_rates(rates, 0, ++ priv->curr_bss_params.data_rates, ++ priv->curr_bss_params.num_of_rates); ++} ++ ++/* ++ * This function locates the Channel-Frequency-Power triplet based upon ++ * band and channel parameters. ++ */ ++struct mwifiex_chan_freq_power * ++mwifiex_get_cfp_by_band_and_channel_from_cfg80211(struct mwifiex_private ++ *priv, u8 band, u16 channel) ++{ ++ struct mwifiex_chan_freq_power *cfp = NULL; ++ struct ieee80211_supported_band *sband; ++ struct ieee80211_channel *ch; ++ int i; ++ ++ if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) ++ sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; ++ else ++ sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; ++ ++ if (!sband) { ++ dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" ++ " & channel %d\n", __func__, band, channel); ++ return cfp; ++ } ++ ++ for (i = 0; i < sband->n_channels; i++) { ++ ch = &sband->channels[i]; ++ if (((ch->hw_value == channel) || ++ (channel == FIRST_VALID_CHANNEL)) ++ && !(ch->flags & IEEE80211_CHAN_DISABLED)) { ++ priv->cfp.channel = channel; ++ priv->cfp.freq = ch->center_freq; ++ priv->cfp.max_tx_power = ch->max_power; ++ cfp = &priv->cfp; ++ break; ++ } ++ } ++ if (i == sband->n_channels) ++ dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" ++ " & channel %d\n", __func__, band, channel); ++ ++ return cfp; ++} ++ ++/* ++ * This function locates the Channel-Frequency-Power triplet based upon ++ * band and frequency parameters. ++ */ ++struct mwifiex_chan_freq_power * ++mwifiex_get_cfp_by_band_and_freq_from_cfg80211(struct mwifiex_private *priv, ++ u8 band, u32 freq) ++{ ++ struct mwifiex_chan_freq_power *cfp = NULL; ++ struct ieee80211_supported_band *sband; ++ struct ieee80211_channel *ch; ++ int i; ++ ++ if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) ++ sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; ++ else ++ sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; ++ ++ if (!sband) { ++ dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" ++ " & freq %d\n", __func__, band, freq); ++ return cfp; ++ } ++ ++ for (i = 0; i < sband->n_channels; i++) { ++ ch = &sband->channels[i]; ++ if ((ch->center_freq == freq) && ++ !(ch->flags & IEEE80211_CHAN_DISABLED)) { ++ priv->cfp.channel = ch->hw_value; ++ priv->cfp.freq = freq; ++ priv->cfp.max_tx_power = ch->max_power; ++ cfp = &priv->cfp; ++ break; ++ } ++ } ++ if (i == sband->n_channels) ++ dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" ++ " & freq %d\n", __func__, band, freq); ++ ++ return cfp; ++} ++ ++/* ++ * This function checks if the data rate is set to auto. ++ */ ++u8 ++mwifiex_is_rate_auto(struct mwifiex_private *priv) ++{ ++ u32 i; ++ int rate_num = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++) ++ if (priv->bitmap_rates[i]) ++ rate_num++; ++ ++ if (rate_num > 1) ++ return true; ++ else ++ return false; ++} ++ ++/* ++ * This function converts rate bitmap into rate index. ++ */ ++int mwifiex_get_rate_index(u16 *rate_bitmap, int size) ++{ ++ int i; ++ ++ for (i = 0; i < size * 8; i++) ++ if (rate_bitmap[i / 16] & (1 << (i % 16))) ++ return i; ++ ++ return 0; ++} ++ ++/* ++ * This function gets the supported data rates. ++ * ++ * The function works in both Ad-Hoc and infra mode by printing the ++ * band and returning the data rates. ++ */ ++u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) ++{ ++ u32 k = 0; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ if (priv->bss_mode == NL80211_IFTYPE_STATION) { ++ switch (adapter->config_bands) { ++ case BAND_B: ++ dev_dbg(adapter->dev, "info: infra band=%d " ++ "supported_rates_b\n", adapter->config_bands); ++ k = mwifiex_copy_rates(rates, k, supported_rates_b, ++ sizeof(supported_rates_b)); ++ break; ++ case BAND_G: ++ case BAND_G | BAND_GN: ++ dev_dbg(adapter->dev, "info: infra band=%d " ++ "supported_rates_g\n", adapter->config_bands); ++ k = mwifiex_copy_rates(rates, k, supported_rates_g, ++ sizeof(supported_rates_g)); ++ break; ++ case BAND_B | BAND_G: ++ case BAND_A | BAND_B | BAND_G: ++ case BAND_A | BAND_B: ++ case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN: ++ case BAND_B | BAND_G | BAND_GN: ++ dev_dbg(adapter->dev, "info: infra band=%d " ++ "supported_rates_bg\n", adapter->config_bands); ++ k = mwifiex_copy_rates(rates, k, supported_rates_bg, ++ sizeof(supported_rates_bg)); ++ break; ++ case BAND_A: ++ case BAND_A | BAND_G: ++ dev_dbg(adapter->dev, "info: infra band=%d " ++ "supported_rates_a\n", adapter->config_bands); ++ k = mwifiex_copy_rates(rates, k, supported_rates_a, ++ sizeof(supported_rates_a)); ++ break; ++ case BAND_A | BAND_AN: ++ case BAND_A | BAND_G | BAND_AN | BAND_GN: ++ dev_dbg(adapter->dev, "info: infra band=%d " ++ "supported_rates_a\n", adapter->config_bands); ++ k = mwifiex_copy_rates(rates, k, supported_rates_a, ++ sizeof(supported_rates_a)); ++ break; ++ case BAND_GN: ++ dev_dbg(adapter->dev, "info: infra band=%d " ++ "supported_rates_n\n", adapter->config_bands); ++ k = mwifiex_copy_rates(rates, k, supported_rates_n, ++ sizeof(supported_rates_n)); ++ break; ++ } ++ } else { ++ /* Ad-hoc mode */ ++ switch (adapter->adhoc_start_band) { ++ case BAND_B: ++ dev_dbg(adapter->dev, "info: adhoc B\n"); ++ k = mwifiex_copy_rates(rates, k, adhoc_rates_b, ++ sizeof(adhoc_rates_b)); ++ break; ++ case BAND_G: ++ case BAND_G | BAND_GN: ++ dev_dbg(adapter->dev, "info: adhoc G only\n"); ++ k = mwifiex_copy_rates(rates, k, adhoc_rates_g, ++ sizeof(adhoc_rates_g)); ++ break; ++ case BAND_B | BAND_G: ++ case BAND_B | BAND_G | BAND_GN: ++ dev_dbg(adapter->dev, "info: adhoc BG\n"); ++ k = mwifiex_copy_rates(rates, k, adhoc_rates_bg, ++ sizeof(adhoc_rates_bg)); ++ break; ++ case BAND_A: ++ case BAND_A | BAND_AN: ++ dev_dbg(adapter->dev, "info: adhoc A\n"); ++ k = mwifiex_copy_rates(rates, k, adhoc_rates_a, ++ sizeof(adhoc_rates_a)); ++ break; ++ } ++ } ++ ++ return k; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/cmdevt.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/cmdevt.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/cmdevt.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/cmdevt.c 2011-05-05 23:29:45.474441731 +0200 +@@ -0,0 +1,1415 @@ ++/* ++ * Marvell Wireless LAN device driver: commands and events ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++ ++/* ++ * This function initializes a command node. ++ * ++ * The actual allocation of the node is not done by this function. It only ++ * initiates a node by filling it with default parameters. Similarly, ++ * allocation of the different buffers used (IOCTL buffer, data buffer) are ++ * not done by this function either. ++ */ ++static void ++mwifiex_init_cmd_node(struct mwifiex_private *priv, ++ struct cmd_ctrl_node *cmd_node, ++ u32 cmd_oid, void *data_buf) ++{ ++ cmd_node->priv = priv; ++ cmd_node->cmd_oid = cmd_oid; ++ cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required; ++ priv->adapter->cmd_wait_q_required = false; ++ cmd_node->data_buf = data_buf; ++ cmd_node->cmd_skb = cmd_node->skb; ++} ++ ++/* ++ * This function returns a command node from the free queue depending upon ++ * availability. ++ */ ++static struct cmd_ctrl_node * ++mwifiex_get_cmd_node(struct mwifiex_adapter *adapter) ++{ ++ struct cmd_ctrl_node *cmd_node; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&adapter->cmd_free_q_lock, flags); ++ if (list_empty(&adapter->cmd_free_q)) { ++ dev_err(adapter->dev, "GET_CMD_NODE: cmd node not available\n"); ++ spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); ++ return NULL; ++ } ++ cmd_node = list_first_entry(&adapter->cmd_free_q, ++ struct cmd_ctrl_node, list); ++ list_del(&cmd_node->list); ++ spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); ++ ++ return cmd_node; ++} ++ ++/* ++ * This function cleans up a command node. ++ * ++ * The function resets the fields including the buffer pointers. ++ * This function does not try to free the buffers. They must be ++ * freed before calling this function. ++ * ++ * This function will however call the receive completion callback ++ * in case a response buffer is still available before resetting ++ * the pointer. ++ */ ++static void ++mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter, ++ struct cmd_ctrl_node *cmd_node) ++{ ++ cmd_node->cmd_oid = 0; ++ cmd_node->cmd_flag = 0; ++ cmd_node->data_buf = NULL; ++ cmd_node->wait_q_enabled = false; ++ ++ if (cmd_node->resp_skb) { ++ mwifiex_recv_complete(adapter, cmd_node->resp_skb, 0); ++ cmd_node->resp_skb = NULL; ++ } ++} ++ ++/* ++ * This function sends a host command to the firmware. ++ * ++ * The function copies the host command into the driver command ++ * buffer, which will be transferred to the firmware later by the ++ * main thread. ++ */ ++static int mwifiex_cmd_host_cmd(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, void *data_buf) ++{ ++ struct mwifiex_ds_misc_cmd *pcmd_ptr = ++ (struct mwifiex_ds_misc_cmd *) data_buf; ++ ++ /* Copy the HOST command to command buffer */ ++ memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len); ++ dev_dbg(priv->adapter->dev, "cmd: host cmd size = %d\n", pcmd_ptr->len); ++ return 0; ++} ++ ++/* ++ * This function downloads a command to the firmware. ++ * ++ * The function performs sanity tests, sets the command sequence ++ * number and size, converts the header fields to CPU format before ++ * sending. Afterwards, it logs the command ID and action for debugging ++ * and sets up the command timeout timer. ++ */ ++static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, ++ struct cmd_ctrl_node *cmd_node) ++{ ++ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ int ret = 0; ++ struct host_cmd_ds_command *host_cmd; ++ uint16_t cmd_code; ++ uint16_t cmd_size; ++ struct timeval tstamp; ++ unsigned long flags; ++ ++ if (!adapter || !cmd_node) ++ return -1; ++ ++ host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); ++ ++ /* Sanity test */ ++ if (host_cmd == NULL || host_cmd->size == 0) { ++ dev_err(adapter->dev, "DNLD_CMD: host_cmd is null" ++ " or cmd size is 0, not sending\n"); ++ if (cmd_node->wait_q_enabled) ++ adapter->cmd_wait_q.status = -1; ++ mwifiex_insert_cmd_to_free_q(adapter, cmd_node); ++ return -1; ++ } ++ ++ /* Set command sequence number */ ++ adapter->seq_num++; ++ host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO ++ (adapter->seq_num, cmd_node->priv->bss_num, ++ cmd_node->priv->bss_type)); ++ ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); ++ adapter->curr_cmd = cmd_node; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); ++ ++ cmd_code = le16_to_cpu(host_cmd->command); ++ cmd_size = le16_to_cpu(host_cmd->size); ++ ++ skb_trim(cmd_node->cmd_skb, cmd_size); ++ ++ do_gettimeofday(&tstamp); ++ dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d," ++ " seqno %#x\n", ++ tstamp.tv_sec, tstamp.tv_usec, cmd_code, ++ le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size, ++ le16_to_cpu(host_cmd->seq_num)); ++ ++ skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN); ++ ++ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, ++ cmd_node->cmd_skb->data, ++ cmd_node->cmd_skb->len, NULL); ++ ++ skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN); ++ ++ if (ret == -1) { ++ dev_err(adapter->dev, "DNLD_CMD: host to card failed\n"); ++ if (cmd_node->wait_q_enabled) ++ adapter->cmd_wait_q.status = -1; ++ mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); ++ ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); ++ adapter->curr_cmd = NULL; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); ++ ++ adapter->dbg.num_cmd_host_to_card_failure++; ++ return -1; ++ } ++ ++ /* Save the last command id and action to debug log */ ++ adapter->dbg.last_cmd_index = ++ (adapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM; ++ adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index] = cmd_code; ++ adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index] = ++ le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)); ++ ++ /* Clear BSS_NO_BITS from HostCmd */ ++ cmd_code &= HostCmd_CMD_ID_MASK; ++ ++ /* Setup the timer after transmit command */ ++ mod_timer(&adapter->cmd_timer, ++ jiffies + (MWIFIEX_TIMER_10S * HZ) / 1000); ++ ++ return 0; ++} ++ ++/* ++ * This function downloads a sleep confirm command to the firmware. ++ * ++ * The function performs sanity tests, sets the command sequence ++ * number and size, converts the header fields to CPU format before ++ * sending. ++ * ++ * No responses are needed for sleep confirm command. ++ */ ++static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) ++{ ++ int ret = 0; ++ u16 cmd_len = 0; ++ struct mwifiex_private *priv; ++ struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = ++ (struct mwifiex_opt_sleep_confirm_buffer *) ++ adapter->sleep_cfm->data; ++ cmd_len = sizeof(struct mwifiex_opt_sleep_confirm); ++ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); ++ ++ sleep_cfm_buf->ps_cfm_sleep.seq_num = ++ cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO ++ (adapter->seq_num, priv->bss_num, ++ priv->bss_type))); ++ adapter->seq_num++; ++ ++ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, ++ adapter->sleep_cfm->data, ++ adapter->sleep_cfm->len + ++ INTF_HEADER_LEN, NULL); ++ ++ if (ret == -1) { ++ dev_err(adapter->dev, "SLEEP_CFM: failed\n"); ++ adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++; ++ return -1; ++ } ++ if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY)) ++ == MWIFIEX_BSS_ROLE_STA) { ++ if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl) ++ /* Response is not needed for sleep ++ confirm command */ ++ adapter->ps_state = PS_STATE_SLEEP; ++ else ++ adapter->ps_state = PS_STATE_SLEEP_CFM; ++ ++ if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl ++ && (adapter->is_hs_configured ++ && !adapter->sleep_period.period)) { ++ adapter->pm_wakeup_card_req = true; ++ mwifiex_hs_activated_event(mwifiex_get_priv(adapter, ++ MWIFIEX_BSS_ROLE_STA), true); ++ } ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function allocates the command buffers and links them to ++ * the command free queue. ++ * ++ * The driver uses a pre allocated number of command buffers, which ++ * are created at driver initializations and freed at driver cleanup. ++ * Every command needs to obtain a command buffer from this pool before ++ * it can be issued. The command free queue lists the command buffers ++ * currently free to use, while the command pending queue lists the ++ * command buffers already in use and awaiting handling. Command buffers ++ * are returned to the free queue after use. ++ */ ++int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter) ++{ ++ struct cmd_ctrl_node *cmd_array; ++ u32 buf_size; ++ u32 i; ++ ++ /* Allocate and initialize struct cmd_ctrl_node */ ++ buf_size = sizeof(struct cmd_ctrl_node) * MWIFIEX_NUM_OF_CMD_BUFFER; ++ cmd_array = kzalloc(buf_size, GFP_KERNEL); ++ if (!cmd_array) { ++ dev_err(adapter->dev, "%s: failed to alloc cmd_array\n", ++ __func__); ++ return -1; ++ } ++ ++ adapter->cmd_pool = cmd_array; ++ memset(adapter->cmd_pool, 0, buf_size); ++ ++ /* Allocate and initialize command buffers */ ++ for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) { ++ cmd_array[i].skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER); ++ if (!cmd_array[i].skb) { ++ dev_err(adapter->dev, "ALLOC_CMD_BUF: out of memory\n"); ++ return -1; ++ } ++ } ++ ++ for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) ++ mwifiex_insert_cmd_to_free_q(adapter, &cmd_array[i]); ++ ++ return 0; ++} ++ ++/* ++ * This function frees the command buffers. ++ * ++ * The function calls the completion callback for all the command ++ * buffers that still have response buffers associated with them. ++ */ ++int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) ++{ ++ struct cmd_ctrl_node *cmd_array; ++ u32 i; ++ ++ /* Need to check if cmd pool is allocated or not */ ++ if (!adapter->cmd_pool) { ++ dev_dbg(adapter->dev, "info: FREE_CMD_BUF: cmd_pool is null\n"); ++ return 0; ++ } ++ ++ cmd_array = adapter->cmd_pool; ++ ++ /* Release shared memory buffers */ ++ for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) { ++ if (cmd_array[i].skb) { ++ dev_dbg(adapter->dev, "cmd: free cmd buffer %d\n", i); ++ dev_kfree_skb_any(cmd_array[i].skb); ++ } ++ if (!cmd_array[i].resp_skb) ++ continue; ++ mwifiex_recv_complete(adapter, cmd_array[i].resp_skb, 0); ++ } ++ /* Release struct cmd_ctrl_node */ ++ if (adapter->cmd_pool) { ++ dev_dbg(adapter->dev, "cmd: free cmd pool\n"); ++ kfree(adapter->cmd_pool); ++ adapter->cmd_pool = NULL; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function handles events generated by firmware. ++ * ++ * Event body of events received from firmware are not used (though they are ++ * saved), only the event ID is used. Some events are re-invoked by ++ * the driver, with a new event body. ++ * ++ * After processing, the function calls the completion callback ++ * for cleanup. ++ */ ++int mwifiex_process_event(struct mwifiex_adapter *adapter) ++{ ++ int ret = 0; ++ struct mwifiex_private *priv = ++ mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); ++ struct sk_buff *skb = adapter->event_skb; ++ u32 eventcause = adapter->event_cause; ++ struct timeval tstamp; ++ struct mwifiex_rxinfo *rx_info = NULL; ++ ++ /* Save the last event to debug log */ ++ adapter->dbg.last_event_index = ++ (adapter->dbg.last_event_index + 1) % DBG_CMD_NUM; ++ adapter->dbg.last_event[adapter->dbg.last_event_index] = ++ (u16) eventcause; ++ ++ /* Get BSS number and corresponding priv */ ++ priv = mwifiex_get_priv_by_id(adapter, EVENT_GET_BSS_NUM(eventcause), ++ EVENT_GET_BSS_TYPE(eventcause)); ++ if (!priv) ++ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); ++ /* Clear BSS_NO_BITS from event */ ++ eventcause &= EVENT_ID_MASK; ++ adapter->event_cause = eventcause; ++ ++ if (skb) { ++ rx_info = MWIFIEX_SKB_RXCB(skb); ++ rx_info->bss_index = priv->bss_index; ++ } ++ ++ if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) { ++ do_gettimeofday(&tstamp); ++ dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n", ++ tstamp.tv_sec, tstamp.tv_usec, eventcause); ++ } ++ ++ ret = mwifiex_process_sta_event(priv); ++ ++ adapter->event_cause = 0; ++ adapter->event_skb = NULL; ++ ++ mwifiex_recv_complete(adapter, skb, 0); ++ ++ return ret; ++} ++ ++/* ++ * This function is used to send synchronous command to the firmware. ++ * ++ * it allocates a wait queue for the command and wait for the command ++ * response. ++ */ ++int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, ++ u16 cmd_action, u32 cmd_oid, void *data_buf) ++{ ++ int ret = 0; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ ++ adapter->cmd_wait_q_required = true; ++ adapter->cmd_wait_q.condition = false; ++ ++ ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid, ++ data_buf); ++ if (!ret) ++ ret = mwifiex_wait_queue_complete(adapter); ++ ++ return ret; ++} ++ ++ ++/* ++ * This function prepares a command and asynchronously send it to the firmware. ++ * ++ * Preparation includes - ++ * - Sanity tests to make sure the card is still present or the FW ++ * is not reset ++ * - Getting a new command node from the command free queue ++ * - Initializing the command node for default parameters ++ * - Fill up the non-default parameters and buffer pointers ++ * - Add the command to pending queue ++ */ ++int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, ++ u16 cmd_action, u32 cmd_oid, void *data_buf) ++{ ++ int ret = 0; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct cmd_ctrl_node *cmd_node = NULL; ++ struct host_cmd_ds_command *cmd_ptr = NULL; ++ ++ if (!adapter) { ++ pr_err("PREP_CMD: adapter is NULL\n"); ++ return -1; ++ } ++ ++ if (adapter->is_suspended) { ++ dev_err(adapter->dev, "PREP_CMD: device in suspended state\n"); ++ return -1; ++ } ++ ++ if (adapter->surprise_removed) { ++ dev_err(adapter->dev, "PREP_CMD: card is removed\n"); ++ return -1; ++ } ++ ++ if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) { ++ if (cmd_no != HostCmd_CMD_FUNC_INIT) { ++ dev_err(adapter->dev, "PREP_CMD: FW in reset state\n"); ++ return -1; ++ } ++ } ++ ++ /* Get a new command node */ ++ cmd_node = mwifiex_get_cmd_node(adapter); ++ ++ if (!cmd_node) { ++ dev_err(adapter->dev, "PREP_CMD: no free cmd node\n"); ++ return -1; ++ } ++ ++ /* Initialize the command node */ ++ mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf); ++ ++ if (!cmd_node->cmd_skb) { ++ dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n"); ++ return -1; ++ } ++ ++ memset(skb_put(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)), ++ 0, sizeof(struct host_cmd_ds_command)); ++ ++ cmd_ptr = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); ++ cmd_ptr->command = cpu_to_le16(cmd_no); ++ cmd_ptr->result = 0; ++ ++ /* Prepare command */ ++ if (cmd_no) { ++ ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action, ++ cmd_oid, data_buf, cmd_ptr); ++ } else { ++ ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf); ++ cmd_node->cmd_flag |= CMD_F_HOSTCMD; ++ } ++ ++ /* Return error, since the command preparation failed */ ++ if (ret) { ++ dev_err(adapter->dev, "PREP_CMD: cmd %#x preparation failed\n", ++ cmd_no); ++ mwifiex_insert_cmd_to_free_q(adapter, cmd_node); ++ return -1; ++ } ++ ++ /* Send command */ ++ if (cmd_no == HostCmd_CMD_802_11_SCAN) ++ mwifiex_queue_scan_cmd(priv, cmd_node); ++ else ++ mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); ++ ++ return ret; ++} ++ ++/* ++ * This function returns a command to the command free queue. ++ * ++ * The function also calls the completion callback if required, before ++ * cleaning the command node and re-inserting it into the free queue. ++ */ ++void ++mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, ++ struct cmd_ctrl_node *cmd_node) ++{ ++ unsigned long flags; ++ ++ if (!cmd_node) ++ return; ++ ++ if (cmd_node->wait_q_enabled) ++ mwifiex_complete_cmd(adapter); ++ /* Clean the node */ ++ mwifiex_clean_cmd_node(adapter, cmd_node); ++ ++ /* Insert node into cmd_free_q */ ++ spin_lock_irqsave(&adapter->cmd_free_q_lock, flags); ++ list_add_tail(&cmd_node->list, &adapter->cmd_free_q); ++ spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); ++} ++ ++/* ++ * This function queues a command to the command pending queue. ++ * ++ * This in effect adds the command to the command list to be executed. ++ * Exit PS command is handled specially, by placing it always to the ++ * front of the command queue. ++ */ ++void ++mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, ++ struct cmd_ctrl_node *cmd_node, u32 add_tail) ++{ ++ struct host_cmd_ds_command *host_cmd = NULL; ++ u16 command; ++ unsigned long flags; ++ ++ host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); ++ if (!host_cmd) { ++ dev_err(adapter->dev, "QUEUE_CMD: host_cmd is NULL\n"); ++ return; ++ } ++ ++ command = le16_to_cpu(host_cmd->command); ++ ++ /* Exit_PS command needs to be queued in the header always. */ ++ if (command == HostCmd_CMD_802_11_PS_MODE_ENH) { ++ struct host_cmd_ds_802_11_ps_mode_enh *pm = ++ &host_cmd->params.psmode_enh; ++ if ((le16_to_cpu(pm->action) == DIS_PS) ++ || (le16_to_cpu(pm->action) == DIS_AUTO_PS)) { ++ if (adapter->ps_state != PS_STATE_AWAKE) ++ add_tail = false; ++ } ++ } ++ ++ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); ++ if (add_tail) ++ list_add_tail(&cmd_node->list, &adapter->cmd_pending_q); ++ else ++ list_add(&cmd_node->list, &adapter->cmd_pending_q); ++ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); ++ ++ dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command); ++} ++ ++/* ++ * This function executes the next command in command pending queue. ++ * ++ * This function will fail if a command is already in processing stage, ++ * otherwise it will dequeue the first command from the command pending ++ * queue and send to the firmware. ++ * ++ * If the device is currently in host sleep mode, any commands, except the ++ * host sleep configuration command will de-activate the host sleep. For PS ++ * mode, the function will put the firmware back to sleep if applicable. ++ */ ++int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter) ++{ ++ struct mwifiex_private *priv = NULL; ++ struct cmd_ctrl_node *cmd_node = NULL; ++ int ret = 0; ++ struct host_cmd_ds_command *host_cmd; ++ unsigned long cmd_flags; ++ unsigned long cmd_pending_q_flags; ++ ++ /* Check if already in processing */ ++ if (adapter->curr_cmd) { ++ dev_err(adapter->dev, "EXEC_NEXT_CMD: cmd in processing\n"); ++ return -1; ++ } ++ ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); ++ /* Check if any command is pending */ ++ spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); ++ if (list_empty(&adapter->cmd_pending_q)) { ++ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, ++ cmd_pending_q_flags); ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); ++ return 0; ++ } ++ cmd_node = list_first_entry(&adapter->cmd_pending_q, ++ struct cmd_ctrl_node, list); ++ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, ++ cmd_pending_q_flags); ++ ++ host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); ++ priv = cmd_node->priv; ++ ++ if (adapter->ps_state != PS_STATE_AWAKE) { ++ dev_err(adapter->dev, "%s: cannot send cmd in sleep state," ++ " this should not happen\n", __func__); ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); ++ return ret; ++ } ++ ++ spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); ++ list_del(&cmd_node->list); ++ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, ++ cmd_pending_q_flags); ++ ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); ++ ret = mwifiex_dnld_cmd_to_fw(priv, cmd_node); ++ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); ++ /* Any command sent to the firmware when host is in sleep ++ * mode should de-configure host sleep. We should skip the ++ * host sleep configuration command itself though ++ */ ++ if (priv && (host_cmd->command != ++ cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) { ++ if (adapter->hs_activated) { ++ adapter->is_hs_configured = false; ++ mwifiex_hs_activated_event(priv, false); ++ } ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function handles the command response. ++ * ++ * After processing, the function cleans the command node and puts ++ * it back to the command free queue. ++ */ ++int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) ++{ ++ struct host_cmd_ds_command *resp = NULL; ++ struct mwifiex_private *priv = ++ mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); ++ int ret = 0; ++ uint16_t orig_cmdresp_no; ++ uint16_t cmdresp_no; ++ uint16_t cmdresp_result; ++ struct timeval tstamp; ++ unsigned long flags; ++ ++ /* Now we got response from FW, cancel the command timer */ ++ del_timer(&adapter->cmd_timer); ++ ++ if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) { ++ resp = (struct host_cmd_ds_command *) adapter->upld_buf; ++ dev_err(adapter->dev, "CMD_RESP: NULL curr_cmd, %#x\n", ++ le16_to_cpu(resp->command)); ++ return -1; ++ } ++ ++ adapter->num_cmd_timeout = 0; ++ ++ resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data; ++ if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { ++ dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n", ++ le16_to_cpu(resp->command)); ++ mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); ++ adapter->curr_cmd = NULL; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); ++ return -1; ++ } ++ ++ if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { ++ /* Copy original response back to response buffer */ ++ struct mwifiex_ds_misc_cmd *hostcmd = NULL; ++ uint16_t size = le16_to_cpu(resp->size); ++ dev_dbg(adapter->dev, "info: host cmd resp size = %d\n", size); ++ size = min_t(u16, size, MWIFIEX_SIZE_OF_CMD_BUFFER); ++ if (adapter->curr_cmd->data_buf) { ++ hostcmd = (struct mwifiex_ds_misc_cmd *) ++ adapter->curr_cmd->data_buf; ++ hostcmd->len = size; ++ memcpy(hostcmd->cmd, (void *) resp, size); ++ } ++ } ++ orig_cmdresp_no = le16_to_cpu(resp->command); ++ ++ /* Get BSS number and corresponding priv */ ++ priv = mwifiex_get_priv_by_id(adapter, ++ HostCmd_GET_BSS_NO(le16_to_cpu(resp->seq_num)), ++ HostCmd_GET_BSS_TYPE(le16_to_cpu(resp->seq_num))); ++ if (!priv) ++ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); ++ /* Clear RET_BIT from HostCmd */ ++ resp->command = cpu_to_le16(orig_cmdresp_no & HostCmd_CMD_ID_MASK); ++ ++ cmdresp_no = le16_to_cpu(resp->command); ++ cmdresp_result = le16_to_cpu(resp->result); ++ ++ /* Save the last command response to debug log */ ++ adapter->dbg.last_cmd_resp_index = ++ (adapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM; ++ adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] = ++ orig_cmdresp_no; ++ ++ do_gettimeofday(&tstamp); ++ dev_dbg(adapter->dev, "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d," ++ " len %d, seqno 0x%x\n", ++ tstamp.tv_sec, tstamp.tv_usec, orig_cmdresp_no, cmdresp_result, ++ le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num)); ++ ++ if (!(orig_cmdresp_no & HostCmd_RET_BIT)) { ++ dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n"); ++ if (adapter->curr_cmd->wait_q_enabled) ++ adapter->cmd_wait_q.status = -1; ++ ++ mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); ++ adapter->curr_cmd = NULL; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); ++ return -1; ++ } ++ ++ if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { ++ adapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD; ++ if ((cmdresp_result == HostCmd_RESULT_OK) ++ && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH)) ++ ret = mwifiex_ret_802_11_hs_cfg(priv, resp); ++ } else { ++ /* handle response */ ++ ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp); ++ } ++ ++ /* Check init command response */ ++ if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) { ++ if (ret == -1) { ++ dev_err(adapter->dev, "%s: cmd %#x failed during " ++ "initialization\n", __func__, cmdresp_no); ++ mwifiex_init_fw_complete(adapter); ++ return -1; ++ } else if (adapter->last_init_cmd == cmdresp_no) ++ adapter->hw_status = MWIFIEX_HW_STATUS_INIT_DONE; ++ } ++ ++ if (adapter->curr_cmd) { ++ if (adapter->curr_cmd->wait_q_enabled && (!ret)) ++ adapter->cmd_wait_q.status = 0; ++ else if (adapter->curr_cmd->wait_q_enabled && (ret == -1)) ++ adapter->cmd_wait_q.status = -1; ++ ++ /* Clean up and put current command back to cmd_free_q */ ++ mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); ++ ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); ++ adapter->curr_cmd = NULL; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function handles the timeout of command sending. ++ * ++ * It will re-send the same command again. ++ */ ++void ++mwifiex_cmd_timeout_func(unsigned long function_context) ++{ ++ struct mwifiex_adapter *adapter = ++ (struct mwifiex_adapter *) function_context; ++ struct cmd_ctrl_node *cmd_node = NULL; ++ struct timeval tstamp; ++ ++ adapter->num_cmd_timeout++; ++ adapter->dbg.num_cmd_timeout++; ++ if (!adapter->curr_cmd) { ++ dev_dbg(adapter->dev, "cmd: empty curr_cmd\n"); ++ return; ++ } ++ cmd_node = adapter->curr_cmd; ++ if (cmd_node->wait_q_enabled) ++ adapter->cmd_wait_q.status = -ETIMEDOUT; ++ ++ if (cmd_node) { ++ adapter->dbg.timeout_cmd_id = ++ adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; ++ adapter->dbg.timeout_cmd_act = ++ adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index]; ++ do_gettimeofday(&tstamp); ++ dev_err(adapter->dev, "%s: Timeout cmd id (%lu.%lu) = %#x," ++ " act = %#x\n", __func__, ++ tstamp.tv_sec, tstamp.tv_usec, ++ adapter->dbg.timeout_cmd_id, ++ adapter->dbg.timeout_cmd_act); ++ ++ dev_err(adapter->dev, "num_data_h2c_failure = %d\n", ++ adapter->dbg.num_tx_host_to_card_failure); ++ dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n", ++ adapter->dbg.num_cmd_host_to_card_failure); ++ ++ dev_err(adapter->dev, "num_cmd_timeout = %d\n", ++ adapter->dbg.num_cmd_timeout); ++ dev_err(adapter->dev, "num_tx_timeout = %d\n", ++ adapter->dbg.num_tx_timeout); ++ ++ dev_err(adapter->dev, "last_cmd_index = %d\n", ++ adapter->dbg.last_cmd_index); ++ print_hex_dump_bytes("last_cmd_id: ", DUMP_PREFIX_OFFSET, ++ adapter->dbg.last_cmd_id, DBG_CMD_NUM); ++ print_hex_dump_bytes("last_cmd_act: ", DUMP_PREFIX_OFFSET, ++ adapter->dbg.last_cmd_act, DBG_CMD_NUM); ++ ++ dev_err(adapter->dev, "last_cmd_resp_index = %d\n", ++ adapter->dbg.last_cmd_resp_index); ++ print_hex_dump_bytes("last_cmd_resp_id: ", DUMP_PREFIX_OFFSET, ++ adapter->dbg.last_cmd_resp_id, DBG_CMD_NUM); ++ ++ dev_err(adapter->dev, "last_event_index = %d\n", ++ adapter->dbg.last_event_index); ++ print_hex_dump_bytes("last_event: ", DUMP_PREFIX_OFFSET, ++ adapter->dbg.last_event, DBG_CMD_NUM); ++ ++ dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n", ++ adapter->data_sent, adapter->cmd_sent); ++ ++ dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n", ++ adapter->ps_mode, adapter->ps_state); ++ } ++ if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) ++ mwifiex_init_fw_complete(adapter); ++} ++ ++/* ++ * This function cancels all the pending commands. ++ * ++ * The current command, all commands in command pending queue and all scan ++ * commands in scan pending queue are cancelled. All the completion callbacks ++ * are called with failure status to ensure cleanup. ++ */ ++void ++mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) ++{ ++ struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; ++ unsigned long flags; ++ ++ /* Cancel current cmd */ ++ if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) { ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); ++ adapter->curr_cmd->wait_q_enabled = false; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); ++ adapter->cmd_wait_q.status = -1; ++ mwifiex_complete_cmd(adapter); ++ } ++ /* Cancel all pending command */ ++ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); ++ list_for_each_entry_safe(cmd_node, tmp_node, ++ &adapter->cmd_pending_q, list) { ++ list_del(&cmd_node->list); ++ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); ++ ++ if (cmd_node->wait_q_enabled) { ++ adapter->cmd_wait_q.status = -1; ++ mwifiex_complete_cmd(adapter); ++ cmd_node->wait_q_enabled = false; ++ } ++ mwifiex_insert_cmd_to_free_q(adapter, cmd_node); ++ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); ++ } ++ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); ++ ++ /* Cancel all pending scan command */ ++ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); ++ list_for_each_entry_safe(cmd_node, tmp_node, ++ &adapter->scan_pending_q, list) { ++ list_del(&cmd_node->list); ++ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); ++ ++ cmd_node->wait_q_enabled = false; ++ mwifiex_insert_cmd_to_free_q(adapter, cmd_node); ++ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); ++ } ++ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); ++ ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); ++ adapter->scan_processing = false; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); ++} ++ ++/* ++ * This function cancels all pending commands that matches with ++ * the given IOCTL request. ++ * ++ * Both the current command buffer and the pending command queue are ++ * searched for matching IOCTL request. The completion callback of ++ * the matched command is called with failure status to ensure cleanup. ++ * In case of scan commands, all pending commands in scan pending queue ++ * are cancelled. ++ */ ++void ++mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) ++{ ++ struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; ++ unsigned long cmd_flags; ++ unsigned long cmd_pending_q_flags; ++ unsigned long scan_pending_q_flags; ++ uint16_t cancel_scan_cmd = false; ++ ++ if ((adapter->curr_cmd) && ++ (adapter->curr_cmd->wait_q_enabled)) { ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); ++ cmd_node = adapter->curr_cmd; ++ cmd_node->wait_q_enabled = false; ++ cmd_node->cmd_flag |= CMD_F_CANCELED; ++ spin_lock_irqsave(&adapter->cmd_pending_q_lock, ++ cmd_pending_q_flags); ++ list_del(&cmd_node->list); ++ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, ++ cmd_pending_q_flags); ++ mwifiex_insert_cmd_to_free_q(adapter, cmd_node); ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); ++ } ++ ++ /* Cancel all pending scan command */ ++ spin_lock_irqsave(&adapter->scan_pending_q_lock, ++ scan_pending_q_flags); ++ list_for_each_entry_safe(cmd_node, tmp_node, ++ &adapter->scan_pending_q, list) { ++ list_del(&cmd_node->list); ++ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, ++ scan_pending_q_flags); ++ cmd_node->wait_q_enabled = false; ++ mwifiex_insert_cmd_to_free_q(adapter, cmd_node); ++ spin_lock_irqsave(&adapter->scan_pending_q_lock, ++ scan_pending_q_flags); ++ cancel_scan_cmd = true; ++ } ++ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, ++ scan_pending_q_flags); ++ ++ if (cancel_scan_cmd) { ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); ++ adapter->scan_processing = false; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); ++ } ++ adapter->cmd_wait_q.status = -1; ++ mwifiex_complete_cmd(adapter); ++} ++ ++/* ++ * This function sends the sleep confirm command to firmware, if ++ * possible. ++ * ++ * The sleep confirm command cannot be issued if command response, ++ * data response or event response is awaiting handling, or if we ++ * are in the middle of sending a command, or expecting a command ++ * response. ++ */ ++void ++mwifiex_check_ps_cond(struct mwifiex_adapter *adapter) ++{ ++ if (!adapter->cmd_sent && ++ !adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter)) ++ mwifiex_dnld_sleep_confirm_cmd(adapter); ++ else ++ dev_dbg(adapter->dev, ++ "cmd: Delay Sleep Confirm (%s%s%s)\n", ++ (adapter->cmd_sent) ? "D" : "", ++ (adapter->curr_cmd) ? "C" : "", ++ (IS_CARD_RX_RCVD(adapter)) ? "R" : ""); ++} ++ ++/* ++ * This function sends a Host Sleep activated event to applications. ++ * ++ * This event is generated by the driver, with a blank event body. ++ */ ++void ++mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated) ++{ ++ if (activated) { ++ if (priv->adapter->is_hs_configured) { ++ priv->adapter->hs_activated = true; ++ dev_dbg(priv->adapter->dev, "event: hs_activated\n"); ++ priv->adapter->hs_activate_wait_q_woken = true; ++ wake_up_interruptible( ++ &priv->adapter->hs_activate_wait_q); ++ } else { ++ dev_dbg(priv->adapter->dev, "event: HS not configured\n"); ++ } ++ } else { ++ dev_dbg(priv->adapter->dev, "event: hs_deactivated\n"); ++ priv->adapter->hs_activated = false; ++ } ++} ++ ++/* ++ * This function handles the command response of a Host Sleep configuration ++ * command. ++ * ++ * Handling includes changing the header fields into CPU format ++ * and setting the current host sleep activation status in driver. ++ * ++ * In case host sleep status change, the function generates an event to ++ * notify the applications. ++ */ ++int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct host_cmd_ds_802_11_hs_cfg_enh *phs_cfg = ++ &resp->params.opt_hs_cfg; ++ uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions); ++ ++ if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) { ++ mwifiex_hs_activated_event(priv, true); ++ return 0; ++ } else { ++ dev_dbg(adapter->dev, "cmd: CMD_RESP: HS_CFG cmd reply" ++ " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n", ++ resp->result, conditions, ++ phs_cfg->params.hs_config.gpio, ++ phs_cfg->params.hs_config.gap); ++ } ++ if (conditions != HOST_SLEEP_CFG_CANCEL) { ++ adapter->is_hs_configured = true; ++ } else { ++ adapter->is_hs_configured = false; ++ if (adapter->hs_activated) ++ mwifiex_hs_activated_event(priv, false); ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function wakes up the adapter and generates a Host Sleep ++ * cancel event on receiving the power up interrupt. ++ */ ++void ++mwifiex_process_hs_config(struct mwifiex_adapter *adapter) ++{ ++ dev_dbg(adapter->dev, "info: %s: auto cancelling host sleep" ++ " since there is interrupt from the firmware\n", __func__); ++ ++ adapter->if_ops.wakeup(adapter); ++ adapter->hs_activated = false; ++ adapter->is_hs_configured = false; ++ mwifiex_hs_activated_event(mwifiex_get_priv(adapter, ++ MWIFIEX_BSS_ROLE_ANY), false); ++} ++ ++/* ++ * This function handles the command response of a sleep confirm command. ++ * ++ * The function sets the card state to SLEEP if the response indicates success. ++ */ ++void ++mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, ++ u8 *pbuf, u32 upld_len) ++{ ++ struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf; ++ struct mwifiex_private *priv = ++ mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); ++ uint16_t result = le16_to_cpu(cmd->result); ++ uint16_t command = le16_to_cpu(cmd->command); ++ uint16_t seq_num = le16_to_cpu(cmd->seq_num); ++ ++ if (!upld_len) { ++ dev_err(adapter->dev, "%s: cmd size is 0\n", __func__); ++ return; ++ } ++ ++ /* Get BSS number and corresponding priv */ ++ priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num), ++ HostCmd_GET_BSS_TYPE(seq_num)); ++ if (!priv) ++ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); ++ ++ /* Update sequence number */ ++ seq_num = HostCmd_GET_SEQ_NO(seq_num); ++ /* Clear RET_BIT from HostCmd */ ++ command &= HostCmd_CMD_ID_MASK; ++ ++ if (command != HostCmd_CMD_802_11_PS_MODE_ENH) { ++ dev_err(adapter->dev, "%s: received unexpected response for" ++ " cmd %x, result = %x\n", __func__, command, result); ++ return; ++ } ++ ++ if (result) { ++ dev_err(adapter->dev, "%s: sleep confirm cmd failed\n", ++ __func__); ++ adapter->pm_wakeup_card_req = false; ++ adapter->ps_state = PS_STATE_AWAKE; ++ return; ++ } ++ adapter->pm_wakeup_card_req = true; ++ if (adapter->is_hs_configured) ++ mwifiex_hs_activated_event(mwifiex_get_priv(adapter, ++ MWIFIEX_BSS_ROLE_ANY), true); ++ adapter->ps_state = PS_STATE_SLEEP; ++ cmd->command = cpu_to_le16(command); ++ cmd->seq_num = cpu_to_le16(seq_num); ++} ++EXPORT_SYMBOL_GPL(mwifiex_process_sleep_confirm_resp); ++ ++/* ++ * This function prepares an enhanced power mode command. ++ * ++ * This function can be used to disable power save or to configure ++ * power save with auto PS or STA PS or auto deep sleep. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting Power Save bitmap, PS parameters TLV, PS mode TLV, ++ * auto deep sleep TLV (as required) ++ * - Ensuring correct endian-ness ++ */ ++int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ u16 cmd_action, uint16_t ps_bitmap, ++ void *data_buf) ++{ ++ struct host_cmd_ds_802_11_ps_mode_enh *psmode_enh = ++ &cmd->params.psmode_enh; ++ u8 *tlv = NULL; ++ u16 cmd_size = 0; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); ++ if (cmd_action == DIS_AUTO_PS) { ++ psmode_enh->action = cpu_to_le16(DIS_AUTO_PS); ++ psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); ++ cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) + ++ sizeof(psmode_enh->params.ps_bitmap)); ++ } else if (cmd_action == GET_PS) { ++ psmode_enh->action = cpu_to_le16(GET_PS); ++ psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); ++ cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) + ++ sizeof(psmode_enh->params.ps_bitmap)); ++ } else if (cmd_action == EN_AUTO_PS) { ++ psmode_enh->action = cpu_to_le16(EN_AUTO_PS); ++ psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); ++ cmd_size = S_DS_GEN + sizeof(psmode_enh->action) + ++ sizeof(psmode_enh->params.ps_bitmap); ++ tlv = (u8 *) cmd + cmd_size; ++ if (ps_bitmap & BITMAP_STA_PS) { ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct mwifiex_ie_types_ps_param *ps_tlv = ++ (struct mwifiex_ie_types_ps_param *) tlv; ++ struct mwifiex_ps_param *ps_mode = &ps_tlv->param; ++ ps_tlv->header.type = cpu_to_le16(TLV_TYPE_PS_PARAM); ++ ps_tlv->header.len = cpu_to_le16(sizeof(*ps_tlv) - ++ sizeof(struct mwifiex_ie_types_header)); ++ cmd_size += sizeof(*ps_tlv); ++ tlv += sizeof(*ps_tlv); ++ dev_dbg(adapter->dev, "cmd: PS Command: Enter PS\n"); ++ ps_mode->null_pkt_interval = ++ cpu_to_le16(adapter->null_pkt_interval); ++ ps_mode->multiple_dtims = ++ cpu_to_le16(adapter->multiple_dtim); ++ ps_mode->bcn_miss_timeout = ++ cpu_to_le16(adapter->bcn_miss_time_out); ++ ps_mode->local_listen_interval = ++ cpu_to_le16(adapter->local_listen_interval); ++ ps_mode->adhoc_wake_period = ++ cpu_to_le16(adapter->adhoc_awake_period); ++ ps_mode->delay_to_ps = ++ cpu_to_le16(adapter->delay_to_ps); ++ ps_mode->mode = ++ cpu_to_le16(adapter->enhanced_ps_mode); ++ ++ } ++ if (ps_bitmap & BITMAP_AUTO_DS) { ++ struct mwifiex_ie_types_auto_ds_param *auto_ds_tlv = ++ (struct mwifiex_ie_types_auto_ds_param *) tlv; ++ u16 idletime = 0; ++ ++ auto_ds_tlv->header.type = ++ cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM); ++ auto_ds_tlv->header.len = ++ cpu_to_le16(sizeof(*auto_ds_tlv) - ++ sizeof(struct mwifiex_ie_types_header)); ++ cmd_size += sizeof(*auto_ds_tlv); ++ tlv += sizeof(*auto_ds_tlv); ++ if (data_buf) ++ idletime = ((struct mwifiex_ds_auto_ds *) ++ data_buf)->idle_time; ++ dev_dbg(priv->adapter->dev, ++ "cmd: PS Command: Enter Auto Deep Sleep\n"); ++ auto_ds_tlv->deep_sleep_timeout = cpu_to_le16(idletime); ++ } ++ cmd->size = cpu_to_le16(cmd_size); ++ } ++ return 0; ++} ++ ++/* ++ * This function handles the command response of an enhanced power mode ++ * command. ++ * ++ * Handling includes changing the header fields into CPU format ++ * and setting the current enhanced power mode in driver. ++ */ ++int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp, ++ void *data_buf) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct host_cmd_ds_802_11_ps_mode_enh *ps_mode = ++ &resp->params.psmode_enh; ++ uint16_t action = le16_to_cpu(ps_mode->action); ++ uint16_t ps_bitmap = le16_to_cpu(ps_mode->params.ps_bitmap); ++ uint16_t auto_ps_bitmap = ++ le16_to_cpu(ps_mode->params.ps_bitmap); ++ ++ dev_dbg(adapter->dev, "info: %s: PS_MODE cmd reply result=%#x action=%#X\n", ++ __func__, resp->result, action); ++ if (action == EN_AUTO_PS) { ++ if (auto_ps_bitmap & BITMAP_AUTO_DS) { ++ dev_dbg(adapter->dev, "cmd: Enabled auto deep sleep\n"); ++ priv->adapter->is_deep_sleep = true; ++ } ++ if (auto_ps_bitmap & BITMAP_STA_PS) { ++ dev_dbg(adapter->dev, "cmd: Enabled STA power save\n"); ++ if (adapter->sleep_period.period) ++ dev_dbg(adapter->dev, "cmd: set to uapsd/pps mode\n"); ++ } ++ } else if (action == DIS_AUTO_PS) { ++ if (ps_bitmap & BITMAP_AUTO_DS) { ++ priv->adapter->is_deep_sleep = false; ++ dev_dbg(adapter->dev, "cmd: Disabled auto deep sleep\n"); ++ } ++ if (ps_bitmap & BITMAP_STA_PS) { ++ dev_dbg(adapter->dev, "cmd: Disabled STA power save\n"); ++ if (adapter->sleep_period.period) { ++ adapter->delay_null_pkt = false; ++ adapter->tx_lock_flag = false; ++ adapter->pps_uapsd_mode = false; ++ } ++ } ++ } else if (action == GET_PS) { ++ if (ps_bitmap & BITMAP_STA_PS) ++ adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; ++ else ++ adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; ++ ++ dev_dbg(adapter->dev, "cmd: ps_bitmap=%#x\n", ps_bitmap); ++ ++ if (data_buf) { ++ /* This section is for get power save mode */ ++ struct mwifiex_ds_pm_cfg *pm_cfg = ++ (struct mwifiex_ds_pm_cfg *)data_buf; ++ if (ps_bitmap & BITMAP_STA_PS) ++ pm_cfg->param.ps_mode = 1; ++ else ++ pm_cfg->param.ps_mode = 0; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * This function prepares command to get hardware specifications. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting permanent address parameter ++ * - Ensuring correct endian-ness ++ */ ++int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd) ++{ ++ struct host_cmd_ds_get_hw_spec *hw_spec = &cmd->params.hw_spec; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_GET_HW_SPEC); ++ cmd->size = ++ cpu_to_le16(sizeof(struct host_cmd_ds_get_hw_spec) + S_DS_GEN); ++ memcpy(hw_spec->permanent_addr, priv->curr_addr, ETH_ALEN); ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of get hardware ++ * specifications. ++ * ++ * Handling includes changing the header fields into CPU format ++ * and saving/updating the following parameters in driver - ++ * - Firmware capability information ++ * - Firmware band settings ++ * - Ad-hoc start band and channel ++ * - Ad-hoc 11n activation status ++ * - Firmware release number ++ * - Number of antennas ++ * - Hardware address ++ * - Hardware interface version ++ * - Firmware version ++ * - Region code ++ * - 11n capabilities ++ * - MCS support fields ++ * - MP end port ++ */ ++int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ int i; ++ ++ adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info); ++ ++ if (IS_SUPPORT_MULTI_BANDS(adapter)) ++ adapter->fw_bands = (u8) GET_FW_DEFAULT_BANDS(adapter); ++ else ++ adapter->fw_bands = BAND_B; ++ ++ adapter->config_bands = adapter->fw_bands; ++ ++ if (adapter->fw_bands & BAND_A) { ++ if (adapter->fw_bands & BAND_GN) { ++ adapter->config_bands |= BAND_AN; ++ adapter->fw_bands |= BAND_AN; ++ } ++ if (adapter->fw_bands & BAND_AN) { ++ adapter->adhoc_start_band = BAND_A | BAND_AN; ++ adapter->adhoc_11n_enabled = true; ++ } else { ++ adapter->adhoc_start_band = BAND_A; ++ } ++ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A; ++ } else if (adapter->fw_bands & BAND_GN) { ++ adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN; ++ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; ++ adapter->adhoc_11n_enabled = true; ++ } else if (adapter->fw_bands & BAND_G) { ++ adapter->adhoc_start_band = BAND_G | BAND_B; ++ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; ++ } else if (adapter->fw_bands & BAND_B) { ++ adapter->adhoc_start_band = BAND_B; ++ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; ++ } ++ ++ adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); ++ adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna); ++ ++ dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n", ++ adapter->fw_release_number); ++ dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n", ++ hw_spec->permanent_addr); ++ dev_dbg(adapter->dev, "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n", ++ le16_to_cpu(hw_spec->hw_if_version), ++ le16_to_cpu(hw_spec->version)); ++ ++ if (priv->curr_addr[0] == 0xff) ++ memmove(priv->curr_addr, hw_spec->permanent_addr, ETH_ALEN); ++ ++ adapter->region_code = le16_to_cpu(hw_spec->region_code); ++ ++ for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++) ++ /* Use the region code to search for the index */ ++ if (adapter->region_code == region_code_index[i]) ++ break; ++ ++ /* If it's unidentified region code, use the default (USA) */ ++ if (i >= MWIFIEX_MAX_REGION_CODE) { ++ adapter->region_code = 0x10; ++ dev_dbg(adapter->dev, "cmd: unknown region code, use default (USA)\n"); ++ } ++ ++ adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap); ++ adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support; ++ ++ if (adapter->if_ops.update_mp_end_port) ++ adapter->if_ops.update_mp_end_port(adapter, ++ le16_to_cpu(hw_spec->mp_end_port)); ++ ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/debugfs.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/debugfs.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/debugfs.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/debugfs.c 2011-05-05 23:29:45.477441767 +0200 +@@ -0,0 +1,770 @@ ++/* ++ * Marvell Wireless LAN device driver: debugfs ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include ++ ++#include "main.h" ++#include "11n.h" ++ ++ ++static struct dentry *mwifiex_dfs_dir; ++ ++static char *bss_modes[] = { ++ "Unknown", ++ "Managed", ++ "Ad-hoc", ++ "Auto" ++}; ++ ++/* size/addr for mwifiex_debug_info */ ++#define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n)) ++#define item_addr(n) (offsetof(struct mwifiex_debug_info, n)) ++ ++/* size/addr for struct mwifiex_adapter */ ++#define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n)) ++#define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n)) ++ ++struct mwifiex_debug_data { ++ char name[32]; /* variable/array name */ ++ u32 size; /* size of the variable/array */ ++ size_t addr; /* address of the variable/array */ ++ int num; /* number of variables in an array */ ++}; ++ ++static struct mwifiex_debug_data items[] = { ++ {"int_counter", item_size(int_counter), ++ item_addr(int_counter), 1}, ++ {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]), ++ item_addr(packets_out[WMM_AC_VO]), 1}, ++ {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]), ++ item_addr(packets_out[WMM_AC_VI]), 1}, ++ {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]), ++ item_addr(packets_out[WMM_AC_BE]), 1}, ++ {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), ++ item_addr(packets_out[WMM_AC_BK]), 1}, ++ {"max_tx_buf_size", item_size(max_tx_buf_size), ++ item_addr(max_tx_buf_size), 1}, ++ {"tx_buf_size", item_size(tx_buf_size), ++ item_addr(tx_buf_size), 1}, ++ {"curr_tx_buf_size", item_size(curr_tx_buf_size), ++ item_addr(curr_tx_buf_size), 1}, ++ {"ps_mode", item_size(ps_mode), ++ item_addr(ps_mode), 1}, ++ {"ps_state", item_size(ps_state), ++ item_addr(ps_state), 1}, ++ {"is_deep_sleep", item_size(is_deep_sleep), ++ item_addr(is_deep_sleep), 1}, ++ {"wakeup_dev_req", item_size(pm_wakeup_card_req), ++ item_addr(pm_wakeup_card_req), 1}, ++ {"wakeup_tries", item_size(pm_wakeup_fw_try), ++ item_addr(pm_wakeup_fw_try), 1}, ++ {"hs_configured", item_size(is_hs_configured), ++ item_addr(is_hs_configured), 1}, ++ {"hs_activated", item_size(hs_activated), ++ item_addr(hs_activated), 1}, ++ {"num_tx_timeout", item_size(num_tx_timeout), ++ item_addr(num_tx_timeout), 1}, ++ {"num_cmd_timeout", item_size(num_cmd_timeout), ++ item_addr(num_cmd_timeout), 1}, ++ {"timeout_cmd_id", item_size(timeout_cmd_id), ++ item_addr(timeout_cmd_id), 1}, ++ {"timeout_cmd_act", item_size(timeout_cmd_act), ++ item_addr(timeout_cmd_act), 1}, ++ {"last_cmd_id", item_size(last_cmd_id), ++ item_addr(last_cmd_id), DBG_CMD_NUM}, ++ {"last_cmd_act", item_size(last_cmd_act), ++ item_addr(last_cmd_act), DBG_CMD_NUM}, ++ {"last_cmd_index", item_size(last_cmd_index), ++ item_addr(last_cmd_index), 1}, ++ {"last_cmd_resp_id", item_size(last_cmd_resp_id), ++ item_addr(last_cmd_resp_id), DBG_CMD_NUM}, ++ {"last_cmd_resp_index", item_size(last_cmd_resp_index), ++ item_addr(last_cmd_resp_index), 1}, ++ {"last_event", item_size(last_event), ++ item_addr(last_event), DBG_CMD_NUM}, ++ {"last_event_index", item_size(last_event_index), ++ item_addr(last_event_index), 1}, ++ {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), ++ item_addr(num_cmd_host_to_card_failure), 1}, ++ {"num_cmd_sleep_cfm_fail", ++ item_size(num_cmd_sleep_cfm_host_to_card_failure), ++ item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1}, ++ {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure), ++ item_addr(num_tx_host_to_card_failure), 1}, ++ {"num_evt_deauth", item_size(num_event_deauth), ++ item_addr(num_event_deauth), 1}, ++ {"num_evt_disassoc", item_size(num_event_disassoc), ++ item_addr(num_event_disassoc), 1}, ++ {"num_evt_link_lost", item_size(num_event_link_lost), ++ item_addr(num_event_link_lost), 1}, ++ {"num_cmd_deauth", item_size(num_cmd_deauth), ++ item_addr(num_cmd_deauth), 1}, ++ {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success), ++ item_addr(num_cmd_assoc_success), 1}, ++ {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure), ++ item_addr(num_cmd_assoc_failure), 1}, ++ {"cmd_sent", item_size(cmd_sent), ++ item_addr(cmd_sent), 1}, ++ {"data_sent", item_size(data_sent), ++ item_addr(data_sent), 1}, ++ {"cmd_resp_received", item_size(cmd_resp_received), ++ item_addr(cmd_resp_received), 1}, ++ {"event_received", item_size(event_received), ++ item_addr(event_received), 1}, ++ ++ /* variables defined in struct mwifiex_adapter */ ++ {"cmd_pending", adapter_item_size(cmd_pending), ++ adapter_item_addr(cmd_pending), 1}, ++ {"tx_pending", adapter_item_size(tx_pending), ++ adapter_item_addr(tx_pending), 1}, ++ {"rx_pending", adapter_item_size(rx_pending), ++ adapter_item_addr(rx_pending), 1}, ++}; ++ ++static int num_of_items = ARRAY_SIZE(items); ++ ++/* ++ * Generic proc file open handler. ++ * ++ * This function is called every time a file is accessed for read or write. ++ */ ++static int ++mwifiex_open_generic(struct inode *inode, struct file *file) ++{ ++ file->private_data = inode->i_private; ++ return 0; ++} ++ ++/* ++ * Proc info file read handler. ++ * ++ * This function is called when the 'info' file is opened for reading. ++ * It prints the following driver related information - ++ * - Driver name ++ * - Driver version ++ * - Driver extended version ++ * - Interface name ++ * - BSS mode ++ * - Media state (connected or disconnected) ++ * - MAC address ++ * - Total number of Tx bytes ++ * - Total number of Rx bytes ++ * - Total number of Tx packets ++ * - Total number of Rx packets ++ * - Total number of dropped Tx packets ++ * - Total number of dropped Rx packets ++ * - Total number of corrupted Tx packets ++ * - Total number of corrupted Rx packets ++ * - Carrier status (on or off) ++ * - Tx queue status (started or stopped) ++ * ++ * For STA mode drivers, it also prints the following extra - ++ * - ESSID ++ * - BSSID ++ * - Channel ++ * - Region code ++ * - Multicast count ++ * - Multicast addresses ++ */ ++static ssize_t ++mwifiex_info_read(struct file *file, char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct mwifiex_private *priv = ++ (struct mwifiex_private *) file->private_data; ++ struct net_device *netdev = priv->netdev; ++ struct netdev_hw_addr *ha; ++ unsigned long page = get_zeroed_page(GFP_KERNEL); ++ char *p = (char *) page, fmt[64]; ++ struct mwifiex_bss_info info; ++ ssize_t ret = 0; ++ int i = 0; ++ ++ if (!p) ++ return -ENOMEM; ++ ++ memset(&info, 0, sizeof(info)); ++ ret = mwifiex_get_bss_info(priv, &info); ++ if (ret) ++ goto free_and_exit; ++ ++ mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1); ++ ++ if (!priv->version_str[0]) ++ mwifiex_get_ver_ext(priv); ++ ++ p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); ++ p += sprintf(p, "driver_version = %s", fmt); ++ p += sprintf(p, "\nverext = %s", priv->version_str); ++ p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); ++ p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); ++ p += sprintf(p, "media_state=\"%s\"\n", ++ (!priv->media_connected ? "Disconnected" : "Connected")); ++ p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", ++ netdev->dev_addr[0], netdev->dev_addr[1], ++ netdev->dev_addr[2], netdev->dev_addr[3], ++ netdev->dev_addr[4], netdev->dev_addr[5]); ++ ++ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { ++ p += sprintf(p, "multicast_count=\"%d\"\n", ++ netdev_mc_count(netdev)); ++ p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); ++ p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", ++ info.bssid[0], info.bssid[1], ++ info.bssid[2], info.bssid[3], ++ info.bssid[4], info.bssid[5]); ++ p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); ++ p += sprintf(p, "region_code = \"%02x\"\n", info.region_code); ++ ++ netdev_for_each_mc_addr(ha, netdev) ++ p += sprintf(p, "multicast_address[%d]=" ++ "\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", i++, ++ ha->addr[0], ha->addr[1], ++ ha->addr[2], ha->addr[3], ++ ha->addr[4], ha->addr[5]); ++ } ++ ++ p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); ++ p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); ++ p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); ++ p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); ++ p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); ++ p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); ++ p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); ++ p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); ++ p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) ++ ? "on" : "off")); ++ p += sprintf(p, "tx queue %s\n", ((netif_queue_stopped(priv->netdev)) ++ ? "stopped" : "started")); ++ ++ ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, ++ (unsigned long) p - page); ++ ++free_and_exit: ++ free_page(page); ++ return ret; ++} ++ ++/* ++ * Proc getlog file read handler. ++ * ++ * This function is called when the 'getlog' file is opened for reading ++ * It prints the following log information - ++ * - Number of multicast Tx frames ++ * - Number of failed packets ++ * - Number of Tx retries ++ * - Number of multicast Tx retries ++ * - Number of duplicate frames ++ * - Number of RTS successes ++ * - Number of RTS failures ++ * - Number of ACK failures ++ * - Number of fragmented Rx frames ++ * - Number of multicast Rx frames ++ * - Number of FCS errors ++ * - Number of Tx frames ++ * - WEP ICV error counts ++ */ ++static ssize_t ++mwifiex_getlog_read(struct file *file, char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct mwifiex_private *priv = ++ (struct mwifiex_private *) file->private_data; ++ unsigned long page = get_zeroed_page(GFP_KERNEL); ++ char *p = (char *) page; ++ ssize_t ret = 0; ++ struct mwifiex_ds_get_stats stats; ++ ++ if (!p) ++ return -ENOMEM; ++ ++ memset(&stats, 0, sizeof(stats)); ++ ret = mwifiex_get_stats_info(priv, &stats); ++ if (ret) ++ goto free_and_exit; ++ ++ p += sprintf(p, "\n" ++ "mcasttxframe %u\n" ++ "failed %u\n" ++ "retry %u\n" ++ "multiretry %u\n" ++ "framedup %u\n" ++ "rtssuccess %u\n" ++ "rtsfailure %u\n" ++ "ackfailure %u\n" ++ "rxfrag %u\n" ++ "mcastrxframe %u\n" ++ "fcserror %u\n" ++ "txframe %u\n" ++ "wepicverrcnt-1 %u\n" ++ "wepicverrcnt-2 %u\n" ++ "wepicverrcnt-3 %u\n" ++ "wepicverrcnt-4 %u\n", ++ stats.mcast_tx_frame, ++ stats.failed, ++ stats.retry, ++ stats.multi_retry, ++ stats.frame_dup, ++ stats.rts_success, ++ stats.rts_failure, ++ stats.ack_failure, ++ stats.rx_frag, ++ stats.mcast_rx_frame, ++ stats.fcs_error, ++ stats.tx_frame, ++ stats.wep_icv_error[0], ++ stats.wep_icv_error[1], ++ stats.wep_icv_error[2], ++ stats.wep_icv_error[3]); ++ ++ ++ ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, ++ (unsigned long) p - page); ++ ++free_and_exit: ++ free_page(page); ++ return ret; ++} ++ ++static struct mwifiex_debug_info info; ++ ++/* ++ * Proc debug file read handler. ++ * ++ * This function is called when the 'debug' file is opened for reading ++ * It prints the following log information - ++ * - Interrupt count ++ * - WMM AC VO packets count ++ * - WMM AC VI packets count ++ * - WMM AC BE packets count ++ * - WMM AC BK packets count ++ * - Maximum Tx buffer size ++ * - Tx buffer size ++ * - Current Tx buffer size ++ * - Power Save mode ++ * - Power Save state ++ * - Deep Sleep status ++ * - Device wakeup required status ++ * - Number of wakeup tries ++ * - Host Sleep configured status ++ * - Host Sleep activated status ++ * - Number of Tx timeouts ++ * - Number of command timeouts ++ * - Last timed out command ID ++ * - Last timed out command action ++ * - Last command ID ++ * - Last command action ++ * - Last command index ++ * - Last command response ID ++ * - Last command response index ++ * - Last event ++ * - Last event index ++ * - Number of host to card command failures ++ * - Number of sleep confirm command failures ++ * - Number of host to card data failure ++ * - Number of deauthentication events ++ * - Number of disassociation events ++ * - Number of link lost events ++ * - Number of deauthentication commands ++ * - Number of association success commands ++ * - Number of association failure commands ++ * - Number of commands sent ++ * - Number of data packets sent ++ * - Number of command responses received ++ * - Number of events received ++ * - Tx BA stream table (TID, RA) ++ * - Rx reorder table (TID, TA, Start window, Window size, Buffer) ++ */ ++static ssize_t ++mwifiex_debug_read(struct file *file, char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct mwifiex_private *priv = ++ (struct mwifiex_private *) file->private_data; ++ struct mwifiex_debug_data *d = &items[0]; ++ unsigned long page = get_zeroed_page(GFP_KERNEL); ++ char *p = (char *) page; ++ ssize_t ret = 0; ++ size_t size, addr; ++ long val; ++ int i, j; ++ ++ if (!p) ++ return -ENOMEM; ++ ++ ret = mwifiex_get_debug_info(priv, &info); ++ if (ret) ++ goto free_and_exit; ++ ++ for (i = 0; i < num_of_items; i++) { ++ p += sprintf(p, "%s=", d[i].name); ++ ++ size = d[i].size / d[i].num; ++ ++ if (i < (num_of_items - 3)) ++ addr = d[i].addr + (size_t) &info; ++ else /* The last 3 items are struct mwifiex_adapter variables */ ++ addr = d[i].addr + (size_t) priv->adapter; ++ ++ for (j = 0; j < d[i].num; j++) { ++ switch (size) { ++ case 1: ++ val = *((u8 *) addr); ++ break; ++ case 2: ++ val = *((u16 *) addr); ++ break; ++ case 4: ++ val = *((u32 *) addr); ++ break; ++ case 8: ++ val = *((long long *) addr); ++ break; ++ default: ++ val = -1; ++ break; ++ } ++ ++ p += sprintf(p, "%#lx ", val); ++ addr += size; ++ } ++ ++ p += sprintf(p, "\n"); ++ } ++ ++ if (info.tx_tbl_num) { ++ p += sprintf(p, "Tx BA stream table:\n"); ++ for (i = 0; i < info.tx_tbl_num; i++) ++ p += sprintf(p, "tid = %d, " ++ "ra = %02x:%02x:%02x:%02x:%02x:%02x\n", ++ info.tx_tbl[i].tid, info.tx_tbl[i].ra[0], ++ info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2], ++ info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4], ++ info.tx_tbl[i].ra[5]); ++ } ++ ++ if (info.rx_tbl_num) { ++ p += sprintf(p, "Rx reorder table:\n"); ++ for (i = 0; i < info.rx_tbl_num; i++) { ++ ++ p += sprintf(p, "tid = %d, " ++ "ta = %02x:%02x:%02x:%02x:%02x:%02x, " ++ "start_win = %d, " ++ "win_size = %d, buffer: ", ++ info.rx_tbl[i].tid, ++ info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1], ++ info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3], ++ info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5], ++ info.rx_tbl[i].start_win, ++ info.rx_tbl[i].win_size); ++ ++ for (j = 0; j < info.rx_tbl[i].win_size; j++) ++ p += sprintf(p, "%c ", ++ info.rx_tbl[i].buffer[j] ? ++ '1' : '0'); ++ ++ p += sprintf(p, "\n"); ++ } ++ } ++ ++ ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, ++ (unsigned long) p - page); ++ ++free_and_exit: ++ free_page(page); ++ return ret; ++} ++ ++static u32 saved_reg_type, saved_reg_offset, saved_reg_value; ++ ++/* ++ * Proc regrdwr file write handler. ++ * ++ * This function is called when the 'regrdwr' file is opened for writing ++ * ++ * This function can be used to write to a register. ++ */ ++static ssize_t ++mwifiex_regrdwr_write(struct file *file, ++ const char __user *ubuf, size_t count, loff_t *ppos) ++{ ++ unsigned long addr = get_zeroed_page(GFP_KERNEL); ++ char *buf = (char *) addr; ++ size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); ++ int ret = 0; ++ u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; ++ ++ if (!buf) ++ return -ENOMEM; ++ ++ ++ if (copy_from_user(buf, ubuf, buf_size)) { ++ ret = -EFAULT; ++ goto done; ++ } ++ ++ sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value); ++ ++ if (reg_type == 0 || reg_offset == 0) { ++ ret = -EINVAL; ++ goto done; ++ } else { ++ saved_reg_type = reg_type; ++ saved_reg_offset = reg_offset; ++ saved_reg_value = reg_value; ++ ret = count; ++ } ++done: ++ free_page(addr); ++ return ret; ++} ++ ++/* ++ * Proc regrdwr file read handler. ++ * ++ * This function is called when the 'regrdwr' file is opened for reading ++ * ++ * This function can be used to read from a register. ++ */ ++static ssize_t ++mwifiex_regrdwr_read(struct file *file, char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct mwifiex_private *priv = ++ (struct mwifiex_private *) file->private_data; ++ unsigned long addr = get_zeroed_page(GFP_KERNEL); ++ char *buf = (char *) addr; ++ int pos = 0, ret = 0; ++ u32 reg_value; ++ ++ if (!buf) ++ return -ENOMEM; ++ ++ if (!saved_reg_type) { ++ /* No command has been given */ ++ pos += snprintf(buf, PAGE_SIZE, "0"); ++ goto done; ++ } ++ /* Set command has been given */ ++ if (saved_reg_value != UINT_MAX) { ++ ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset, ++ saved_reg_value); ++ ++ pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", ++ saved_reg_type, saved_reg_offset, ++ saved_reg_value); ++ ++ ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); ++ ++ goto done; ++ } ++ /* Get command has been given */ ++ ret = mwifiex_reg_read(priv, saved_reg_type, ++ saved_reg_offset, ®_value); ++ if (ret) { ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type, ++ saved_reg_offset, reg_value); ++ ++ ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); ++ ++done: ++ free_page(addr); ++ return ret; ++} ++ ++static u32 saved_offset = -1, saved_bytes = -1; ++ ++/* ++ * Proc rdeeprom file write handler. ++ * ++ * This function is called when the 'rdeeprom' file is opened for writing ++ * ++ * This function can be used to write to a RDEEPROM location. ++ */ ++static ssize_t ++mwifiex_rdeeprom_write(struct file *file, ++ const char __user *ubuf, size_t count, loff_t *ppos) ++{ ++ unsigned long addr = get_zeroed_page(GFP_KERNEL); ++ char *buf = (char *) addr; ++ size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); ++ int ret = 0; ++ int offset = -1, bytes = -1; ++ ++ if (!buf) ++ return -ENOMEM; ++ ++ ++ if (copy_from_user(buf, ubuf, buf_size)) { ++ ret = -EFAULT; ++ goto done; ++ } ++ ++ sscanf(buf, "%d %d", &offset, &bytes); ++ ++ if (offset == -1 || bytes == -1) { ++ ret = -EINVAL; ++ goto done; ++ } else { ++ saved_offset = offset; ++ saved_bytes = bytes; ++ ret = count; ++ } ++done: ++ free_page(addr); ++ return ret; ++} ++ ++/* ++ * Proc rdeeprom read write handler. ++ * ++ * This function is called when the 'rdeeprom' file is opened for reading ++ * ++ * This function can be used to read from a RDEEPROM location. ++ */ ++static ssize_t ++mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct mwifiex_private *priv = ++ (struct mwifiex_private *) file->private_data; ++ unsigned long addr = get_zeroed_page(GFP_KERNEL); ++ char *buf = (char *) addr; ++ int pos = 0, ret = 0, i = 0; ++ u8 value[MAX_EEPROM_DATA]; ++ ++ if (!buf) ++ return -ENOMEM; ++ ++ if (saved_offset == -1) { ++ /* No command has been given */ ++ pos += snprintf(buf, PAGE_SIZE, "0"); ++ goto done; ++ } ++ ++ /* Get command has been given */ ++ ret = mwifiex_eeprom_read(priv, (u16) saved_offset, ++ (u16) saved_bytes, value); ++ if (ret) { ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); ++ ++ for (i = 0; i < saved_bytes; i++) ++ pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]); ++ ++ ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); ++ ++done: ++ free_page(addr); ++ return ret; ++} ++ ++ ++#define MWIFIEX_DFS_ADD_FILE(name) do { \ ++ if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \ ++ priv, &mwifiex_dfs_##name##_fops)) \ ++ return; \ ++} while (0); ++ ++#define MWIFIEX_DFS_FILE_OPS(name) \ ++static const struct file_operations mwifiex_dfs_##name##_fops = { \ ++ .read = mwifiex_##name##_read, \ ++ .write = mwifiex_##name##_write, \ ++ .open = mwifiex_open_generic, \ ++}; ++ ++#define MWIFIEX_DFS_FILE_READ_OPS(name) \ ++static const struct file_operations mwifiex_dfs_##name##_fops = { \ ++ .read = mwifiex_##name##_read, \ ++ .open = mwifiex_open_generic, \ ++}; ++ ++#define MWIFIEX_DFS_FILE_WRITE_OPS(name) \ ++static const struct file_operations mwifiex_dfs_##name##_fops = { \ ++ .write = mwifiex_##name##_write, \ ++ .open = mwifiex_open_generic, \ ++}; ++ ++ ++MWIFIEX_DFS_FILE_READ_OPS(info); ++MWIFIEX_DFS_FILE_READ_OPS(debug); ++MWIFIEX_DFS_FILE_READ_OPS(getlog); ++MWIFIEX_DFS_FILE_OPS(regrdwr); ++MWIFIEX_DFS_FILE_OPS(rdeeprom); ++ ++/* ++ * This function creates the debug FS directory structure and the files. ++ */ ++void ++mwifiex_dev_debugfs_init(struct mwifiex_private *priv) ++{ ++ if (!mwifiex_dfs_dir || !priv) ++ return; ++ ++ priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, ++ mwifiex_dfs_dir); ++ ++ if (!priv->dfs_dev_dir) ++ return; ++ ++ MWIFIEX_DFS_ADD_FILE(info); ++ MWIFIEX_DFS_ADD_FILE(debug); ++ MWIFIEX_DFS_ADD_FILE(getlog); ++ MWIFIEX_DFS_ADD_FILE(regrdwr); ++ MWIFIEX_DFS_ADD_FILE(rdeeprom); ++} ++ ++/* ++ * This function removes the debug FS directory structure and the files. ++ */ ++void ++mwifiex_dev_debugfs_remove(struct mwifiex_private *priv) ++{ ++ if (!priv) ++ return; ++ ++ debugfs_remove_recursive(priv->dfs_dev_dir); ++} ++ ++/* ++ * This function creates the top level proc directory. ++ */ ++void ++mwifiex_debugfs_init(void) ++{ ++ if (!mwifiex_dfs_dir) ++ mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL); ++} ++ ++/* ++ * This function removes the top level proc directory. ++ */ ++void ++mwifiex_debugfs_remove(void) ++{ ++ if (mwifiex_dfs_dir) ++ debugfs_remove(mwifiex_dfs_dir); ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/decl.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/decl.h +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/decl.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/decl.h 2011-05-05 23:29:45.474441731 +0200 +@@ -0,0 +1,129 @@ ++/* ++ * Marvell Wireless LAN device driver: generic data structures and APIs ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#ifndef _MWIFIEX_DECL_H_ ++#define _MWIFIEX_DECL_H_ ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++ ++ ++#define MWIFIEX_MAX_BSS_NUM (1) ++ ++#define MWIFIEX_MIN_DATA_HEADER_LEN 32 /* (sizeof(mwifiex_txpd)) */ ++ ++#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2 ++#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16 ++ ++#define MWIFIEX_AMPDU_DEF_TXWINSIZE 32 ++#define MWIFIEX_AMPDU_DEF_RXWINSIZE 16 ++#define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff ++ ++#define MWIFIEX_RATE_INDEX_HRDSSS0 0 ++#define MWIFIEX_RATE_INDEX_HRDSSS3 3 ++#define MWIFIEX_RATE_INDEX_OFDM0 4 ++#define MWIFIEX_RATE_INDEX_OFDM7 11 ++#define MWIFIEX_RATE_INDEX_MCS0 12 ++ ++#define MWIFIEX_RATE_BITMAP_OFDM0 16 ++#define MWIFIEX_RATE_BITMAP_OFDM7 23 ++#define MWIFIEX_RATE_BITMAP_MCS0 32 ++#define MWIFIEX_RATE_BITMAP_MCS127 159 ++ ++#define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024) ++ ++#define MWIFIEX_RTS_MIN_VALUE (0) ++#define MWIFIEX_RTS_MAX_VALUE (2347) ++#define MWIFIEX_FRAG_MIN_VALUE (256) ++#define MWIFIEX_FRAG_MAX_VALUE (2346) ++ ++#define MWIFIEX_SDIO_BLOCK_SIZE 256 ++ ++#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) ++ ++enum mwifiex_bss_type { ++ MWIFIEX_BSS_TYPE_STA = 0, ++ MWIFIEX_BSS_TYPE_UAP = 1, ++ MWIFIEX_BSS_TYPE_ANY = 0xff, ++}; ++ ++enum mwifiex_bss_role { ++ MWIFIEX_BSS_ROLE_STA = 0, ++ MWIFIEX_BSS_ROLE_UAP = 1, ++ MWIFIEX_BSS_ROLE_ANY = 0xff, ++}; ++ ++#define BSS_ROLE_BIT_MASK BIT(0) ++ ++#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK) ++ ++enum mwifiex_data_frame_type { ++ MWIFIEX_DATA_FRAME_TYPE_ETH_II = 0, ++ MWIFIEX_DATA_FRAME_TYPE_802_11, ++}; ++ ++struct mwifiex_fw_image { ++ u8 *helper_buf; ++ u32 helper_len; ++ u8 *fw_buf; ++ u32 fw_len; ++}; ++ ++struct mwifiex_802_11_ssid { ++ u32 ssid_len; ++ u8 ssid[IEEE80211_MAX_SSID_LEN]; ++}; ++ ++struct mwifiex_wait_queue { ++ wait_queue_head_t wait; ++ u16 condition; ++ int status; ++}; ++ ++struct mwifiex_rxinfo { ++ u8 bss_index; ++ struct sk_buff *parent; ++ u8 use_count; ++}; ++ ++struct mwifiex_txinfo { ++ u32 status_code; ++ u8 flags; ++ u8 bss_index; ++}; ++ ++struct mwifiex_bss_attr { ++ u8 bss_type; ++ u8 frame_type; ++ u8 active; ++ u8 bss_priority; ++ u8 bss_num; ++}; ++ ++enum mwifiex_wmm_ac_e { ++ WMM_AC_BK, ++ WMM_AC_BE, ++ WMM_AC_VI, ++ WMM_AC_VO ++} __packed; ++#endif /* !_MWIFIEX_DECL_H_ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/fw.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/fw.h +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/fw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/fw.h 2011-05-05 23:29:45.440441321 +0200 +@@ -0,0 +1,1206 @@ ++/* ++ * Marvell Wireless LAN device driver: Firmware specific macros & structures ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#ifndef _MWIFIEX_FW_H_ ++#define _MWIFIEX_FW_H_ ++ ++#include ++ ++ ++#define INTF_HEADER_LEN 4 ++ ++struct rfc_1042_hdr { ++ u8 llc_dsap; ++ u8 llc_ssap; ++ u8 llc_ctrl; ++ u8 snap_oui[3]; ++ u16 snap_type; ++}; ++ ++struct rx_packet_hdr { ++ struct ethhdr eth803_hdr; ++ struct rfc_1042_hdr rfc1042_hdr; ++}; ++ ++struct tx_packet_hdr { ++ struct ethhdr eth803_hdr; ++ struct rfc_1042_hdr rfc1042_hdr; ++}; ++ ++#define B_SUPPORTED_RATES 5 ++#define G_SUPPORTED_RATES 9 ++#define BG_SUPPORTED_RATES 13 ++#define A_SUPPORTED_RATES 9 ++#define HOSTCMD_SUPPORTED_RATES 14 ++#define N_SUPPORTED_RATES 3 ++#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN) ++ ++#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11)) ++#define IS_SUPPORT_MULTI_BANDS(adapter) \ ++ (adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT) ++#define GET_FW_DEFAULT_BANDS(adapter) \ ++ ((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS) ++ ++extern u8 supported_rates_b[B_SUPPORTED_RATES]; ++extern u8 supported_rates_g[G_SUPPORTED_RATES]; ++extern u8 supported_rates_bg[BG_SUPPORTED_RATES]; ++extern u8 supported_rates_a[A_SUPPORTED_RATES]; ++extern u8 supported_rates_n[N_SUPPORTED_RATES]; ++ ++#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff ++ ++#define KEY_INFO_ENABLED 0x01 ++enum KEY_TYPE_ID { ++ KEY_TYPE_ID_WEP = 0, ++ KEY_TYPE_ID_TKIP, ++ KEY_TYPE_ID_AES, ++ KEY_TYPE_ID_WAPI, ++}; ++#define KEY_MCAST BIT(0) ++#define KEY_UNICAST BIT(1) ++#define KEY_ENABLED BIT(2) ++ ++#define WAPI_KEY_LEN 50 ++ ++#define MAX_POLL_TRIES 100 ++ ++#define MAX_MULTI_INTERFACE_POLL_TRIES 1000 ++ ++#define MAX_FIRMWARE_POLL_TRIES 100 ++ ++#define FIRMWARE_READY 0xfedc ++ ++enum MWIFIEX_802_11_PRIVACY_FILTER { ++ MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL, ++ MWIFIEX_802_11_PRIV_FILTER_8021X_WEP ++}; ++ ++enum MWIFIEX_802_11_WEP_STATUS { ++ MWIFIEX_802_11_WEP_ENABLED, ++ MWIFIEX_802_11_WEP_DISABLED, ++}; ++ ++#define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF))) ++ ++#define PROPRIETARY_TLV_BASE_ID 0x0100 ++#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) ++#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1) ++#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2) ++#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10) ++#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16) ++#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) ++#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) ++#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) ++#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42) ++#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82) ++#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83) ++#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84) ++#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94) ++#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113) ++#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114) ++ ++#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 ++ ++#define SSN_MASK 0xfff0 ++ ++#define BA_RESULT_SUCCESS 0x0 ++#define BA_RESULT_TIMEOUT 0x2 ++ ++#define IS_BASTREAM_SETUP(ptr) (ptr->ba_status) ++ ++#define BA_STREAM_NOT_ALLOWED 0xff ++ ++#define IS_11N_ENABLED(priv) ((priv->adapter->config_bands & BAND_GN || \ ++ priv->adapter->config_bands & BAND_AN) \ ++ && priv->curr_bss_params.bss_descriptor.bcn_ht_cap) ++#define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) &\ ++ BIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS) ++ ++#define MWIFIEX_TX_DATA_BUF_SIZE_4K 4096 ++#define MWIFIEX_TX_DATA_BUF_SIZE_8K 8192 ++ ++#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) ++ ++/* dev_cap bitmap ++ * BIT ++ * 0-16 reserved ++ * 17 IEEE80211_HT_CAP_SUP_WIDTH_20_40 ++ * 18-22 reserved ++ * 23 IEEE80211_HT_CAP_SGI_20 ++ * 24 IEEE80211_HT_CAP_SGI_40 ++ * 25 IEEE80211_HT_CAP_TX_STBC ++ * 26 IEEE80211_HT_CAP_RX_STBC ++ * 27-28 reserved ++ * 29 IEEE80211_HT_CAP_GRN_FLD ++ * 30-31 reserved ++ */ ++#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & BIT(17)) ++#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & BIT(23)) ++#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & BIT(24)) ++#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25)) ++#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26)) ++#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) ++ ++#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f) ++#define SETHT_MCS32(x) (x[4] |= 1) ++ ++#define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4)) ++ ++#define LLC_SNAP_LEN 8 ++ ++#define MOD_CLASS_HR_DSSS 0x03 ++#define MOD_CLASS_OFDM 0x07 ++#define MOD_CLASS_HT 0x08 ++#define HT_BW_20 0 ++#define HT_BW_40 1 ++ ++#define HostCmd_CMD_GET_HW_SPEC 0x0003 ++#define HostCmd_CMD_802_11_SCAN 0x0006 ++#define HostCmd_CMD_802_11_GET_LOG 0x000b ++#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010 ++#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059 ++#define HostCmd_CMD_802_11_ASSOCIATE 0x0012 ++#define HostCmd_CMD_802_11_SNMP_MIB 0x0016 ++#define HostCmd_CMD_MAC_REG_ACCESS 0x0019 ++#define HostCmd_CMD_BBP_REG_ACCESS 0x001a ++#define HostCmd_CMD_RF_REG_ACCESS 0x001b ++#define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad ++#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d ++#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024 ++#define HostCmd_CMD_MAC_CONTROL 0x0028 ++#define HostCmd_CMD_802_11_AD_HOC_START 0x002b ++#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c ++#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040 ++#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D ++#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b ++#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e ++#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c ++#define HostCmd_CMD_WMM_GET_STATUS 0x0071 ++#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f ++#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083 ++#define HostCmd_CMD_VERSION_EXT 0x0097 ++#define HostCmd_CMD_RSSI_INFO 0x00a4 ++#define HostCmd_CMD_FUNC_INIT 0x00a9 ++#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa ++#define HostCmd_CMD_11N_CFG 0x00cd ++#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce ++#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf ++#define HostCmd_CMD_11N_DELBA 0x00d0 ++#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9 ++#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df ++#define HostCmd_CMD_TXPWR_CFG 0x00d1 ++#define HostCmd_CMD_TX_RATE_CFG 0x00d6 ++#define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4 ++#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5 ++#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed ++#define HostCmd_CMD_SET_BSS_MODE 0x00f7 ++ ++ ++enum ENH_PS_MODES { ++ EN_PS = 1, ++ DIS_PS = 2, ++ EN_AUTO_DS = 3, ++ DIS_AUTO_DS = 4, ++ SLEEP_CONFIRM = 5, ++ GET_PS = 0, ++ EN_AUTO_PS = 0xff, ++ DIS_AUTO_PS = 0xfe, ++}; ++ ++#define HostCmd_RET_BIT 0x8000 ++#define HostCmd_ACT_GEN_GET 0x0000 ++#define HostCmd_ACT_GEN_SET 0x0001 ++#define HostCmd_RESULT_OK 0x0000 ++ ++#define HostCmd_ACT_MAC_RX_ON 0x0001 ++#define HostCmd_ACT_MAC_TX_ON 0x0002 ++#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008 ++#define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010 ++#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 ++#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 ++#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000 ++ ++#define HostCmd_BSS_MODE_IBSS 0x0002 ++#define HostCmd_BSS_MODE_ANY 0x0003 ++ ++#define HostCmd_SCAN_RADIO_TYPE_BG 0 ++#define HostCmd_SCAN_RADIO_TYPE_A 1 ++ ++#define HOST_SLEEP_CFG_CANCEL 0xffffffff ++#define HOST_SLEEP_CFG_COND_DEF 0x0000000f ++#define HOST_SLEEP_CFG_GPIO_DEF 0xff ++#define HOST_SLEEP_CFG_GAP_DEF 0 ++ ++#define CMD_F_HOSTCMD (1 << 0) ++#define CMD_F_CANCELED (1 << 1) ++ ++#define HostCmd_CMD_ID_MASK 0x0fff ++ ++#define HostCmd_SEQ_NUM_MASK 0x00ff ++ ++#define HostCmd_BSS_NUM_MASK 0x0f00 ++ ++#define HostCmd_BSS_TYPE_MASK 0xf000 ++ ++#define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) { \ ++ (((seq) & 0x00ff) | \ ++ (((num) & 0x000f) << 8)) | \ ++ (((type) & 0x000f) << 12); } ++ ++#define HostCmd_GET_SEQ_NO(seq) \ ++ ((seq) & HostCmd_SEQ_NUM_MASK) ++ ++#define HostCmd_GET_BSS_NO(seq) \ ++ (((seq) & HostCmd_BSS_NUM_MASK) >> 8) ++ ++#define HostCmd_GET_BSS_TYPE(seq) \ ++ (((seq) & HostCmd_BSS_TYPE_MASK) >> 12) ++ ++#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001 ++#define EVENT_LINK_LOST 0x00000003 ++#define EVENT_LINK_SENSED 0x00000004 ++#define EVENT_MIB_CHANGED 0x00000006 ++#define EVENT_INIT_DONE 0x00000007 ++#define EVENT_DEAUTHENTICATED 0x00000008 ++#define EVENT_DISASSOCIATED 0x00000009 ++#define EVENT_PS_AWAKE 0x0000000a ++#define EVENT_PS_SLEEP 0x0000000b ++#define EVENT_MIC_ERR_MULTICAST 0x0000000d ++#define EVENT_MIC_ERR_UNICAST 0x0000000e ++#define EVENT_DEEP_SLEEP_AWAKE 0x00000010 ++#define EVENT_ADHOC_BCN_LOST 0x00000011 ++ ++#define EVENT_WMM_STATUS_CHANGE 0x00000017 ++#define EVENT_BG_SCAN_REPORT 0x00000018 ++#define EVENT_RSSI_LOW 0x00000019 ++#define EVENT_SNR_LOW 0x0000001a ++#define EVENT_MAX_FAIL 0x0000001b ++#define EVENT_RSSI_HIGH 0x0000001c ++#define EVENT_SNR_HIGH 0x0000001d ++#define EVENT_IBSS_COALESCED 0x0000001e ++#define EVENT_DATA_RSSI_LOW 0x00000024 ++#define EVENT_DATA_SNR_LOW 0x00000025 ++#define EVENT_DATA_RSSI_HIGH 0x00000026 ++#define EVENT_DATA_SNR_HIGH 0x00000027 ++#define EVENT_LINK_QUALITY 0x00000028 ++#define EVENT_PORT_RELEASE 0x0000002b ++#define EVENT_PRE_BEACON_LOST 0x00000031 ++#define EVENT_ADDBA 0x00000033 ++#define EVENT_DELBA 0x00000034 ++#define EVENT_BA_STREAM_TIEMOUT 0x00000037 ++#define EVENT_AMSDU_AGGR_CTRL 0x00000042 ++#define EVENT_WEP_ICV_ERR 0x00000046 ++#define EVENT_HS_ACT_REQ 0x00000047 ++#define EVENT_BW_CHANGE 0x00000048 ++ ++#define EVENT_HOSTWAKE_STAIE 0x0000004d ++ ++#define EVENT_ID_MASK 0xffff ++#define BSS_NUM_MASK 0xf ++ ++#define EVENT_GET_BSS_NUM(event_cause) \ ++ (((event_cause) >> 16) & BSS_NUM_MASK) ++ ++#define EVENT_GET_BSS_TYPE(event_cause) \ ++ (((event_cause) >> 24) & 0x00ff) ++ ++struct mwifiex_ie_types_header { ++ __le16 type; ++ __le16 len; ++} __packed; ++ ++struct mwifiex_ie_types_data { ++ struct mwifiex_ie_types_header header; ++ u8 data[1]; ++} __packed; ++ ++#define MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET 0x01 ++#define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08 ++ ++struct txpd { ++ u8 bss_type; ++ u8 bss_num; ++ __le16 tx_pkt_length; ++ __le16 tx_pkt_offset; ++ __le16 tx_pkt_type; ++ __le32 tx_control; ++ u8 priority; ++ u8 flags; ++ u8 pkt_delay_2ms; ++ u8 reserved1; ++} __packed; ++ ++struct rxpd { ++ u8 bss_type; ++ u8 bss_num; ++ u16 rx_pkt_length; ++ u16 rx_pkt_offset; ++ u16 rx_pkt_type; ++ u16 seq_num; ++ u8 priority; ++ u8 rx_rate; ++ s8 snr; ++ s8 nf; ++ /* Ht Info [Bit 0] RxRate format: LG=0, HT=1 ++ * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 ++ * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */ ++ u8 ht_info; ++ u8 reserved; ++} __packed; ++ ++enum mwifiex_chan_scan_mode_bitmasks { ++ MWIFIEX_PASSIVE_SCAN = BIT(0), ++ MWIFIEX_DISABLE_CHAN_FILT = BIT(1), ++}; ++ ++#define SECOND_CHANNEL_BELOW 0x30 ++#define SECOND_CHANNEL_ABOVE 0x10 ++struct mwifiex_chan_scan_param_set { ++ u8 radio_type; ++ u8 chan_number; ++ u8 chan_scan_mode_bitmap; ++ __le16 min_scan_time; ++ __le16 max_scan_time; ++} __packed; ++ ++struct mwifiex_ie_types_chan_list_param_set { ++ struct mwifiex_ie_types_header header; ++ struct mwifiex_chan_scan_param_set chan_scan_param[1]; ++} __packed; ++ ++struct chan_band_param_set { ++ u8 radio_type; ++ u8 chan_number; ++}; ++ ++struct mwifiex_ie_types_chan_band_list_param_set { ++ struct mwifiex_ie_types_header header; ++ struct chan_band_param_set chan_band_param[1]; ++} __packed; ++ ++struct mwifiex_ie_types_rates_param_set { ++ struct mwifiex_ie_types_header header; ++ u8 rates[1]; ++} __packed; ++ ++struct mwifiex_ie_types_ssid_param_set { ++ struct mwifiex_ie_types_header header; ++ u8 ssid[1]; ++} __packed; ++ ++struct mwifiex_ie_types_num_probes { ++ struct mwifiex_ie_types_header header; ++ __le16 num_probes; ++} __packed; ++ ++struct mwifiex_ie_types_wildcard_ssid_params { ++ struct mwifiex_ie_types_header header; ++ u8 max_ssid_length; ++ u8 ssid[1]; ++} __packed; ++ ++#define TSF_DATA_SIZE 8 ++struct mwifiex_ie_types_tsf_timestamp { ++ struct mwifiex_ie_types_header header; ++ u8 tsf_data[1]; ++} __packed; ++ ++struct mwifiex_cf_param_set { ++ u8 cfp_cnt; ++ u8 cfp_period; ++ u16 cfp_max_duration; ++ u16 cfp_duration_remaining; ++} __packed; ++ ++struct mwifiex_ibss_param_set { ++ u16 atim_window; ++} __packed; ++ ++struct mwifiex_ie_types_ss_param_set { ++ struct mwifiex_ie_types_header header; ++ union { ++ struct mwifiex_cf_param_set cf_param_set[1]; ++ struct mwifiex_ibss_param_set ibss_param_set[1]; ++ } cf_ibss; ++} __packed; ++ ++struct mwifiex_fh_param_set { ++ u16 dwell_time; ++ u8 hop_set; ++ u8 hop_pattern; ++ u8 hop_index; ++} __packed; ++ ++struct mwifiex_ds_param_set { ++ u8 current_chan; ++} __packed; ++ ++struct mwifiex_ie_types_phy_param_set { ++ struct mwifiex_ie_types_header header; ++ union { ++ struct mwifiex_fh_param_set fh_param_set[1]; ++ struct mwifiex_ds_param_set ds_param_set[1]; ++ } fh_ds; ++} __packed; ++ ++struct mwifiex_ie_types_auth_type { ++ struct mwifiex_ie_types_header header; ++ __le16 auth_type; ++} __packed; ++ ++struct mwifiex_ie_types_vendor_param_set { ++ struct mwifiex_ie_types_header header; ++ u8 ie[MWIFIEX_MAX_VSIE_LEN]; ++}; ++ ++struct mwifiex_ie_types_rsn_param_set { ++ struct mwifiex_ie_types_header header; ++ u8 rsn_ie[1]; ++} __packed; ++ ++#define KEYPARAMSET_FIXED_LEN 6 ++ ++struct mwifiex_ie_type_key_param_set { ++ __le16 type; ++ __le16 length; ++ __le16 key_type_id; ++ __le16 key_info; ++ __le16 key_len; ++ u8 key[50]; ++} __packed; ++ ++struct host_cmd_ds_802_11_key_material { ++ __le16 action; ++ struct mwifiex_ie_type_key_param_set key_param_set; ++} __packed; ++ ++struct host_cmd_ds_gen { ++ u16 command; ++ u16 size; ++ u16 seq_num; ++ u16 result; ++}; ++ ++#define S_DS_GEN sizeof(struct host_cmd_ds_gen) ++ ++enum sleep_resp_ctrl { ++ RESP_NOT_NEEDED = 0, ++ RESP_NEEDED, ++}; ++ ++struct mwifiex_ps_param { ++ __le16 null_pkt_interval; ++ __le16 multiple_dtims; ++ __le16 bcn_miss_timeout; ++ __le16 local_listen_interval; ++ __le16 adhoc_wake_period; ++ __le16 mode; ++ __le16 delay_to_ps; ++}; ++ ++#define BITMAP_AUTO_DS 0x01 ++#define BITMAP_STA_PS 0x10 ++ ++struct mwifiex_ie_types_auto_ds_param { ++ struct mwifiex_ie_types_header header; ++ __le16 deep_sleep_timeout; ++} __packed; ++ ++struct mwifiex_ie_types_ps_param { ++ struct mwifiex_ie_types_header header; ++ struct mwifiex_ps_param param; ++} __packed; ++ ++struct host_cmd_ds_802_11_ps_mode_enh { ++ __le16 action; ++ ++ union { ++ struct mwifiex_ps_param opt_ps; ++ __le16 ps_bitmap; ++ } params; ++} __packed; ++ ++struct host_cmd_ds_get_hw_spec { ++ __le16 hw_if_version; ++ __le16 version; ++ __le16 reserved; ++ __le16 num_of_mcast_adr; ++ u8 permanent_addr[ETH_ALEN]; ++ __le16 region_code; ++ __le16 number_of_antenna; ++ __le32 fw_release_number; ++ __le32 reserved_1; ++ __le32 reserved_2; ++ __le32 reserved_3; ++ __le32 fw_cap_info; ++ __le32 dot_11n_dev_cap; ++ u8 dev_mcs_support; ++ __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ ++ __le16 reserved_4; ++} __packed; ++ ++struct host_cmd_ds_802_11_rssi_info { ++ __le16 action; ++ __le16 ndata; ++ __le16 nbcn; ++ __le16 reserved[9]; ++ long long reserved_1; ++}; ++ ++struct host_cmd_ds_802_11_rssi_info_rsp { ++ __le16 action; ++ __le16 ndata; ++ __le16 nbcn; ++ __le16 data_rssi_last; ++ __le16 data_nf_last; ++ __le16 data_rssi_avg; ++ __le16 data_nf_avg; ++ __le16 bcn_rssi_last; ++ __le16 bcn_nf_last; ++ __le16 bcn_rssi_avg; ++ __le16 bcn_nf_avg; ++ long long tsf_bcn; ++}; ++ ++struct host_cmd_ds_802_11_mac_address { ++ __le16 action; ++ u8 mac_addr[ETH_ALEN]; ++}; ++ ++struct host_cmd_ds_mac_control { ++ __le16 action; ++ __le16 reserved; ++}; ++ ++struct host_cmd_ds_mac_multicast_adr { ++ __le16 action; ++ __le16 num_of_adrs; ++ u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; ++} __packed; ++ ++struct host_cmd_ds_802_11_deauthenticate { ++ u8 mac_addr[ETH_ALEN]; ++ __le16 reason_code; ++} __packed; ++ ++struct host_cmd_ds_802_11_associate { ++ u8 peer_sta_addr[ETH_ALEN]; ++ __le16 cap_info_bitmap; ++ __le16 listen_interval; ++ __le16 beacon_period; ++ u8 dtim_period; ++} __packed; ++ ++struct ieee_types_assoc_rsp { ++ __le16 cap_info_bitmap; ++ __le16 status_code; ++ __le16 a_id; ++ u8 ie_buffer[1]; ++} __packed; ++ ++struct host_cmd_ds_802_11_associate_rsp { ++ struct ieee_types_assoc_rsp assoc_rsp; ++} __packed; ++ ++struct ieee_types_cf_param_set { ++ u8 element_id; ++ u8 len; ++ u8 cfp_cnt; ++ u8 cfp_period; ++ u16 cfp_max_duration; ++ u16 cfp_duration_remaining; ++} __packed; ++ ++struct ieee_types_ibss_param_set { ++ u8 element_id; ++ u8 len; ++ __le16 atim_window; ++} __packed; ++ ++union ieee_types_ss_param_set { ++ struct ieee_types_cf_param_set cf_param_set; ++ struct ieee_types_ibss_param_set ibss_param_set; ++} __packed; ++ ++struct ieee_types_fh_param_set { ++ u8 element_id; ++ u8 len; ++ __le16 dwell_time; ++ u8 hop_set; ++ u8 hop_pattern; ++ u8 hop_index; ++} __packed; ++ ++struct ieee_types_ds_param_set { ++ u8 element_id; ++ u8 len; ++ u8 current_chan; ++} __packed; ++ ++union ieee_types_phy_param_set { ++ struct ieee_types_fh_param_set fh_param_set; ++ struct ieee_types_ds_param_set ds_param_set; ++} __packed; ++ ++struct host_cmd_ds_802_11_ad_hoc_start { ++ u8 ssid[IEEE80211_MAX_SSID_LEN]; ++ u8 bss_mode; ++ __le16 beacon_period; ++ u8 dtim_period; ++ union ieee_types_ss_param_set ss_param_set; ++ union ieee_types_phy_param_set phy_param_set; ++ u16 reserved1; ++ __le16 cap_info_bitmap; ++ u8 DataRate[HOSTCMD_SUPPORTED_RATES]; ++} __packed; ++ ++struct host_cmd_ds_802_11_ad_hoc_result { ++ u8 pad[3]; ++ u8 bssid[ETH_ALEN]; ++} __packed; ++ ++struct adhoc_bss_desc { ++ u8 bssid[ETH_ALEN]; ++ u8 ssid[IEEE80211_MAX_SSID_LEN]; ++ u8 bss_mode; ++ __le16 beacon_period; ++ u8 dtim_period; ++ u8 time_stamp[8]; ++ u8 local_time[8]; ++ union ieee_types_phy_param_set phy_param_set; ++ union ieee_types_ss_param_set ss_param_set; ++ __le16 cap_info_bitmap; ++ u8 data_rates[HOSTCMD_SUPPORTED_RATES]; ++ ++ /* ++ * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. ++ * It is used in the Adhoc join command and will cause a ++ * binary layout mismatch with the firmware ++ */ ++} __packed; ++ ++struct host_cmd_ds_802_11_ad_hoc_join { ++ struct adhoc_bss_desc bss_descriptor; ++ u16 reserved1; ++ u16 reserved2; ++} __packed; ++ ++struct host_cmd_ds_802_11_get_log { ++ __le32 mcast_tx_frame; ++ __le32 failed; ++ __le32 retry; ++ __le32 multi_retry; ++ __le32 frame_dup; ++ __le32 rts_success; ++ __le32 rts_failure; ++ __le32 ack_failure; ++ __le32 rx_frag; ++ __le32 mcast_rx_frame; ++ __le32 fcs_error; ++ __le32 tx_frame; ++ __le32 reserved; ++ __le32 wep_icv_err_cnt[4]; ++}; ++ ++struct host_cmd_ds_tx_rate_query { ++ u8 tx_rate; ++ /* Ht Info [Bit 0] RxRate format: LG=0, HT=1 ++ * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 ++ * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */ ++ u8 ht_info; ++} __packed; ++ ++enum Host_Sleep_Action { ++ HS_CONFIGURE = 0x0001, ++ HS_ACTIVATE = 0x0002, ++}; ++ ++struct mwifiex_hs_config_param { ++ __le32 conditions; ++ u8 gpio; ++ u8 gap; ++} __packed; ++ ++struct hs_activate_param { ++ u16 resp_ctrl; ++} __packed; ++ ++struct host_cmd_ds_802_11_hs_cfg_enh { ++ __le16 action; ++ ++ union { ++ struct mwifiex_hs_config_param hs_config; ++ struct hs_activate_param hs_activate; ++ } params; ++} __packed; ++ ++enum SNMP_MIB_INDEX { ++ OP_RATE_SET_I = 1, ++ DTIM_PERIOD_I = 3, ++ RTS_THRESH_I = 5, ++ SHORT_RETRY_LIM_I = 6, ++ LONG_RETRY_LIM_I = 7, ++ FRAG_THRESH_I = 8, ++ DOT11D_I = 9, ++}; ++ ++#define MAX_SNMP_BUF_SIZE 128 ++ ++struct host_cmd_ds_802_11_snmp_mib { ++ __le16 query_type; ++ __le16 oid; ++ __le16 buf_size; ++ u8 value[1]; ++} __packed; ++ ++struct mwifiex_rate_scope { ++ __le16 type; ++ __le16 length; ++ __le16 hr_dsss_rate_bitmap; ++ __le16 ofdm_rate_bitmap; ++ __le16 ht_mcs_rate_bitmap[8]; ++} __packed; ++ ++struct mwifiex_rate_drop_pattern { ++ __le16 type; ++ __le16 length; ++ __le32 rate_drop_mode; ++} __packed; ++ ++struct host_cmd_ds_tx_rate_cfg { ++ __le16 action; ++ __le16 cfg_index; ++} __packed; ++ ++struct mwifiex_power_group { ++ u8 modulation_class; ++ u8 first_rate_code; ++ u8 last_rate_code; ++ s8 power_step; ++ s8 power_min; ++ s8 power_max; ++ u8 ht_bandwidth; ++ u8 reserved; ++} __packed; ++ ++struct mwifiex_types_power_group { ++ u16 type; ++ u16 length; ++} __packed; ++ ++struct host_cmd_ds_txpwr_cfg { ++ __le16 action; ++ __le16 cfg_index; ++ __le32 mode; ++} __packed; ++ ++#define MWIFIEX_USER_SCAN_CHAN_MAX 50 ++ ++#define MWIFIEX_MAX_SSID_LIST_LENGTH 10 ++ ++struct mwifiex_scan_cmd_config { ++ /* ++ * BSS Type to be sent in the firmware command ++ * ++ * Field can be used to restrict the types of networks returned in the ++ * scan. Valid settings are: ++ * ++ * - MWIFIEX_SCAN_MODE_BSS (infrastructure) ++ * - MWIFIEX_SCAN_MODE_IBSS (adhoc) ++ * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure) ++ */ ++ u8 bss_mode; ++ ++ /* Specific BSSID used to filter scan results in the firmware */ ++ u8 specific_bssid[ETH_ALEN]; ++ ++ /* Length of TLVs sent in command starting at tlvBuffer */ ++ u32 tlv_buf_len; ++ ++ /* ++ * SSID TLV(s) and ChanList TLVs to be sent in the firmware command ++ * ++ * TLV_TYPE_CHANLIST, mwifiex_ie_types_chan_list_param_set ++ * WLAN_EID_SSID, mwifiex_ie_types_ssid_param_set ++ */ ++ u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored ++ here */ ++} __packed; ++ ++struct mwifiex_user_scan_chan { ++ u8 chan_number; ++ u8 radio_type; ++ u8 scan_type; ++ u8 reserved; ++ u32 scan_time; ++} __packed; ++ ++struct mwifiex_user_scan_ssid { ++ u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; ++ u8 max_len; ++} __packed; ++ ++struct mwifiex_user_scan_cfg { ++ /* ++ * Flag set to keep the previous scan table intact ++ * ++ * If set, the scan results will accumulate, replacing any previous ++ * matched entries for a BSS with the new scan data ++ */ ++ u8 keep_previous_scan; ++ /* ++ * BSS mode to be sent in the firmware command ++ * ++ * Field can be used to restrict the types of networks returned in the ++ * scan. Valid settings are: ++ * ++ * - MWIFIEX_SCAN_MODE_BSS (infrastructure) ++ * - MWIFIEX_SCAN_MODE_IBSS (adhoc) ++ * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure) ++ */ ++ u8 bss_mode; ++ /* Configure the number of probe requests for active chan scans */ ++ u8 num_probes; ++ u8 reserved; ++ /* BSSID filter sent in the firmware command to limit the results */ ++ u8 specific_bssid[ETH_ALEN]; ++ /* SSID filter list used in the to limit the scan results */ ++ struct mwifiex_user_scan_ssid ssid_list[MWIFIEX_MAX_SSID_LIST_LENGTH]; ++ /* Variable number (fixed maximum) of channels to scan up */ ++ struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX]; ++} __packed; ++ ++struct ie_body { ++ u8 grp_key_oui[4]; ++ u8 ptk_cnt[2]; ++ u8 ptk_body[4]; ++} __packed; ++ ++struct host_cmd_ds_802_11_scan { ++ u8 bss_mode; ++ u8 bssid[ETH_ALEN]; ++ u8 tlv_buffer[1]; ++} __packed; ++ ++struct host_cmd_ds_802_11_scan_rsp { ++ __le16 bss_descript_size; ++ u8 number_of_sets; ++ u8 bss_desc_and_tlv_buffer[1]; ++} __packed; ++ ++struct host_cmd_ds_802_11_bg_scan_query { ++ u8 flush; ++} __packed; ++ ++struct host_cmd_ds_802_11_bg_scan_query_rsp { ++ u32 report_condition; ++ struct host_cmd_ds_802_11_scan_rsp scan_resp; ++} __packed; ++ ++struct mwifiex_ietypes_domain_param_set { ++ struct mwifiex_ie_types_header header; ++ u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; ++ struct ieee80211_country_ie_triplet triplet[1]; ++} __packed; ++ ++struct host_cmd_ds_802_11d_domain_info { ++ __le16 action; ++ struct mwifiex_ietypes_domain_param_set domain; ++} __packed; ++ ++struct host_cmd_ds_802_11d_domain_info_rsp { ++ __le16 action; ++ struct mwifiex_ietypes_domain_param_set domain; ++} __packed; ++ ++struct host_cmd_ds_11n_addba_req { ++ u8 add_req_result; ++ u8 peer_mac_addr[ETH_ALEN]; ++ u8 dialog_token; ++ __le16 block_ack_param_set; ++ __le16 block_ack_tmo; ++ __le16 ssn; ++} __packed; ++ ++struct host_cmd_ds_11n_addba_rsp { ++ u8 add_rsp_result; ++ u8 peer_mac_addr[ETH_ALEN]; ++ u8 dialog_token; ++ __le16 status_code; ++ __le16 block_ack_param_set; ++ __le16 block_ack_tmo; ++ __le16 ssn; ++} __packed; ++ ++struct host_cmd_ds_11n_delba { ++ u8 del_result; ++ u8 peer_mac_addr[ETH_ALEN]; ++ __le16 del_ba_param_set; ++ __le16 reason_code; ++ u8 reserved; ++} __packed; ++ ++struct host_cmd_ds_11n_batimeout { ++ u8 tid; ++ u8 peer_mac_addr[ETH_ALEN]; ++ u8 origninator; ++} __packed; ++ ++struct host_cmd_ds_11n_cfg { ++ __le16 action; ++ __le16 ht_tx_cap; ++ __le16 ht_tx_info; ++} __packed; ++ ++struct host_cmd_ds_txbuf_cfg { ++ __le16 action; ++ __le16 buff_size; ++ __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ ++ __le16 reserved3; ++} __packed; ++ ++struct host_cmd_ds_amsdu_aggr_ctrl { ++ __le16 action; ++ __le16 enable; ++ __le16 curr_buf_size; ++} __packed; ++ ++struct mwifiex_ie_types_wmm_param_set { ++ struct mwifiex_ie_types_header header; ++ u8 wmm_ie[1]; ++}; ++ ++struct mwifiex_ie_types_wmm_queue_status { ++ struct mwifiex_ie_types_header header; ++ u8 queue_index; ++ u8 disabled; ++ u16 medium_time; ++ u8 flow_required; ++ u8 flow_created; ++ u32 reserved; ++}; ++ ++struct ieee_types_vendor_header { ++ u8 element_id; ++ u8 len; ++ u8 oui[3]; ++ u8 oui_type; ++ u8 oui_subtype; ++ u8 version; ++} __packed; ++ ++struct ieee_types_wmm_ac_parameters { ++ u8 aci_aifsn_bitmap; ++ u8 ecw_bitmap; ++ __le16 tx_op_limit; ++} __packed; ++ ++struct ieee_types_wmm_parameter { ++ /* ++ * WMM Parameter IE - Vendor Specific Header: ++ * element_id [221/0xdd] ++ * Len [24] ++ * Oui [00:50:f2] ++ * OuiType [2] ++ * OuiSubType [1] ++ * Version [1] ++ */ ++ struct ieee_types_vendor_header vend_hdr; ++ u8 qos_info_bitmap; ++ u8 reserved; ++ struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_MAX_QUEUES]; ++} __packed; ++ ++struct ieee_types_wmm_info { ++ ++ /* ++ * WMM Info IE - Vendor Specific Header: ++ * element_id [221/0xdd] ++ * Len [7] ++ * Oui [00:50:f2] ++ * OuiType [2] ++ * OuiSubType [0] ++ * Version [1] ++ */ ++ struct ieee_types_vendor_header vend_hdr; ++ ++ u8 qos_info_bitmap; ++} __packed; ++ ++struct host_cmd_ds_wmm_get_status { ++ u8 queue_status_tlv[sizeof(struct mwifiex_ie_types_wmm_queue_status) * ++ IEEE80211_MAX_QUEUES]; ++ u8 wmm_param_tlv[sizeof(struct ieee_types_wmm_parameter) + 2]; ++} __packed; ++ ++struct mwifiex_wmm_ac_status { ++ u8 disabled; ++ u8 flow_required; ++ u8 flow_created; ++}; ++ ++struct mwifiex_ie_types_htcap { ++ struct mwifiex_ie_types_header header; ++ struct ieee80211_ht_cap ht_cap; ++} __packed; ++ ++struct mwifiex_ie_types_htinfo { ++ struct mwifiex_ie_types_header header; ++ struct ieee80211_ht_info ht_info; ++} __packed; ++ ++struct mwifiex_ie_types_2040bssco { ++ struct mwifiex_ie_types_header header; ++ u8 bss_co_2040; ++} __packed; ++ ++struct mwifiex_ie_types_extcap { ++ struct mwifiex_ie_types_header header; ++ u8 ext_cap; ++} __packed; ++ ++struct host_cmd_ds_mac_reg_access { ++ __le16 action; ++ __le16 offset; ++ __le32 value; ++} __packed; ++ ++struct host_cmd_ds_bbp_reg_access { ++ __le16 action; ++ __le16 offset; ++ u8 value; ++ u8 reserved[3]; ++} __packed; ++ ++struct host_cmd_ds_rf_reg_access { ++ __le16 action; ++ __le16 offset; ++ u8 value; ++ u8 reserved[3]; ++} __packed; ++ ++struct host_cmd_ds_pmic_reg_access { ++ __le16 action; ++ __le16 offset; ++ u8 value; ++ u8 reserved[3]; ++} __packed; ++ ++struct host_cmd_ds_802_11_eeprom_access { ++ __le16 action; ++ ++ __le16 offset; ++ __le16 byte_count; ++ u8 value; ++} __packed; ++ ++struct host_cmd_ds_802_11_rf_channel { ++ __le16 action; ++ __le16 current_channel; ++ __le16 rf_type; ++ __le16 reserved; ++ u8 reserved_1[32]; ++} __packed; ++ ++struct host_cmd_ds_version_ext { ++ u8 version_str_sel; ++ char version_str[128]; ++} __packed; ++ ++struct host_cmd_ds_802_11_ibss_status { ++ __le16 action; ++ __le16 enable; ++ u8 bssid[ETH_ALEN]; ++ __le16 beacon_interval; ++ __le16 atim_window; ++ __le16 use_g_rate_protect; ++} __packed; ++ ++#define CONNECTION_TYPE_INFRA 0 ++#define CONNECTION_TYPE_ADHOC 1 ++ ++struct host_cmd_ds_set_bss_mode { ++ u8 con_type; ++} __packed; ++ ++struct host_cmd_ds_command { ++ __le16 command; ++ __le16 size; ++ __le16 seq_num; ++ __le16 result; ++ union { ++ struct host_cmd_ds_get_hw_spec hw_spec; ++ struct host_cmd_ds_mac_control mac_ctrl; ++ struct host_cmd_ds_802_11_mac_address mac_addr; ++ struct host_cmd_ds_mac_multicast_adr mc_addr; ++ struct host_cmd_ds_802_11_get_log get_log; ++ struct host_cmd_ds_802_11_rssi_info rssi_info; ++ struct host_cmd_ds_802_11_rssi_info_rsp rssi_info_rsp; ++ struct host_cmd_ds_802_11_snmp_mib smib; ++ struct host_cmd_ds_802_11_rf_channel rf_channel; ++ struct host_cmd_ds_tx_rate_query tx_rate; ++ struct host_cmd_ds_tx_rate_cfg tx_rate_cfg; ++ struct host_cmd_ds_txpwr_cfg txp_cfg; ++ struct host_cmd_ds_802_11_ps_mode_enh psmode_enh; ++ struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg; ++ struct host_cmd_ds_802_11_scan scan; ++ struct host_cmd_ds_802_11_scan_rsp scan_resp; ++ struct host_cmd_ds_802_11_bg_scan_query bg_scan_query; ++ struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp; ++ struct host_cmd_ds_802_11_associate associate; ++ struct host_cmd_ds_802_11_associate_rsp associate_rsp; ++ struct host_cmd_ds_802_11_deauthenticate deauth; ++ struct host_cmd_ds_802_11_ad_hoc_start adhoc_start; ++ struct host_cmd_ds_802_11_ad_hoc_result adhoc_result; ++ struct host_cmd_ds_802_11_ad_hoc_join adhoc_join; ++ struct host_cmd_ds_802_11d_domain_info domain_info; ++ struct host_cmd_ds_802_11d_domain_info_rsp domain_info_resp; ++ struct host_cmd_ds_11n_addba_req add_ba_req; ++ struct host_cmd_ds_11n_addba_rsp add_ba_rsp; ++ struct host_cmd_ds_11n_delba del_ba; ++ struct host_cmd_ds_txbuf_cfg tx_buf; ++ struct host_cmd_ds_amsdu_aggr_ctrl amsdu_aggr_ctrl; ++ struct host_cmd_ds_11n_cfg htcfg; ++ struct host_cmd_ds_wmm_get_status get_wmm_status; ++ struct host_cmd_ds_802_11_key_material key_material; ++ struct host_cmd_ds_version_ext verext; ++ struct host_cmd_ds_802_11_ibss_status ibss_coalescing; ++ struct host_cmd_ds_mac_reg_access mac_reg; ++ struct host_cmd_ds_bbp_reg_access bbp_reg; ++ struct host_cmd_ds_rf_reg_access rf_reg; ++ struct host_cmd_ds_pmic_reg_access pmic_reg; ++ struct host_cmd_ds_set_bss_mode bss_mode; ++ struct host_cmd_ds_802_11_eeprom_access eeprom; ++ } params; ++} __packed; ++ ++struct mwifiex_opt_sleep_confirm { ++ __le16 command; ++ __le16 size; ++ __le16 seq_num; ++ __le16 result; ++ __le16 action; ++ __le16 resp_ctrl; ++} __packed; ++ ++struct mwifiex_opt_sleep_confirm_buffer { ++ u8 hdr[4]; ++ struct mwifiex_opt_sleep_confirm ps_cfm_sleep; ++} __packed; ++#endif /* !_MWIFIEX_FW_H_ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/init.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/init.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/init.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/init.c 2011-05-05 23:29:45.476441755 +0200 +@@ -0,0 +1,652 @@ ++/* ++ * Marvell Wireless LAN device driver: HW/FW Initialization ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++ ++/* ++ * This function adds a BSS priority table to the table list. ++ * ++ * The function allocates a new BSS priority table node and adds it to ++ * the end of BSS priority table list, kept in driver memory. ++ */ ++static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct mwifiex_bss_prio_node *bss_prio; ++ unsigned long flags; ++ ++ bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL); ++ if (!bss_prio) { ++ dev_err(adapter->dev, "%s: failed to alloc bss_prio\n", ++ __func__); ++ return -1; ++ } ++ ++ bss_prio->priv = priv; ++ INIT_LIST_HEAD(&bss_prio->list); ++ if (!adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur) ++ adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = ++ bss_prio; ++ ++ spin_lock_irqsave(&adapter->bss_prio_tbl[priv->bss_priority] ++ .bss_prio_lock, flags); ++ list_add_tail(&bss_prio->list, ++ &adapter->bss_prio_tbl[priv->bss_priority] ++ .bss_prio_head); ++ spin_unlock_irqrestore(&adapter->bss_prio_tbl[priv->bss_priority] ++ .bss_prio_lock, flags); ++ ++ return 0; ++} ++ ++/* ++ * This function initializes the private structure and sets default ++ * values to the members. ++ * ++ * Additionally, it also initializes all the locks and sets up all the ++ * lists. ++ */ ++static int mwifiex_init_priv(struct mwifiex_private *priv) ++{ ++ u32 i; ++ ++ priv->media_connected = false; ++ memset(priv->curr_addr, 0xff, ETH_ALEN); ++ ++ priv->pkt_tx_ctrl = 0; ++ priv->bss_mode = NL80211_IFTYPE_STATION; ++ priv->data_rate = 0; /* Initially indicate the rate as auto */ ++ priv->is_data_rate_auto = true; ++ priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; ++ priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; ++ ++ priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; ++ priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; ++ priv->sec_info.encryption_mode = 0; ++ for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++) ++ memset(&priv->wep_key[i], 0, sizeof(struct mwifiex_wep_key)); ++ priv->wep_key_curr_index = 0; ++ priv->curr_pkt_filter = HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON | ++ HostCmd_ACT_MAC_ETHERNETII_ENABLE; ++ ++ priv->beacon_period = 100; /* beacon interval */ ; ++ priv->attempted_bss_desc = NULL; ++ memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params)); ++ priv->listen_interval = MWIFIEX_DEFAULT_LISTEN_INTERVAL; ++ ++ memset(&priv->prev_ssid, 0, sizeof(priv->prev_ssid)); ++ memset(&priv->prev_bssid, 0, sizeof(priv->prev_bssid)); ++ memset(&priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf)); ++ priv->assoc_rsp_size = 0; ++ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; ++ priv->atim_window = 0; ++ priv->adhoc_state = ADHOC_IDLE; ++ priv->tx_power_level = 0; ++ priv->max_tx_power_level = 0; ++ priv->min_tx_power_level = 0; ++ priv->tx_rate = 0; ++ priv->rxpd_htinfo = 0; ++ priv->rxpd_rate = 0; ++ priv->rate_bitmap = 0; ++ priv->data_rssi_last = 0; ++ priv->data_rssi_avg = 0; ++ priv->data_nf_avg = 0; ++ priv->data_nf_last = 0; ++ priv->bcn_rssi_last = 0; ++ priv->bcn_rssi_avg = 0; ++ priv->bcn_nf_avg = 0; ++ priv->bcn_nf_last = 0; ++ memset(&priv->wpa_ie, 0, sizeof(priv->wpa_ie)); ++ memset(&priv->aes_key, 0, sizeof(priv->aes_key)); ++ priv->wpa_ie_len = 0; ++ priv->wpa_is_gtk_set = false; ++ ++ memset(&priv->assoc_tlv_buf, 0, sizeof(priv->assoc_tlv_buf)); ++ priv->assoc_tlv_buf_len = 0; ++ memset(&priv->wps, 0, sizeof(priv->wps)); ++ memset(&priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf)); ++ priv->gen_ie_buf_len = 0; ++ memset(priv->vs_ie, 0, sizeof(priv->vs_ie)); ++ ++ priv->wmm_required = true; ++ priv->wmm_enabled = false; ++ priv->wmm_qosinfo = 0; ++ priv->curr_bcn_buf = NULL; ++ priv->curr_bcn_size = 0; ++ ++ priv->scan_block = false; ++ ++ return mwifiex_add_bss_prio_tbl(priv); ++} ++ ++/* ++ * This function allocates buffers for members of the adapter ++ * structure. ++ * ++ * The memory allocated includes scan table, command buffers, and ++ * sleep confirm command buffer. In addition, the queues are ++ * also initialized. ++ */ ++static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) ++{ ++ int ret = 0; ++ u32 buf_size; ++ struct mwifiex_bssdescriptor *temp_scan_table; ++ ++ /* Allocate buffer to store the BSSID list */ ++ buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP; ++ temp_scan_table = kzalloc(buf_size, GFP_KERNEL); ++ if (!temp_scan_table) { ++ dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n", ++ __func__); ++ return -1; ++ } ++ ++ adapter->scan_table = temp_scan_table; ++ ++ /* Allocate command buffer */ ++ ret = mwifiex_alloc_cmd_buffer(adapter); ++ if (ret) { ++ dev_err(adapter->dev, "%s: failed to alloc cmd buffer\n", ++ __func__); ++ return -1; ++ } ++ ++ adapter->sleep_cfm = ++ dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm_buffer) ++ + INTF_HEADER_LEN); ++ ++ if (!adapter->sleep_cfm) { ++ dev_err(adapter->dev, "%s: failed to alloc sleep cfm" ++ " cmd buffer\n", __func__); ++ return -1; ++ } ++ skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN); ++ ++ return 0; ++} ++ ++/* ++ * This function initializes the adapter structure and sets default ++ * values to the members of adapter. ++ * ++ * This also initializes the WMM related parameters in the driver private ++ * structures. ++ */ ++static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) ++{ ++ struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = NULL; ++ ++ skb_put(adapter->sleep_cfm, sizeof(sleep_cfm_buf->ps_cfm_sleep)); ++ sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm_buffer *) ++ (adapter->sleep_cfm->data); ++ ++ adapter->cmd_sent = false; ++ adapter->data_sent = true; ++ adapter->cmd_resp_received = false; ++ adapter->event_received = false; ++ adapter->data_received = false; ++ ++ adapter->surprise_removed = false; ++ ++ adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; ++ ++ adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; ++ adapter->ps_state = PS_STATE_AWAKE; ++ adapter->need_to_wakeup = false; ++ ++ adapter->scan_mode = HostCmd_BSS_MODE_ANY; ++ adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME; ++ adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME; ++ adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME; ++ ++ adapter->num_in_scan_table = 0; ++ memset(adapter->scan_table, 0, ++ (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP)); ++ adapter->scan_probes = 1; ++ ++ memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf)); ++ adapter->bcn_buf_end = adapter->bcn_buf; ++ ++ adapter->multiple_dtim = 1; ++ ++ adapter->local_listen_interval = 0; /* default value in firmware ++ will be used */ ++ ++ adapter->is_deep_sleep = false; ++ ++ adapter->delay_null_pkt = false; ++ adapter->delay_to_ps = 1000; ++ adapter->enhanced_ps_mode = PS_MODE_AUTO; ++ ++ adapter->gen_null_pkt = false; /* Disable NULL Pkg generation by ++ default */ ++ adapter->pps_uapsd_mode = false; /* Disable pps/uapsd mode by ++ default */ ++ adapter->pm_wakeup_card_req = false; ++ ++ adapter->pm_wakeup_fw_try = false; ++ ++ adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; ++ adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; ++ adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; ++ ++ adapter->is_hs_configured = false; ++ adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF); ++ adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF; ++ adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF; ++ adapter->hs_activated = false; ++ ++ memset(adapter->event_body, 0, sizeof(adapter->event_body)); ++ adapter->hw_dot_11n_dev_cap = 0; ++ adapter->hw_dev_mcs_support = 0; ++ adapter->chan_offset = 0; ++ adapter->adhoc_11n_enabled = false; ++ ++ mwifiex_wmm_init(adapter); ++ ++ if (adapter->sleep_cfm) { ++ memset(&sleep_cfm_buf->ps_cfm_sleep, 0, ++ adapter->sleep_cfm->len); ++ sleep_cfm_buf->ps_cfm_sleep.command = ++ cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); ++ sleep_cfm_buf->ps_cfm_sleep.size = ++ cpu_to_le16(adapter->sleep_cfm->len); ++ sleep_cfm_buf->ps_cfm_sleep.result = 0; ++ sleep_cfm_buf->ps_cfm_sleep.action = cpu_to_le16(SLEEP_CONFIRM); ++ sleep_cfm_buf->ps_cfm_sleep.resp_ctrl = ++ cpu_to_le16(RESP_NEEDED); ++ } ++ memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params)); ++ memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period)); ++ adapter->tx_lock_flag = false; ++ adapter->null_pkt_interval = 0; ++ adapter->fw_bands = 0; ++ adapter->config_bands = 0; ++ adapter->adhoc_start_band = 0; ++ adapter->scan_channels = NULL; ++ adapter->fw_release_number = 0; ++ adapter->fw_cap_info = 0; ++ memset(&adapter->upld_buf, 0, sizeof(adapter->upld_buf)); ++ adapter->event_cause = 0; ++ adapter->region_code = 0; ++ adapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT; ++ adapter->adhoc_awake_period = 0; ++ memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); ++ adapter->arp_filter_size = 0; ++} ++ ++/* ++ * This function frees the adapter structure. ++ * ++ * The freeing operation is done recursively, by canceling all ++ * pending commands, freeing the member buffers previously ++ * allocated (command buffers, scan table buffer, sleep confirm ++ * command buffer), stopping the timers and calling the cleanup ++ * routines for every interface, before the actual adapter ++ * structure is freed. ++ */ ++static void ++mwifiex_free_adapter(struct mwifiex_adapter *adapter) ++{ ++ if (!adapter) { ++ pr_err("%s: adapter is NULL\n", __func__); ++ return; ++ } ++ ++ mwifiex_cancel_all_pending_cmd(adapter); ++ ++ /* Free lock variables */ ++ mwifiex_free_lock_list(adapter); ++ ++ /* Free command buffer */ ++ dev_dbg(adapter->dev, "info: free cmd buffer\n"); ++ mwifiex_free_cmd_buffer(adapter); ++ ++ del_timer(&adapter->cmd_timer); ++ ++ dev_dbg(adapter->dev, "info: free scan table\n"); ++ kfree(adapter->scan_table); ++ adapter->scan_table = NULL; ++ ++ adapter->if_ops.cleanup_if(adapter); ++ ++ dev_kfree_skb_any(adapter->sleep_cfm); ++} ++ ++/* ++ * This function intializes the lock variables and ++ * the list heads. ++ */ ++int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) ++{ ++ struct mwifiex_private *priv = NULL; ++ s32 i = 0; ++ u32 j = 0; ++ ++ spin_lock_init(&adapter->mwifiex_lock); ++ spin_lock_init(&adapter->int_lock); ++ spin_lock_init(&adapter->main_proc_lock); ++ spin_lock_init(&adapter->mwifiex_cmd_lock); ++ for (i = 0; i < adapter->priv_num; i++) { ++ if (adapter->priv[i]) { ++ priv = adapter->priv[i]; ++ spin_lock_init(&priv->rx_pkt_lock); ++ spin_lock_init(&priv->wmm.ra_list_spinlock); ++ spin_lock_init(&priv->curr_bcn_buf_lock); ++ } ++ } ++ ++ /* Initialize cmd_free_q */ ++ INIT_LIST_HEAD(&adapter->cmd_free_q); ++ /* Initialize cmd_pending_q */ ++ INIT_LIST_HEAD(&adapter->cmd_pending_q); ++ /* Initialize scan_pending_q */ ++ INIT_LIST_HEAD(&adapter->scan_pending_q); ++ ++ spin_lock_init(&adapter->cmd_free_q_lock); ++ spin_lock_init(&adapter->cmd_pending_q_lock); ++ spin_lock_init(&adapter->scan_pending_q_lock); ++ ++ for (i = 0; i < adapter->priv_num; ++i) { ++ INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); ++ adapter->bss_prio_tbl[i].bss_prio_cur = NULL; ++ spin_lock_init(&adapter->bss_prio_tbl[i].bss_prio_lock); ++ } ++ ++ for (i = 0; i < adapter->priv_num; i++) { ++ if (!adapter->priv[i]) ++ continue; ++ priv = adapter->priv[i]; ++ for (j = 0; j < MAX_NUM_TID; ++j) { ++ INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list); ++ spin_lock_init(&priv->wmm.tid_tbl_ptr[j].tid_tbl_lock); ++ } ++ INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); ++ INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); ++ ++ spin_lock_init(&priv->tx_ba_stream_tbl_lock); ++ spin_lock_init(&priv->rx_reorder_tbl_lock); ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function releases the lock variables and frees the locks and ++ * associated locks. ++ */ ++void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) ++{ ++ struct mwifiex_private *priv = NULL; ++ s32 i = 0; ++ s32 j = 0; ++ ++ /* Free lists */ ++ list_del(&adapter->cmd_free_q); ++ list_del(&adapter->cmd_pending_q); ++ list_del(&adapter->scan_pending_q); ++ ++ for (i = 0; i < adapter->priv_num; i++) ++ list_del(&adapter->bss_prio_tbl[i].bss_prio_head); ++ ++ for (i = 0; i < adapter->priv_num; i++) { ++ if (adapter->priv[i]) { ++ priv = adapter->priv[i]; ++ for (j = 0; j < MAX_NUM_TID; ++j) ++ list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); ++ list_del(&priv->tx_ba_stream_tbl_ptr); ++ list_del(&priv->rx_reorder_tbl_ptr); ++ } ++ } ++} ++ ++/* ++ * This function initializes the firmware. ++ * ++ * The following operations are performed sequentially - ++ * - Allocate adapter structure ++ * - Initialize the adapter structure ++ * - Initialize the private structure ++ * - Add BSS priority tables to the adapter structure ++ * - For each interface, send the init commands to firmware ++ * - Send the first command in command pending queue, if available ++ */ ++int mwifiex_init_fw(struct mwifiex_adapter *adapter) ++{ ++ int ret = 0; ++ struct mwifiex_private *priv = NULL; ++ u8 i = 0; ++ u8 first_sta = true; ++ int is_cmd_pend_q_empty; ++ unsigned long flags; ++ ++ adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; ++ ++ /* Allocate memory for member of adapter structure */ ++ ret = mwifiex_allocate_adapter(adapter); ++ if (ret) ++ return -1; ++ ++ /* Initialize adapter structure */ ++ mwifiex_init_adapter(adapter); ++ ++ for (i = 0; i < adapter->priv_num; i++) { ++ if (adapter->priv[i]) { ++ priv = adapter->priv[i]; ++ ++ /* Initialize private structure */ ++ ret = mwifiex_init_priv(priv); ++ if (ret) ++ return -1; ++ } ++ } ++ for (i = 0; i < adapter->priv_num; i++) { ++ if (adapter->priv[i]) { ++ ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta); ++ if (ret == -1) ++ return -1; ++ ++ first_sta = false; ++ } ++ } ++ ++ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); ++ is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); ++ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); ++ if (!is_cmd_pend_q_empty) { ++ /* Send the first command in queue and return */ ++ if (mwifiex_main_process(adapter) != -1) ++ ret = -EINPROGRESS; ++ } else { ++ adapter->hw_status = MWIFIEX_HW_STATUS_READY; ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function deletes the BSS priority tables. ++ * ++ * The function traverses through all the allocated BSS priority nodes ++ * in every BSS priority table and frees them. ++ */ ++static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv) ++{ ++ int i; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct mwifiex_bss_prio_node *bssprio_node = NULL, *tmp_node = NULL, ++ **cur = NULL; ++ struct list_head *head; ++ spinlock_t *lock; ++ unsigned long flags; ++ ++ for (i = 0; i < adapter->priv_num; ++i) { ++ head = &adapter->bss_prio_tbl[i].bss_prio_head; ++ cur = &adapter->bss_prio_tbl[i].bss_prio_cur; ++ lock = &adapter->bss_prio_tbl[i].bss_prio_lock; ++ dev_dbg(adapter->dev, "info: delete BSS priority table," ++ " index = %d, i = %d, head = %p, cur = %p\n", ++ priv->bss_index, i, head, *cur); ++ if (*cur) { ++ spin_lock_irqsave(lock, flags); ++ if (list_empty(head)) { ++ spin_unlock_irqrestore(lock, flags); ++ continue; ++ } ++ bssprio_node = list_first_entry(head, ++ struct mwifiex_bss_prio_node, list); ++ spin_unlock_irqrestore(lock, flags); ++ ++ list_for_each_entry_safe(bssprio_node, tmp_node, head, ++ list) { ++ if (bssprio_node->priv == priv) { ++ dev_dbg(adapter->dev, "info: Delete " ++ "node %p, next = %p\n", ++ bssprio_node, tmp_node); ++ spin_lock_irqsave(lock, flags); ++ list_del(&bssprio_node->list); ++ spin_unlock_irqrestore(lock, flags); ++ kfree(bssprio_node); ++ } ++ } ++ *cur = (struct mwifiex_bss_prio_node *)head; ++ } ++ } ++} ++ ++/* ++ * This function is used to shutdown the driver. ++ * ++ * The following operations are performed sequentially - ++ * - Check if already shut down ++ * - Make sure the main process has stopped ++ * - Clean up the Tx and Rx queues ++ * - Delete BSS priority tables ++ * - Free the adapter ++ * - Notify completion ++ */ ++int ++mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) ++{ ++ int ret = -EINPROGRESS; ++ struct mwifiex_private *priv = NULL; ++ s32 i = 0; ++ unsigned long flags; ++ ++ /* mwifiex already shutdown */ ++ if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) ++ return 0; ++ ++ adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING; ++ /* wait for mwifiex_process to complete */ ++ if (adapter->mwifiex_processing) { ++ dev_warn(adapter->dev, "main process is still running\n"); ++ return ret; ++ } ++ ++ /* shut down mwifiex */ ++ dev_dbg(adapter->dev, "info: shutdown mwifiex...\n"); ++ ++ /* Clean up Tx/Rx queues and delete BSS priority table */ ++ for (i = 0; i < adapter->priv_num; i++) { ++ if (adapter->priv[i]) { ++ priv = adapter->priv[i]; ++ ++ mwifiex_clean_txrx(priv); ++ mwifiex_delete_bss_prio_tbl(priv); ++ } ++ } ++ ++ spin_lock_irqsave(&adapter->mwifiex_lock, flags); ++ ++ /* Free adapter structure */ ++ mwifiex_free_adapter(adapter); ++ ++ spin_unlock_irqrestore(&adapter->mwifiex_lock, flags); ++ ++ /* Notify completion */ ++ ret = mwifiex_shutdown_fw_complete(adapter); ++ ++ return ret; ++} ++ ++/* ++ * This function downloads the firmware to the card. ++ * ++ * The actual download is preceded by two sanity checks - ++ * - Check if firmware is already running ++ * - Check if the interface is the winner to download the firmware ++ * ++ * ...and followed by another - ++ * - Check if the firmware is downloaded successfully ++ * ++ * After download is successfully completed, the host interrupts are enabled. ++ */ ++int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, ++ struct mwifiex_fw_image *pmfw) ++{ ++ int ret = 0; ++ u32 poll_num = 1; ++ int winner; ++ ++ /* Check if firmware is already running */ ++ ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner); ++ if (!ret) { ++ dev_notice(adapter->dev, ++ "WLAN FW already running! Skip FW download\n"); ++ goto done; ++ } ++ poll_num = MAX_FIRMWARE_POLL_TRIES; ++ ++ /* Check if we are the winner for downloading FW */ ++ if (!winner) { ++ dev_notice(adapter->dev, ++ "Other interface already running!" ++ " Skip FW download\n"); ++ poll_num = MAX_MULTI_INTERFACE_POLL_TRIES; ++ goto poll_fw; ++ } ++ if (pmfw) { ++ /* Download firmware with helper */ ++ ret = adapter->if_ops.prog_fw(adapter, pmfw); ++ if (ret) { ++ dev_err(adapter->dev, "prog_fw failed ret=%#x\n", ret); ++ return ret; ++ } ++ } ++ ++poll_fw: ++ /* Check if the firmware is downloaded successfully or not */ ++ ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL); ++ if (ret) { ++ dev_err(adapter->dev, "FW failed to be active in time\n"); ++ return -1; ++ } ++done: ++ /* re-enable host interrupt for mwifiex after fw dnld is successful */ ++ adapter->if_ops.enable_int(adapter); ++ return ret; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/ioctl.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/ioctl.h +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/ioctl.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/ioctl.h 2011-05-05 23:29:45.471441695 +0200 +@@ -0,0 +1,410 @@ ++/* ++ * Marvell Wireless LAN device driver: ioctl data structures & APIs ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#ifndef _MWIFIEX_IOCTL_H_ ++#define _MWIFIEX_IOCTL_H_ ++ ++#include ++ ++enum { ++ MWIFIEX_SCAN_MODE_UNCHANGED = 0, ++ MWIFIEX_SCAN_MODE_BSS, ++ MWIFIEX_SCAN_MODE_IBSS, ++ MWIFIEX_SCAN_MODE_ANY ++}; ++ ++enum { ++ MWIFIEX_SCAN_TYPE_UNCHANGED = 0, ++ MWIFIEX_SCAN_TYPE_ACTIVE, ++ MWIFIEX_SCAN_TYPE_PASSIVE ++}; ++ ++struct mwifiex_get_scan_table_fixed { ++ u8 bssid[ETH_ALEN]; ++ u8 channel; ++ u8 rssi; ++ long long network_tsf; ++}; ++ ++struct mwifiex_scan_time_params { ++ u32 specific_scan_time; ++ u32 active_scan_time; ++ u32 passive_scan_time; ++}; ++ ++struct mwifiex_user_scan { ++ u32 scan_cfg_len; ++ u8 scan_cfg_buf[1]; ++}; ++ ++struct mwifiex_scan_req { ++ u32 scan_mode; ++ u32 scan_type; ++ struct mwifiex_802_11_ssid scan_ssid; ++ struct mwifiex_scan_time_params scan_time; ++ struct mwifiex_user_scan user_scan; ++}; ++ ++struct mwifiex_scan_resp { ++ u32 num_in_scan_table; ++ u8 *scan_table; ++}; ++ ++#define MWIFIEX_PROMISC_MODE 1 ++#define MWIFIEX_MULTICAST_MODE 2 ++#define MWIFIEX_ALL_MULTI_MODE 4 ++#define MWIFIEX_MAX_MULTICAST_LIST_SIZE 32 ++ ++struct mwifiex_multicast_list { ++ u32 mode; ++ u32 num_multicast_addr; ++ u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; ++}; ++ ++#define MWIFIEX_MAX_CHANNEL_NUM 128 ++ ++struct mwifiex_chan_freq { ++ u32 channel; ++ u32 freq; ++}; ++ ++struct mwifiex_chan_list { ++ u32 num_of_chan; ++ struct mwifiex_chan_freq cf[MWIFIEX_MAX_CHANNEL_NUM]; ++}; ++ ++struct mwifiex_ssid_bssid { ++ struct mwifiex_802_11_ssid ssid; ++ u8 bssid[ETH_ALEN]; ++}; ++ ++enum { ++ BAND_B = 1, ++ BAND_G = 2, ++ BAND_A = 4, ++ BAND_GN = 8, ++ BAND_AN = 16, ++}; ++ ++#define NO_SEC_CHANNEL 0 ++#define SEC_CHANNEL_ABOVE 1 ++#define SEC_CHANNEL_BELOW 3 ++ ++struct mwifiex_ds_band_cfg { ++ u32 config_bands; ++ u32 adhoc_start_band; ++ u32 adhoc_channel; ++ u32 sec_chan_offset; ++}; ++ ++enum { ++ ADHOC_IDLE, ++ ADHOC_STARTED, ++ ADHOC_JOINED, ++ ADHOC_COALESCED ++}; ++ ++struct mwifiex_ds_get_stats { ++ u32 mcast_tx_frame; ++ u32 failed; ++ u32 retry; ++ u32 multi_retry; ++ u32 frame_dup; ++ u32 rts_success; ++ u32 rts_failure; ++ u32 ack_failure; ++ u32 rx_frag; ++ u32 mcast_rx_frame; ++ u32 fcs_error; ++ u32 tx_frame; ++ u32 wep_icv_error[4]; ++}; ++ ++#define BCN_RSSI_LAST_MASK 0x00000001 ++#define BCN_RSSI_AVG_MASK 0x00000002 ++#define DATA_RSSI_LAST_MASK 0x00000004 ++#define DATA_RSSI_AVG_MASK 0x00000008 ++#define BCN_SNR_LAST_MASK 0x00000010 ++#define BCN_SNR_AVG_MASK 0x00000020 ++#define DATA_SNR_LAST_MASK 0x00000040 ++#define DATA_SNR_AVG_MASK 0x00000080 ++#define BCN_NF_LAST_MASK 0x00000100 ++#define BCN_NF_AVG_MASK 0x00000200 ++#define DATA_NF_LAST_MASK 0x00000400 ++#define DATA_NF_AVG_MASK 0x00000800 ++#define ALL_RSSI_INFO_MASK 0x00000fff ++ ++struct mwifiex_ds_get_signal { ++ /* ++ * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI, ++ * Bit2: Last Data RSSI, Bit3: Average Data RSSI, ++ * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR, ++ * Bit6: Last Data SNR, Bit7: Average Data SNR, ++ * Bit8: Last Beacon NF, Bit9: Average Beacon NF, ++ * Bit10: Last Data NF, Bit11: Average Data NF ++ */ ++ u16 selector; ++ s16 bcn_rssi_last; ++ s16 bcn_rssi_avg; ++ s16 data_rssi_last; ++ s16 data_rssi_avg; ++ s16 bcn_snr_last; ++ s16 bcn_snr_avg; ++ s16 data_snr_last; ++ s16 data_snr_avg; ++ s16 bcn_nf_last; ++ s16 bcn_nf_avg; ++ s16 data_nf_last; ++ s16 data_nf_avg; ++}; ++ ++struct mwifiex_fw_info { ++ u32 fw_ver; ++ u8 mac_addr[ETH_ALEN]; ++}; ++ ++#define MWIFIEX_MAX_VER_STR_LEN 128 ++ ++struct mwifiex_ver_ext { ++ u32 version_str_sel; ++ char version_str[MWIFIEX_MAX_VER_STR_LEN]; ++}; ++ ++struct mwifiex_bss_info { ++ u32 bss_mode; ++ struct mwifiex_802_11_ssid ssid; ++ u32 scan_table_idx; ++ u32 bss_chan; ++ u32 region_code; ++ u32 media_connected; ++ u32 max_power_level; ++ u32 min_power_level; ++ u32 adhoc_state; ++ signed int bcn_nf_last; ++ u32 wep_status; ++ u32 is_hs_configured; ++ u32 is_deep_sleep; ++ u8 bssid[ETH_ALEN]; ++}; ++ ++#define MAX_NUM_TID 8 ++ ++#define MAX_RX_WINSIZE 64 ++ ++struct mwifiex_ds_rx_reorder_tbl { ++ u16 tid; ++ u8 ta[ETH_ALEN]; ++ u32 start_win; ++ u32 win_size; ++ u32 buffer[MAX_RX_WINSIZE]; ++}; ++ ++struct mwifiex_ds_tx_ba_stream_tbl { ++ u16 tid; ++ u8 ra[ETH_ALEN]; ++}; ++ ++#define DBG_CMD_NUM 5 ++ ++struct mwifiex_debug_info { ++ u32 int_counter; ++ u32 packets_out[MAX_NUM_TID]; ++ u32 max_tx_buf_size; ++ u32 tx_buf_size; ++ u32 curr_tx_buf_size; ++ u32 tx_tbl_num; ++ struct mwifiex_ds_tx_ba_stream_tbl ++ tx_tbl[MWIFIEX_MAX_TX_BASTREAM_SUPPORTED]; ++ u32 rx_tbl_num; ++ struct mwifiex_ds_rx_reorder_tbl rx_tbl ++ [MWIFIEX_MAX_RX_BASTREAM_SUPPORTED]; ++ u16 ps_mode; ++ u32 ps_state; ++ u8 is_deep_sleep; ++ u8 pm_wakeup_card_req; ++ u32 pm_wakeup_fw_try; ++ u8 is_hs_configured; ++ u8 hs_activated; ++ u32 num_cmd_host_to_card_failure; ++ u32 num_cmd_sleep_cfm_host_to_card_failure; ++ u32 num_tx_host_to_card_failure; ++ u32 num_event_deauth; ++ u32 num_event_disassoc; ++ u32 num_event_link_lost; ++ u32 num_cmd_deauth; ++ u32 num_cmd_assoc_success; ++ u32 num_cmd_assoc_failure; ++ u32 num_tx_timeout; ++ u32 num_cmd_timeout; ++ u16 timeout_cmd_id; ++ u16 timeout_cmd_act; ++ u16 last_cmd_id[DBG_CMD_NUM]; ++ u16 last_cmd_act[DBG_CMD_NUM]; ++ u16 last_cmd_index; ++ u16 last_cmd_resp_id[DBG_CMD_NUM]; ++ u16 last_cmd_resp_index; ++ u16 last_event[DBG_CMD_NUM]; ++ u16 last_event_index; ++ u8 data_sent; ++ u8 cmd_sent; ++ u8 cmd_resp_received; ++ u8 event_received; ++}; ++ ++#define MWIFIEX_KEY_INDEX_UNICAST 0x40000000 ++#define WAPI_RXPN_LEN 16 ++ ++struct mwifiex_ds_encrypt_key { ++ u32 key_disable; ++ u32 key_index; ++ u32 key_len; ++ u8 key_material[WLAN_MAX_KEY_LEN]; ++ u8 mac_addr[ETH_ALEN]; ++ u32 is_wapi_key; ++ u8 wapi_rxpn[WAPI_RXPN_LEN]; ++}; ++ ++struct mwifiex_rate_cfg { ++ u32 action; ++ u32 is_rate_auto; ++ u32 rate; ++}; ++ ++struct mwifiex_data_rate { ++ u32 tx_data_rate; ++ u32 rx_data_rate; ++}; ++ ++struct mwifiex_power_cfg { ++ u32 is_power_auto; ++ u32 power_level; ++}; ++ ++struct mwifiex_ds_hs_cfg { ++ u32 is_invoke_hostcmd; ++ /* Bit0: non-unicast data ++ * Bit1: unicast data ++ * Bit2: mac events ++ * Bit3: magic packet ++ */ ++ u32 conditions; ++ u32 gpio; ++ u32 gap; ++}; ++ ++#define DEEP_SLEEP_ON 1 ++#define DEEP_SLEEP_OFF 0 ++ ++#define DEEP_SLEEP_IDLE_TIME 100 ++ ++struct mwifiex_ds_auto_ds { ++ u16 auto_ds; ++ u16 idle_time; ++}; ++ ++#define PS_MODE_UNCHANGED 0 ++#define PS_MODE_AUTO 1 ++#define PS_MODE_POLL 2 ++#define PS_MODE_NULL 3 ++ ++ ++struct mwifiex_ds_pm_cfg { ++ union { ++ u32 ps_mode; ++ struct mwifiex_ds_hs_cfg hs_cfg; ++ struct mwifiex_ds_auto_ds auto_deep_sleep; ++ u32 sleep_period; ++ } param; ++}; ++ ++struct mwifiex_ioctl_wmm_queue_status_ac { ++ u8 wmm_acm; ++ u8 flow_required; ++ u8 flow_created; ++ u8 disabled; ++}; ++ ++struct mwifiex_ds_wmm_queue_status { ++ struct mwifiex_ioctl_wmm_queue_status_ac ++ ac_status[IEEE80211_MAX_QUEUES]; ++}; ++ ++struct mwifiex_ds_11n_tx_cfg { ++ u16 tx_htcap; ++ u16 tx_htinfo; ++}; ++ ++struct mwifiex_ds_11n_amsdu_aggr_ctrl { ++ u16 enable; ++ u16 curr_buf_size; ++}; ++ ++#define MWIFIEX_NUM_OF_CMD_BUFFER 20 ++#define MWIFIEX_SIZE_OF_CMD_BUFFER 2048 ++ ++enum { ++ MWIFIEX_IE_TYPE_GEN_IE = 0, ++ MWIFIEX_IE_TYPE_ARP_FILTER, ++}; ++ ++enum { ++ MWIFIEX_REG_MAC = 1, ++ MWIFIEX_REG_BBP, ++ MWIFIEX_REG_RF, ++ MWIFIEX_REG_PMIC, ++ MWIFIEX_REG_CAU, ++}; ++ ++struct mwifiex_ds_reg_rw { ++ __le32 type; ++ __le32 offset; ++ __le32 value; ++}; ++ ++#define MAX_EEPROM_DATA 256 ++ ++struct mwifiex_ds_read_eeprom { ++ __le16 offset; ++ __le16 byte_count; ++ u8 value[MAX_EEPROM_DATA]; ++}; ++ ++struct mwifiex_ds_misc_gen_ie { ++ u32 type; ++ u32 len; ++ u8 ie_data[IW_CUSTOM_MAX]; ++}; ++ ++struct mwifiex_ds_misc_cmd { ++ u32 len; ++ u8 cmd[MWIFIEX_SIZE_OF_CMD_BUFFER]; ++}; ++ ++#define MWIFIEX_MAX_VSIE_LEN (256) ++#define MWIFIEX_MAX_VSIE_NUM (8) ++#define MWIFIEX_VSIE_MASK_SCAN 0x01 ++#define MWIFIEX_VSIE_MASK_ASSOC 0x02 ++#define MWIFIEX_VSIE_MASK_ADHOC 0x04 ++ ++enum { ++ MWIFIEX_FUNC_INIT = 1, ++ MWIFIEX_FUNC_SHUTDOWN, ++}; ++ ++#endif /* !_MWIFIEX_IOCTL_H_ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/join.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/join.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/join.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/join.c 2011-05-05 23:29:45.491441937 +0200 +@@ -0,0 +1,1424 @@ ++/* ++ * Marvell Wireless LAN device driver: association and ad-hoc start/join ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++ ++#define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9))) ++ ++/* ++ * Append a generic IE as a pass through TLV to a TLV buffer. ++ * ++ * This function is called from the network join command preparation routine. ++ * ++ * If the IE buffer has been setup by the application, this routine appends ++ * the buffer as a pass through TLV type to the request. ++ */ ++static int ++mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer) ++{ ++ int ret_len = 0; ++ struct mwifiex_ie_types_header ie_header; ++ ++ /* Null Checks */ ++ if (!buffer) ++ return 0; ++ if (!(*buffer)) ++ return 0; ++ ++ /* ++ * If there is a generic ie buffer setup, append it to the return ++ * parameter buffer pointer. ++ */ ++ if (priv->gen_ie_buf_len) { ++ dev_dbg(priv->adapter->dev, "info: %s: append generic %d to %p\n", ++ __func__, priv->gen_ie_buf_len, *buffer); ++ ++ /* Wrap the generic IE buffer with a pass through TLV type */ ++ ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); ++ ie_header.len = cpu_to_le16(priv->gen_ie_buf_len); ++ memcpy(*buffer, &ie_header, sizeof(ie_header)); ++ ++ /* Increment the return size and the return buffer pointer ++ param */ ++ *buffer += sizeof(ie_header); ++ ret_len += sizeof(ie_header); ++ ++ /* Copy the generic IE buffer to the output buffer, advance ++ pointer */ ++ memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len); ++ ++ /* Increment the return size and the return buffer pointer ++ param */ ++ *buffer += priv->gen_ie_buf_len; ++ ret_len += priv->gen_ie_buf_len; ++ ++ /* Reset the generic IE buffer */ ++ priv->gen_ie_buf_len = 0; ++ } ++ ++ /* return the length appended to the buffer */ ++ return ret_len; ++} ++ ++/* ++ * Append TSF tracking info from the scan table for the target AP. ++ * ++ * This function is called from the network join command preparation routine. ++ * ++ * The TSF table TSF sent to the firmware contains two TSF values: ++ * - The TSF of the target AP from its previous beacon/probe response ++ * - The TSF timestamp of our local MAC at the time we observed the ++ * beacon/probe response. ++ * ++ * The firmware uses the timestamp values to set an initial TSF value ++ * in the MAC for the new association after a reassociation attempt. ++ */ ++static int ++mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, ++ struct mwifiex_bssdescriptor *bss_desc) ++{ ++ struct mwifiex_ie_types_tsf_timestamp tsf_tlv; ++ __le64 tsf_val; ++ ++ /* Null Checks */ ++ if (buffer == NULL) ++ return 0; ++ if (*buffer == NULL) ++ return 0; ++ ++ memset(&tsf_tlv, 0x00, sizeof(struct mwifiex_ie_types_tsf_timestamp)); ++ ++ tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP); ++ tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val)); ++ ++ memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header)); ++ *buffer += sizeof(tsf_tlv.header); ++ ++ /* TSF at the time when beacon/probe_response was received */ ++ tsf_val = cpu_to_le64(bss_desc->network_tsf); ++ memcpy(*buffer, &tsf_val, sizeof(tsf_val)); ++ *buffer += sizeof(tsf_val); ++ ++ memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val)); ++ ++ dev_dbg(priv->adapter->dev, "info: %s: TSF offset calc: %016llx - " ++ "%016llx\n", __func__, tsf_val, bss_desc->network_tsf); ++ ++ memcpy(*buffer, &tsf_val, sizeof(tsf_val)); ++ *buffer += sizeof(tsf_val); ++ ++ return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val)); ++} ++ ++/* ++ * This function finds out the common rates between rate1 and rate2. ++ * ++ * It will fill common rates in rate1 as output if found. ++ * ++ * NOTE: Setting the MSB of the basic rates needs to be taken ++ * care of, either before or after calling this function. ++ */ ++static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, ++ u32 rate1_size, u8 *rate2, u32 rate2_size) ++{ ++ int ret = 0; ++ u8 *ptr = rate1; ++ u8 *tmp = NULL; ++ u32 i, j; ++ ++ tmp = kmalloc(rate1_size, GFP_KERNEL); ++ if (!tmp) { ++ dev_err(priv->adapter->dev, "failed to alloc tmp buf\n"); ++ return -ENOMEM; ++ } ++ ++ memcpy(tmp, rate1, rate1_size); ++ memset(rate1, 0, rate1_size); ++ ++ for (i = 0; rate2[i] && i < rate2_size; i++) { ++ for (j = 0; tmp[j] && j < rate1_size; j++) { ++ /* Check common rate, excluding the bit for ++ basic rate */ ++ if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) { ++ *rate1++ = tmp[j]; ++ break; ++ } ++ } ++ } ++ ++ dev_dbg(priv->adapter->dev, "info: Tx data rate set to %#x\n", ++ priv->data_rate); ++ ++ if (!priv->is_data_rate_auto) { ++ while (*ptr) { ++ if ((*ptr & 0x7f) == priv->data_rate) { ++ ret = 0; ++ goto done; ++ } ++ ptr++; ++ } ++ dev_err(priv->adapter->dev, "previously set fixed data rate %#x" ++ " is not compatible with the network\n", ++ priv->data_rate); ++ ++ ret = -1; ++ goto done; ++ } ++ ++ ret = 0; ++done: ++ kfree(tmp); ++ return ret; ++} ++ ++/* ++ * This function creates the intersection of the rates supported by a ++ * target BSS and our adapter settings for use in an assoc/join command. ++ */ ++static int ++mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc, ++ u8 *out_rates, u32 *out_rates_size) ++{ ++ u8 card_rates[MWIFIEX_SUPPORTED_RATES]; ++ u32 card_rates_size = 0; ++ ++ /* Copy AP supported rates */ ++ memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES); ++ /* Get the STA supported rates */ ++ card_rates_size = mwifiex_get_active_data_rates(priv, card_rates); ++ /* Get the common rates between AP and STA supported rates */ ++ if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES, ++ card_rates, card_rates_size)) { ++ *out_rates_size = 0; ++ dev_err(priv->adapter->dev, "%s: cannot get common rates\n", ++ __func__); ++ return -1; ++ } ++ ++ *out_rates_size = ++ min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES); ++ ++ return 0; ++} ++ ++/* ++ * This function updates the scan entry TSF timestamps to reflect ++ * a new association. ++ */ ++static void ++mwifiex_update_tsf_timestamps(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *new_bss_desc) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ u32 table_idx; ++ long long new_tsf_base; ++ signed long long tsf_delta; ++ ++ memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base)); ++ ++ tsf_delta = new_tsf_base - new_bss_desc->network_tsf; ++ ++ dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, " ++ "0x%016llx -> 0x%016llx\n", ++ new_bss_desc->network_tsf, new_tsf_base); ++ ++ for (table_idx = 0; table_idx < adapter->num_in_scan_table; ++ table_idx++) ++ adapter->scan_table[table_idx].network_tsf += tsf_delta; ++} ++ ++/* ++ * This function appends a WAPI IE. ++ * ++ * This function is called from the network join command preparation routine. ++ * ++ * If the IE buffer has been setup by the application, this routine appends ++ * the buffer as a WAPI TLV type to the request. ++ */ ++static int ++mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer) ++{ ++ int retLen = 0; ++ struct mwifiex_ie_types_header ie_header; ++ ++ /* Null Checks */ ++ if (buffer == NULL) ++ return 0; ++ if (*buffer == NULL) ++ return 0; ++ ++ /* ++ * If there is a wapi ie buffer setup, append it to the return ++ * parameter buffer pointer. ++ */ ++ if (priv->wapi_ie_len) { ++ dev_dbg(priv->adapter->dev, "cmd: append wapi ie %d to %p\n", ++ priv->wapi_ie_len, *buffer); ++ ++ /* Wrap the generic IE buffer with a pass through TLV type */ ++ ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE); ++ ie_header.len = cpu_to_le16(priv->wapi_ie_len); ++ memcpy(*buffer, &ie_header, sizeof(ie_header)); ++ ++ /* Increment the return size and the return buffer pointer ++ param */ ++ *buffer += sizeof(ie_header); ++ retLen += sizeof(ie_header); ++ ++ /* Copy the wapi IE buffer to the output buffer, advance ++ pointer */ ++ memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len); ++ ++ /* Increment the return size and the return buffer pointer ++ param */ ++ *buffer += priv->wapi_ie_len; ++ retLen += priv->wapi_ie_len; ++ ++ } ++ /* return the length appended to the buffer */ ++ return retLen; ++} ++ ++/* ++ * This function appends rsn ie tlv for wpa/wpa2 security modes. ++ * It is called from the network join command preparation routine. ++ */ ++static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv, ++ u8 **buffer) ++{ ++ struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv; ++ int rsn_ie_len; ++ ++ if (!buffer || !(*buffer)) ++ return 0; ++ ++ rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer); ++ rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]); ++ rsn_ie_tlv->header.type = cpu_to_le16( ++ le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF); ++ rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]); ++ rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len) ++ & 0x00FF); ++ if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2)) ++ memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2], ++ le16_to_cpu(rsn_ie_tlv->header.len)); ++ else ++ return -1; ++ ++ rsn_ie_len = sizeof(rsn_ie_tlv->header) + ++ le16_to_cpu(rsn_ie_tlv->header.len); ++ *buffer += rsn_ie_len; ++ ++ return rsn_ie_len; ++} ++ ++/* ++ * This function prepares command for association. ++ * ++ * This sets the following parameters - ++ * - Peer MAC address ++ * - Listen interval ++ * - Beacon interval ++ * - Capability information ++ * ++ * ...and the following TLVs, as required - ++ * - SSID TLV ++ * - PHY TLV ++ * - SS TLV ++ * - Rates TLV ++ * - Authentication TLV ++ * - Channel TLV ++ * - WPA/WPA2 IE ++ * - 11n TLV ++ * - Vendor specific TLV ++ * - WMM TLV ++ * - WAPI IE ++ * - Generic IE ++ * - TSF TLV ++ * ++ * Preparation also includes - ++ * - Setting command ID and proper size ++ * - Ensuring correct endian-ness ++ */ ++int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ void *data_buf) ++{ ++ struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate; ++ struct mwifiex_bssdescriptor *bss_desc; ++ struct mwifiex_ie_types_ssid_param_set *ssid_tlv; ++ struct mwifiex_ie_types_phy_param_set *phy_tlv; ++ struct mwifiex_ie_types_ss_param_set *ss_tlv; ++ struct mwifiex_ie_types_rates_param_set *rates_tlv; ++ struct mwifiex_ie_types_auth_type *auth_tlv; ++ struct mwifiex_ie_types_chan_list_param_set *chan_tlv; ++ u8 rates[MWIFIEX_SUPPORTED_RATES]; ++ u32 rates_size; ++ u16 tmp_cap; ++ u8 *pos; ++ int rsn_ie_len = 0; ++ ++ bss_desc = (struct mwifiex_bssdescriptor *) data_buf; ++ pos = (u8 *) assoc; ++ ++ mwifiex_cfg_tx_buf(priv, bss_desc); ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); ++ ++ /* Save so we know which BSS Desc to use in the response handler */ ++ priv->attempted_bss_desc = bss_desc; ++ ++ memcpy(assoc->peer_sta_addr, ++ bss_desc->mac_address, sizeof(assoc->peer_sta_addr)); ++ pos += sizeof(assoc->peer_sta_addr); ++ ++ /* Set the listen interval */ ++ assoc->listen_interval = cpu_to_le16(priv->listen_interval); ++ /* Set the beacon period */ ++ assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period); ++ ++ pos += sizeof(assoc->cap_info_bitmap); ++ pos += sizeof(assoc->listen_interval); ++ pos += sizeof(assoc->beacon_period); ++ pos += sizeof(assoc->dtim_period); ++ ++ ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos; ++ ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID); ++ ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len); ++ memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid, ++ le16_to_cpu(ssid_tlv->header.len)); ++ pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len); ++ ++ phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos; ++ phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS); ++ phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set)); ++ memcpy(&phy_tlv->fh_ds.ds_param_set, ++ &bss_desc->phy_param_set.ds_param_set.current_chan, ++ sizeof(phy_tlv->fh_ds.ds_param_set)); ++ pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len); ++ ++ ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos; ++ ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS); ++ ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set)); ++ pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len); ++ ++ /* Get the common rates supported between the driver and the BSS Desc */ ++ if (mwifiex_setup_rates_from_bssdesc ++ (priv, bss_desc, rates, &rates_size)) ++ return -1; ++ ++ /* Save the data rates into Current BSS state structure */ ++ priv->curr_bss_params.num_of_rates = rates_size; ++ memcpy(&priv->curr_bss_params.data_rates, rates, rates_size); ++ ++ /* Setup the Rates TLV in the association command */ ++ rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos; ++ rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); ++ rates_tlv->header.len = cpu_to_le16((u16) rates_size); ++ memcpy(rates_tlv->rates, rates, rates_size); ++ pos += sizeof(rates_tlv->header) + rates_size; ++ dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n", ++ rates_size); ++ ++ /* Add the Authentication type to be used for Auth frames */ ++ auth_tlv = (struct mwifiex_ie_types_auth_type *) pos; ++ auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); ++ auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type)); ++ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) ++ auth_tlv->auth_type = cpu_to_le16( ++ (u16) priv->sec_info.authentication_mode); ++ else ++ auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM); ++ ++ pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); ++ ++ if (IS_SUPPORT_MULTI_BANDS(priv->adapter) ++ && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) ++ && (!bss_desc->disable_11n) ++ && (priv->adapter->config_bands & BAND_GN ++ || priv->adapter->config_bands & BAND_AN) ++ && (bss_desc->bcn_ht_cap) ++ ) ++ ) { ++ /* Append a channel TLV for the channel the attempted AP was ++ found on */ ++ chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; ++ chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); ++ chan_tlv->header.len = ++ cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); ++ ++ memset(chan_tlv->chan_scan_param, 0x00, ++ sizeof(struct mwifiex_chan_scan_param_set)); ++ chan_tlv->chan_scan_param[0].chan_number = ++ (bss_desc->phy_param_set.ds_param_set.current_chan); ++ dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n", ++ chan_tlv->chan_scan_param[0].chan_number); ++ ++ chan_tlv->chan_scan_param[0].radio_type = ++ mwifiex_band_to_radio_type((u8) bss_desc->bss_band); ++ ++ dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n", ++ chan_tlv->chan_scan_param[0].radio_type); ++ pos += sizeof(chan_tlv->header) + ++ sizeof(struct mwifiex_chan_scan_param_set); ++ } ++ ++ if (!priv->wps.session_enable) { ++ if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) ++ rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); ++ ++ if (rsn_ie_len == -1) ++ return -1; ++ } ++ ++ if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) ++ && (!bss_desc->disable_11n) ++ && (priv->adapter->config_bands & BAND_GN ++ || priv->adapter->config_bands & BAND_AN)) ++ mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos); ++ ++ /* Append vendor specific IE TLV */ ++ mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos); ++ ++ mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie, ++ bss_desc->bcn_ht_cap); ++ if (priv->sec_info.wapi_enabled && priv->wapi_ie_len) ++ mwifiex_cmd_append_wapi_ie(priv, &pos); ++ ++ ++ mwifiex_cmd_append_generic_ie(priv, &pos); ++ ++ mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc); ++ ++ cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN); ++ ++ /* Set the Capability info at last */ ++ tmp_cap = bss_desc->cap_info_bitmap; ++ ++ if (priv->adapter->config_bands == BAND_B) ++ tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; ++ ++ tmp_cap &= CAPINFO_MASK; ++ dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", ++ tmp_cap, CAPINFO_MASK); ++ assoc->cap_info_bitmap = cpu_to_le16(tmp_cap); ++ ++ return 0; ++} ++ ++/* ++ * Association firmware command response handler ++ * ++ * The response buffer for the association command has the following ++ * memory layout. ++ * ++ * For cases where an association response was not received (indicated ++ * by the CapInfo and AId field): ++ * ++ * .------------------------------------------------------------. ++ * | Header(4 * sizeof(t_u16)): Standard command response hdr | ++ * .------------------------------------------------------------. ++ * | cap_info/Error Return(t_u16): | ++ * | 0xFFFF(-1): Internal error | ++ * | 0xFFFE(-2): Authentication unhandled message | ++ * | 0xFFFD(-3): Authentication refused | ++ * | 0xFFFC(-4): Timeout waiting for AP response | ++ * .------------------------------------------------------------. ++ * | status_code(t_u16): | ++ * | If cap_info is -1: | ++ * | An internal firmware failure prevented the | ++ * | command from being processed. The status_code | ++ * | will be set to 1. | ++ * | | ++ * | If cap_info is -2: | ++ * | An authentication frame was received but was | ++ * | not handled by the firmware. IEEE Status | ++ * | code for the failure is returned. | ++ * | | ++ * | If cap_info is -3: | ++ * | An authentication frame was received and the | ++ * | status_code is the IEEE Status reported in the | ++ * | response. | ++ * | | ++ * | If cap_info is -4: | ++ * | (1) Association response timeout | ++ * | (2) Authentication response timeout | ++ * .------------------------------------------------------------. ++ * | a_id(t_u16): 0xFFFF | ++ * .------------------------------------------------------------. ++ * ++ * ++ * For cases where an association response was received, the IEEE ++ * standard association response frame is returned: ++ * ++ * .------------------------------------------------------------. ++ * | Header(4 * sizeof(t_u16)): Standard command response hdr | ++ * .------------------------------------------------------------. ++ * | cap_info(t_u16): IEEE Capability | ++ * .------------------------------------------------------------. ++ * | status_code(t_u16): IEEE Status Code | ++ * .------------------------------------------------------------. ++ * | a_id(t_u16): IEEE Association ID | ++ * .------------------------------------------------------------. ++ * | IEEE IEs(variable): Any received IEs comprising the | ++ * | remaining portion of a received | ++ * | association response frame. | ++ * .------------------------------------------------------------. ++ * ++ * For simplistic handling, the status_code field can be used to determine ++ * an association success (0) or failure (non-zero). ++ */ ++int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ int ret = 0; ++ struct ieee_types_assoc_rsp *assoc_rsp; ++ struct mwifiex_bssdescriptor *bss_desc; ++ u8 enable_data = true; ++ ++ assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; ++ ++ priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, ++ sizeof(priv->assoc_rsp_buf)); ++ ++ memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); ++ ++ if (le16_to_cpu(assoc_rsp->status_code)) { ++ priv->adapter->dbg.num_cmd_assoc_failure++; ++ dev_err(priv->adapter->dev, "ASSOC_RESP: association failed, " ++ "status code = %d, error = 0x%x, a_id = 0x%x\n", ++ le16_to_cpu(assoc_rsp->status_code), ++ le16_to_cpu(assoc_rsp->cap_info_bitmap), ++ le16_to_cpu(assoc_rsp->a_id)); ++ ++ ret = -1; ++ goto done; ++ } ++ ++ /* Send a Media Connected event, according to the Spec */ ++ priv->media_connected = true; ++ ++ priv->adapter->ps_state = PS_STATE_AWAKE; ++ priv->adapter->pps_uapsd_mode = false; ++ priv->adapter->tx_lock_flag = false; ++ ++ /* Set the attempted BSSID Index to current */ ++ bss_desc = priv->attempted_bss_desc; ++ ++ dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n", ++ bss_desc->ssid.ssid); ++ ++ /* Make a copy of current BSSID descriptor */ ++ memcpy(&priv->curr_bss_params.bss_descriptor, ++ bss_desc, sizeof(struct mwifiex_bssdescriptor)); ++ ++ /* Update curr_bss_params */ ++ priv->curr_bss_params.bss_descriptor.channel ++ = bss_desc->phy_param_set.ds_param_set.current_chan; ++ ++ priv->curr_bss_params.band = (u8) bss_desc->bss_band; ++ ++ /* ++ * Adjust the timestamps in the scan table to be relative to the newly ++ * associated AP's TSF ++ */ ++ mwifiex_update_tsf_timestamps(priv, bss_desc); ++ ++ if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) ++ priv->curr_bss_params.wmm_enabled = true; ++ else ++ priv->curr_bss_params.wmm_enabled = false; ++ ++ if ((priv->wmm_required || bss_desc->bcn_ht_cap) ++ && priv->curr_bss_params.wmm_enabled) ++ priv->wmm_enabled = true; ++ else ++ priv->wmm_enabled = false; ++ ++ priv->curr_bss_params.wmm_uapsd_enabled = false; ++ ++ if (priv->wmm_enabled) ++ priv->curr_bss_params.wmm_uapsd_enabled ++ = ((bss_desc->wmm_ie.qos_info_bitmap & ++ IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); ++ ++ dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n", ++ priv->curr_pkt_filter); ++ if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) ++ priv->wpa_is_gtk_set = false; ++ ++ if (priv->wmm_enabled) { ++ /* Don't re-enable carrier until we get the WMM_GET_STATUS ++ event */ ++ enable_data = false; ++ } else { ++ /* Since WMM is not enabled, setup the queues with the ++ defaults */ ++ mwifiex_wmm_setup_queue_priorities(priv, NULL); ++ mwifiex_wmm_setup_ac_downgrade(priv); ++ } ++ ++ if (enable_data) ++ dev_dbg(priv->adapter->dev, ++ "info: post association, re-enabling data flow\n"); ++ ++ /* Reset SNR/NF/RSSI values */ ++ priv->data_rssi_last = 0; ++ priv->data_nf_last = 0; ++ priv->data_rssi_avg = 0; ++ priv->data_nf_avg = 0; ++ priv->bcn_rssi_last = 0; ++ priv->bcn_nf_last = 0; ++ priv->bcn_rssi_avg = 0; ++ priv->bcn_nf_avg = 0; ++ priv->rxpd_rate = 0; ++ priv->rxpd_htinfo = 0; ++ ++ mwifiex_save_curr_bcn(priv); ++ ++ priv->adapter->dbg.num_cmd_assoc_success++; ++ ++ dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n"); ++ ++ /* Add the ra_list here for infra mode as there will be only 1 ra ++ always */ ++ mwifiex_ralist_add(priv, ++ priv->curr_bss_params.bss_descriptor.mac_address); ++ ++ if (!netif_carrier_ok(priv->netdev)) ++ netif_carrier_on(priv->netdev); ++ if (netif_queue_stopped(priv->netdev)) ++ netif_wake_queue(priv->netdev); ++ ++ if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) ++ priv->scan_block = true; ++ ++done: ++ /* Need to indicate IOCTL complete */ ++ if (adapter->curr_cmd->wait_q_enabled) { ++ if (ret) ++ adapter->cmd_wait_q.status = -1; ++ else ++ adapter->cmd_wait_q.status = 0; ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function prepares command for ad-hoc start. ++ * ++ * Driver will fill up SSID, BSS mode, IBSS parameters, physical ++ * parameters, probe delay, and capability information. Firmware ++ * will fill up beacon period, basic rates and operational rates. ++ * ++ * In addition, the following TLVs are added - ++ * - Channel TLV ++ * - Vendor specific IE ++ * - WPA/WPA2 IE ++ * - HT Capabilities IE ++ * - HT Information IE ++ * ++ * Preparation also includes - ++ * - Setting command ID and proper size ++ * - Ensuring correct endian-ness ++ */ ++int ++mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, void *data_buf) ++{ ++ int rsn_ie_len = 0; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start = ++ &cmd->params.adhoc_start; ++ struct mwifiex_bssdescriptor *bss_desc; ++ u32 cmd_append_size = 0; ++ u32 i; ++ u16 tmp_cap; ++ uint16_t ht_cap_info; ++ struct mwifiex_ie_types_chan_list_param_set *chan_tlv; ++ ++ struct mwifiex_ie_types_htcap *ht_cap; ++ struct mwifiex_ie_types_htinfo *ht_info; ++ u8 *pos = (u8 *) adhoc_start + ++ sizeof(struct host_cmd_ds_802_11_ad_hoc_start); ++ ++ if (!adapter) ++ return -1; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START); ++ ++ bss_desc = &priv->curr_bss_params.bss_descriptor; ++ priv->attempted_bss_desc = bss_desc; ++ ++ /* ++ * Fill in the parameters for 2 data structures: ++ * 1. struct host_cmd_ds_802_11_ad_hoc_start command ++ * 2. bss_desc ++ * Driver will fill up SSID, bss_mode,IBSS param, Physical Param, ++ * probe delay, and Cap info. ++ * Firmware will fill up beacon period, Basic rates ++ * and operational rates. ++ */ ++ ++ memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN); ++ ++ memcpy(adhoc_start->ssid, ++ ((struct mwifiex_802_11_ssid *) data_buf)->ssid, ++ ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len); ++ ++ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n", ++ adhoc_start->ssid); ++ ++ memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN); ++ memcpy(bss_desc->ssid.ssid, ++ ((struct mwifiex_802_11_ssid *) data_buf)->ssid, ++ ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len); ++ ++ bss_desc->ssid.ssid_len = ++ ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len; ++ ++ /* Set the BSS mode */ ++ adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS; ++ bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; ++ adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period); ++ bss_desc->beacon_period = priv->beacon_period; ++ ++ /* Set Physical param set */ ++/* Parameter IE Id */ ++#define DS_PARA_IE_ID 3 ++/* Parameter IE length */ ++#define DS_PARA_IE_LEN 1 ++ ++ adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID; ++ adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN; ++ ++ if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 ++ (priv, adapter->adhoc_start_band, (u16) ++ priv->adhoc_channel)) { ++ struct mwifiex_chan_freq_power *cfp; ++ cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, ++ adapter->adhoc_start_band, FIRST_VALID_CHANNEL); ++ if (cfp) ++ priv->adhoc_channel = (u8) cfp->channel; ++ } ++ ++ if (!priv->adhoc_channel) { ++ dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n"); ++ return -1; ++ } ++ ++ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n", ++ priv->adhoc_channel); ++ ++ priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel; ++ priv->curr_bss_params.band = adapter->adhoc_start_band; ++ ++ bss_desc->channel = priv->adhoc_channel; ++ adhoc_start->phy_param_set.ds_param_set.current_chan = ++ priv->adhoc_channel; ++ ++ memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set, ++ sizeof(union ieee_types_phy_param_set)); ++ ++ /* Set IBSS param set */ ++/* IBSS parameter IE Id */ ++#define IBSS_PARA_IE_ID 6 ++/* IBSS parameter IE length */ ++#define IBSS_PARA_IE_LEN 2 ++ ++ adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID; ++ adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN; ++ adhoc_start->ss_param_set.ibss_param_set.atim_window ++ = cpu_to_le16(priv->atim_window); ++ memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set, ++ sizeof(union ieee_types_ss_param_set)); ++ ++ /* Set Capability info */ ++ bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS; ++ tmp_cap = le16_to_cpu(adhoc_start->cap_info_bitmap); ++ tmp_cap &= ~WLAN_CAPABILITY_ESS; ++ tmp_cap |= WLAN_CAPABILITY_IBSS; ++ ++ /* Set up privacy in bss_desc */ ++ if (priv->sec_info.encryption_mode) { ++ /* Ad-Hoc capability privacy on */ ++ dev_dbg(adapter->dev, ++ "info: ADHOC_S_CMD: wep_status set privacy to WEP\n"); ++ bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; ++ tmp_cap |= WLAN_CAPABILITY_PRIVACY; ++ } else { ++ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set," ++ " setting privacy to ACCEPT ALL\n"); ++ bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; ++ } ++ ++ memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate)); ++ mwifiex_get_active_data_rates(priv, adhoc_start->DataRate); ++ if ((adapter->adhoc_start_band & BAND_G) && ++ (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { ++ if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, ++ HostCmd_ACT_GEN_SET, 0, ++ &priv->curr_pkt_filter)) { ++ dev_err(adapter->dev, ++ "ADHOC_S_CMD: G Protection config failed\n"); ++ return -1; ++ } ++ } ++ /* Find the last non zero */ ++ for (i = 0; i < sizeof(adhoc_start->DataRate) && ++ adhoc_start->DataRate[i]; ++ i++) ++ ; ++ ++ priv->curr_bss_params.num_of_rates = i; ++ ++ /* Copy the ad-hoc creating rates into Current BSS rate structure */ ++ memcpy(&priv->curr_bss_params.data_rates, ++ &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates); ++ ++ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n", ++ adhoc_start->DataRate[0], adhoc_start->DataRate[1], ++ adhoc_start->DataRate[2], adhoc_start->DataRate[3]); ++ ++ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); ++ ++ if (IS_SUPPORT_MULTI_BANDS(adapter)) { ++ /* Append a channel TLV */ ++ chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; ++ chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); ++ chan_tlv->header.len = ++ cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); ++ ++ memset(chan_tlv->chan_scan_param, 0x00, ++ sizeof(struct mwifiex_chan_scan_param_set)); ++ chan_tlv->chan_scan_param[0].chan_number = ++ (u8) priv->curr_bss_params.bss_descriptor.channel; ++ ++ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n", ++ chan_tlv->chan_scan_param[0].chan_number); ++ ++ chan_tlv->chan_scan_param[0].radio_type ++ = mwifiex_band_to_radio_type(priv->curr_bss_params.band); ++ if (adapter->adhoc_start_band & BAND_GN ++ || adapter->adhoc_start_band & BAND_AN) { ++ if (adapter->chan_offset == SEC_CHANNEL_ABOVE) ++ chan_tlv->chan_scan_param[0].radio_type |= ++ SECOND_CHANNEL_ABOVE; ++ else if (adapter->chan_offset == SEC_CHANNEL_BELOW) ++ chan_tlv->chan_scan_param[0].radio_type |= ++ SECOND_CHANNEL_BELOW; ++ } ++ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n", ++ chan_tlv->chan_scan_param[0].radio_type); ++ pos += sizeof(chan_tlv->header) + ++ sizeof(struct mwifiex_chan_scan_param_set); ++ cmd_append_size += ++ sizeof(chan_tlv->header) + ++ sizeof(struct mwifiex_chan_scan_param_set); ++ } ++ ++ /* Append vendor specific IE TLV */ ++ cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, ++ MWIFIEX_VSIE_MASK_ADHOC, &pos); ++ ++ if (priv->sec_info.wpa_enabled) { ++ rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); ++ if (rsn_ie_len == -1) ++ return -1; ++ cmd_append_size += rsn_ie_len; ++ } ++ ++ if (adapter->adhoc_11n_enabled) { ++ { ++ ht_cap = (struct mwifiex_ie_types_htcap *) pos; ++ memset(ht_cap, 0, ++ sizeof(struct mwifiex_ie_types_htcap)); ++ ht_cap->header.type = ++ cpu_to_le16(WLAN_EID_HT_CAPABILITY); ++ ht_cap->header.len = ++ cpu_to_le16(sizeof(struct ieee80211_ht_cap)); ++ ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); ++ ++ ht_cap_info |= IEEE80211_HT_CAP_SGI_20; ++ if (adapter->chan_offset) { ++ ht_cap_info |= IEEE80211_HT_CAP_SGI_40; ++ ht_cap_info |= IEEE80211_HT_CAP_DSSSCCK40; ++ ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; ++ SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); ++ } ++ ++ ht_cap->ht_cap.ampdu_params_info ++ = IEEE80211_HT_MAX_AMPDU_64K; ++ ht_cap->ht_cap.mcs.rx_mask[0] = 0xff; ++ pos += sizeof(struct mwifiex_ie_types_htcap); ++ cmd_append_size += ++ sizeof(struct mwifiex_ie_types_htcap); ++ } ++ { ++ ht_info = (struct mwifiex_ie_types_htinfo *) pos; ++ memset(ht_info, 0, ++ sizeof(struct mwifiex_ie_types_htinfo)); ++ ht_info->header.type = ++ cpu_to_le16(WLAN_EID_HT_INFORMATION); ++ ht_info->header.len = ++ cpu_to_le16(sizeof(struct ieee80211_ht_info)); ++ ht_info->ht_info.control_chan = ++ (u8) priv->curr_bss_params.bss_descriptor. ++ channel; ++ if (adapter->chan_offset) { ++ ht_info->ht_info.ht_param = ++ adapter->chan_offset; ++ ht_info->ht_info.ht_param |= ++ IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; ++ } ++ ht_info->ht_info.operation_mode = ++ cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); ++ ht_info->ht_info.basic_set[0] = 0xff; ++ pos += sizeof(struct mwifiex_ie_types_htinfo); ++ cmd_append_size += ++ sizeof(struct mwifiex_ie_types_htinfo); ++ } ++ } ++ ++ cmd->size = cpu_to_le16((u16) ++ (sizeof(struct host_cmd_ds_802_11_ad_hoc_start) ++ + S_DS_GEN + cmd_append_size)); ++ ++ if (adapter->adhoc_start_band == BAND_B) ++ tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; ++ else ++ tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME; ++ ++ adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap); ++ ++ return 0; ++} ++ ++/* ++ * This function prepares command for ad-hoc join. ++ * ++ * Most of the parameters are set up by copying from the target BSS descriptor ++ * from the scan response. ++ * ++ * In addition, the following TLVs are added - ++ * - Channel TLV ++ * - Vendor specific IE ++ * - WPA/WPA2 IE ++ * - 11n IE ++ * ++ * Preparation also includes - ++ * - Setting command ID and proper size ++ * - Ensuring correct endian-ness ++ */ ++int ++mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, void *data_buf) ++{ ++ int rsn_ie_len = 0; ++ struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join = ++ &cmd->params.adhoc_join; ++ struct mwifiex_bssdescriptor *bss_desc = ++ (struct mwifiex_bssdescriptor *) data_buf; ++ struct mwifiex_ie_types_chan_list_param_set *chan_tlv; ++ u32 cmd_append_size = 0; ++ u16 tmp_cap; ++ u32 i, rates_size = 0; ++ u16 curr_pkt_filter; ++ u8 *pos = ++ (u8 *) adhoc_join + ++ sizeof(struct host_cmd_ds_802_11_ad_hoc_join); ++ ++/* Use G protection */ ++#define USE_G_PROTECTION 0x02 ++ if (bss_desc->erp_flags & USE_G_PROTECTION) { ++ curr_pkt_filter = ++ priv-> ++ curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON; ++ ++ if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, ++ HostCmd_ACT_GEN_SET, 0, ++ &curr_pkt_filter)) { ++ dev_err(priv->adapter->dev, ++ "ADHOC_J_CMD: G Protection config failed\n"); ++ return -1; ++ } ++ } ++ ++ priv->attempted_bss_desc = bss_desc; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN); ++ ++ adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS; ++ ++ adhoc_join->bss_descriptor.beacon_period ++ = cpu_to_le16(bss_desc->beacon_period); ++ ++ memcpy(&adhoc_join->bss_descriptor.bssid, ++ &bss_desc->mac_address, ETH_ALEN); ++ ++ memcpy(&adhoc_join->bss_descriptor.ssid, ++ &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len); ++ ++ memcpy(&adhoc_join->bss_descriptor.phy_param_set, ++ &bss_desc->phy_param_set, ++ sizeof(union ieee_types_phy_param_set)); ++ ++ memcpy(&adhoc_join->bss_descriptor.ss_param_set, ++ &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set)); ++ ++ tmp_cap = bss_desc->cap_info_bitmap; ++ ++ tmp_cap &= CAPINFO_MASK; ++ ++ dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: tmp_cap=%4X" ++ " CAPINFO_MASK=%4lX\n", tmp_cap, CAPINFO_MASK); ++ ++ /* Information on BSSID descriptor passed to FW */ ++ dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: BSSID = %pM, SSID = %s\n", ++ adhoc_join->bss_descriptor.bssid, ++ adhoc_join->bss_descriptor.ssid); ++ ++ for (i = 0; bss_desc->supported_rates[i] && ++ i < MWIFIEX_SUPPORTED_RATES; ++ i++) ++ ; ++ rates_size = i; ++ ++ /* Copy Data Rates from the Rates recorded in scan response */ ++ memset(adhoc_join->bss_descriptor.data_rates, 0, ++ sizeof(adhoc_join->bss_descriptor.data_rates)); ++ memcpy(adhoc_join->bss_descriptor.data_rates, ++ bss_desc->supported_rates, rates_size); ++ ++ /* Copy the adhoc join rates into Current BSS state structure */ ++ priv->curr_bss_params.num_of_rates = rates_size; ++ memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates, ++ rates_size); ++ ++ /* Copy the channel information */ ++ priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel; ++ priv->curr_bss_params.band = (u8) bss_desc->bss_band; ++ ++ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED ++ || priv->sec_info.wpa_enabled) ++ tmp_cap |= WLAN_CAPABILITY_PRIVACY; ++ ++ if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) { ++ /* Append a channel TLV */ ++ chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; ++ chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); ++ chan_tlv->header.len = ++ cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); ++ ++ memset(chan_tlv->chan_scan_param, 0x00, ++ sizeof(struct mwifiex_chan_scan_param_set)); ++ chan_tlv->chan_scan_param[0].chan_number = ++ (bss_desc->phy_param_set.ds_param_set.current_chan); ++ dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Chan = %d\n", ++ chan_tlv->chan_scan_param[0].chan_number); ++ ++ chan_tlv->chan_scan_param[0].radio_type = ++ mwifiex_band_to_radio_type((u8) bss_desc->bss_band); ++ ++ dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Band = %d\n", ++ chan_tlv->chan_scan_param[0].radio_type); ++ pos += sizeof(chan_tlv->header) + ++ sizeof(struct mwifiex_chan_scan_param_set); ++ cmd_append_size += sizeof(chan_tlv->header) + ++ sizeof(struct mwifiex_chan_scan_param_set); ++ } ++ ++ if (priv->sec_info.wpa_enabled) ++ rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); ++ if (rsn_ie_len == -1) ++ return -1; ++ cmd_append_size += rsn_ie_len; ++ ++ if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) ++ cmd_append_size += mwifiex_cmd_append_11n_tlv(priv, ++ bss_desc, &pos); ++ ++ /* Append vendor specific IE TLV */ ++ cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, ++ MWIFIEX_VSIE_MASK_ADHOC, &pos); ++ ++ cmd->size = cpu_to_le16((u16) ++ (sizeof(struct host_cmd_ds_802_11_ad_hoc_join) ++ + S_DS_GEN + cmd_append_size)); ++ ++ adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap); ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of ad-hoc start and ++ * ad-hoc join. ++ * ++ * The function generates a device-connected event to notify ++ * the applications, in case of successful ad-hoc start/join, and ++ * saves the beacon buffer. ++ */ ++int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ int ret = 0; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result; ++ struct mwifiex_bssdescriptor *bss_desc; ++ ++ adhoc_result = &resp->params.adhoc_result; ++ ++ bss_desc = priv->attempted_bss_desc; ++ ++ /* Join result code 0 --> SUCCESS */ ++ if (le16_to_cpu(resp->result)) { ++ dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n"); ++ if (priv->media_connected) ++ mwifiex_reset_connect_state(priv); ++ ++ memset(&priv->curr_bss_params.bss_descriptor, ++ 0x00, sizeof(struct mwifiex_bssdescriptor)); ++ ++ ret = -1; ++ goto done; ++ } ++ ++ /* Send a Media Connected event, according to the Spec */ ++ priv->media_connected = true; ++ ++ if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) { ++ dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n", ++ bss_desc->ssid.ssid); ++ ++ /* Update the created network descriptor with the new BSSID */ ++ memcpy(bss_desc->mac_address, ++ adhoc_result->bssid, ETH_ALEN); ++ ++ priv->adhoc_state = ADHOC_STARTED; ++ } else { ++ /* ++ * Now the join cmd should be successful. ++ * If BSSID has changed use SSID to compare instead of BSSID ++ */ ++ dev_dbg(priv->adapter->dev, "info: ADHOC_J_RESP %s\n", ++ bss_desc->ssid.ssid); ++ ++ /* ++ * Make a copy of current BSSID descriptor, only needed for ++ * join since the current descriptor is already being used ++ * for adhoc start ++ */ ++ memcpy(&priv->curr_bss_params.bss_descriptor, ++ bss_desc, sizeof(struct mwifiex_bssdescriptor)); ++ ++ priv->adhoc_state = ADHOC_JOINED; ++ } ++ ++ dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: channel = %d\n", ++ priv->adhoc_channel); ++ dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: BSSID = %pM\n", ++ priv->curr_bss_params.bss_descriptor.mac_address); ++ ++ if (!netif_carrier_ok(priv->netdev)) ++ netif_carrier_on(priv->netdev); ++ if (netif_queue_stopped(priv->netdev)) ++ netif_wake_queue(priv->netdev); ++ ++ mwifiex_save_curr_bcn(priv); ++ ++done: ++ /* Need to indicate IOCTL complete */ ++ if (adapter->curr_cmd->wait_q_enabled) { ++ if (ret) ++ adapter->cmd_wait_q.status = -1; ++ else ++ adapter->cmd_wait_q.status = 0; ++ ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function associates to a specific BSS discovered in a scan. ++ * ++ * It clears any past association response stored for application ++ * retrieval and calls the command preparation routine to send the ++ * command to firmware. ++ */ ++int mwifiex_associate(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc) ++{ ++ u8 current_bssid[ETH_ALEN]; ++ ++ /* Return error if the adapter or table entry is not marked as infra */ ++ if ((priv->bss_mode != NL80211_IFTYPE_STATION) || ++ (bss_desc->bss_mode != NL80211_IFTYPE_STATION)) ++ return -1; ++ ++ memcpy(¤t_bssid, ++ &priv->curr_bss_params.bss_descriptor.mac_address, ++ sizeof(current_bssid)); ++ ++ /* Clear any past association response stored for application ++ retrieval */ ++ priv->assoc_rsp_size = 0; ++ ++ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_ASSOCIATE, ++ HostCmd_ACT_GEN_SET, 0, bss_desc); ++} ++ ++/* ++ * This function starts an ad-hoc network. ++ * ++ * It calls the command preparation routine to send the command to firmware. ++ */ ++int ++mwifiex_adhoc_start(struct mwifiex_private *priv, ++ struct mwifiex_802_11_ssid *adhoc_ssid) ++{ ++ dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n", ++ priv->adhoc_channel); ++ dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n", ++ priv->curr_bss_params.bss_descriptor.channel); ++ dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n", ++ priv->curr_bss_params.band); ++ ++ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START, ++ HostCmd_ACT_GEN_SET, 0, adhoc_ssid); ++} ++ ++/* ++ * This function joins an ad-hoc network found in a previous scan. ++ * ++ * It calls the command preparation routine to send the command to firmware, ++ * if already not connected to the requested SSID. ++ */ ++int mwifiex_adhoc_join(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc) ++{ ++ dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid =%s\n", ++ priv->curr_bss_params.bss_descriptor.ssid.ssid); ++ dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid_len =%u\n", ++ priv->curr_bss_params.bss_descriptor.ssid.ssid_len); ++ dev_dbg(priv->adapter->dev, "info: adhoc join: ssid =%s\n", ++ bss_desc->ssid.ssid); ++ dev_dbg(priv->adapter->dev, "info: adhoc join: ssid_len =%u\n", ++ bss_desc->ssid.ssid_len); ++ ++ /* Check if the requested SSID is already joined */ ++ if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len && ++ !mwifiex_ssid_cmp(&bss_desc->ssid, ++ &priv->curr_bss_params.bss_descriptor.ssid) && ++ (priv->curr_bss_params.bss_descriptor.bss_mode == ++ NL80211_IFTYPE_ADHOC)) { ++ dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: new ad-hoc SSID" ++ " is the same as current; not attempting to re-join\n"); ++ return -1; ++ } ++ ++ dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n", ++ priv->curr_bss_params.bss_descriptor.channel); ++ dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n", ++ priv->curr_bss_params.band); ++ ++ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, ++ HostCmd_ACT_GEN_SET, 0, bss_desc); ++} ++ ++/* ++ * This function deauthenticates/disconnects from infra network by sending ++ * deauthentication request. ++ */ ++static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac) ++{ ++ u8 mac_address[ETH_ALEN]; ++ int ret = 0; ++ u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; ++ ++ if (mac) { ++ if (!memcmp(mac, zero_mac, sizeof(zero_mac))) ++ memcpy((u8 *) &mac_address, ++ (u8 *) &priv->curr_bss_params.bss_descriptor. ++ mac_address, ETH_ALEN); ++ else ++ memcpy((u8 *) &mac_address, (u8 *) mac, ETH_ALEN); ++ } else { ++ memcpy((u8 *) &mac_address, (u8 *) &priv->curr_bss_params. ++ bss_descriptor.mac_address, ETH_ALEN); ++ } ++ ++ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, ++ HostCmd_ACT_GEN_SET, 0, &mac_address); ++ ++ return ret; ++} ++ ++/* ++ * This function deauthenticates/disconnects from a BSS. ++ * ++ * In case of infra made, it sends deauthentication request, and ++ * in case of ad-hoc mode, a stop network request is sent to the firmware. ++ */ ++int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac) ++{ ++ int ret = 0; ++ ++ if (priv->media_connected) { ++ if (priv->bss_mode == NL80211_IFTYPE_STATION) { ++ ret = mwifiex_deauthenticate_infra(priv, mac); ++ } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { ++ ret = mwifiex_send_cmd_sync(priv, ++ HostCmd_CMD_802_11_AD_HOC_STOP, ++ HostCmd_ACT_GEN_SET, 0, NULL); ++ } ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mwifiex_deauthenticate); ++ ++/* ++ * This function converts band to radio type used in channel TLV. ++ */ ++u8 ++mwifiex_band_to_radio_type(u8 band) ++{ ++ switch (band) { ++ case BAND_A: ++ case BAND_AN: ++ case BAND_A | BAND_AN: ++ return HostCmd_SCAN_RADIO_TYPE_A; ++ case BAND_B: ++ case BAND_G: ++ case BAND_B | BAND_G: ++ default: ++ return HostCmd_SCAN_RADIO_TYPE_BG; ++ } ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/Kconfig linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/Kconfig +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/Kconfig 2011-05-05 23:29:45.493441961 +0200 +@@ -0,0 +1,21 @@ ++config MWIFIEX ++ tristate "Marvell WiFi-Ex Driver" ++ depends on CFG80211 ++ select LIB80211 ++ ---help--- ++ This adds support for wireless adapters based on Marvell ++ 802.11n chipsets. ++ ++ If you choose to build it as a module, it will be called ++ mwifiex. ++ ++config MWIFIEX_SDIO ++ tristate "Marvell WiFi-Ex Driver for SD8787" ++ depends on MWIFIEX && MMC ++ select FW_LOADER ++ ---help--- ++ This adds support for wireless adapters based on Marvell ++ 8787 chipset with SDIO interface. ++ ++ If you choose to build it as a module, it will be called ++ mwifiex_sdio. +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/main.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/main.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/main.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/main.c 2011-05-05 23:29:45.489441913 +0200 +@@ -0,0 +1,1060 @@ ++/* ++ * Marvell Wireless LAN device driver: major functions ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "main.h" ++#include "wmm.h" ++#include "cfg80211.h" ++#include "11n.h" ++ ++#define VERSION "1.0" ++ ++const char driver_version[] = "mwifiex " VERSION " (%s) "; ++ ++struct mwifiex_adapter *g_adapter; ++EXPORT_SYMBOL_GPL(g_adapter); ++ ++static struct mwifiex_bss_attr mwifiex_bss_sta[] = { ++ {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0}, ++}; ++ ++static int drv_mode = DRV_MODE_STA; ++ ++static char fw_name[32] = DEFAULT_FW_NAME; ++ ++/* Supported drv_mode table */ ++static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { ++ { ++ .drv_mode = DRV_MODE_STA, ++ .intf_num = ARRAY_SIZE(mwifiex_bss_sta), ++ .bss_attr = mwifiex_bss_sta, ++ }, ++}; ++ ++/* ++ * This function registers the device and performs all the necessary ++ * initializations. ++ * ++ * The following initialization operations are performed - ++ * - Allocate adapter structure ++ * - Save interface specific operations table in adapter ++ * - Call interface specific initialization routine ++ * - Allocate private structures ++ * - Set default adapter structure parameters ++ * - Initialize locks ++ * ++ * In case of any errors during inittialization, this function also ensures ++ * proper cleanup before exiting. ++ */ ++static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, ++ struct mwifiex_drv_mode *drv_mode_ptr) ++{ ++ struct mwifiex_adapter *adapter; ++ int i; ++ ++ adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL); ++ if (!adapter) ++ return -1; ++ ++ g_adapter = adapter; ++ adapter->card = card; ++ ++ /* Save interface specific operations in adapter */ ++ memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops)); ++ ++ /* card specific initialization has been deferred until now .. */ ++ if (adapter->if_ops.init_if(adapter)) ++ goto error; ++ ++ adapter->priv_num = 0; ++ for (i = 0; i < drv_mode_ptr->intf_num; i++) { ++ adapter->priv[i] = NULL; ++ ++ if (!drv_mode_ptr->bss_attr[i].active) ++ continue; ++ ++ /* Allocate memory for private structure */ ++ adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private), ++ GFP_KERNEL); ++ if (!adapter->priv[i]) { ++ dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n", ++ __func__, i); ++ goto error; ++ } ++ ++ adapter->priv_num++; ++ adapter->priv[i]->adapter = adapter; ++ /* Save bss_type, frame_type & bss_priority */ ++ adapter->priv[i]->bss_type = drv_mode_ptr->bss_attr[i].bss_type; ++ adapter->priv[i]->frame_type = ++ drv_mode_ptr->bss_attr[i].frame_type; ++ adapter->priv[i]->bss_priority = ++ drv_mode_ptr->bss_attr[i].bss_priority; ++ ++ if (drv_mode_ptr->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA) ++ adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA; ++ else if (drv_mode_ptr->bss_attr[i].bss_type == ++ MWIFIEX_BSS_TYPE_UAP) ++ adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP; ++ ++ /* Save bss_index & bss_num */ ++ adapter->priv[i]->bss_index = i; ++ adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num; ++ } ++ adapter->drv_mode = drv_mode_ptr; ++ ++ if (mwifiex_init_lock_list(adapter)) ++ goto error; ++ ++ init_timer(&adapter->cmd_timer); ++ adapter->cmd_timer.function = mwifiex_cmd_timeout_func; ++ adapter->cmd_timer.data = (unsigned long) adapter; ++ ++ return 0; ++ ++error: ++ dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); ++ ++ mwifiex_free_lock_list(adapter); ++ for (i = 0; i < drv_mode_ptr->intf_num; i++) ++ kfree(adapter->priv[i]); ++ kfree(adapter); ++ ++ return -1; ++} ++ ++/* ++ * This function unregisters the device and performs all the necessary ++ * cleanups. ++ * ++ * The following cleanup operations are performed - ++ * - Free the timers ++ * - Free beacon buffers ++ * - Free private structures ++ * - Free adapter structure ++ */ ++static int mwifiex_unregister(struct mwifiex_adapter *adapter) ++{ ++ s32 i = 0; ++ ++ del_timer(&adapter->cmd_timer); ++ ++ /* Free private structures */ ++ for (i = 0; i < adapter->priv_num; i++) { ++ if (adapter->priv[i]) { ++ mwifiex_free_curr_bcn(adapter->priv[i]); ++ kfree(adapter->priv[i]); ++ } ++ } ++ ++ kfree(adapter); ++ return 0; ++} ++ ++/* ++ * The main process. ++ * ++ * This function is the main procedure of the driver and handles various driver ++ * operations. It runs in a loop and provides the core functionalities. ++ * ++ * The main responsibilities of this function are - ++ * - Ensure concurrency control ++ * - Handle pending interrupts and call interrupt handlers ++ * - Wake up the card if required ++ * - Handle command responses and call response handlers ++ * - Handle events and call event handlers ++ * - Execute pending commands ++ * - Transmit pending data packets ++ */ ++int mwifiex_main_process(struct mwifiex_adapter *adapter) ++{ ++ int ret = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&adapter->main_proc_lock, flags); ++ ++ /* Check if already processing */ ++ if (adapter->mwifiex_processing) { ++ spin_unlock_irqrestore(&adapter->main_proc_lock, flags); ++ goto exit_main_proc; ++ } else { ++ adapter->mwifiex_processing = true; ++ spin_unlock_irqrestore(&adapter->main_proc_lock, flags); ++ } ++process_start: ++ do { ++ if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) || ++ (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) ++ break; ++ ++ /* Handle pending interrupt if any */ ++ if (adapter->int_status) { ++ if (adapter->hs_activated) ++ mwifiex_process_hs_config(adapter); ++ adapter->if_ops.process_int_status(adapter); ++ } ++ ++ /* Need to wake up the card ? */ ++ if ((adapter->ps_state == PS_STATE_SLEEP) && ++ (adapter->pm_wakeup_card_req && ++ !adapter->pm_wakeup_fw_try) && ++ (is_command_pending(adapter) ++ || !mwifiex_wmm_lists_empty(adapter))) { ++ adapter->pm_wakeup_fw_try = true; ++ adapter->if_ops.wakeup(adapter); ++ continue; ++ } ++ if (IS_CARD_RX_RCVD(adapter)) { ++ adapter->pm_wakeup_fw_try = false; ++ if (adapter->ps_state == PS_STATE_SLEEP) ++ adapter->ps_state = PS_STATE_AWAKE; ++ } else { ++ /* We have tried to wakeup the card already */ ++ if (adapter->pm_wakeup_fw_try) ++ break; ++ if (adapter->ps_state != PS_STATE_AWAKE || ++ adapter->tx_lock_flag) ++ break; ++ ++ if (adapter->scan_processing || adapter->data_sent ++ || mwifiex_wmm_lists_empty(adapter)) { ++ if (adapter->cmd_sent || adapter->curr_cmd ++ || (!is_command_pending(adapter))) ++ break; ++ } ++ } ++ ++ /* Check for Cmd Resp */ ++ if (adapter->cmd_resp_received) { ++ adapter->cmd_resp_received = false; ++ mwifiex_process_cmdresp(adapter); ++ ++ /* call mwifiex back when init_fw is done */ ++ if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) { ++ adapter->hw_status = MWIFIEX_HW_STATUS_READY; ++ mwifiex_init_fw_complete(adapter); ++ } ++ } ++ ++ /* Check for event */ ++ if (adapter->event_received) { ++ adapter->event_received = false; ++ mwifiex_process_event(adapter); ++ } ++ ++ /* Check if we need to confirm Sleep Request ++ received previously */ ++ if (adapter->ps_state == PS_STATE_PRE_SLEEP) { ++ if (!adapter->cmd_sent && !adapter->curr_cmd) ++ mwifiex_check_ps_cond(adapter); ++ } ++ ++ /* * The ps_state may have been changed during processing of ++ * Sleep Request event. ++ */ ++ if ((adapter->ps_state == PS_STATE_SLEEP) ++ || (adapter->ps_state == PS_STATE_PRE_SLEEP) ++ || (adapter->ps_state == PS_STATE_SLEEP_CFM) ++ || adapter->tx_lock_flag) ++ continue; ++ ++ if (!adapter->cmd_sent && !adapter->curr_cmd) { ++ if (mwifiex_exec_next_cmd(adapter) == -1) { ++ ret = -1; ++ break; ++ } ++ } ++ ++ if (!adapter->scan_processing && !adapter->data_sent && ++ !mwifiex_wmm_lists_empty(adapter)) { ++ mwifiex_wmm_process_tx(adapter); ++ if (adapter->hs_activated) { ++ adapter->is_hs_configured = false; ++ mwifiex_hs_activated_event ++ (mwifiex_get_priv ++ (adapter, MWIFIEX_BSS_ROLE_ANY), ++ false); ++ } ++ } ++ ++ if (adapter->delay_null_pkt && !adapter->cmd_sent && ++ !adapter->curr_cmd && !is_command_pending(adapter) ++ && mwifiex_wmm_lists_empty(adapter)) { ++ if (!mwifiex_send_null_packet ++ (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), ++ MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | ++ MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) { ++ adapter->delay_null_pkt = false; ++ adapter->ps_state = PS_STATE_SLEEP; ++ } ++ break; ++ } ++ } while (true); ++ ++ if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter)) ++ goto process_start; ++ ++ spin_lock_irqsave(&adapter->main_proc_lock, flags); ++ adapter->mwifiex_processing = false; ++ spin_unlock_irqrestore(&adapter->main_proc_lock, flags); ++ ++exit_main_proc: ++ if (adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) ++ mwifiex_shutdown_drv(adapter); ++ return ret; ++} ++ ++/* ++ * This function initializes the software. ++ * ++ * The main work includes allocating and initializing the adapter structure ++ * and initializing the private structures. ++ */ ++static int ++mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops) ++{ ++ int i; ++ struct mwifiex_drv_mode *drv_mode_ptr; ++ ++ /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */ ++ drv_mode_ptr = NULL; ++ for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) { ++ if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) { ++ drv_mode_ptr = &mwifiex_drv_mode_tbl[i]; ++ break; ++ } ++ } ++ ++ if (!drv_mode_ptr) { ++ pr_err("invalid drv_mode=%d\n", drv_mode); ++ return -1; ++ } ++ ++ if (mwifiex_register(card, if_ops, drv_mode_ptr)) ++ return -1; ++ ++ return 0; ++} ++ ++/* ++ * This function frees the adapter structure. ++ * ++ * Additionally, this closes the netlink socket, frees the timers ++ * and private structures. ++ */ ++static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) ++{ ++ if (!adapter) { ++ pr_err("%s: adapter is NULL\n", __func__); ++ return; ++ } ++ ++ mwifiex_unregister(adapter); ++ pr_debug("info: %s: free adapter\n", __func__); ++} ++ ++/* ++ * This function initializes the hardware and firmware. ++ * ++ * The main initialization steps followed are - ++ * - Download the correct firmware to card ++ * - Allocate and initialize the adapter structure ++ * - Initialize the private structures ++ * - Issue the init commands to firmware ++ */ ++static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) ++{ ++ int ret = 0; ++ int err; ++ struct mwifiex_fw_image fw; ++ ++ memset(&fw, 0, sizeof(struct mwifiex_fw_image)); ++ ++ switch (adapter->revision_id) { ++ case SD8787_W0: ++ case SD8787_W1: ++ strcpy(fw_name, SD8787_W1_FW_NAME); ++ break; ++ case SD8787_A0: ++ case SD8787_A1: ++ strcpy(fw_name, SD8787_AX_FW_NAME); ++ break; ++ default: ++ break; ++ } ++ ++ err = request_firmware(&adapter->firmware, fw_name, adapter->dev); ++ if (err < 0) { ++ dev_err(adapter->dev, "request_firmware() returned" ++ " error code %#x\n", err); ++ ret = -1; ++ goto done; ++ } ++ fw.fw_buf = (u8 *) adapter->firmware->data; ++ fw.fw_len = adapter->firmware->size; ++ ++ ret = mwifiex_dnld_fw(adapter, &fw); ++ if (ret == -1) ++ goto done; ++ ++ dev_notice(adapter->dev, "WLAN FW is active\n"); ++ ++ adapter->init_wait_q_woken = false; ++ ret = mwifiex_init_fw(adapter); ++ if (ret == -1) { ++ goto done; ++ } else if (!ret) { ++ adapter->hw_status = MWIFIEX_HW_STATUS_READY; ++ goto done; ++ } ++ /* Wait for mwifiex_init to complete */ ++ wait_event_interruptible(adapter->init_wait_q, ++ adapter->init_wait_q_woken); ++ if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) { ++ ret = -1; ++ goto done; ++ } ++ ret = 0; ++ ++done: ++ if (adapter->firmware) ++ release_firmware(adapter->firmware); ++ if (ret) ++ ret = -1; ++ return ret; ++} ++ ++/* ++ * This function fills a driver buffer. ++ * ++ * The function associates a given SKB with the provided driver buffer ++ * and also updates some of the SKB parameters, including IP header, ++ * priority and timestamp. ++ */ ++static void ++mwifiex_fill_buffer(struct sk_buff *skb) ++{ ++ struct ethhdr *eth = NULL; ++ struct iphdr *iph; ++ struct timeval tv; ++ u8 tid = 0; ++ ++ eth = (struct ethhdr *) skb->data; ++ switch (eth->h_proto) { ++ case __constant_htons(ETH_P_IP): ++ iph = ip_hdr(skb); ++ tid = IPTOS_PREC(iph->tos); ++ pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n", ++ eth->h_proto, tid, skb->priority); ++ break; ++ case __constant_htons(ETH_P_ARP): ++ pr_debug("data: ARP packet: %04x\n", eth->h_proto); ++ default: ++ break; ++ } ++/* Offset for TOS field in the IP header */ ++#define IPTOS_OFFSET 5 ++ tid = (tid >> IPTOS_OFFSET); ++ skb->priority = tid; ++ /* Record the current time the packet was queued; used to ++ determine the amount of time the packet was queued in ++ the driver before it was sent to the firmware. ++ The delay is then sent along with the packet to the ++ firmware for aggregate delay calculation for stats and ++ MSDU lifetime expiry. ++ */ ++ do_gettimeofday(&tv); ++ skb->tstamp = timeval_to_ktime(tv); ++} ++ ++/* ++ * CFG802.11 network device handler for open. ++ * ++ * Starts the data queue. ++ */ ++static int ++mwifiex_open(struct net_device *dev) ++{ ++ netif_start_queue(dev); ++ return 0; ++} ++ ++/* ++ * CFG802.11 network device handler for close. ++ */ ++static int ++mwifiex_close(struct net_device *dev) ++{ ++ return 0; ++} ++ ++/* ++ * CFG802.11 network device handler for data transmission. ++ */ ++static int ++mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); ++ struct sk_buff *new_skb = NULL; ++ struct mwifiex_txinfo *tx_info; ++ ++ dev_dbg(priv->adapter->dev, "data: %lu BSS(%d): Data <= kernel\n", ++ jiffies, priv->bss_index); ++ ++ if (priv->adapter->surprise_removed) { ++ kfree(skb); ++ priv->stats.tx_dropped++; ++ return 0; ++ } ++ if (!skb->len || (skb->len > ETH_FRAME_LEN)) { ++ dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len); ++ kfree(skb); ++ priv->stats.tx_dropped++; ++ return 0; ++ } ++ if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) { ++ dev_dbg(priv->adapter->dev, ++ "data: Tx: insufficient skb headroom %d\n", ++ skb_headroom(skb)); ++ /* Insufficient skb headroom - allocate a new skb */ ++ new_skb = ++ skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN); ++ if (unlikely(!new_skb)) { ++ dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n"); ++ kfree(skb); ++ priv->stats.tx_dropped++; ++ return 0; ++ } ++ kfree_skb(skb); ++ skb = new_skb; ++ dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n", ++ skb_headroom(skb)); ++ } ++ ++ tx_info = MWIFIEX_SKB_TXCB(skb); ++ tx_info->bss_index = priv->bss_index; ++ mwifiex_fill_buffer(skb); ++ ++ mwifiex_wmm_add_buf_txqueue(priv->adapter, skb); ++ atomic_inc(&priv->adapter->tx_pending); ++ ++ if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) { ++ netif_stop_queue(priv->netdev); ++ dev->trans_start = jiffies; ++ } ++ ++ queue_work(priv->adapter->workqueue, &priv->adapter->main_work); ++ ++ return 0; ++} ++ ++/* ++ * CFG802.11 network device handler for setting MAC address. ++ */ ++static int ++mwifiex_set_mac_address(struct net_device *dev, void *addr) ++{ ++ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); ++ struct sockaddr *hw_addr = (struct sockaddr *) addr; ++ int ret = 0; ++ ++ memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); ++ ++ /* Send request to firmware */ ++ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_MAC_ADDRESS, ++ HostCmd_ACT_GEN_SET, 0, NULL); ++ ++ if (!ret) ++ memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN); ++ else ++ dev_err(priv->adapter->dev, "set mac address failed: ret=%d" ++ "\n", ret); ++ ++ memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); ++ ++ return ret; ++} ++ ++/* ++ * CFG802.11 network device handler for setting multicast list. ++ */ ++static void mwifiex_set_multicast_list(struct net_device *dev) ++{ ++ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); ++ struct mwifiex_multicast_list mcast_list; ++ ++ if (dev->flags & IFF_PROMISC) { ++ mcast_list.mode = MWIFIEX_PROMISC_MODE; ++ } else if (dev->flags & IFF_ALLMULTI || ++ netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) { ++ mcast_list.mode = MWIFIEX_ALL_MULTI_MODE; ++ } else { ++ mcast_list.mode = MWIFIEX_MULTICAST_MODE; ++ if (netdev_mc_count(dev)) ++ mcast_list.num_multicast_addr = ++ mwifiex_copy_mcast_addr(&mcast_list, dev); ++ } ++ mwifiex_request_set_multicast_list(priv, &mcast_list); ++} ++ ++/* ++ * CFG802.11 network device handler for transmission timeout. ++ */ ++static void ++mwifiex_tx_timeout(struct net_device *dev) ++{ ++ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); ++ ++ dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_index=%d\n", ++ jiffies, priv->bss_index); ++ dev->trans_start = jiffies; ++ priv->num_tx_timeout++; ++} ++ ++/* ++ * CFG802.11 network device handler for statistics retrieval. ++ */ ++static struct net_device_stats *mwifiex_get_stats(struct net_device *dev) ++{ ++ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); ++ ++ return &priv->stats; ++} ++ ++/* Network device handlers */ ++static const struct net_device_ops mwifiex_netdev_ops = { ++ .ndo_open = mwifiex_open, ++ .ndo_stop = mwifiex_close, ++ .ndo_start_xmit = mwifiex_hard_start_xmit, ++ .ndo_set_mac_address = mwifiex_set_mac_address, ++ .ndo_tx_timeout = mwifiex_tx_timeout, ++ .ndo_get_stats = mwifiex_get_stats, ++ .ndo_set_multicast_list = mwifiex_set_multicast_list, ++}; ++ ++/* ++ * This function initializes the private structure parameters. ++ * ++ * The following wait queues are initialized - ++ * - IOCTL wait queue ++ * - Command wait queue ++ * - Statistics wait queue ++ * ++ * ...and the following default parameters are set - ++ * - Current key index : Set to 0 ++ * - Rate index : Set to auto ++ * - Media connected : Set to disconnected ++ * - Adhoc link sensed : Set to false ++ * - Nick name : Set to null ++ * - Number of Tx timeout : Set to 0 ++ * - Device address : Set to current address ++ * ++ * In addition, the CFG80211 work queue is also created. ++ */ ++static void ++mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) ++{ ++ dev->netdev_ops = &mwifiex_netdev_ops; ++ /* Initialize private structure */ ++ priv->current_key_index = 0; ++ priv->media_connected = false; ++ memset(&priv->nick_name, 0, sizeof(priv->nick_name)); ++ priv->num_tx_timeout = 0; ++ priv->workqueue = create_singlethread_workqueue("cfg80211_wq"); ++ INIT_WORK(&priv->cfg_workqueue, mwifiex_cfg80211_results); ++ memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); ++} ++ ++/* ++ * This function adds a new logical interface. ++ * ++ * It allocates, initializes and registers the interface by performing ++ * the following opearations - ++ * - Allocate a new net device structure ++ * - Assign device name ++ * - Register the new device with CFG80211 subsystem ++ * - Initialize semaphore and private structure ++ * - Register the new device with kernel ++ * - Create the complete debug FS structure if configured ++ */ ++static struct mwifiex_private *mwifiex_add_interface( ++ struct mwifiex_adapter *adapter, ++ u8 bss_index, u8 bss_type) ++{ ++ struct net_device *dev = NULL; ++ struct mwifiex_private *priv = NULL; ++ void *mdev_priv = NULL; ++ ++ dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d", ++ ether_setup, 1); ++ if (!dev) { ++ dev_err(adapter->dev, "no memory available for netdevice\n"); ++ goto error; ++ } ++ if (dev_alloc_name(dev, dev->name)) { ++ dev_err(adapter->dev, "unable to alloc name for netdevice\n"); ++ goto error; ++ } ++ ++ if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr, ++ adapter->priv[bss_index]) != 0) { ++ dev_err(adapter->dev, "cannot register netdevice with cfg80211\n"); ++ goto error; ++ } ++ /* Save the priv pointer in netdev */ ++ priv = adapter->priv[bss_index]; ++ mdev_priv = netdev_priv(dev); ++ *((unsigned long *) mdev_priv) = (unsigned long) priv; ++ ++ priv->netdev = dev; ++ ++ sema_init(&priv->async_sem, 1); ++ priv->scan_pending_on_block = false; ++ ++ mwifiex_init_priv_params(priv, dev); ++ ++ SET_NETDEV_DEV(dev, adapter->dev); ++ ++ /* Register network device */ ++ if (register_netdev(dev)) { ++ dev_err(adapter->dev, "cannot register virtual network device\n"); ++ goto error; ++ } ++ ++ dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); ++#ifdef CONFIG_DEBUG_FS ++ mwifiex_dev_debugfs_init(priv); ++#endif ++ return priv; ++error: ++ if (dev) ++ free_netdev(dev); ++ return NULL; ++} ++ ++/* ++ * This function removes a logical interface. ++ * ++ * It deregisters, resets and frees the interface by performing ++ * the following operations - ++ * - Disconnect the device if connected, send wireless event to ++ * notify applications. ++ * - Remove the debug FS structure if configured ++ * - Unregister the device from kernel ++ * - Free the net device structure ++ * - Cancel all works and destroy work queue ++ * - Unregister and free the wireless device from CFG80211 subsystem ++ */ ++static void ++mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index) ++{ ++ struct net_device *dev = NULL; ++ struct mwifiex_private *priv = adapter->priv[bss_index]; ++ ++ if (!priv) ++ return; ++ dev = priv->netdev; ++ ++ if (priv->media_connected) ++ priv->media_connected = false; ++ ++#ifdef CONFIG_DEBUG_FS ++ mwifiex_dev_debugfs_remove(priv); ++#endif ++ /* Last reference is our one */ ++ dev_dbg(adapter->dev, "info: %s: refcnt = %d\n", ++ dev->name, netdev_refcnt_read(dev)); ++ ++ if (dev->reg_state == NETREG_REGISTERED) ++ unregister_netdev(dev); ++ ++ /* Clear the priv in adapter */ ++ priv->netdev = NULL; ++ if (dev) ++ free_netdev(dev); ++ ++ cancel_work_sync(&priv->cfg_workqueue); ++ flush_workqueue(priv->workqueue); ++ destroy_workqueue(priv->workqueue); ++ wiphy_unregister(priv->wdev->wiphy); ++ wiphy_free(priv->wdev->wiphy); ++ kfree(priv->wdev); ++} ++ ++/* ++ * This function check if command is pending. ++ */ ++int is_command_pending(struct mwifiex_adapter *adapter) ++{ ++ unsigned long flags; ++ int is_cmd_pend_q_empty; ++ ++ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); ++ is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); ++ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); ++ ++ return !is_cmd_pend_q_empty; ++} ++ ++/* ++ * This function returns the correct private structure pointer based ++ * upon the BSS number. ++ */ ++struct mwifiex_private * ++mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index) ++{ ++ if (!adapter || (bss_index >= adapter->priv_num)) ++ return NULL; ++ return adapter->priv[bss_index]; ++} ++ ++/* ++ * This is the main work queue function. ++ * ++ * It handles the main process, which in turn handles the complete ++ * driver operations. ++ */ ++static void mwifiex_main_work_queue(struct work_struct *work) ++{ ++ struct mwifiex_adapter *adapter = ++ container_of(work, struct mwifiex_adapter, main_work); ++ ++ if (adapter->surprise_removed) ++ return; ++ mwifiex_main_process(adapter); ++} ++ ++/* ++ * This function cancels all works in the queue and destroys ++ * the main workqueue. ++ */ ++static void ++mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) ++{ ++ flush_workqueue(adapter->workqueue); ++ destroy_workqueue(adapter->workqueue); ++ adapter->workqueue = NULL; ++} ++ ++/* ++ * This function adds the card. ++ * ++ * This function follows the following major steps to set up the device - ++ * - Initialize software. This includes probing the card, registering ++ * the interface operations table, and allocating/initializing the ++ * adapter structure ++ * - Set up the netlink socket ++ * - Create and start the main work queue ++ * - Register the device ++ * - Initialize firmware and hardware ++ * - Add logical interfaces ++ */ ++int ++mwifiex_add_card(void *card, struct semaphore *sem, ++ struct mwifiex_if_ops *if_ops) ++{ ++ int i; ++ struct mwifiex_adapter *adapter; ++ ++ if (down_interruptible(sem)) ++ goto exit_sem_err; ++ ++ if (mwifiex_init_sw(card, if_ops)) { ++ pr_err("%s: software init failed\n", __func__); ++ goto err_init_sw; ++ } ++ ++ adapter = g_adapter; ++ ++ adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; ++ adapter->surprise_removed = false; ++ init_waitqueue_head(&adapter->init_wait_q); ++ adapter->is_suspended = false; ++ adapter->hs_activated = false; ++ init_waitqueue_head(&adapter->hs_activate_wait_q); ++ adapter->cmd_wait_q_required = false; ++ init_waitqueue_head(&adapter->cmd_wait_q.wait); ++ adapter->cmd_wait_q.condition = false; ++ adapter->cmd_wait_q.status = 0; ++ ++ adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE"); ++ if (!adapter->workqueue) ++ goto err_kmalloc; ++ ++ INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); ++ ++ /* Register the device. Fill up the private data structure with relevant ++ information from the card and request for the required IRQ. */ ++ if (adapter->if_ops.register_dev(adapter)) { ++ pr_err("%s: failed to register mwifiex device\n", __func__); ++ goto err_registerdev; ++ } ++ ++ if (mwifiex_init_hw_fw(adapter)) { ++ pr_err("%s: firmware init failed\n", __func__); ++ goto err_init_fw; ++ } ++ ++ /* Add interfaces */ ++ for (i = 0; i < adapter->drv_mode->intf_num; i++) { ++ if (!mwifiex_add_interface(adapter, i, ++ adapter->drv_mode->bss_attr[i].bss_type)) { ++ goto err_add_intf; ++ } ++ } ++ ++ up(sem); ++ ++ return 0; ++ ++err_add_intf: ++ for (i = 0; i < adapter->priv_num; i++) ++ mwifiex_remove_interface(adapter, i); ++err_init_fw: ++ pr_debug("info: %s: unregister device\n", __func__); ++ adapter->if_ops.unregister_dev(adapter); ++err_registerdev: ++ adapter->surprise_removed = true; ++ mwifiex_terminate_workqueue(adapter); ++err_kmalloc: ++ if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || ++ (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { ++ pr_debug("info: %s: shutdown mwifiex\n", __func__); ++ adapter->init_wait_q_woken = false; ++ ++ if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS) ++ wait_event_interruptible(adapter->init_wait_q, ++ adapter->init_wait_q_woken); ++ } ++ ++ mwifiex_free_adapter(adapter); ++ ++err_init_sw: ++ up(sem); ++ ++exit_sem_err: ++ return -1; ++} ++EXPORT_SYMBOL_GPL(mwifiex_add_card); ++ ++/* ++ * This function removes the card. ++ * ++ * This function follows the following major steps to remove the device - ++ * - Stop data traffic ++ * - Shutdown firmware ++ * - Remove the logical interfaces ++ * - Terminate the work queue ++ * - Unregister the device ++ * - Free the adapter structure ++ */ ++int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) ++{ ++ struct mwifiex_private *priv = NULL; ++ int i; ++ ++ if (down_interruptible(sem)) ++ goto exit_sem_err; ++ ++ if (!adapter) ++ goto exit_remove; ++ ++ adapter->surprise_removed = true; ++ ++ /* Stop data */ ++ for (i = 0; i < adapter->priv_num; i++) { ++ priv = adapter->priv[i]; ++ if (priv) { ++ if (!netif_queue_stopped(priv->netdev)) ++ netif_stop_queue(priv->netdev); ++ if (netif_carrier_ok(priv->netdev)) ++ netif_carrier_off(priv->netdev); ++ } ++ } ++ ++ dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n"); ++ adapter->init_wait_q_woken = false; ++ ++ if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS) ++ wait_event_interruptible(adapter->init_wait_q, ++ adapter->init_wait_q_woken); ++ dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n"); ++ if (atomic_read(&adapter->rx_pending) || ++ atomic_read(&adapter->tx_pending) || ++ atomic_read(&adapter->cmd_pending)) { ++ dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, " ++ "cmd_pending=%d\n", ++ atomic_read(&adapter->rx_pending), ++ atomic_read(&adapter->tx_pending), ++ atomic_read(&adapter->cmd_pending)); ++ } ++ ++ /* Remove interface */ ++ for (i = 0; i < adapter->priv_num; i++) ++ mwifiex_remove_interface(adapter, i); ++ ++ mwifiex_terminate_workqueue(adapter); ++ ++ /* Unregister device */ ++ dev_dbg(adapter->dev, "info: unregister device\n"); ++ adapter->if_ops.unregister_dev(adapter); ++ /* Free adapter structure */ ++ dev_dbg(adapter->dev, "info: free adapter\n"); ++ mwifiex_free_adapter(adapter); ++ ++exit_remove: ++ up(sem); ++exit_sem_err: ++ return 0; ++} ++EXPORT_SYMBOL_GPL(mwifiex_remove_card); ++ ++/* ++ * This function initializes the module. ++ * ++ * The debug FS is also initialized if configured. ++ */ ++static int ++mwifiex_init_module(void) ++{ ++#ifdef CONFIG_DEBUG_FS ++ mwifiex_debugfs_init(); ++#endif ++ return 0; ++} ++ ++/* ++ * This function cleans up the module. ++ * ++ * The debug FS is removed if available. ++ */ ++static void ++mwifiex_cleanup_module(void) ++{ ++#ifdef CONFIG_DEBUG_FS ++ mwifiex_debugfs_remove(); ++#endif ++} ++ ++module_init(mwifiex_init_module); ++module_exit(mwifiex_cleanup_module); ++ ++MODULE_AUTHOR("Marvell International Ltd."); ++MODULE_DESCRIPTION("Marvell WiFi-Ex Driver version " VERSION); ++MODULE_VERSION(VERSION); ++MODULE_LICENSE("GPL v2"); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/main.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/main.h +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/main.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/main.h 2011-05-05 23:29:45.466441635 +0200 +@@ -0,0 +1,1008 @@ ++/* ++ * Marvell Wireless LAN device driver: major data structures and prototypes ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#ifndef _MWIFIEX_MAIN_H_ ++#define _MWIFIEX_MAIN_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++ ++extern const char driver_version[]; ++extern struct mwifiex_adapter *g_adapter; ++ ++enum { ++ MWIFIEX_ASYNC_CMD, ++ MWIFIEX_SYNC_CMD ++}; ++ ++#define DRV_MODE_STA 0x1 ++ ++#define SD8787_W0 0x30 ++#define SD8787_W1 0x31 ++#define SD8787_A0 0x40 ++#define SD8787_A1 0x41 ++ ++#define DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin" ++#define SD8787_W1_FW_NAME "mrvl/sd8787_uapsta_w1.bin" ++#define SD8787_AX_FW_NAME "mrvl/sd8787_uapsta.bin" ++ ++struct mwifiex_drv_mode { ++ u16 drv_mode; ++ u16 intf_num; ++ struct mwifiex_bss_attr *bss_attr; ++}; ++ ++ ++#define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) ++ ++#define MWIFIEX_TIMER_10S 10000 ++#define MWIFIEX_TIMER_1S 1000 ++ ++#define MAX_TX_PENDING 60 ++ ++#define MWIFIEX_UPLD_SIZE (2312) ++ ++#define MAX_EVENT_SIZE 1024 ++ ++#define ARP_FILTER_MAX_BUF_SIZE 68 ++ ++#define MWIFIEX_KEY_BUFFER_SIZE 16 ++#define MWIFIEX_DEFAULT_LISTEN_INTERVAL 10 ++#define MWIFIEX_MAX_REGION_CODE 7 ++ ++#define DEFAULT_BCN_AVG_FACTOR 8 ++#define DEFAULT_DATA_AVG_FACTOR 8 ++ ++#define FIRST_VALID_CHANNEL 0xff ++#define DEFAULT_AD_HOC_CHANNEL 6 ++#define DEFAULT_AD_HOC_CHANNEL_A 36 ++ ++#define DEFAULT_BCN_MISS_TIMEOUT 5 ++ ++#define MAX_SCAN_BEACON_BUFFER 8000 ++ ++#define SCAN_BEACON_ENTRY_PAD 6 ++ ++#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 200 ++#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 200 ++#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 110 ++ ++#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI))) ++ ++#define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S) ++ ++#define RSN_GTK_OUI_OFFSET 2 ++ ++#define MWIFIEX_OUI_NOT_PRESENT 0 ++#define MWIFIEX_OUI_PRESENT 1 ++ ++#define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \ ++ adapter->event_received || \ ++ adapter->data_received) ++ ++#define MWIFIEX_TYPE_CMD 1 ++#define MWIFIEX_TYPE_DATA 0 ++#define MWIFIEX_TYPE_EVENT 3 ++ ++#define DBG_CMD_NUM 5 ++ ++#define MAX_BITMAP_RATES_SIZE 10 ++ ++#define MAX_CHANNEL_BAND_BG 14 ++ ++#define MAX_FREQUENCY_BAND_BG 2484 ++ ++struct mwifiex_dbg { ++ u32 num_cmd_host_to_card_failure; ++ u32 num_cmd_sleep_cfm_host_to_card_failure; ++ u32 num_tx_host_to_card_failure; ++ u32 num_event_deauth; ++ u32 num_event_disassoc; ++ u32 num_event_link_lost; ++ u32 num_cmd_deauth; ++ u32 num_cmd_assoc_success; ++ u32 num_cmd_assoc_failure; ++ u32 num_tx_timeout; ++ u32 num_cmd_timeout; ++ u16 timeout_cmd_id; ++ u16 timeout_cmd_act; ++ u16 last_cmd_id[DBG_CMD_NUM]; ++ u16 last_cmd_act[DBG_CMD_NUM]; ++ u16 last_cmd_index; ++ u16 last_cmd_resp_id[DBG_CMD_NUM]; ++ u16 last_cmd_resp_index; ++ u16 last_event[DBG_CMD_NUM]; ++ u16 last_event_index; ++}; ++ ++enum MWIFIEX_HARDWARE_STATUS { ++ MWIFIEX_HW_STATUS_READY, ++ MWIFIEX_HW_STATUS_INITIALIZING, ++ MWIFIEX_HW_STATUS_FW_READY, ++ MWIFIEX_HW_STATUS_INIT_DONE, ++ MWIFIEX_HW_STATUS_RESET, ++ MWIFIEX_HW_STATUS_CLOSING, ++ MWIFIEX_HW_STATUS_NOT_READY ++}; ++ ++enum MWIFIEX_802_11_POWER_MODE { ++ MWIFIEX_802_11_POWER_MODE_CAM, ++ MWIFIEX_802_11_POWER_MODE_PSP ++}; ++ ++struct mwifiex_tx_param { ++ u32 next_pkt_len; ++}; ++ ++enum MWIFIEX_PS_STATE { ++ PS_STATE_AWAKE, ++ PS_STATE_PRE_SLEEP, ++ PS_STATE_SLEEP_CFM, ++ PS_STATE_SLEEP ++}; ++ ++struct mwifiex_add_ba_param { ++ u32 tx_win_size; ++ u32 rx_win_size; ++ u32 timeout; ++}; ++ ++struct mwifiex_tx_aggr { ++ u8 ampdu_user; ++ u8 ampdu_ap; ++ u8 amsdu; ++}; ++ ++struct mwifiex_ra_list_tbl { ++ struct list_head list; ++ struct sk_buff_head skb_head; ++ u8 ra[ETH_ALEN]; ++ u32 total_pkts_size; ++ u32 is_11n_enabled; ++}; ++ ++struct mwifiex_tid_tbl { ++ struct list_head ra_list; ++ /* spin lock for tid table */ ++ spinlock_t tid_tbl_lock; ++ struct mwifiex_ra_list_tbl *ra_list_curr; ++}; ++ ++#define WMM_HIGHEST_PRIORITY 7 ++#define HIGH_PRIO_TID 7 ++#define LOW_PRIO_TID 0 ++ ++struct mwifiex_wmm_desc { ++ struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID]; ++ u32 packets_out[MAX_NUM_TID]; ++ /* spin lock to protect ra_list */ ++ spinlock_t ra_list_spinlock; ++ struct mwifiex_wmm_ac_status ac_status[IEEE80211_MAX_QUEUES]; ++ enum mwifiex_wmm_ac_e ac_down_graded_vals[IEEE80211_MAX_QUEUES]; ++ u32 drv_pkt_delay_max; ++ u8 queue_priority[IEEE80211_MAX_QUEUES]; ++ u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */ ++ ++}; ++ ++struct mwifiex_802_11_security { ++ u8 wpa_enabled; ++ u8 wpa2_enabled; ++ u8 wapi_enabled; ++ u8 wapi_key_on; ++ enum MWIFIEX_802_11_WEP_STATUS wep_status; ++ u32 authentication_mode; ++ u32 encryption_mode; ++}; ++ ++struct ieee_types_header { ++ u8 element_id; ++ u8 len; ++} __packed; ++ ++struct ieee_obss_scan_param { ++ u16 obss_scan_passive_dwell; ++ u16 obss_scan_active_dwell; ++ u16 bss_chan_width_trigger_scan_int; ++ u16 obss_scan_passive_total; ++ u16 obss_scan_active_total; ++ u16 bss_width_chan_trans_delay; ++ u16 obss_scan_active_threshold; ++} __packed; ++ ++struct ieee_types_obss_scan_param { ++ struct ieee_types_header ieee_hdr; ++ struct ieee_obss_scan_param obss_scan; ++} __packed; ++ ++#define MWIFIEX_SUPPORTED_RATES 14 ++ ++#define MWIFIEX_SUPPORTED_RATES_EXT 32 ++ ++#define IEEE_MAX_IE_SIZE 256 ++ ++struct ieee_types_vendor_specific { ++ struct ieee_types_vendor_header vend_hdr; ++ u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)]; ++} __packed; ++ ++struct ieee_types_generic { ++ struct ieee_types_header ieee_hdr; ++ u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header)]; ++} __packed; ++ ++struct mwifiex_bssdescriptor { ++ u8 mac_address[ETH_ALEN]; ++ struct mwifiex_802_11_ssid ssid; ++ u32 privacy; ++ s32 rssi; ++ u32 channel; ++ u32 freq; ++ u16 beacon_period; ++ u8 erp_flags; ++ u32 bss_mode; ++ u8 supported_rates[MWIFIEX_SUPPORTED_RATES]; ++ u8 data_rates[MWIFIEX_SUPPORTED_RATES]; ++ /* Network band. ++ * BAND_B(0x01): 'b' band ++ * BAND_G(0x02): 'g' band ++ * BAND_A(0X04): 'a' band ++ */ ++ u16 bss_band; ++ u64 network_tsf; ++ u8 time_stamp[8]; ++ union ieee_types_phy_param_set phy_param_set; ++ union ieee_types_ss_param_set ss_param_set; ++ u16 cap_info_bitmap; ++ struct ieee_types_wmm_parameter wmm_ie; ++ u8 disable_11n; ++ struct ieee80211_ht_cap *bcn_ht_cap; ++ u16 ht_cap_offset; ++ struct ieee80211_ht_info *bcn_ht_info; ++ u16 ht_info_offset; ++ u8 *bcn_bss_co_2040; ++ u16 bss_co_2040_offset; ++ u8 *bcn_ext_cap; ++ u16 ext_cap_offset; ++ struct ieee_types_obss_scan_param *bcn_obss_scan; ++ u16 overlap_bss_offset; ++ struct ieee_types_vendor_specific *bcn_wpa_ie; ++ u16 wpa_offset; ++ struct ieee_types_generic *bcn_rsn_ie; ++ u16 rsn_offset; ++ struct ieee_types_generic *bcn_wapi_ie; ++ u16 wapi_offset; ++ u8 *beacon_buf; ++ u32 beacon_buf_size; ++ u32 beacon_buf_size_max; ++ ++}; ++ ++struct mwifiex_current_bss_params { ++ struct mwifiex_bssdescriptor bss_descriptor; ++ u8 wmm_enabled; ++ u8 wmm_uapsd_enabled; ++ u8 band; ++ u32 num_of_rates; ++ u8 data_rates[MWIFIEX_SUPPORTED_RATES]; ++}; ++ ++struct mwifiex_sleep_params { ++ u16 sp_error; ++ u16 sp_offset; ++ u16 sp_stable_time; ++ u8 sp_cal_control; ++ u8 sp_ext_sleep_clk; ++ u16 sp_reserved; ++}; ++ ++struct mwifiex_sleep_period { ++ u16 period; ++ u16 reserved; ++}; ++ ++struct mwifiex_wep_key { ++ u32 length; ++ u32 key_index; ++ u32 key_length; ++ u8 key_material[MWIFIEX_KEY_BUFFER_SIZE]; ++}; ++ ++#define MAX_REGION_CHANNEL_NUM 2 ++ ++struct mwifiex_chan_freq_power { ++ u16 channel; ++ u32 freq; ++ u16 max_tx_power; ++ u8 unsupported; ++}; ++ ++enum state_11d_t { ++ DISABLE_11D = 0, ++ ENABLE_11D = 1, ++}; ++ ++#define MWIFIEX_MAX_TRIPLET_802_11D 83 ++ ++struct mwifiex_802_11d_domain_reg { ++ u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; ++ u8 no_of_triplet; ++ struct ieee80211_country_ie_triplet ++ triplet[MWIFIEX_MAX_TRIPLET_802_11D]; ++}; ++ ++struct mwifiex_vendor_spec_cfg_ie { ++ u16 mask; ++ u16 flag; ++ u8 ie[MWIFIEX_MAX_VSIE_LEN]; ++}; ++ ++struct wps { ++ u8 session_enable; ++}; ++ ++struct mwifiex_adapter; ++struct mwifiex_private; ++ ++struct mwifiex_private { ++ struct mwifiex_adapter *adapter; ++ u8 bss_index; ++ u8 bss_type; ++ u8 bss_role; ++ u8 bss_priority; ++ u8 bss_num; ++ u8 frame_type; ++ u8 curr_addr[ETH_ALEN]; ++ u8 media_connected; ++ u32 num_tx_timeout; ++ struct net_device *netdev; ++ struct net_device_stats stats; ++ u16 curr_pkt_filter; ++ u32 bss_mode; ++ u32 pkt_tx_ctrl; ++ u16 tx_power_level; ++ u8 max_tx_power_level; ++ u8 min_tx_power_level; ++ u8 tx_rate; ++ u8 tx_htinfo; ++ u8 rxpd_htinfo; ++ u8 rxpd_rate; ++ u16 rate_bitmap; ++ u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; ++ u32 data_rate; ++ u8 is_data_rate_auto; ++ u16 bcn_avg_factor; ++ u16 data_avg_factor; ++ s16 data_rssi_last; ++ s16 data_nf_last; ++ s16 data_rssi_avg; ++ s16 data_nf_avg; ++ s16 bcn_rssi_last; ++ s16 bcn_nf_last; ++ s16 bcn_rssi_avg; ++ s16 bcn_nf_avg; ++ struct mwifiex_bssdescriptor *attempted_bss_desc; ++ struct mwifiex_802_11_ssid prev_ssid; ++ u8 prev_bssid[ETH_ALEN]; ++ struct mwifiex_current_bss_params curr_bss_params; ++ u16 beacon_period; ++ u16 listen_interval; ++ u16 atim_window; ++ u8 adhoc_channel; ++ u8 adhoc_is_link_sensed; ++ u8 adhoc_state; ++ struct mwifiex_802_11_security sec_info; ++ struct mwifiex_wep_key wep_key[NUM_WEP_KEYS]; ++ u16 wep_key_curr_index; ++ u8 wpa_ie[256]; ++ u8 wpa_ie_len; ++ u8 wpa_is_gtk_set; ++ struct host_cmd_ds_802_11_key_material aes_key; ++ u8 wapi_ie[256]; ++ u8 wapi_ie_len; ++ u8 wmm_required; ++ u8 wmm_enabled; ++ u8 wmm_qosinfo; ++ struct mwifiex_wmm_desc wmm; ++ struct list_head tx_ba_stream_tbl_ptr; ++ /* spin lock for tx_ba_stream_tbl_ptr queue */ ++ spinlock_t tx_ba_stream_tbl_lock; ++ struct mwifiex_tx_aggr aggr_prio_tbl[MAX_NUM_TID]; ++ struct mwifiex_add_ba_param add_ba_param; ++ u16 rx_seq[MAX_NUM_TID]; ++ struct list_head rx_reorder_tbl_ptr; ++ /* spin lock for rx_reorder_tbl_ptr queue */ ++ spinlock_t rx_reorder_tbl_lock; ++ /* spin lock for Rx packets */ ++ spinlock_t rx_pkt_lock; ++ ++#define MWIFIEX_ASSOC_RSP_BUF_SIZE 500 ++ u8 assoc_rsp_buf[MWIFIEX_ASSOC_RSP_BUF_SIZE]; ++ u32 assoc_rsp_size; ++ ++#define MWIFIEX_GENIE_BUF_SIZE 256 ++ u8 gen_ie_buf[MWIFIEX_GENIE_BUF_SIZE]; ++ u8 gen_ie_buf_len; ++ ++ struct mwifiex_vendor_spec_cfg_ie vs_ie[MWIFIEX_MAX_VSIE_NUM]; ++ ++#define MWIFIEX_ASSOC_TLV_BUF_SIZE 256 ++ u8 assoc_tlv_buf[MWIFIEX_ASSOC_TLV_BUF_SIZE]; ++ u8 assoc_tlv_buf_len; ++ ++ u8 *curr_bcn_buf; ++ u32 curr_bcn_size; ++ /* spin lock for beacon buffer */ ++ spinlock_t curr_bcn_buf_lock; ++ struct wireless_dev *wdev; ++ struct mwifiex_chan_freq_power cfp; ++ char version_str[128]; ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *dfs_dev_dir; ++#endif ++ u8 nick_name[16]; ++ struct iw_statistics w_stats; ++ u16 current_key_index; ++ struct semaphore async_sem; ++ u8 scan_pending_on_block; ++ u8 report_scan_result; ++ struct cfg80211_scan_request *scan_request; ++ int scan_result_status; ++ bool assoc_request; ++ u16 assoc_result; ++ bool ibss_join_request; ++ u16 ibss_join_result; ++ bool disconnect; ++ u8 cfg_bssid[6]; ++ struct workqueue_struct *workqueue; ++ struct work_struct cfg_workqueue; ++ u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; ++ struct wps wps; ++ u8 scan_block; ++}; ++ ++enum mwifiex_ba_status { ++ BA_STREAM_NOT_SETUP = 0, ++ BA_STREAM_SETUP_INPROGRESS, ++ BA_STREAM_SETUP_COMPLETE ++}; ++ ++struct mwifiex_tx_ba_stream_tbl { ++ struct list_head list; ++ int tid; ++ u8 ra[ETH_ALEN]; ++ enum mwifiex_ba_status ba_status; ++}; ++ ++struct mwifiex_rx_reorder_tbl; ++ ++struct reorder_tmr_cnxt { ++ struct timer_list timer; ++ struct mwifiex_rx_reorder_tbl *ptr; ++ struct mwifiex_private *priv; ++}; ++ ++struct mwifiex_rx_reorder_tbl { ++ struct list_head list; ++ int tid; ++ u8 ta[ETH_ALEN]; ++ int start_win; ++ int win_size; ++ void **rx_reorder_ptr; ++ struct reorder_tmr_cnxt timer_context; ++}; ++ ++struct mwifiex_bss_prio_node { ++ struct list_head list; ++ struct mwifiex_private *priv; ++}; ++ ++struct mwifiex_bss_prio_tbl { ++ struct list_head bss_prio_head; ++ /* spin lock for bss priority */ ++ spinlock_t bss_prio_lock; ++ struct mwifiex_bss_prio_node *bss_prio_cur; ++}; ++ ++struct cmd_ctrl_node { ++ struct list_head list; ++ struct mwifiex_private *priv; ++ u32 cmd_oid; ++ u32 cmd_flag; ++ struct sk_buff *cmd_skb; ++ struct sk_buff *resp_skb; ++ void *data_buf; ++ u32 wait_q_enabled; ++ struct sk_buff *skb; ++}; ++ ++struct mwifiex_if_ops { ++ int (*init_if) (struct mwifiex_adapter *); ++ void (*cleanup_if) (struct mwifiex_adapter *); ++ int (*check_fw_status) (struct mwifiex_adapter *, u32, int *); ++ int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); ++ int (*register_dev) (struct mwifiex_adapter *); ++ void (*unregister_dev) (struct mwifiex_adapter *); ++ int (*enable_int) (struct mwifiex_adapter *); ++ int (*process_int_status) (struct mwifiex_adapter *); ++ int (*host_to_card) (struct mwifiex_adapter *, u8, ++ u8 *payload, u32 pkt_len, ++ struct mwifiex_tx_param *); ++ int (*wakeup) (struct mwifiex_adapter *); ++ int (*wakeup_complete) (struct mwifiex_adapter *); ++ ++ void (*update_mp_end_port) (struct mwifiex_adapter *, u16); ++ void (*cleanup_mpa_buf) (struct mwifiex_adapter *); ++}; ++ ++struct mwifiex_adapter { ++ struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM]; ++ u8 priv_num; ++ struct mwifiex_drv_mode *drv_mode; ++ const struct firmware *firmware; ++ struct device *dev; ++ bool surprise_removed; ++ u32 fw_release_number; ++ u32 revision_id; ++ u16 init_wait_q_woken; ++ wait_queue_head_t init_wait_q; ++ void *card; ++ struct mwifiex_if_ops if_ops; ++ atomic_t rx_pending; ++ atomic_t tx_pending; ++ atomic_t cmd_pending; ++ struct workqueue_struct *workqueue; ++ struct work_struct main_work; ++ struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; ++ /* spin lock for init/shutdown */ ++ spinlock_t mwifiex_lock; ++ /* spin lock for main process */ ++ spinlock_t main_proc_lock; ++ u32 mwifiex_processing; ++ u16 max_tx_buf_size; ++ u16 tx_buf_size; ++ u16 curr_tx_buf_size; ++ u32 ioport; ++ enum MWIFIEX_HARDWARE_STATUS hw_status; ++ u16 number_of_antenna; ++ u32 fw_cap_info; ++ /* spin lock for interrupt handling */ ++ spinlock_t int_lock; ++ u8 int_status; ++ u32 event_cause; ++ struct sk_buff *event_skb; ++ u8 upld_buf[MWIFIEX_UPLD_SIZE]; ++ u8 data_sent; ++ u8 cmd_sent; ++ u8 cmd_resp_received; ++ u8 event_received; ++ u8 data_received; ++ u16 seq_num; ++ struct cmd_ctrl_node *cmd_pool; ++ struct cmd_ctrl_node *curr_cmd; ++ /* spin lock for command */ ++ spinlock_t mwifiex_cmd_lock; ++ u32 num_cmd_timeout; ++ u16 last_init_cmd; ++ struct timer_list cmd_timer; ++ struct list_head cmd_free_q; ++ /* spin lock for cmd_free_q */ ++ spinlock_t cmd_free_q_lock; ++ struct list_head cmd_pending_q; ++ /* spin lock for cmd_pending_q */ ++ spinlock_t cmd_pending_q_lock; ++ struct list_head scan_pending_q; ++ /* spin lock for scan_pending_q */ ++ spinlock_t scan_pending_q_lock; ++ u32 scan_processing; ++ u16 region_code; ++ struct mwifiex_802_11d_domain_reg domain_reg; ++ struct mwifiex_bssdescriptor *scan_table; ++ u32 num_in_scan_table; ++ u16 scan_probes; ++ u32 scan_mode; ++ u16 specific_scan_time; ++ u16 active_scan_time; ++ u16 passive_scan_time; ++ u8 bcn_buf[MAX_SCAN_BEACON_BUFFER]; ++ u8 *bcn_buf_end; ++ u8 fw_bands; ++ u8 adhoc_start_band; ++ u8 config_bands; ++ struct mwifiex_chan_scan_param_set *scan_channels; ++ u8 tx_lock_flag; ++ struct mwifiex_sleep_params sleep_params; ++ struct mwifiex_sleep_period sleep_period; ++ u16 ps_mode; ++ u32 ps_state; ++ u8 need_to_wakeup; ++ u16 multiple_dtim; ++ u16 local_listen_interval; ++ u16 null_pkt_interval; ++ struct sk_buff *sleep_cfm; ++ u16 bcn_miss_time_out; ++ u16 adhoc_awake_period; ++ u8 is_deep_sleep; ++ u8 delay_null_pkt; ++ u16 delay_to_ps; ++ u16 enhanced_ps_mode; ++ u8 pm_wakeup_card_req; ++ u16 gen_null_pkt; ++ u16 pps_uapsd_mode; ++ u32 pm_wakeup_fw_try; ++ u8 is_hs_configured; ++ struct mwifiex_hs_config_param hs_cfg; ++ u8 hs_activated; ++ u16 hs_activate_wait_q_woken; ++ wait_queue_head_t hs_activate_wait_q; ++ bool is_suspended; ++ u8 event_body[MAX_EVENT_SIZE]; ++ u32 hw_dot_11n_dev_cap; ++ u8 hw_dev_mcs_support; ++ u8 adhoc_11n_enabled; ++ u8 chan_offset; ++ struct mwifiex_dbg dbg; ++ u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE]; ++ u32 arp_filter_size; ++ u16 cmd_wait_q_required; ++ struct mwifiex_wait_queue cmd_wait_q; ++}; ++ ++int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); ++void mwifiex_free_lock_list(struct mwifiex_adapter *adapter); ++ ++int mwifiex_init_fw(struct mwifiex_adapter *adapter); ++ ++int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter); ++ ++int mwifiex_shutdown_drv(struct mwifiex_adapter *adapter); ++ ++int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter); ++ ++int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *); ++ ++int mwifiex_recv_complete(struct mwifiex_adapter *, ++ struct sk_buff *skb, ++ int status); ++ ++int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb); ++ ++int mwifiex_process_event(struct mwifiex_adapter *adapter); ++ ++int mwifiex_complete_cmd(struct mwifiex_adapter *adapter); ++ ++int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, ++ u16 cmd_action, u32 cmd_oid, void *data_buf); ++ ++int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, ++ u16 cmd_action, u32 cmd_oid, void *data_buf); ++ ++void mwifiex_cmd_timeout_func(unsigned long function_context); ++ ++int mwifiex_get_debug_info(struct mwifiex_private *, ++ struct mwifiex_debug_info *); ++ ++int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter); ++int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter); ++void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter); ++void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter); ++ ++void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, ++ struct cmd_ctrl_node *cmd_node); ++ ++void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, ++ struct cmd_ctrl_node *cmd_node, ++ u32 addtail); ++ ++int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter); ++int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter); ++int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb); ++int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, ++ struct mwifiex_tx_param *tx_param); ++int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags); ++int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb, int status); ++int mwifiex_recv_packet_complete(struct mwifiex_adapter *, ++ struct sk_buff *skb, int status); ++void mwifiex_clean_txrx(struct mwifiex_private *priv); ++u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv); ++void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter); ++void mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *, u8 *, ++ u32); ++int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ u16 cmd_action, uint16_t ps_bitmap, ++ void *data_buf); ++int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp, ++ void *data_buf); ++void mwifiex_process_hs_config(struct mwifiex_adapter *adapter); ++void mwifiex_hs_activated_event(struct mwifiex_private *priv, ++ u8 activated); ++int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp); ++int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb); ++int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no, ++ u16 cmd_action, u32 cmd_oid, ++ void *data_buf, void *cmd_buf); ++int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no, ++ void *cmd_buf); ++int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, ++ struct sk_buff *skb); ++int mwifiex_process_sta_event(struct mwifiex_private *); ++void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb); ++int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta); ++int mwifiex_scan_networks(struct mwifiex_private *priv, ++ const struct mwifiex_user_scan_cfg *user_scan_in); ++int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, ++ void *data_buf); ++void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, ++ struct cmd_ctrl_node *cmd_node); ++int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp); ++s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv, ++ struct mwifiex_802_11_ssid *ssid, u8 *bssid, ++ u32 mode); ++s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, ++ u32 mode); ++int mwifiex_find_best_network(struct mwifiex_private *priv, ++ struct mwifiex_ssid_bssid *req_ssid_bssid); ++s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, ++ struct mwifiex_802_11_ssid *ssid2); ++int mwifiex_associate(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc); ++int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, ++ struct host_cmd_ds_command ++ *cmd, void *data_buf); ++int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp); ++void mwifiex_reset_connect_state(struct mwifiex_private *priv); ++void mwifiex_2040_coex_event(struct mwifiex_private *priv); ++u8 mwifiex_band_to_radio_type(u8 band); ++int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac); ++int mwifiex_adhoc_start(struct mwifiex_private *priv, ++ struct mwifiex_802_11_ssid *adhoc_ssid); ++int mwifiex_adhoc_join(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc); ++int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ void *data_buf); ++int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ void *data_buf); ++int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp); ++int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd); ++struct mwifiex_chan_freq_power * ++ mwifiex_get_cfp_by_band_and_channel_from_cfg80211( ++ struct mwifiex_private *priv, ++ u8 band, u16 channel); ++struct mwifiex_chan_freq_power *mwifiex_get_cfp_by_band_and_freq_from_cfg80211( ++ struct mwifiex_private *priv, ++ u8 band, u32 freq); ++u32 mwifiex_index_to_data_rate(u8 index, u8 ht_info); ++u32 mwifiex_find_freq_from_band_chan(u8, u8); ++int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask, ++ u8 **buffer); ++u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, ++ u8 *rates); ++u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates); ++u8 mwifiex_data_rate_to_index(u32 rate); ++u8 mwifiex_is_rate_auto(struct mwifiex_private *priv); ++int mwifiex_get_rate_index(u16 *rateBitmap, int size); ++extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE]; ++void mwifiex_save_curr_bcn(struct mwifiex_private *priv); ++void mwifiex_free_curr_bcn(struct mwifiex_private *priv); ++int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd); ++int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp); ++int is_command_pending(struct mwifiex_adapter *adapter); ++ ++/* ++ * This function checks if the queuing is RA based or not. ++ */ ++static inline u8 ++mwifiex_queuing_ra_based(struct mwifiex_private *priv) ++{ ++ /* ++ * Currently we assume if we are in Infra, then DA=RA. This might not be ++ * true in the future ++ */ ++ if ((priv->bss_mode == NL80211_IFTYPE_STATION) && ++ (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)) ++ return false; ++ ++ return true; ++} ++ ++/* ++ * This function copies rates. ++ */ ++static inline u32 ++mwifiex_copy_rates(u8 *dest, u32 pos, u8 *src, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len && src[i]; i++, pos++) { ++ if (pos >= MWIFIEX_SUPPORTED_RATES) ++ break; ++ dest[pos] = src[i]; ++ } ++ ++ return pos; ++} ++ ++/* ++ * This function returns the correct private structure pointer based ++ * upon the BSS type and BSS number. ++ */ ++static inline struct mwifiex_private * ++mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter, ++ u8 bss_num, u8 bss_type) ++{ ++ int i; ++ ++ for (i = 0; i < adapter->priv_num; i++) { ++ if (adapter->priv[i]) { ++ if ((adapter->priv[i]->bss_num == bss_num) ++ && (adapter->priv[i]->bss_type == bss_type)) ++ break; ++ } ++ } ++ return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); ++} ++ ++/* ++ * This function returns the first available private structure pointer ++ * based upon the BSS role. ++ */ ++static inline struct mwifiex_private * ++mwifiex_get_priv(struct mwifiex_adapter *adapter, ++ enum mwifiex_bss_role bss_role) ++{ ++ int i; ++ ++ for (i = 0; i < adapter->priv_num; i++) { ++ if (adapter->priv[i]) { ++ if (bss_role == MWIFIEX_BSS_ROLE_ANY || ++ GET_BSS_ROLE(adapter->priv[i]) == bss_role) ++ break; ++ } ++ } ++ ++ return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); ++} ++ ++/* ++ * This function returns the driver private structure of a network device. ++ */ ++static inline struct mwifiex_private * ++mwifiex_netdev_get_priv(struct net_device *dev) ++{ ++ return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev)); ++} ++ ++struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter ++ *adapter, u8 bss_index); ++int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, ++ u32 func_init_shutdown); ++int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *); ++int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *); ++ ++void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version, ++ int maxlen); ++int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, ++ struct mwifiex_multicast_list *mcast_list); ++int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, ++ struct net_device *dev); ++int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); ++int mwifiex_bss_start(struct mwifiex_private *priv, ++ struct mwifiex_ssid_bssid *ssid_bssid); ++int mwifiex_set_hs_params(struct mwifiex_private *priv, ++ u16 action, int cmd_type, ++ struct mwifiex_ds_hs_cfg *hscfg); ++int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); ++int mwifiex_enable_hs(struct mwifiex_adapter *adapter); ++int mwifiex_get_signal_info(struct mwifiex_private *priv, ++ struct mwifiex_ds_get_signal *signal); ++int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, ++ struct mwifiex_rate_cfg *rate); ++int mwifiex_find_best_bss(struct mwifiex_private *priv, ++ struct mwifiex_ssid_bssid *ssid_bssid); ++int mwifiex_request_scan(struct mwifiex_private *priv, ++ struct mwifiex_802_11_ssid *req_ssid); ++int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, ++ struct mwifiex_user_scan_cfg *scan_req); ++int mwifiex_change_adhoc_chan(struct mwifiex_private *priv, int channel); ++int mwifiex_set_radio(struct mwifiex_private *priv, u8 option); ++ ++int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel); ++ ++int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, ++ int key_len, u8 key_index, int disable); ++ ++int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len); ++ ++int mwifiex_get_ver_ext(struct mwifiex_private *priv); ++ ++int mwifiex_get_stats_info(struct mwifiex_private *priv, ++ struct mwifiex_ds_get_stats *log); ++ ++int mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, ++ u32 reg_offset, u32 reg_value); ++ ++int mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, ++ u32 reg_offset, u32 *value); ++ ++int mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, ++ u8 *value); ++ ++int mwifiex_set_11n_httx_cfg(struct mwifiex_private *priv, int data); ++ ++int mwifiex_get_11n_httx_cfg(struct mwifiex_private *priv, int *data); ++ ++int mwifiex_set_tx_rate_cfg(struct mwifiex_private *priv, int tx_rate_index); ++ ++int mwifiex_get_tx_rate_cfg(struct mwifiex_private *priv, int *tx_rate_index); ++ ++int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode); ++ ++int mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, ++ char *version, int max_len); ++ ++int mwifiex_set_tx_power(struct mwifiex_private *priv, ++ struct mwifiex_power_cfg *power_cfg); ++ ++int mwifiex_main_process(struct mwifiex_adapter *); ++ ++int mwifiex_bss_set_channel(struct mwifiex_private *, ++ struct mwifiex_chan_freq_power *cfp); ++int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *, ++ struct mwifiex_ssid_bssid *); ++int mwifiex_set_radio_band_cfg(struct mwifiex_private *, ++ struct mwifiex_ds_band_cfg *); ++int mwifiex_get_bss_info(struct mwifiex_private *, ++ struct mwifiex_bss_info *); ++ ++#ifdef CONFIG_DEBUG_FS ++void mwifiex_debugfs_init(void); ++void mwifiex_debugfs_remove(void); ++ ++void mwifiex_dev_debugfs_init(struct mwifiex_private *priv); ++void mwifiex_dev_debugfs_remove(struct mwifiex_private *priv); ++#endif ++#endif /* !_MWIFIEX_MAIN_H_ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/Makefile linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/Makefile +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/Makefile 2011-05-05 23:29:45.472441707 +0200 +@@ -0,0 +1,41 @@ ++# ++# Copyright (C) 2011, Marvell International Ltd. ++# ++# This software file (the "File") is distributed by Marvell International ++# Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++# (the "License"). You may use, redistribute and/or modify this File in ++# accordance with the terms and conditions of the License, a copy of which ++# is available by writing to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++# ++# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++# ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++# this warranty disclaimer. ++ ++ ++mwifiex-y += main.o ++mwifiex-y += init.o ++mwifiex-y += cfp.o ++mwifiex-y += cmdevt.o ++mwifiex-y += util.o ++mwifiex-y += txrx.o ++mwifiex-y += wmm.o ++mwifiex-y += 11n.o ++mwifiex-y += 11n_aggr.o ++mwifiex-y += 11n_rxreorder.o ++mwifiex-y += scan.o ++mwifiex-y += join.o ++mwifiex-y += sta_ioctl.o ++mwifiex-y += sta_cmd.o ++mwifiex-y += sta_cmdresp.o ++mwifiex-y += sta_event.o ++mwifiex-y += sta_tx.o ++mwifiex-y += sta_rx.o ++mwifiex-y += cfg80211.o ++mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o ++obj-$(CONFIG_MWIFIEX) += mwifiex.o ++ ++mwifiex_sdio-y += sdio.o ++obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/README linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/README +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/README 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/README 2011-05-05 23:29:45.491441937 +0200 +@@ -0,0 +1,204 @@ ++# Copyright (C) 2011, Marvell International Ltd. ++# ++# This software file (the "File") is distributed by Marvell International ++# Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++# (the "License"). You may use, redistribute and/or modify this File in ++# accordance with the terms and conditions of the License, a copy of which ++# is available by writing to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++# ++# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++# ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++# this warranty disclaimer. ++ ++ ++=============================================================================== ++ U S E R M A N U A L ++ ++1) FOR DRIVER INSTALL ++ ++ a) Copy sd8787.bin to /lib/firmware/mrvl/ directory, ++ create the directory if it doesn't exist. ++ b) Install WLAN driver, ++ insmod mwifiex.ko ++ c) Uninstall WLAN driver, ++ ifconfig mlanX down ++ rmmod mwifiex ++ ++ ++2) FOR DRIVER CONFIGURATION AND INFO ++ The configurations can be done either using the 'iw' user space ++ utility or debugfs. ++ ++ a) 'iw' utility commands ++ ++ Following are some useful iw commands:- ++ ++iw dev mlan0 scan ++ ++ This command will trigger a scan. ++ The command will then display the scan table entries ++ ++iw dev mlan0 connect -w [] [] [key 0:abcde d:1123456789a] ++ The above command can be used to connect to an AP with a particular SSID. ++ Ap's operating frequency can be specified or even the bssid. If the AP is using ++ WEP encryption, wep keys can be specified in the command. ++ Note: Every time before connecting to an AP scan command (iw dev mlan0 scan) should be used by user. ++ ++iw dev mlan0 disconnect ++ This command will be used to disconnect from an AP. ++ ++ ++iw dev mlan0 ibss join [fixed-freq] [fixed-bssid] [key 0:abcde] ++ The command will be used to join or create an ibss. Optionally, operating frequency, ++ bssid and the security related parameters can be specified while joining/creating ++ and ibss. ++ ++iw dev mlan0 ibss leave ++ The command will be used to leave an ibss network. ++ ++iw dev mlan0 link ++ The command will be used to get the connection status. The command will return parameters ++ such as SSID, operating frequency, rx/tx packets, signal strength, tx bitrate. ++ ++ Apart from the iw utility all standard configurations using the 'iwconfig' utility are also supported. ++ ++ b) Debugfs interface ++ ++ The debugfs interface can be used for configurations and for getting ++ some useful information from the driver. ++ The section below explains the configurations that can be ++ done. ++ ++ Mount debugfs to /debugfs mount point: ++ ++ mkdir /debugfs ++ mount -t debugfs debugfs /debugfs ++ ++ The information is provided in /debugfs/mwifiex/mlanX/: ++ ++iw reg set ++ The command will be used to change the regulatory domain. ++ ++iw reg get ++ The command will be used to get current regulatory domain. ++ ++info ++ This command is used to get driver info. ++ ++ Usage: ++ cat info ++ ++ driver_name = "mwifiex" ++ driver_version = ++ interface_name = "mlanX" ++ bss_mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown" ++ media_state = "Disconnected" | "Connected" ++ mac_address = <6-byte adapter MAC address> ++ multicase_count = ++ essid = ++ bssid = ++ channel = ++ region_code = ++ multicasr_address[n] = ++ num_tx_bytes = ++ num_rx_bytes = ++ num_tx_pkts = ++ num_rx_pkts = ++ num_tx_pkts_dropped = ++ num_rx_pkts_dropped = ++ num_tx_pkts_err = ++ num_rx_pkts_err = ++ carrier "on" | "off" ++ tx queue "stopped" | "started" ++ ++ The following debug info are provided in /debugfs/mwifiex/mlanX/debug: ++ ++ int_counter = ++ wmm_ac_vo = ++ wmm_ac_vi = ++ wmm_ac_be = ++ wmm_ac_bk = ++ max_tx_buf_size = ++ tx_buf_size = ++ curr_tx_buf_size = ++ ps_mode = <0/1, CAM mode/PS mode> ++ ps_state = <0/1/2/3, full power state/awake state/pre-sleep state/sleep state> ++ is_deep_sleep = <0/1, not deep sleep state/deep sleep state> ++ wakeup_dev_req = <0/1, wakeup device not required/required> ++ wakeup_tries = ++ hs_configured = <0/1, host sleep not configured/configured> ++ hs_activated = <0/1, extended host sleep not activated/activated> ++ num_tx_timeout = ++ num_cmd_timeout = ++ timeout_cmd_id = ++ timeout_cmd_act = ++ last_cmd_id = ++ last_cmd_act = ++ last_cmd_index = <0 based last command index> ++ last_cmd_resp_id = ++ last_cmd_resp_index = <0 based last command response index> ++ last_event = ++ last_event_index = <0 based last event index> ++ num_cmd_h2c_fail = ++ num_cmd_sleep_cfm_fail = ++ num_tx_h2c_fail = ++ num_evt_deauth = ++ num_evt_disassoc = ++ num_evt_link_lost = ++ num_cmd_deauth = ++ num_cmd_assoc_ok = ++ num_cmd_assoc_fail = ++ cmd_sent = <0/1, send command resources available/sending command to device> ++ data_sent = <0/1, send data resources available/sending data to device> ++ mp_rd_bitmap = ++ mp_wr_bitmap = ++ cmd_resp_received = <0/1, no cmd response to process/response received and yet to process> ++ event_received = <0/1, no event to process/event received and yet to process> ++ cmd_pending = ++ tx_pending = ++ rx_pending = ++ ++ ++3) FOR DRIVER CONFIGURATION ++ ++regrdwr ++ This command is used to read/write the adapter register. ++ ++ Usage: ++ echo " [value]" > regrdwr ++ cat regrdwr ++ ++ where the parameters are, ++ : 1:MAC/SOC, 2:BBP, 3:RF, 4:PMIC, 5:CAU ++ : offset of register ++ [value]: value to be written ++ ++ Examples: ++ echo "1 0xa060" > regrdwr : Read the MAC register ++ echo "1 0xa060 0x12" > regrdwr : Write the MAC register ++ echo "1 0xa794 0x80000000" > regrdwr ++ : Write 0x80000000 to MAC register ++rdeeprom ++ This command is used to read the EEPROM contents of the card. ++ ++ Usage: ++ echo " " > rdeeprom ++ cat rdeeprom ++ ++ where the parameters are, ++ : multiples of 4 ++ : 4-20, multiples of 4 ++ ++ Example: ++ echo "0 20" > rdeeprom : Read 20 bytes of EEPROM data from offset 0 ++ ++getlog ++ This command is used to get the statistics available in the station. ++ Usage: ++ ++ cat getlog ++ ++=============================================================================== +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/scan.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/scan.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/scan.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/scan.c 2011-05-05 23:29:45.445441381 +0200 +@@ -0,0 +1,3025 @@ ++/* ++ * Marvell Wireless LAN device driver: scan ioctl and command handling ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "11n.h" ++#include "cfg80211.h" ++ ++/* The maximum number of channels the firmware can scan per command */ ++#define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN 14 ++ ++#define MWIFIEX_CHANNELS_PER_SCAN_CMD 4 ++ ++/* Memory needed to store a max sized Channel List TLV for a firmware scan */ ++#define CHAN_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_header) \ ++ + (MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN \ ++ *sizeof(struct mwifiex_chan_scan_param_set))) ++ ++/* Memory needed to store supported rate */ ++#define RATE_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_rates_param_set) \ ++ + HOSTCMD_SUPPORTED_RATES) ++ ++/* Memory needed to store a max number/size WildCard SSID TLV for a firmware ++ scan */ ++#define WILDCARD_SSID_TLV_MAX_SIZE \ ++ (MWIFIEX_MAX_SSID_LIST_LENGTH * \ ++ (sizeof(struct mwifiex_ie_types_wildcard_ssid_params) \ ++ + IEEE80211_MAX_SSID_LEN)) ++ ++/* Maximum memory needed for a mwifiex_scan_cmd_config with all TLVs at max */ ++#define MAX_SCAN_CFG_ALLOC (sizeof(struct mwifiex_scan_cmd_config) \ ++ + sizeof(struct mwifiex_ie_types_num_probes) \ ++ + sizeof(struct mwifiex_ie_types_htcap) \ ++ + CHAN_TLV_MAX_SIZE \ ++ + RATE_TLV_MAX_SIZE \ ++ + WILDCARD_SSID_TLV_MAX_SIZE) ++ ++ ++union mwifiex_scan_cmd_config_tlv { ++ /* Scan configuration (variable length) */ ++ struct mwifiex_scan_cmd_config config; ++ /* Max allocated block */ ++ u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC]; ++}; ++ ++enum cipher_suite { ++ CIPHER_SUITE_TKIP, ++ CIPHER_SUITE_CCMP, ++ CIPHER_SUITE_MAX ++}; ++static u8 mwifiex_wpa_oui[CIPHER_SUITE_MAX][4] = { ++ { 0x00, 0x50, 0xf2, 0x02 }, /* TKIP */ ++ { 0x00, 0x50, 0xf2, 0x04 }, /* AES */ ++}; ++static u8 mwifiex_rsn_oui[CIPHER_SUITE_MAX][4] = { ++ { 0x00, 0x0f, 0xac, 0x02 }, /* TKIP */ ++ { 0x00, 0x0f, 0xac, 0x04 }, /* AES */ ++}; ++ ++/* ++ * This function parses a given IE for a given OUI. ++ * ++ * This is used to parse a WPA/RSN IE to find if it has ++ * a given oui in PTK. ++ */ ++static u8 ++mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui) ++{ ++ u8 count; ++ ++ count = iebody->ptk_cnt[0]; ++ ++ /* There could be multiple OUIs for PTK hence ++ 1) Take the length. ++ 2) Check all the OUIs for AES. ++ 3) If one of them is AES then pass success. */ ++ while (count) { ++ if (!memcmp(iebody->ptk_body, oui, sizeof(iebody->ptk_body))) ++ return MWIFIEX_OUI_PRESENT; ++ ++ --count; ++ if (count) ++ iebody = (struct ie_body *) ((u8 *) iebody + ++ sizeof(iebody->ptk_body)); ++ } ++ ++ pr_debug("info: %s: OUI is not found in PTK\n", __func__); ++ return MWIFIEX_OUI_NOT_PRESENT; ++} ++ ++/* ++ * This function checks if a given OUI is present in a RSN IE. ++ * ++ * The function first checks if a RSN IE is present or not in the ++ * BSS descriptor. It tries to locate the OUI only if such an IE is ++ * present. ++ */ ++static u8 ++mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) ++{ ++ u8 *oui = NULL; ++ struct ie_body *iebody = NULL; ++ u8 ret = MWIFIEX_OUI_NOT_PRESENT; ++ ++ if (((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)). ++ ieee_hdr.element_id == WLAN_EID_RSN))) { ++ iebody = (struct ie_body *) ++ (((u8 *) bss_desc->bcn_rsn_ie->data) + ++ RSN_GTK_OUI_OFFSET); ++ oui = &mwifiex_rsn_oui[cipher][0]; ++ ret = mwifiex_search_oui_in_ie(iebody, oui); ++ if (ret) ++ return ret; ++ } ++ return ret; ++} ++ ++/* ++ * This function checks if a given OUI is present in a WPA IE. ++ * ++ * The function first checks if a WPA IE is present or not in the ++ * BSS descriptor. It tries to locate the OUI only if such an IE is ++ * present. ++ */ ++static u8 ++mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) ++{ ++ u8 *oui = NULL; ++ struct ie_body *iebody = NULL; ++ u8 ret = MWIFIEX_OUI_NOT_PRESENT; ++ ++ if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)). ++ vend_hdr.element_id == WLAN_EID_WPA))) { ++ iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data; ++ oui = &mwifiex_wpa_oui[cipher][0]; ++ ret = mwifiex_search_oui_in_ie(iebody, oui); ++ if (ret) ++ return ret; ++ } ++ return ret; ++} ++ ++/* ++ * This function compares two SSIDs and checks if they match. ++ */ ++s32 ++mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, ++ struct mwifiex_802_11_ssid *ssid2) ++{ ++ if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len)) ++ return -1; ++ return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len); ++} ++ ++/* ++ * Sends IOCTL request to get the best BSS. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ */ ++int mwifiex_find_best_bss(struct mwifiex_private *priv, ++ struct mwifiex_ssid_bssid *ssid_bssid) ++{ ++ struct mwifiex_ssid_bssid tmp_ssid_bssid; ++ u8 *mac = NULL; ++ ++ if (!ssid_bssid) ++ return -1; ++ ++ memcpy(&tmp_ssid_bssid, ssid_bssid, ++ sizeof(struct mwifiex_ssid_bssid)); ++ ++ if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) { ++ memcpy(ssid_bssid, &tmp_ssid_bssid, ++ sizeof(struct mwifiex_ssid_bssid)); ++ mac = (u8 *) &ssid_bssid->bssid; ++ dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s," ++ " %pM\n", ssid_bssid->ssid.ssid, mac); ++ return 0; ++ } ++ ++ return -1; ++} ++ ++/* ++ * Sends IOCTL request to start a scan with user configurations. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ * ++ * Upon completion, it also generates a wireless event to notify ++ * applications. ++ */ ++int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, ++ struct mwifiex_user_scan_cfg *scan_req) ++{ ++ int status = 0; ++ ++ priv->adapter->cmd_wait_q.condition = false; ++ ++ status = mwifiex_scan_networks(priv, scan_req); ++ if (!status) ++ status = mwifiex_wait_queue_complete(priv->adapter); ++ ++ return status; ++} ++ ++/* ++ * This function checks if wapi is enabled in driver and scanned network is ++ * compatible with it. ++ */ ++static bool ++mwifiex_is_network_compatible_for_wapi(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc) ++{ ++ if (priv->sec_info.wapi_enabled && ++ (bss_desc->bcn_wapi_ie && ++ ((*(bss_desc->bcn_wapi_ie)).ieee_hdr.element_id == ++ WLAN_EID_BSS_AC_ACCESS_DELAY))) { ++ return true; ++ } ++ return false; ++} ++ ++/* ++ * This function checks if driver is configured with no security mode and ++ * scanned network is compatible with it. ++ */ ++static bool ++mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc) ++{ ++ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED ++ && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled ++ && ((!bss_desc->bcn_wpa_ie) || ++ ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != ++ WLAN_EID_WPA)) ++ && ((!bss_desc->bcn_rsn_ie) || ++ ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != ++ WLAN_EID_RSN)) ++ && !priv->sec_info.encryption_mode ++ && !bss_desc->privacy) { ++ return true; ++ } ++ return false; ++} ++ ++/* ++ * This function checks if static WEP is enabled in driver and scanned network ++ * is compatible with it. ++ */ ++static bool ++mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc) ++{ ++ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED ++ && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled ++ && bss_desc->privacy) { ++ return true; ++ } ++ return false; ++} ++ ++/* ++ * This function checks if wpa is enabled in driver and scanned network is ++ * compatible with it. ++ */ ++static bool ++mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc, ++ int index) ++{ ++ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED ++ && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled ++ && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr. ++ element_id == WLAN_EID_WPA)) ++ /* ++ * Privacy bit may NOT be set in some APs like ++ * LinkSys WRT54G && bss_desc->privacy ++ */ ++ ) { ++ dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d" ++ " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " ++ "EncMode=%#x privacy=%#x\n", __func__, index, ++ (bss_desc->bcn_wpa_ie) ? ++ (*(bss_desc->bcn_wpa_ie)). ++ vend_hdr.element_id : 0, ++ (bss_desc->bcn_rsn_ie) ? ++ (*(bss_desc->bcn_rsn_ie)). ++ ieee_hdr.element_id : 0, ++ (priv->sec_info.wep_status == ++ MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", ++ (priv->sec_info.wpa_enabled) ? "e" : "d", ++ (priv->sec_info.wpa2_enabled) ? "e" : "d", ++ priv->sec_info.encryption_mode, ++ bss_desc->privacy); ++ return true; ++ } ++ return false; ++} ++ ++/* ++ * This function checks if wpa2 is enabled in driver and scanned network is ++ * compatible with it. ++ */ ++static bool ++mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc, ++ int index) ++{ ++ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED ++ && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled ++ && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. ++ element_id == WLAN_EID_RSN)) ++ /* ++ * Privacy bit may NOT be set in some APs like ++ * LinkSys WRT54G && bss_desc->privacy ++ */ ++ ) { ++ dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d" ++ " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " ++ "EncMode=%#x privacy=%#x\n", __func__, index, ++ (bss_desc->bcn_wpa_ie) ? ++ (*(bss_desc->bcn_wpa_ie)). ++ vend_hdr.element_id : 0, ++ (bss_desc->bcn_rsn_ie) ? ++ (*(bss_desc->bcn_rsn_ie)). ++ ieee_hdr.element_id : 0, ++ (priv->sec_info.wep_status == ++ MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", ++ (priv->sec_info.wpa_enabled) ? "e" : "d", ++ (priv->sec_info.wpa2_enabled) ? "e" : "d", ++ priv->sec_info.encryption_mode, ++ bss_desc->privacy); ++ return true; ++ } ++ return false; ++} ++ ++/* ++ * This function checks if adhoc AES is enabled in driver and scanned network is ++ * compatible with it. ++ */ ++static bool ++mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc) ++{ ++ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED ++ && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled ++ && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr. ++ element_id != WLAN_EID_WPA)) ++ && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. ++ element_id != WLAN_EID_RSN)) ++ && !priv->sec_info.encryption_mode ++ && bss_desc->privacy) { ++ return true; ++ } ++ return false; ++} ++ ++/* ++ * This function checks if dynamic WEP is enabled in driver and scanned network ++ * is compatible with it. ++ */ ++static bool ++mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, ++ struct mwifiex_bssdescriptor *bss_desc, ++ int index) ++{ ++ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED ++ && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled ++ && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr. ++ element_id != WLAN_EID_WPA)) ++ && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. ++ element_id != WLAN_EID_RSN)) ++ && priv->sec_info.encryption_mode ++ && bss_desc->privacy) { ++ dev_dbg(priv->adapter->dev, "info: %s: dynamic " ++ "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x " ++ "EncMode=%#x privacy=%#x\n", ++ __func__, index, ++ (bss_desc->bcn_wpa_ie) ? ++ (*(bss_desc->bcn_wpa_ie)). ++ vend_hdr.element_id : 0, ++ (bss_desc->bcn_rsn_ie) ? ++ (*(bss_desc->bcn_rsn_ie)). ++ ieee_hdr.element_id : 0, ++ priv->sec_info.encryption_mode, ++ bss_desc->privacy); ++ return true; ++ } ++ return false; ++} ++ ++/* ++ * This function checks if a scanned network is compatible with the driver ++ * settings. ++ * ++ * WEP WPA WPA2 ad-hoc encrypt Network ++ * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible ++ * 0 0 0 0 NONE 0 0 0 yes No security ++ * 0 1 0 0 x 1x 1 x yes WPA (disable ++ * HT if no AES) ++ * 0 0 1 0 x 1x x 1 yes WPA2 (disable ++ * HT if no AES) ++ * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES ++ * 1 0 0 0 NONE 1 0 0 yes Static WEP ++ * (disable HT) ++ * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP ++ * ++ * Compatibility is not matched while roaming, except for mode. ++ */ ++static s32 ++mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct mwifiex_bssdescriptor *bss_desc; ++ ++ bss_desc = &adapter->scan_table[index]; ++ bss_desc->disable_11n = false; ++ ++ /* Don't check for compatibility if roaming */ ++ if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION) ++ && (bss_desc->bss_mode == NL80211_IFTYPE_STATION)) ++ return index; ++ ++ if (priv->wps.session_enable) { ++ dev_dbg(adapter->dev, ++ "info: return success directly in WPS period\n"); ++ return index; ++ } ++ ++ if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) { ++ dev_dbg(adapter->dev, "info: return success for WAPI AP\n"); ++ return index; ++ } ++ ++ if (bss_desc->bss_mode == mode) { ++ if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) { ++ /* No security */ ++ return index; ++ } else if (mwifiex_is_network_compatible_for_static_wep(priv, ++ bss_desc)) { ++ /* Static WEP enabled */ ++ dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n"); ++ bss_desc->disable_11n = true; ++ return index; ++ } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc, ++ index)) { ++ /* WPA enabled */ ++ if (((priv->adapter->config_bands & BAND_GN ++ || priv->adapter->config_bands & BAND_AN) ++ && bss_desc->bcn_ht_cap) ++ && !mwifiex_is_wpa_oui_present(bss_desc, ++ CIPHER_SUITE_CCMP)) { ++ ++ if (mwifiex_is_wpa_oui_present(bss_desc, ++ CIPHER_SUITE_TKIP)) { ++ dev_dbg(adapter->dev, ++ "info: Disable 11n if AES " ++ "is not supported by AP\n"); ++ bss_desc->disable_11n = true; ++ } else { ++ return -1; ++ } ++ } ++ return index; ++ } else if (mwifiex_is_network_compatible_for_wpa2(priv, ++ bss_desc, index)) { ++ /* WPA2 enabled */ ++ if (((priv->adapter->config_bands & BAND_GN ++ || priv->adapter->config_bands & BAND_AN) ++ && bss_desc->bcn_ht_cap) ++ && !mwifiex_is_rsn_oui_present(bss_desc, ++ CIPHER_SUITE_CCMP)) { ++ ++ if (mwifiex_is_rsn_oui_present(bss_desc, ++ CIPHER_SUITE_TKIP)) { ++ dev_dbg(adapter->dev, ++ "info: Disable 11n if AES " ++ "is not supported by AP\n"); ++ bss_desc->disable_11n = true; ++ } else { ++ return -1; ++ } ++ } ++ return index; ++ } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv, ++ bss_desc)) { ++ /* Ad-hoc AES enabled */ ++ return index; ++ } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv, ++ bss_desc, index)) { ++ /* Dynamic WEP enabled */ ++ return index; ++ } ++ ++ /* Security doesn't match */ ++ dev_dbg(adapter->dev, "info: %s: failed: index=%d " ++ "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode" ++ "=%#x privacy=%#x\n", ++ __func__, index, ++ (bss_desc->bcn_wpa_ie) ? ++ (*(bss_desc->bcn_wpa_ie)).vend_hdr. ++ element_id : 0, ++ (bss_desc->bcn_rsn_ie) ? ++ (*(bss_desc->bcn_rsn_ie)).ieee_hdr. ++ element_id : 0, ++ (priv->sec_info.wep_status == ++ MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", ++ (priv->sec_info.wpa_enabled) ? "e" : "d", ++ (priv->sec_info.wpa2_enabled) ? "e" : "d", ++ priv->sec_info.encryption_mode, bss_desc->privacy); ++ return -1; ++ } ++ ++ /* Mode doesn't match */ ++ return -1; ++} ++ ++/* ++ * This function finds the best SSID in the scan list. ++ * ++ * It searches the scan table for the best SSID that also matches the current ++ * adapter network preference (mode, security etc.). ++ */ ++static s32 ++mwifiex_find_best_network_in_list(struct mwifiex_private *priv) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ u32 mode = priv->bss_mode; ++ s32 best_net = -1; ++ s32 best_rssi = 0; ++ u32 i; ++ ++ dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n", ++ adapter->num_in_scan_table); ++ ++ for (i = 0; i < adapter->num_in_scan_table; i++) { ++ switch (mode) { ++ case NL80211_IFTYPE_STATION: ++ case NL80211_IFTYPE_ADHOC: ++ if (mwifiex_is_network_compatible(priv, i, mode) >= 0) { ++ if (SCAN_RSSI(adapter->scan_table[i].rssi) > ++ best_rssi) { ++ best_rssi = SCAN_RSSI(adapter-> ++ scan_table[i].rssi); ++ best_net = i; ++ } ++ } ++ break; ++ case NL80211_IFTYPE_UNSPECIFIED: ++ default: ++ if (SCAN_RSSI(adapter->scan_table[i].rssi) > ++ best_rssi) { ++ best_rssi = SCAN_RSSI(adapter->scan_table[i]. ++ rssi); ++ best_net = i; ++ } ++ break; ++ } ++ } ++ ++ return best_net; ++} ++ ++/* ++ * This function creates a channel list for the driver to scan, based ++ * on region/band information. ++ * ++ * This routine is used for any scan that is not provided with a ++ * specific channel list to scan. ++ */ ++static void ++mwifiex_scan_create_channel_list(struct mwifiex_private *priv, ++ const struct mwifiex_user_scan_cfg ++ *user_scan_in, ++ struct mwifiex_chan_scan_param_set ++ *scan_chan_list, ++ u8 filtered_scan) ++{ ++ enum ieee80211_band band; ++ struct ieee80211_supported_band *sband; ++ struct ieee80211_channel *ch; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ int chan_idx = 0, i; ++ u8 scan_type; ++ ++ for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) { ++ ++ if (!priv->wdev->wiphy->bands[band]) ++ continue; ++ ++ sband = priv->wdev->wiphy->bands[band]; ++ ++ for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) { ++ ch = &sband->channels[i]; ++ if (ch->flags & IEEE80211_CHAN_DISABLED) ++ continue; ++ scan_chan_list[chan_idx].radio_type = band; ++ scan_type = ch->flags & IEEE80211_CHAN_PASSIVE_SCAN; ++ if (user_scan_in && ++ user_scan_in->chan_list[0].scan_time) ++ scan_chan_list[chan_idx].max_scan_time = ++ cpu_to_le16((u16) user_scan_in-> ++ chan_list[0].scan_time); ++ else if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) ++ scan_chan_list[chan_idx].max_scan_time = ++ cpu_to_le16(adapter->passive_scan_time); ++ else ++ scan_chan_list[chan_idx].max_scan_time = ++ cpu_to_le16(adapter->active_scan_time); ++ if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) ++ scan_chan_list[chan_idx].chan_scan_mode_bitmap ++ |= MWIFIEX_PASSIVE_SCAN; ++ else ++ scan_chan_list[chan_idx].chan_scan_mode_bitmap ++ &= ~MWIFIEX_PASSIVE_SCAN; ++ scan_chan_list[chan_idx].chan_number = ++ (u32) ch->hw_value; ++ if (filtered_scan) { ++ scan_chan_list[chan_idx].max_scan_time = ++ cpu_to_le16(adapter->specific_scan_time); ++ scan_chan_list[chan_idx].chan_scan_mode_bitmap ++ |= MWIFIEX_DISABLE_CHAN_FILT; ++ } ++ } ++ ++ } ++} ++ ++/* ++ * This function constructs and sends multiple scan config commands to ++ * the firmware. ++ * ++ * Previous routines in the code flow have created a scan command configuration ++ * with any requested TLVs. This function splits the channel TLV into maximum ++ * channels supported per scan lists and sends the portion of the channel TLV, ++ * along with the other TLVs, to the firmware. ++ */ ++static int ++mwifiex_scan_channel_list(struct mwifiex_private *priv, ++ u32 max_chan_per_scan, u8 filtered_scan, ++ struct mwifiex_scan_cmd_config *scan_cfg_out, ++ struct mwifiex_ie_types_chan_list_param_set ++ *chan_tlv_out, ++ struct mwifiex_chan_scan_param_set *scan_chan_list) ++{ ++ int ret = 0; ++ struct mwifiex_chan_scan_param_set *tmp_chan_list; ++ struct mwifiex_chan_scan_param_set *start_chan; ++ ++ u32 tlv_idx; ++ u32 total_scan_time; ++ u32 done_early; ++ ++ if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) { ++ dev_dbg(priv->adapter->dev, ++ "info: Scan: Null detect: %p, %p, %p\n", ++ scan_cfg_out, chan_tlv_out, scan_chan_list); ++ return -1; ++ } ++ ++ chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); ++ ++ /* Set the temp channel struct pointer to the start of the desired ++ list */ ++ tmp_chan_list = scan_chan_list; ++ ++ /* Loop through the desired channel list, sending a new firmware scan ++ commands for each max_chan_per_scan channels (or for 1,6,11 ++ individually if configured accordingly) */ ++ while (tmp_chan_list->chan_number) { ++ ++ tlv_idx = 0; ++ total_scan_time = 0; ++ chan_tlv_out->header.len = 0; ++ start_chan = tmp_chan_list; ++ done_early = false; ++ ++ /* ++ * Construct the Channel TLV for the scan command. Continue to ++ * insert channel TLVs until: ++ * - the tlv_idx hits the maximum configured per scan command ++ * - the next channel to insert is 0 (end of desired channel ++ * list) ++ * - done_early is set (controlling individual scanning of ++ * 1,6,11) ++ */ ++ while (tlv_idx < max_chan_per_scan ++ && tmp_chan_list->chan_number && !done_early) { ++ ++ dev_dbg(priv->adapter->dev, ++ "info: Scan: Chan(%3d), Radio(%d)," ++ " Mode(%d, %d), Dur(%d)\n", ++ tmp_chan_list->chan_number, ++ tmp_chan_list->radio_type, ++ tmp_chan_list->chan_scan_mode_bitmap ++ & MWIFIEX_PASSIVE_SCAN, ++ (tmp_chan_list->chan_scan_mode_bitmap ++ & MWIFIEX_DISABLE_CHAN_FILT) >> 1, ++ le16_to_cpu(tmp_chan_list->max_scan_time)); ++ ++ /* Copy the current channel TLV to the command being ++ prepared */ ++ memcpy(chan_tlv_out->chan_scan_param + tlv_idx, ++ tmp_chan_list, ++ sizeof(chan_tlv_out->chan_scan_param)); ++ ++ /* Increment the TLV header length by the size ++ appended */ ++ chan_tlv_out->header.len = ++ cpu_to_le16(le16_to_cpu(chan_tlv_out->header.len) + ++ (sizeof(chan_tlv_out->chan_scan_param))); ++ ++ /* ++ * The tlv buffer length is set to the number of bytes ++ * of the between the channel tlv pointer and the start ++ * of the tlv buffer. This compensates for any TLVs ++ * that were appended before the channel list. ++ */ ++ scan_cfg_out->tlv_buf_len = (u32) ((u8 *) chan_tlv_out - ++ scan_cfg_out->tlv_buf); ++ ++ /* Add the size of the channel tlv header and the data ++ length */ ++ scan_cfg_out->tlv_buf_len += ++ (sizeof(chan_tlv_out->header) ++ + le16_to_cpu(chan_tlv_out->header.len)); ++ ++ /* Increment the index to the channel tlv we are ++ constructing */ ++ tlv_idx++; ++ ++ /* Count the total scan time per command */ ++ total_scan_time += ++ le16_to_cpu(tmp_chan_list->max_scan_time); ++ ++ done_early = false; ++ ++ /* Stop the loop if the *current* channel is in the ++ 1,6,11 set and we are not filtering on a BSSID ++ or SSID. */ ++ if (!filtered_scan && (tmp_chan_list->chan_number == 1 ++ || tmp_chan_list->chan_number == 6 ++ || tmp_chan_list->chan_number == 11)) ++ done_early = true; ++ ++ /* Increment the tmp pointer to the next channel to ++ be scanned */ ++ tmp_chan_list++; ++ ++ /* Stop the loop if the *next* channel is in the 1,6,11 ++ set. This will cause it to be the only channel ++ scanned on the next interation */ ++ if (!filtered_scan && (tmp_chan_list->chan_number == 1 ++ || tmp_chan_list->chan_number == 6 ++ || tmp_chan_list->chan_number == 11)) ++ done_early = true; ++ } ++ ++ /* The total scan time should be less than scan command timeout ++ value */ ++ if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) { ++ dev_err(priv->adapter->dev, "total scan time %dms" ++ " is over limit (%dms), scan skipped\n", ++ total_scan_time, MWIFIEX_MAX_TOTAL_SCAN_TIME); ++ ret = -1; ++ break; ++ } ++ ++ priv->adapter->scan_channels = start_chan; ++ ++ /* Send the scan command to the firmware with the specified ++ cfg */ ++ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SCAN, ++ HostCmd_ACT_GEN_SET, 0, ++ scan_cfg_out); ++ if (ret) ++ break; ++ } ++ ++ if (ret) ++ return -1; ++ ++ return 0; ++} ++ ++/* ++ * This function constructs a scan command configuration structure to use ++ * in scan commands. ++ * ++ * Application layer or other functions can invoke network scanning ++ * with a scan configuration supplied in a user scan configuration structure. ++ * This structure is used as the basis of one or many scan command configuration ++ * commands that are sent to the command processing module and eventually to the ++ * firmware. ++ * ++ * This function creates a scan command configuration structure based on the ++ * following user supplied parameters (if present): ++ * - SSID filter ++ * - BSSID filter ++ * - Number of Probes to be sent ++ * - Channel list ++ * ++ * If the SSID or BSSID filter is not present, the filter is disabled/cleared. ++ * If the number of probes is not set, adapter default setting is used. ++ */ ++static void ++mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, ++ const struct mwifiex_user_scan_cfg *user_scan_in, ++ struct mwifiex_scan_cmd_config *scan_cfg_out, ++ struct mwifiex_ie_types_chan_list_param_set ++ **chan_list_out, ++ struct mwifiex_chan_scan_param_set ++ *scan_chan_list, ++ u8 *max_chan_per_scan, u8 *filtered_scan, ++ u8 *scan_current_only) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct mwifiex_ie_types_num_probes *num_probes_tlv; ++ struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; ++ struct mwifiex_ie_types_rates_param_set *rates_tlv; ++ const u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; ++ u8 *tlv_pos; ++ u32 num_probes; ++ u32 ssid_len; ++ u32 chan_idx; ++ u32 scan_type; ++ u16 scan_dur; ++ u8 channel; ++ u8 radio_type; ++ u32 ssid_idx; ++ u8 ssid_filter; ++ u8 rates[MWIFIEX_SUPPORTED_RATES]; ++ u32 rates_size; ++ struct mwifiex_ie_types_htcap *ht_cap; ++ ++ /* The tlv_buf_len is calculated for each scan command. The TLVs added ++ in this routine will be preserved since the routine that sends the ++ command will append channelTLVs at *chan_list_out. The difference ++ between the *chan_list_out and the tlv_buf start will be used to ++ calculate the size of anything we add in this routine. */ ++ scan_cfg_out->tlv_buf_len = 0; ++ ++ /* Running tlv pointer. Assigned to chan_list_out at end of function ++ so later routines know where channels can be added to the command ++ buf */ ++ tlv_pos = scan_cfg_out->tlv_buf; ++ ++ /* Initialize the scan as un-filtered; the flag is later set to TRUE ++ below if a SSID or BSSID filter is sent in the command */ ++ *filtered_scan = false; ++ ++ /* Initialize the scan as not being only on the current channel. If ++ the channel list is customized, only contains one channel, and is ++ the active channel, this is set true and data flow is not halted. */ ++ *scan_current_only = false; ++ ++ if (user_scan_in) { ++ ++ /* Default the ssid_filter flag to TRUE, set false under ++ certain wildcard conditions and qualified by the existence ++ of an SSID list before marking the scan as filtered */ ++ ssid_filter = true; ++ ++ /* Set the BSS type scan filter, use Adapter setting if ++ unset */ ++ scan_cfg_out->bss_mode = ++ (user_scan_in->bss_mode ? (u8) user_scan_in-> ++ bss_mode : (u8) adapter->scan_mode); ++ ++ /* Set the number of probes to send, use Adapter setting ++ if unset */ ++ num_probes = ++ (user_scan_in->num_probes ? user_scan_in-> ++ num_probes : adapter->scan_probes); ++ ++ /* ++ * Set the BSSID filter to the incoming configuration, ++ * if non-zero. If not set, it will remain disabled ++ * (all zeros). ++ */ ++ memcpy(scan_cfg_out->specific_bssid, ++ user_scan_in->specific_bssid, ++ sizeof(scan_cfg_out->specific_bssid)); ++ ++ for (ssid_idx = 0; ++ ((ssid_idx < ARRAY_SIZE(user_scan_in->ssid_list)) ++ && (*user_scan_in->ssid_list[ssid_idx].ssid ++ || user_scan_in->ssid_list[ssid_idx].max_len)); ++ ssid_idx++) { ++ ++ ssid_len = strlen(user_scan_in->ssid_list[ssid_idx]. ++ ssid) + 1; ++ ++ wildcard_ssid_tlv = ++ (struct mwifiex_ie_types_wildcard_ssid_params *) ++ tlv_pos; ++ wildcard_ssid_tlv->header.type = ++ cpu_to_le16(TLV_TYPE_WILDCARDSSID); ++ wildcard_ssid_tlv->header.len = cpu_to_le16( ++ (u16) (ssid_len + sizeof(wildcard_ssid_tlv-> ++ max_ssid_length))); ++ wildcard_ssid_tlv->max_ssid_length = ++ user_scan_in->ssid_list[ssid_idx].max_len; ++ ++ memcpy(wildcard_ssid_tlv->ssid, ++ user_scan_in->ssid_list[ssid_idx].ssid, ++ ssid_len); ++ ++ tlv_pos += (sizeof(wildcard_ssid_tlv->header) ++ + le16_to_cpu(wildcard_ssid_tlv->header.len)); ++ ++ dev_dbg(adapter->dev, "info: scan: ssid_list[%d]: %s, %d\n", ++ ssid_idx, wildcard_ssid_tlv->ssid, ++ wildcard_ssid_tlv->max_ssid_length); ++ ++ /* Empty wildcard ssid with a maxlen will match many or ++ potentially all SSIDs (maxlen == 32), therefore do ++ not treat the scan as ++ filtered. */ ++ if (!ssid_len && wildcard_ssid_tlv->max_ssid_length) ++ ssid_filter = false; ++ ++ } ++ ++ /* ++ * The default number of channels sent in the command is low to ++ * ensure the response buffer from the firmware does not ++ * truncate scan results. That is not an issue with an SSID ++ * or BSSID filter applied to the scan results in the firmware. ++ */ ++ if ((ssid_idx && ssid_filter) ++ || memcmp(scan_cfg_out->specific_bssid, &zero_mac, ++ sizeof(zero_mac))) ++ *filtered_scan = true; ++ } else { ++ scan_cfg_out->bss_mode = (u8) adapter->scan_mode; ++ num_probes = adapter->scan_probes; ++ } ++ ++ /* ++ * If a specific BSSID or SSID is used, the number of channels in the ++ * scan command will be increased to the absolute maximum. ++ */ ++ if (*filtered_scan) ++ *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN; ++ else ++ *max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD; ++ ++ /* If the input config or adapter has the number of Probes set, ++ add tlv */ ++ if (num_probes) { ++ ++ dev_dbg(adapter->dev, "info: scan: num_probes = %d\n", ++ num_probes); ++ ++ num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos; ++ num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); ++ num_probes_tlv->header.len = ++ cpu_to_le16(sizeof(num_probes_tlv->num_probes)); ++ num_probes_tlv->num_probes = cpu_to_le16((u16) num_probes); ++ ++ tlv_pos += sizeof(num_probes_tlv->header) + ++ le16_to_cpu(num_probes_tlv->header.len); ++ ++ } ++ ++ /* Append rates tlv */ ++ memset(rates, 0, sizeof(rates)); ++ ++ rates_size = mwifiex_get_supported_rates(priv, rates); ++ ++ rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos; ++ rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); ++ rates_tlv->header.len = cpu_to_le16((u16) rates_size); ++ memcpy(rates_tlv->rates, rates, rates_size); ++ tlv_pos += sizeof(rates_tlv->header) + rates_size; ++ ++ dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size); ++ ++ if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) ++ && (priv->adapter->config_bands & BAND_GN ++ || priv->adapter->config_bands & BAND_AN)) { ++ ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos; ++ memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); ++ ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); ++ ht_cap->header.len = ++ cpu_to_le16(sizeof(struct ieee80211_ht_cap)); ++ radio_type = ++ mwifiex_band_to_radio_type(priv->adapter->config_bands); ++ mwifiex_fill_cap_info(priv, radio_type, ht_cap); ++ tlv_pos += sizeof(struct mwifiex_ie_types_htcap); ++ } ++ ++ /* Append vendor specific IE TLV */ ++ mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_SCAN, &tlv_pos); ++ ++ /* ++ * Set the output for the channel TLV to the address in the tlv buffer ++ * past any TLVs that were added in this function (SSID, num_probes). ++ * Channel TLVs will be added past this for each scan command, ++ * preserving the TLVs that were previously added. ++ */ ++ *chan_list_out = ++ (struct mwifiex_ie_types_chan_list_param_set *) tlv_pos; ++ ++ if (user_scan_in && user_scan_in->chan_list[0].chan_number) { ++ ++ dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n"); ++ ++ for (chan_idx = 0; ++ chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX ++ && user_scan_in->chan_list[chan_idx].chan_number; ++ chan_idx++) { ++ ++ channel = user_scan_in->chan_list[chan_idx].chan_number; ++ (scan_chan_list + chan_idx)->chan_number = channel; ++ ++ radio_type = ++ user_scan_in->chan_list[chan_idx].radio_type; ++ (scan_chan_list + chan_idx)->radio_type = radio_type; ++ ++ scan_type = user_scan_in->chan_list[chan_idx].scan_type; ++ ++ if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) ++ (scan_chan_list + ++ chan_idx)->chan_scan_mode_bitmap ++ |= MWIFIEX_PASSIVE_SCAN; ++ else ++ (scan_chan_list + ++ chan_idx)->chan_scan_mode_bitmap ++ &= ~MWIFIEX_PASSIVE_SCAN; ++ ++ if (user_scan_in->chan_list[chan_idx].scan_time) { ++ scan_dur = (u16) user_scan_in-> ++ chan_list[chan_idx].scan_time; ++ } else { ++ if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) ++ scan_dur = adapter->passive_scan_time; ++ else if (*filtered_scan) ++ scan_dur = adapter->specific_scan_time; ++ else ++ scan_dur = adapter->active_scan_time; ++ } ++ ++ (scan_chan_list + chan_idx)->min_scan_time = ++ cpu_to_le16(scan_dur); ++ (scan_chan_list + chan_idx)->max_scan_time = ++ cpu_to_le16(scan_dur); ++ } ++ ++ /* Check if we are only scanning the current channel */ ++ if ((chan_idx == 1) ++ && (user_scan_in->chan_list[0].chan_number ++ == priv->curr_bss_params.bss_descriptor.channel)) { ++ *scan_current_only = true; ++ dev_dbg(adapter->dev, ++ "info: Scan: Scanning current channel only\n"); ++ } ++ ++ } else { ++ dev_dbg(adapter->dev, ++ "info: Scan: Creating full region channel list\n"); ++ mwifiex_scan_create_channel_list(priv, user_scan_in, ++ scan_chan_list, ++ *filtered_scan); ++ } ++} ++ ++/* ++ * This function inspects the scan response buffer for pointers to ++ * expected TLVs. ++ * ++ * TLVs can be included at the end of the scan response BSS information. ++ * ++ * Data in the buffer is parsed pointers to TLVs that can potentially ++ * be passed back in the response. ++ */ ++static void ++mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, ++ struct mwifiex_ie_types_data *tlv, ++ u32 tlv_buf_size, u32 req_tlv_type, ++ struct mwifiex_ie_types_data **tlv_data) ++{ ++ struct mwifiex_ie_types_data *current_tlv; ++ u32 tlv_buf_left; ++ u32 tlv_type; ++ u32 tlv_len; ++ ++ current_tlv = tlv; ++ tlv_buf_left = tlv_buf_size; ++ *tlv_data = NULL; ++ ++ dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n", ++ tlv_buf_size); ++ ++ while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) { ++ ++ tlv_type = le16_to_cpu(current_tlv->header.type); ++ tlv_len = le16_to_cpu(current_tlv->header.len); ++ ++ if (sizeof(tlv->header) + tlv_len > tlv_buf_left) { ++ dev_err(adapter->dev, "SCAN_RESP: TLV buffer corrupt\n"); ++ break; ++ } ++ ++ if (req_tlv_type == tlv_type) { ++ switch (tlv_type) { ++ case TLV_TYPE_TSFTIMESTAMP: ++ dev_dbg(adapter->dev, "info: SCAN_RESP: TSF " ++ "timestamp TLV, len = %d\n", tlv_len); ++ *tlv_data = (struct mwifiex_ie_types_data *) ++ current_tlv; ++ break; ++ case TLV_TYPE_CHANNELBANDLIST: ++ dev_dbg(adapter->dev, "info: SCAN_RESP: channel" ++ " band list TLV, len = %d\n", tlv_len); ++ *tlv_data = (struct mwifiex_ie_types_data *) ++ current_tlv; ++ break; ++ default: ++ dev_err(adapter->dev, ++ "SCAN_RESP: unhandled TLV = %d\n", ++ tlv_type); ++ /* Give up, this seems corrupted */ ++ return; ++ } ++ } ++ ++ if (*tlv_data) ++ break; ++ ++ ++ tlv_buf_left -= (sizeof(tlv->header) + tlv_len); ++ current_tlv = ++ (struct mwifiex_ie_types_data *) (current_tlv->data + ++ tlv_len); ++ ++ } /* while */ ++} ++ ++/* ++ * This function interprets a BSS scan response returned from the firmware. ++ * ++ * The various fixed fields and IEs are parsed and passed back for a BSS ++ * probe response or beacon from scan command. Information is recorded as ++ * needed in the scan table for that entry. ++ * ++ * The following IE types are recognized and parsed - ++ * - SSID ++ * - Supported rates ++ * - FH parameters set ++ * - DS parameters set ++ * - CF parameters set ++ * - IBSS parameters set ++ * - ERP information ++ * - Extended supported rates ++ * - Vendor specific (221) ++ * - RSN IE ++ * - WAPI IE ++ * - HT capability ++ * - HT operation ++ * - BSS Coexistence 20/40 ++ * - Extended capability ++ * - Overlapping BSS scan parameters ++ */ ++static int ++mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, ++ struct mwifiex_bssdescriptor *bss_entry, ++ u8 **beacon_info, u32 *bytes_left) ++{ ++ int ret = 0; ++ u8 element_id; ++ struct ieee_types_fh_param_set *fh_param_set; ++ struct ieee_types_ds_param_set *ds_param_set; ++ struct ieee_types_cf_param_set *cf_param_set; ++ struct ieee_types_ibss_param_set *ibss_param_set; ++ __le16 beacon_interval; ++ __le16 capabilities; ++ u8 *current_ptr; ++ u8 *rate; ++ u8 element_len; ++ u16 total_ie_len; ++ u8 bytes_to_copy; ++ u8 rate_size; ++ u16 beacon_size; ++ u8 found_data_rate_ie; ++ u32 bytes_left_for_current_beacon; ++ struct ieee_types_vendor_specific *vendor_ie; ++ const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; ++ const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; ++ ++ found_data_rate_ie = false; ++ rate_size = 0; ++ beacon_size = 0; ++ ++ if (*bytes_left >= sizeof(beacon_size)) { ++ /* Extract & convert beacon size from the command buffer */ ++ memcpy(&beacon_size, *beacon_info, sizeof(beacon_size)); ++ *bytes_left -= sizeof(beacon_size); ++ *beacon_info += sizeof(beacon_size); ++ } ++ ++ if (!beacon_size || beacon_size > *bytes_left) { ++ *beacon_info += *bytes_left; ++ *bytes_left = 0; ++ return -1; ++ } ++ ++ /* Initialize the current working beacon pointer for this BSS ++ iteration */ ++ current_ptr = *beacon_info; ++ ++ /* Advance the return beacon pointer past the current beacon */ ++ *beacon_info += beacon_size; ++ *bytes_left -= beacon_size; ++ ++ bytes_left_for_current_beacon = beacon_size; ++ ++ memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN); ++ dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n", ++ bss_entry->mac_address); ++ ++ current_ptr += ETH_ALEN; ++ bytes_left_for_current_beacon -= ETH_ALEN; ++ ++ if (bytes_left_for_current_beacon < 12) { ++ dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); ++ return -1; ++ } ++ ++ /* ++ * Next 4 fields are RSSI, time stamp, beacon interval, ++ * and capability information ++ */ ++ ++ /* RSSI is 1 byte long */ ++ bss_entry->rssi = (s32) (*current_ptr); ++ dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr); ++ current_ptr += 1; ++ bytes_left_for_current_beacon -= 1; ++ ++ /* ++ * The RSSI is not part of the beacon/probe response. After we have ++ * advanced current_ptr past the RSSI field, save the remaining ++ * data for use at the application layer ++ */ ++ bss_entry->beacon_buf = current_ptr; ++ bss_entry->beacon_buf_size = bytes_left_for_current_beacon; ++ ++ /* Time stamp is 8 bytes long */ ++ memcpy(bss_entry->time_stamp, current_ptr, 8); ++ current_ptr += 8; ++ bytes_left_for_current_beacon -= 8; ++ ++ /* Beacon interval is 2 bytes long */ ++ memcpy(&beacon_interval, current_ptr, 2); ++ bss_entry->beacon_period = le16_to_cpu(beacon_interval); ++ current_ptr += 2; ++ bytes_left_for_current_beacon -= 2; ++ ++ /* Capability information is 2 bytes long */ ++ memcpy(&capabilities, current_ptr, 2); ++ dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", ++ capabilities); ++ bss_entry->cap_info_bitmap = le16_to_cpu(capabilities); ++ current_ptr += 2; ++ bytes_left_for_current_beacon -= 2; ++ ++ /* Rest of the current buffer are IE's */ ++ dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n", ++ bytes_left_for_current_beacon); ++ ++ if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { ++ dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n"); ++ bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; ++ } else { ++ bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; ++ } ++ ++ if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS) ++ bss_entry->bss_mode = NL80211_IFTYPE_ADHOC; ++ else ++ bss_entry->bss_mode = NL80211_IFTYPE_STATION; ++ ++ ++ /* Process variable IE */ ++ while (bytes_left_for_current_beacon >= 2) { ++ element_id = *current_ptr; ++ element_len = *(current_ptr + 1); ++ total_ie_len = element_len + sizeof(struct ieee_types_header); ++ ++ if (bytes_left_for_current_beacon < total_ie_len) { ++ dev_err(adapter->dev, "err: InterpretIE: in processing" ++ " IE, bytes left < IE length\n"); ++ bytes_left_for_current_beacon = 0; ++ ret = -1; ++ continue; ++ } ++ switch (element_id) { ++ case WLAN_EID_SSID: ++ bss_entry->ssid.ssid_len = element_len; ++ memcpy(bss_entry->ssid.ssid, (current_ptr + 2), ++ element_len); ++ dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n", ++ bss_entry->ssid.ssid); ++ break; ++ ++ case WLAN_EID_SUPP_RATES: ++ memcpy(bss_entry->data_rates, current_ptr + 2, ++ element_len); ++ memcpy(bss_entry->supported_rates, current_ptr + 2, ++ element_len); ++ rate_size = element_len; ++ found_data_rate_ie = true; ++ break; ++ ++ case WLAN_EID_FH_PARAMS: ++ fh_param_set = ++ (struct ieee_types_fh_param_set *) current_ptr; ++ memcpy(&bss_entry->phy_param_set.fh_param_set, ++ fh_param_set, ++ sizeof(struct ieee_types_fh_param_set)); ++ break; ++ ++ case WLAN_EID_DS_PARAMS: ++ ds_param_set = ++ (struct ieee_types_ds_param_set *) current_ptr; ++ ++ bss_entry->channel = ds_param_set->current_chan; ++ ++ memcpy(&bss_entry->phy_param_set.ds_param_set, ++ ds_param_set, ++ sizeof(struct ieee_types_ds_param_set)); ++ break; ++ ++ case WLAN_EID_CF_PARAMS: ++ cf_param_set = ++ (struct ieee_types_cf_param_set *) current_ptr; ++ memcpy(&bss_entry->ss_param_set.cf_param_set, ++ cf_param_set, ++ sizeof(struct ieee_types_cf_param_set)); ++ break; ++ ++ case WLAN_EID_IBSS_PARAMS: ++ ibss_param_set = ++ (struct ieee_types_ibss_param_set *) ++ current_ptr; ++ memcpy(&bss_entry->ss_param_set.ibss_param_set, ++ ibss_param_set, ++ sizeof(struct ieee_types_ibss_param_set)); ++ break; ++ ++ case WLAN_EID_ERP_INFO: ++ bss_entry->erp_flags = *(current_ptr + 2); ++ break; ++ ++ case WLAN_EID_EXT_SUPP_RATES: ++ /* ++ * Only process extended supported rate ++ * if data rate is already found. ++ * Data rate IE should come before ++ * extended supported rate IE ++ */ ++ if (found_data_rate_ie) { ++ if ((element_len + rate_size) > ++ MWIFIEX_SUPPORTED_RATES) ++ bytes_to_copy = ++ (MWIFIEX_SUPPORTED_RATES - ++ rate_size); ++ else ++ bytes_to_copy = element_len; ++ ++ rate = (u8 *) bss_entry->data_rates; ++ rate += rate_size; ++ memcpy(rate, current_ptr + 2, bytes_to_copy); ++ ++ rate = (u8 *) bss_entry->supported_rates; ++ rate += rate_size; ++ memcpy(rate, current_ptr + 2, bytes_to_copy); ++ } ++ break; ++ ++ case WLAN_EID_VENDOR_SPECIFIC: ++ vendor_ie = (struct ieee_types_vendor_specific *) ++ current_ptr; ++ ++ if (!memcmp ++ (vendor_ie->vend_hdr.oui, wpa_oui, ++ sizeof(wpa_oui))) { ++ bss_entry->bcn_wpa_ie = ++ (struct ieee_types_vendor_specific *) ++ current_ptr; ++ bss_entry->wpa_offset = (u16) (current_ptr - ++ bss_entry->beacon_buf); ++ } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui, ++ sizeof(wmm_oui))) { ++ if (total_ie_len == ++ sizeof(struct ieee_types_wmm_parameter) ++ || total_ie_len == ++ sizeof(struct ieee_types_wmm_info)) ++ /* ++ * Only accept and copy the WMM IE if ++ * it matches the size expected for the ++ * WMM Info IE or the WMM Parameter IE. ++ */ ++ memcpy((u8 *) &bss_entry->wmm_ie, ++ current_ptr, total_ie_len); ++ } ++ break; ++ case WLAN_EID_RSN: ++ bss_entry->bcn_rsn_ie = ++ (struct ieee_types_generic *) current_ptr; ++ bss_entry->rsn_offset = (u16) (current_ptr - ++ bss_entry->beacon_buf); ++ break; ++ case WLAN_EID_BSS_AC_ACCESS_DELAY: ++ bss_entry->bcn_wapi_ie = ++ (struct ieee_types_generic *) current_ptr; ++ bss_entry->wapi_offset = (u16) (current_ptr - ++ bss_entry->beacon_buf); ++ break; ++ case WLAN_EID_HT_CAPABILITY: ++ bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *) ++ (current_ptr + ++ sizeof(struct ieee_types_header)); ++ bss_entry->ht_cap_offset = (u16) (current_ptr + ++ sizeof(struct ieee_types_header) - ++ bss_entry->beacon_buf); ++ break; ++ case WLAN_EID_HT_INFORMATION: ++ bss_entry->bcn_ht_info = (struct ieee80211_ht_info *) ++ (current_ptr + ++ sizeof(struct ieee_types_header)); ++ bss_entry->ht_info_offset = (u16) (current_ptr + ++ sizeof(struct ieee_types_header) - ++ bss_entry->beacon_buf); ++ break; ++ case WLAN_EID_BSS_COEX_2040: ++ bss_entry->bcn_bss_co_2040 = (u8 *) (current_ptr + ++ sizeof(struct ieee_types_header)); ++ bss_entry->bss_co_2040_offset = (u16) (current_ptr + ++ sizeof(struct ieee_types_header) - ++ bss_entry->beacon_buf); ++ break; ++ case WLAN_EID_EXT_CAPABILITY: ++ bss_entry->bcn_ext_cap = (u8 *) (current_ptr + ++ sizeof(struct ieee_types_header)); ++ bss_entry->ext_cap_offset = (u16) (current_ptr + ++ sizeof(struct ieee_types_header) - ++ bss_entry->beacon_buf); ++ break; ++ case WLAN_EID_OVERLAP_BSS_SCAN_PARAM: ++ bss_entry->bcn_obss_scan = ++ (struct ieee_types_obss_scan_param *) ++ current_ptr; ++ bss_entry->overlap_bss_offset = (u16) (current_ptr - ++ bss_entry->beacon_buf); ++ break; ++ default: ++ break; ++ } ++ ++ current_ptr += element_len + 2; ++ ++ /* Need to account for IE ID and IE Len */ ++ bytes_left_for_current_beacon -= (element_len + 2); ++ ++ } /* while (bytes_left_for_current_beacon > 2) */ ++ return ret; ++} ++ ++/* ++ * This function adjusts the pointers used in beacon buffers to reflect ++ * shifts. ++ * ++ * The memory allocated for beacon buffers is of fixed sizes where all the ++ * saved beacons must be stored. New beacons are added in the free portion ++ * of this memory, space permitting; while duplicate beacon buffers are ++ * placed at the same start location. However, since duplicate beacon ++ * buffers may not match the size of the old one, all the following buffers ++ * in the memory must be shifted to either make space, or to fill up freed ++ * up space. ++ * ++ * This function is used to update the beacon buffer pointers that are past ++ * an existing beacon buffer that is updated with a new one of different ++ * size. The pointers are shifted by a fixed amount, either forward or ++ * backward. ++ * ++ * the following pointers in every affected beacon buffers are changed, if ++ * present - ++ * - WPA IE pointer ++ * - RSN IE pointer ++ * - WAPI IE pointer ++ * - HT capability IE pointer ++ * - HT information IE pointer ++ * - BSS coexistence 20/40 IE pointer ++ * - Extended capability IE pointer ++ * - Overlapping BSS scan parameter IE pointer ++ */ ++static void ++mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance, ++ u8 *bcn_store, u32 rem_bcn_size, ++ u32 num_of_ent) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ u32 adj_idx; ++ for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) { ++ if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) { ++ ++ if (advance) ++ adapter->scan_table[adj_idx].beacon_buf += ++ rem_bcn_size; ++ else ++ adapter->scan_table[adj_idx].beacon_buf -= ++ rem_bcn_size; ++ ++ if (adapter->scan_table[adj_idx].bcn_wpa_ie) ++ adapter->scan_table[adj_idx].bcn_wpa_ie = ++ (struct ieee_types_vendor_specific *) ++ (adapter->scan_table[adj_idx].beacon_buf + ++ adapter->scan_table[adj_idx].wpa_offset); ++ if (adapter->scan_table[adj_idx].bcn_rsn_ie) ++ adapter->scan_table[adj_idx].bcn_rsn_ie = ++ (struct ieee_types_generic *) ++ (adapter->scan_table[adj_idx].beacon_buf + ++ adapter->scan_table[adj_idx].rsn_offset); ++ if (adapter->scan_table[adj_idx].bcn_wapi_ie) ++ adapter->scan_table[adj_idx].bcn_wapi_ie = ++ (struct ieee_types_generic *) ++ (adapter->scan_table[adj_idx].beacon_buf + ++ adapter->scan_table[adj_idx].wapi_offset); ++ if (adapter->scan_table[adj_idx].bcn_ht_cap) ++ adapter->scan_table[adj_idx].bcn_ht_cap = ++ (struct ieee80211_ht_cap *) ++ (adapter->scan_table[adj_idx].beacon_buf + ++ adapter->scan_table[adj_idx].ht_cap_offset); ++ ++ if (adapter->scan_table[adj_idx].bcn_ht_info) ++ adapter->scan_table[adj_idx].bcn_ht_info = ++ (struct ieee80211_ht_info *) ++ (adapter->scan_table[adj_idx].beacon_buf + ++ adapter->scan_table[adj_idx].ht_info_offset); ++ if (adapter->scan_table[adj_idx].bcn_bss_co_2040) ++ adapter->scan_table[adj_idx].bcn_bss_co_2040 = ++ (u8 *) ++ (adapter->scan_table[adj_idx].beacon_buf + ++ adapter->scan_table[adj_idx].bss_co_2040_offset); ++ if (adapter->scan_table[adj_idx].bcn_ext_cap) ++ adapter->scan_table[adj_idx].bcn_ext_cap = ++ (u8 *) ++ (adapter->scan_table[adj_idx].beacon_buf + ++ adapter->scan_table[adj_idx].ext_cap_offset); ++ if (adapter->scan_table[adj_idx].bcn_obss_scan) ++ adapter->scan_table[adj_idx].bcn_obss_scan = ++ (struct ieee_types_obss_scan_param *) ++ (adapter->scan_table[adj_idx].beacon_buf + ++ adapter->scan_table[adj_idx].overlap_bss_offset); ++ } ++ } ++} ++ ++/* ++ * This function updates the pointers used in beacon buffer for given bss ++ * descriptor to reflect shifts ++ * ++ * Following pointers are updated ++ * - WPA IE pointer ++ * - RSN IE pointer ++ * - WAPI IE pointer ++ * - HT capability IE pointer ++ * - HT information IE pointer ++ * - BSS coexistence 20/40 IE pointer ++ * - Extended capability IE pointer ++ * - Overlapping BSS scan parameter IE pointer ++ */ ++static void ++mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon) ++{ ++ if (beacon->bcn_wpa_ie) ++ beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *) ++ (beacon->beacon_buf + beacon->wpa_offset); ++ if (beacon->bcn_rsn_ie) ++ beacon->bcn_rsn_ie = (struct ieee_types_generic *) ++ (beacon->beacon_buf + beacon->rsn_offset); ++ if (beacon->bcn_wapi_ie) ++ beacon->bcn_wapi_ie = (struct ieee_types_generic *) ++ (beacon->beacon_buf + beacon->wapi_offset); ++ if (beacon->bcn_ht_cap) ++ beacon->bcn_ht_cap = (struct ieee80211_ht_cap *) ++ (beacon->beacon_buf + beacon->ht_cap_offset); ++ if (beacon->bcn_ht_info) ++ beacon->bcn_ht_info = (struct ieee80211_ht_info *) ++ (beacon->beacon_buf + beacon->ht_info_offset); ++ if (beacon->bcn_bss_co_2040) ++ beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf + ++ beacon->bss_co_2040_offset); ++ if (beacon->bcn_ext_cap) ++ beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf + ++ beacon->ext_cap_offset); ++ if (beacon->bcn_obss_scan) ++ beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *) ++ (beacon->beacon_buf + beacon->overlap_bss_offset); ++} ++ ++/* ++ * This function stores a beacon or probe response for a BSS returned ++ * in the scan. ++ * ++ * This stores a new scan response or an update for a previous scan response. ++ * New entries need to verify that they do not exceed the total amount of ++ * memory allocated for the table. ++ * ++ * Replacement entries need to take into consideration the amount of space ++ * currently allocated for the beacon/probe response and adjust the entry ++ * as needed. ++ * ++ * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved ++ * for an entry in case it is a beacon since a probe response for the ++ * network will by larger per the standard. This helps to reduce the ++ * amount of memory copying to fit a new probe response into an entry ++ * already occupied by a network's previously stored beacon. ++ */ ++static void ++mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv, ++ u32 beacon_idx, u32 num_of_ent, ++ struct mwifiex_bssdescriptor *new_beacon) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ u8 *bcn_store; ++ u32 new_bcn_size; ++ u32 old_bcn_size; ++ u32 bcn_space; ++ ++ if (adapter->scan_table[beacon_idx].beacon_buf) { ++ ++ new_bcn_size = new_beacon->beacon_buf_size; ++ old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size; ++ bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max; ++ bcn_store = adapter->scan_table[beacon_idx].beacon_buf; ++ ++ /* Set the max to be the same as current entry unless changed ++ below */ ++ new_beacon->beacon_buf_size_max = bcn_space; ++ if (new_bcn_size == old_bcn_size) { ++ /* ++ * Beacon is the same size as the previous entry. ++ * Replace the previous contents with the scan result ++ */ ++ memcpy(bcn_store, new_beacon->beacon_buf, ++ new_beacon->beacon_buf_size); ++ ++ } else if (new_bcn_size <= bcn_space) { ++ /* ++ * New beacon size will fit in the amount of space ++ * we have previously allocated for it ++ */ ++ ++ /* Copy the new beacon buffer entry over the old one */ ++ memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); ++ ++ /* ++ * If the old beacon size was less than the maximum ++ * we had alloted for the entry, and the new entry ++ * is even smaller, reset the max size to the old ++ * beacon entry and compress the storage space ++ * (leaving a new pad space of (old_bcn_size - ++ * new_bcn_size). ++ */ ++ if (old_bcn_size < bcn_space ++ && new_bcn_size <= old_bcn_size) { ++ /* ++ * Old Beacon size is smaller than the alloted ++ * storage size. Shrink the alloted storage ++ * space. ++ */ ++ dev_dbg(adapter->dev, "info: AppControl:" ++ " smaller duplicate beacon " ++ "(%d), old = %d, new = %d, space = %d," ++ "left = %d\n", ++ beacon_idx, old_bcn_size, new_bcn_size, ++ bcn_space, ++ (int)(sizeof(adapter->bcn_buf) - ++ (adapter->bcn_buf_end - ++ adapter->bcn_buf))); ++ ++ /* ++ * memmove (since the memory overlaps) the ++ * data after the beacon we just stored to the ++ * end of the current beacon. This cleans up ++ * any unused space the old larger beacon was ++ * using in the buffer ++ */ ++ memmove(bcn_store + old_bcn_size, ++ bcn_store + bcn_space, ++ adapter->bcn_buf_end - (bcn_store + ++ bcn_space)); ++ ++ /* ++ * Decrement the end pointer by the difference ++ * between the old larger size and the new ++ * smaller size since we are using less space ++ * due to the new beacon being smaller ++ */ ++ adapter->bcn_buf_end -= ++ (bcn_space - old_bcn_size); ++ ++ /* Set the maximum storage size to the old ++ beacon size */ ++ new_beacon->beacon_buf_size_max = old_bcn_size; ++ ++ /* Adjust beacon buffer pointers that are past ++ the current */ ++ mwifiex_adjust_beacon_buffer_ptrs(priv, 0, ++ bcn_store, (bcn_space - old_bcn_size), ++ num_of_ent); ++ } ++ } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space) ++ < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) { ++ /* ++ * Beacon is larger than space previously allocated ++ * (bcn_space) and there is enough space left in the ++ * beaconBuffer to store the additional data ++ */ ++ dev_dbg(adapter->dev, "info: AppControl:" ++ " larger duplicate beacon (%d), " ++ "old = %d, new = %d, space = %d, left = %d\n", ++ beacon_idx, old_bcn_size, new_bcn_size, ++ bcn_space, ++ (int)(sizeof(adapter->bcn_buf) - ++ (adapter->bcn_buf_end - ++ adapter->bcn_buf))); ++ ++ /* ++ * memmove (since the memory overlaps) the data ++ * after the beacon we just stored to the end of ++ * the current beacon. This moves the data for ++ * the beacons after this further in memory to ++ * make space for the new larger beacon we are ++ * about to copy in. ++ */ ++ memmove(bcn_store + new_bcn_size, ++ bcn_store + bcn_space, ++ adapter->bcn_buf_end - (bcn_store + bcn_space)); ++ ++ /* Copy the new beacon buffer entry over the old one */ ++ memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); ++ ++ /* Move the beacon end pointer by the amount of new ++ beacon data we are adding */ ++ adapter->bcn_buf_end += (new_bcn_size - bcn_space); ++ ++ /* ++ * This entry is bigger than the alloted max space ++ * previously reserved. Increase the max space to ++ * be equal to the new beacon size ++ */ ++ new_beacon->beacon_buf_size_max = new_bcn_size; ++ ++ /* Adjust beacon buffer pointers that are past the ++ current */ ++ mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store, ++ (new_bcn_size - bcn_space), ++ num_of_ent); ++ } else { ++ /* ++ * Beacon is larger than the previously allocated space, ++ * but there is not enough free space to store the ++ * additional data. ++ */ ++ dev_err(adapter->dev, "AppControl: larger duplicate " ++ " beacon (%d), old = %d new = %d, space = %d," ++ " left = %d\n", beacon_idx, old_bcn_size, ++ new_bcn_size, bcn_space, ++ (int)(sizeof(adapter->bcn_buf) - ++ (adapter->bcn_buf_end - adapter->bcn_buf))); ++ ++ /* Storage failure, keep old beacon intact */ ++ new_beacon->beacon_buf_size = old_bcn_size; ++ if (new_beacon->bcn_wpa_ie) ++ new_beacon->wpa_offset = ++ adapter->scan_table[beacon_idx]. ++ wpa_offset; ++ if (new_beacon->bcn_rsn_ie) ++ new_beacon->rsn_offset = ++ adapter->scan_table[beacon_idx]. ++ rsn_offset; ++ if (new_beacon->bcn_wapi_ie) ++ new_beacon->wapi_offset = ++ adapter->scan_table[beacon_idx]. ++ wapi_offset; ++ if (new_beacon->bcn_ht_cap) ++ new_beacon->ht_cap_offset = ++ adapter->scan_table[beacon_idx]. ++ ht_cap_offset; ++ if (new_beacon->bcn_ht_info) ++ new_beacon->ht_info_offset = ++ adapter->scan_table[beacon_idx]. ++ ht_info_offset; ++ if (new_beacon->bcn_bss_co_2040) ++ new_beacon->bss_co_2040_offset = ++ adapter->scan_table[beacon_idx]. ++ bss_co_2040_offset; ++ if (new_beacon->bcn_ext_cap) ++ new_beacon->ext_cap_offset = ++ adapter->scan_table[beacon_idx]. ++ ext_cap_offset; ++ if (new_beacon->bcn_obss_scan) ++ new_beacon->overlap_bss_offset = ++ adapter->scan_table[beacon_idx]. ++ overlap_bss_offset; ++ } ++ /* Point the new entry to its permanent storage space */ ++ new_beacon->beacon_buf = bcn_store; ++ mwifiex_update_beacon_buffer_ptrs(new_beacon); ++ } else { ++ /* ++ * No existing beacon data exists for this entry, check to see ++ * if we can fit it in the remaining space ++ */ ++ if (adapter->bcn_buf_end + new_beacon->beacon_buf_size + ++ SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf + ++ sizeof(adapter->bcn_buf))) { ++ ++ /* ++ * Copy the beacon buffer data from the local entry to ++ * the adapter dev struct buffer space used to store ++ * the raw beacon data for each entry in the scan table ++ */ ++ memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf, ++ new_beacon->beacon_buf_size); ++ ++ /* Update the beacon ptr to point to the table save ++ area */ ++ new_beacon->beacon_buf = adapter->bcn_buf_end; ++ new_beacon->beacon_buf_size_max = ++ (new_beacon->beacon_buf_size + ++ SCAN_BEACON_ENTRY_PAD); ++ ++ mwifiex_update_beacon_buffer_ptrs(new_beacon); ++ ++ /* Increment the end pointer by the size reserved */ ++ adapter->bcn_buf_end += new_beacon->beacon_buf_size_max; ++ ++ dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]" ++ " sz=%03d, used = %04d, left = %04d\n", ++ beacon_idx, ++ new_beacon->beacon_buf_size, ++ (int)(adapter->bcn_buf_end - adapter->bcn_buf), ++ (int)(sizeof(adapter->bcn_buf) - ++ (adapter->bcn_buf_end - ++ adapter->bcn_buf))); ++ } else { ++ /* No space for new beacon */ ++ dev_dbg(adapter->dev, "info: AppControl: no space for" ++ " beacon (%d): %pM sz=%03d, left=%03d\n", ++ beacon_idx, new_beacon->mac_address, ++ new_beacon->beacon_buf_size, ++ (int)(sizeof(adapter->bcn_buf) - ++ (adapter->bcn_buf_end - ++ adapter->bcn_buf))); ++ ++ /* Storage failure; clear storage records for this ++ bcn */ ++ new_beacon->beacon_buf = NULL; ++ new_beacon->beacon_buf_size = 0; ++ new_beacon->beacon_buf_size_max = 0; ++ new_beacon->bcn_wpa_ie = NULL; ++ new_beacon->wpa_offset = 0; ++ new_beacon->bcn_rsn_ie = NULL; ++ new_beacon->rsn_offset = 0; ++ new_beacon->bcn_wapi_ie = NULL; ++ new_beacon->wapi_offset = 0; ++ new_beacon->bcn_ht_cap = NULL; ++ new_beacon->ht_cap_offset = 0; ++ new_beacon->bcn_ht_info = NULL; ++ new_beacon->ht_info_offset = 0; ++ new_beacon->bcn_bss_co_2040 = NULL; ++ new_beacon->bss_co_2040_offset = 0; ++ new_beacon->bcn_ext_cap = NULL; ++ new_beacon->ext_cap_offset = 0; ++ new_beacon->bcn_obss_scan = NULL; ++ new_beacon->overlap_bss_offset = 0; ++ } ++ } ++} ++ ++/* ++ * This function restores a beacon buffer of the current BSS descriptor. ++ */ ++static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct mwifiex_bssdescriptor *curr_bss = ++ &priv->curr_bss_params.bss_descriptor; ++ unsigned long flags; ++ ++ if (priv->curr_bcn_buf && ++ ((adapter->bcn_buf_end + priv->curr_bcn_size) < ++ (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) { ++ spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); ++ ++ /* restore the current beacon buffer */ ++ memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf, ++ priv->curr_bcn_size); ++ curr_bss->beacon_buf = adapter->bcn_buf_end; ++ curr_bss->beacon_buf_size = priv->curr_bcn_size; ++ adapter->bcn_buf_end += priv->curr_bcn_size; ++ ++ /* adjust the pointers in the current BSS descriptor */ ++ if (curr_bss->bcn_wpa_ie) ++ curr_bss->bcn_wpa_ie = ++ (struct ieee_types_vendor_specific *) ++ (curr_bss->beacon_buf + ++ curr_bss->wpa_offset); ++ ++ if (curr_bss->bcn_rsn_ie) ++ curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) ++ (curr_bss->beacon_buf + ++ curr_bss->rsn_offset); ++ ++ if (curr_bss->bcn_ht_cap) ++ curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) ++ (curr_bss->beacon_buf + ++ curr_bss->ht_cap_offset); ++ ++ if (curr_bss->bcn_ht_info) ++ curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) ++ (curr_bss->beacon_buf + ++ curr_bss->ht_info_offset); ++ ++ if (curr_bss->bcn_bss_co_2040) ++ curr_bss->bcn_bss_co_2040 = ++ (u8 *) (curr_bss->beacon_buf + ++ curr_bss->bss_co_2040_offset); ++ ++ if (curr_bss->bcn_ext_cap) ++ curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf + ++ curr_bss->ext_cap_offset); ++ ++ if (curr_bss->bcn_obss_scan) ++ curr_bss->bcn_obss_scan = ++ (struct ieee_types_obss_scan_param *) ++ (curr_bss->beacon_buf + ++ curr_bss->overlap_bss_offset); ++ ++ spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); ++ ++ dev_dbg(adapter->dev, "info: current beacon restored %d\n", ++ priv->curr_bcn_size); ++ } else { ++ dev_warn(adapter->dev, ++ "curr_bcn_buf not saved or bcn_buf has no space\n"); ++ } ++} ++ ++/* ++ * This function post processes the scan table after a new scan command has ++ * completed. ++ * ++ * It inspects each entry of the scan table and tries to find an entry that ++ * matches with our current associated/joined network from the scan. If ++ * one is found, the stored copy of the BSS descriptor of our current network ++ * is updated. ++ * ++ * It also debug dumps the current scan table contents after processing is over. ++ */ ++static void ++mwifiex_process_scan_results(struct mwifiex_private *priv) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ s32 j; ++ u32 i; ++ unsigned long flags; ++ ++ if (priv->media_connected) { ++ ++ j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params. ++ bss_descriptor.ssid, ++ priv->curr_bss_params. ++ bss_descriptor.mac_address, ++ priv->bss_mode); ++ ++ if (j >= 0) { ++ spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); ++ priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL; ++ priv->curr_bss_params.bss_descriptor.wpa_offset = 0; ++ priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL; ++ priv->curr_bss_params.bss_descriptor.rsn_offset = 0; ++ priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL; ++ priv->curr_bss_params.bss_descriptor.wapi_offset = 0; ++ priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL; ++ priv->curr_bss_params.bss_descriptor.ht_cap_offset = ++ 0; ++ priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL; ++ priv->curr_bss_params.bss_descriptor.ht_info_offset = ++ 0; ++ priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = ++ NULL; ++ priv->curr_bss_params.bss_descriptor. ++ bss_co_2040_offset = 0; ++ priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL; ++ priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0; ++ priv->curr_bss_params.bss_descriptor. ++ bcn_obss_scan = NULL; ++ priv->curr_bss_params.bss_descriptor. ++ overlap_bss_offset = 0; ++ priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; ++ priv->curr_bss_params.bss_descriptor.beacon_buf_size = ++ 0; ++ priv->curr_bss_params.bss_descriptor. ++ beacon_buf_size_max = 0; ++ ++ dev_dbg(adapter->dev, "info: Found current ssid/bssid" ++ " in list @ index #%d\n", j); ++ /* Make a copy of current BSSID descriptor */ ++ memcpy(&priv->curr_bss_params.bss_descriptor, ++ &adapter->scan_table[j], ++ sizeof(priv->curr_bss_params.bss_descriptor)); ++ ++ mwifiex_save_curr_bcn(priv); ++ spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); ++ ++ } else { ++ mwifiex_restore_curr_bcn(priv); ++ } ++ } ++ ++ for (i = 0; i < adapter->num_in_scan_table; i++) ++ dev_dbg(adapter->dev, "info: scan:(%02d) %pM " ++ "RSSI[%03d], SSID[%s]\n", ++ i, adapter->scan_table[i].mac_address, ++ (s32) adapter->scan_table[i].rssi, ++ adapter->scan_table[i].ssid.ssid); ++} ++ ++/* ++ * This function converts radio type scan parameter to a band configuration ++ * to be used in join command. ++ */ ++static u8 ++mwifiex_radio_type_to_band(u8 radio_type) ++{ ++ switch (radio_type) { ++ case HostCmd_SCAN_RADIO_TYPE_A: ++ return BAND_A; ++ case HostCmd_SCAN_RADIO_TYPE_BG: ++ default: ++ return BAND_G; ++ } ++} ++ ++/* ++ * This function deletes a specific indexed entry from the scan table. ++ * ++ * This also compacts the remaining entries and adjusts any buffering ++ * of beacon/probe response data if needed. ++ */ ++static void ++mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ u32 del_idx; ++ u32 beacon_buf_adj; ++ u8 *beacon_buf; ++ ++ /* ++ * Shift the saved beacon buffer data for the scan table back over the ++ * entry being removed. Update the end of buffer pointer. Save the ++ * deleted buffer allocation size for pointer adjustments for entries ++ * compacted after the deleted index. ++ */ ++ beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max; ++ ++ dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer " ++ "removal = %d bytes\n", table_idx, beacon_buf_adj); ++ ++ /* Check if the table entry had storage allocated for its beacon */ ++ if (beacon_buf_adj) { ++ beacon_buf = adapter->scan_table[table_idx].beacon_buf; ++ ++ /* ++ * Remove the entry's buffer space, decrement the table end ++ * pointer by the amount we are removing ++ */ ++ adapter->bcn_buf_end -= beacon_buf_adj; ++ ++ dev_dbg(adapter->dev, "info: scan: delete entry %d," ++ " compact data: %p <- %p (sz = %d)\n", ++ table_idx, beacon_buf, ++ beacon_buf + beacon_buf_adj, ++ (int)(adapter->bcn_buf_end - beacon_buf)); ++ ++ /* ++ * Compact data storage. Copy all data after the deleted ++ * entry's end address (beacon_buf + beacon_buf_adj) back ++ * to the original start address (beacon_buf). ++ * ++ * Scan table entries affected by the move will have their ++ * entry pointer adjusted below. ++ * ++ * Use memmove since the dest/src memory regions overlap. ++ */ ++ memmove(beacon_buf, beacon_buf + beacon_buf_adj, ++ adapter->bcn_buf_end - beacon_buf); ++ } ++ ++ dev_dbg(adapter->dev, ++ "info: Scan: Delete Entry %d, num_in_scan_table = %d\n", ++ table_idx, adapter->num_in_scan_table); ++ ++ /* Shift all of the entries after the table_idx back by one, compacting ++ the table and removing the requested entry */ ++ for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table; ++ del_idx++) { ++ /* Copy the next entry over this one */ ++ memcpy(adapter->scan_table + del_idx, ++ adapter->scan_table + del_idx + 1, ++ sizeof(struct mwifiex_bssdescriptor)); ++ ++ /* ++ * Adjust this entry's pointer to its beacon buffer based on ++ * the removed/compacted entry from the deleted index. Don't ++ * decrement if the buffer pointer is NULL (no data stored for ++ * this entry). ++ */ ++ if (adapter->scan_table[del_idx].beacon_buf) { ++ adapter->scan_table[del_idx].beacon_buf -= ++ beacon_buf_adj; ++ if (adapter->scan_table[del_idx].bcn_wpa_ie) ++ adapter->scan_table[del_idx].bcn_wpa_ie = ++ (struct ieee_types_vendor_specific *) ++ (adapter->scan_table[del_idx]. ++ beacon_buf + ++ adapter->scan_table[del_idx]. ++ wpa_offset); ++ if (adapter->scan_table[del_idx].bcn_rsn_ie) ++ adapter->scan_table[del_idx].bcn_rsn_ie = ++ (struct ieee_types_generic *) ++ (adapter->scan_table[del_idx]. ++ beacon_buf + ++ adapter->scan_table[del_idx]. ++ rsn_offset); ++ if (adapter->scan_table[del_idx].bcn_wapi_ie) ++ adapter->scan_table[del_idx].bcn_wapi_ie = ++ (struct ieee_types_generic *) ++ (adapter->scan_table[del_idx].beacon_buf ++ + adapter->scan_table[del_idx]. ++ wapi_offset); ++ if (adapter->scan_table[del_idx].bcn_ht_cap) ++ adapter->scan_table[del_idx].bcn_ht_cap = ++ (struct ieee80211_ht_cap *) ++ (adapter->scan_table[del_idx].beacon_buf ++ + adapter->scan_table[del_idx]. ++ ht_cap_offset); ++ ++ if (adapter->scan_table[del_idx].bcn_ht_info) ++ adapter->scan_table[del_idx].bcn_ht_info = ++ (struct ieee80211_ht_info *) ++ (adapter->scan_table[del_idx].beacon_buf ++ + adapter->scan_table[del_idx]. ++ ht_info_offset); ++ if (adapter->scan_table[del_idx].bcn_bss_co_2040) ++ adapter->scan_table[del_idx].bcn_bss_co_2040 = ++ (u8 *) ++ (adapter->scan_table[del_idx].beacon_buf ++ + adapter->scan_table[del_idx]. ++ bss_co_2040_offset); ++ if (adapter->scan_table[del_idx].bcn_ext_cap) ++ adapter->scan_table[del_idx].bcn_ext_cap = ++ (u8 *) ++ (adapter->scan_table[del_idx].beacon_buf ++ + adapter->scan_table[del_idx]. ++ ext_cap_offset); ++ if (adapter->scan_table[del_idx].bcn_obss_scan) ++ adapter->scan_table[del_idx]. ++ bcn_obss_scan = ++ (struct ieee_types_obss_scan_param *) ++ (adapter->scan_table[del_idx].beacon_buf ++ + adapter->scan_table[del_idx]. ++ overlap_bss_offset); ++ } ++ } ++ ++ /* The last entry is invalid now that it has been deleted or moved ++ back */ ++ memset(adapter->scan_table + adapter->num_in_scan_table - 1, ++ 0x00, sizeof(struct mwifiex_bssdescriptor)); ++ ++ adapter->num_in_scan_table--; ++} ++ ++/* ++ * This function deletes all occurrences of a given SSID from the scan table. ++ * ++ * This iterates through the scan table and deletes all entries that match ++ * the given SSID. It also compacts the remaining scan table entries. ++ */ ++static int ++mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, ++ struct mwifiex_802_11_ssid *del_ssid) ++{ ++ s32 table_idx = -1; ++ ++ dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n", ++ del_ssid->ssid); ++ ++ /* If the requested SSID is found in the table, delete it. Then keep ++ searching the table for multiple entires for the SSID until no ++ more are found */ ++ while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL, ++ NL80211_IFTYPE_UNSPECIFIED)) >= 0) { ++ dev_dbg(priv->adapter->dev, ++ "info: Scan: Delete SSID Entry: Found Idx = %d\n", ++ table_idx); ++ mwifiex_scan_delete_table_entry(priv, table_idx); ++ } ++ ++ return table_idx == -1 ? -1 : 0; ++} ++ ++/* ++ * This is an internal function used to start a scan based on an input ++ * configuration. ++ * ++ * This uses the input user scan configuration information when provided in ++ * order to send the appropriate scan commands to firmware to populate or ++ * update the internal driver scan table. ++ */ ++int mwifiex_scan_networks(struct mwifiex_private *priv, ++ const struct mwifiex_user_scan_cfg *user_scan_in) ++{ ++ int ret = 0; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct cmd_ctrl_node *cmd_node = NULL; ++ union mwifiex_scan_cmd_config_tlv *scan_cfg_out = NULL; ++ struct mwifiex_ie_types_chan_list_param_set *chan_list_out; ++ u32 buf_size; ++ struct mwifiex_chan_scan_param_set *scan_chan_list; ++ u8 keep_previous_scan; ++ u8 filtered_scan; ++ u8 scan_current_chan_only; ++ u8 max_chan_per_scan; ++ unsigned long flags; ++ ++ if (adapter->scan_processing) { ++ dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); ++ return ret; ++ } ++ ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); ++ adapter->scan_processing = true; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); ++ ++ if (priv->scan_block) { ++ dev_dbg(adapter->dev, ++ "cmd: Scan is blocked during association...\n"); ++ return ret; ++ } ++ ++ scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv), ++ GFP_KERNEL); ++ if (!scan_cfg_out) { ++ dev_err(adapter->dev, "failed to alloc scan_cfg_out\n"); ++ return -1; ++ } ++ ++ buf_size = sizeof(struct mwifiex_chan_scan_param_set) * ++ MWIFIEX_USER_SCAN_CHAN_MAX; ++ scan_chan_list = kzalloc(buf_size, GFP_KERNEL); ++ if (!scan_chan_list) { ++ dev_err(adapter->dev, "failed to alloc scan_chan_list\n"); ++ kfree(scan_cfg_out); ++ return -1; ++ } ++ ++ keep_previous_scan = false; ++ ++ mwifiex_scan_setup_scan_config(priv, user_scan_in, ++ &scan_cfg_out->config, &chan_list_out, ++ scan_chan_list, &max_chan_per_scan, ++ &filtered_scan, &scan_current_chan_only); ++ ++ if (user_scan_in) ++ keep_previous_scan = user_scan_in->keep_previous_scan; ++ ++ ++ if (!keep_previous_scan) { ++ memset(adapter->scan_table, 0x00, ++ sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); ++ adapter->num_in_scan_table = 0; ++ adapter->bcn_buf_end = adapter->bcn_buf; ++ } ++ ++ ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan, ++ &scan_cfg_out->config, chan_list_out, ++ scan_chan_list); ++ ++ /* Get scan command from scan_pending_q and put to cmd_pending_q */ ++ if (!ret) { ++ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); ++ if (!list_empty(&adapter->scan_pending_q)) { ++ cmd_node = list_first_entry(&adapter->scan_pending_q, ++ struct cmd_ctrl_node, list); ++ list_del(&cmd_node->list); ++ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, ++ flags); ++ mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, ++ true); ++ } else { ++ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, ++ flags); ++ } ++ } else { ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); ++ adapter->scan_processing = true; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); ++ } ++ ++ kfree(scan_cfg_out); ++ kfree(scan_chan_list); ++ return ret; ++} ++ ++/* ++ * This function prepares a scan command to be sent to the firmware. ++ * ++ * This uses the scan command configuration sent to the command processing ++ * module in command preparation stage to configure a scan command structure ++ * to send to firmware. ++ * ++ * The fixed fields specifying the BSS type and BSSID filters as well as a ++ * variable number/length of TLVs are sent in the command to firmware. ++ * ++ * Preparation also includes - ++ * - Setting command ID, and proper size ++ * - Ensuring correct endian-ness ++ */ ++int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, void *data_buf) ++{ ++ struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan; ++ struct mwifiex_scan_cmd_config *scan_cfg; ++ ++ scan_cfg = (struct mwifiex_scan_cmd_config *) data_buf; ++ ++ /* Set fixed field variables in scan command */ ++ scan_cmd->bss_mode = scan_cfg->bss_mode; ++ memcpy(scan_cmd->bssid, scan_cfg->specific_bssid, ++ sizeof(scan_cmd->bssid)); ++ memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len); ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN); ++ ++ /* Size is equal to the sizeof(fixed portions) + the TLV len + header */ ++ cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode) ++ + sizeof(scan_cmd->bssid) ++ + scan_cfg->tlv_buf_len + S_DS_GEN)); ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of scan. ++ * ++ * The response buffer for the scan command has the following ++ * memory layout: ++ * ++ * .-------------------------------------------------------------. ++ * | Header (4 * sizeof(t_u16)): Standard command response hdr | ++ * .-------------------------------------------------------------. ++ * | BufSize (t_u16) : sizeof the BSS Description data | ++ * .-------------------------------------------------------------. ++ * | NumOfSet (t_u8) : Number of BSS Descs returned | ++ * .-------------------------------------------------------------. ++ * | BSSDescription data (variable, size given in BufSize) | ++ * .-------------------------------------------------------------. ++ * | TLV data (variable, size calculated using Header->Size, | ++ * | BufSize and sizeof the fixed fields above) | ++ * .-------------------------------------------------------------. ++ */ ++int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ int ret = 0; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct cmd_ctrl_node *cmd_node = NULL; ++ struct host_cmd_ds_802_11_scan_rsp *scan_rsp = NULL; ++ struct mwifiex_bssdescriptor *bss_new_entry = NULL; ++ struct mwifiex_ie_types_data *tlv_data; ++ struct mwifiex_ie_types_tsf_timestamp *tsf_tlv; ++ u8 *bss_info; ++ u32 scan_resp_size; ++ u32 bytes_left; ++ u32 num_in_table; ++ u32 bss_idx; ++ u32 idx; ++ u32 tlv_buf_size; ++ long long tsf_val; ++ struct mwifiex_chan_freq_power *cfp; ++ struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; ++ struct chan_band_param_set *chan_band; ++ u8 band; ++ u8 is_bgscan_resp; ++ unsigned long flags; ++ ++ is_bgscan_resp = (le16_to_cpu(resp->command) ++ == HostCmd_CMD_802_11_BG_SCAN_QUERY); ++ if (is_bgscan_resp) ++ scan_rsp = &resp->params.bg_scan_query_resp.scan_resp; ++ else ++ scan_rsp = &resp->params.scan_resp; ++ ++ ++ if (scan_rsp->number_of_sets > IW_MAX_AP) { ++ dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", ++ scan_rsp->number_of_sets); ++ ret = -1; ++ goto done; ++ } ++ ++ bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); ++ dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n", ++ bytes_left); ++ ++ scan_resp_size = le16_to_cpu(resp->size); ++ ++ dev_dbg(adapter->dev, ++ "info: SCAN_RESP: returned %d APs before parsing\n", ++ scan_rsp->number_of_sets); ++ ++ num_in_table = adapter->num_in_scan_table; ++ bss_info = scan_rsp->bss_desc_and_tlv_buffer; ++ ++ /* ++ * The size of the TLV buffer is equal to the entire command response ++ * size (scan_resp_size) minus the fixed fields (sizeof()'s), the ++ * BSS Descriptions (bss_descript_size as bytesLef) and the command ++ * response header (S_DS_GEN) ++ */ ++ tlv_buf_size = scan_resp_size - (bytes_left ++ + sizeof(scan_rsp->bss_descript_size) ++ + sizeof(scan_rsp->number_of_sets) ++ + S_DS_GEN); ++ ++ tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp-> ++ bss_desc_and_tlv_buffer + ++ bytes_left); ++ ++ /* Search the TLV buffer space in the scan response for any valid ++ TLVs */ ++ mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, ++ TLV_TYPE_TSFTIMESTAMP, ++ (struct mwifiex_ie_types_data **) ++ &tsf_tlv); ++ ++ /* Search the TLV buffer space in the scan response for any valid ++ TLVs */ ++ mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, ++ TLV_TYPE_CHANNELBANDLIST, ++ (struct mwifiex_ie_types_data **) ++ &chan_band_tlv); ++ ++ /* ++ * Process each scan response returned (scan_rsp->number_of_sets). ++ * Save the information in the bss_new_entry and then insert into the ++ * driver scan table either as an update to an existing entry ++ * or as an addition at the end of the table ++ */ ++ bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor), ++ GFP_KERNEL); ++ if (!bss_new_entry) { ++ dev_err(adapter->dev, " failed to alloc bss_new_entry\n"); ++ return -1; ++ } ++ ++ for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { ++ /* Zero out the bss_new_entry we are about to store info in */ ++ memset(bss_new_entry, 0x00, ++ sizeof(struct mwifiex_bssdescriptor)); ++ ++ if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry, ++ &bss_info, ++ &bytes_left)) { ++ /* Error parsing/interpreting scan response, skipped */ ++ dev_err(adapter->dev, "SCAN_RESP: " ++ "mwifiex_interpret_bss_desc_with_ie " ++ "returned ERROR\n"); ++ continue; ++ } ++ ++ /* Process the data fields and IEs returned for this BSS */ ++ dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n", ++ bss_new_entry->mac_address); ++ ++ /* Search the scan table for the same bssid */ ++ for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) { ++ if (memcmp(bss_new_entry->mac_address, ++ adapter->scan_table[bss_idx].mac_address, ++ sizeof(bss_new_entry->mac_address))) { ++ continue; ++ } ++ /* ++ * If the SSID matches as well, it is a ++ * duplicate of this entry. Keep the bss_idx ++ * set to this entry so we replace the old ++ * contents in the table ++ */ ++ if ((bss_new_entry->ssid.ssid_len ++ == adapter->scan_table[bss_idx]. ssid.ssid_len) ++ && (!memcmp(bss_new_entry->ssid.ssid, ++ adapter->scan_table[bss_idx].ssid.ssid, ++ bss_new_entry->ssid.ssid_len))) { ++ dev_dbg(adapter->dev, "info: SCAN_RESP:" ++ " duplicate of index: %d\n", bss_idx); ++ break; ++ } ++ } ++ /* ++ * If the bss_idx is equal to the number of entries in ++ * the table, the new entry was not a duplicate; append ++ * it to the scan table ++ */ ++ if (bss_idx == num_in_table) { ++ /* Range check the bss_idx, keep it limited to ++ the last entry */ ++ if (bss_idx == IW_MAX_AP) ++ bss_idx--; ++ else ++ num_in_table++; ++ } ++ ++ /* ++ * Save the beacon/probe response returned for later application ++ * retrieval. Duplicate beacon/probe responses are updated if ++ * possible ++ */ ++ mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx, ++ num_in_table, bss_new_entry); ++ /* ++ * If the TSF TLV was appended to the scan results, save this ++ * entry's TSF value in the networkTSF field.The networkTSF is ++ * the firmware's TSF value at the time the beacon or probe ++ * response was received. ++ */ ++ if (tsf_tlv) { ++ memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE] ++ , sizeof(tsf_val)); ++ memcpy(&bss_new_entry->network_tsf, &tsf_val, ++ sizeof(bss_new_entry->network_tsf)); ++ } ++ band = BAND_G; ++ if (chan_band_tlv) { ++ chan_band = &chan_band_tlv->chan_band_param[idx]; ++ band = mwifiex_radio_type_to_band(chan_band->radio_type ++ & (BIT(0) | BIT(1))); ++ } ++ ++ /* Save the band designation for this entry for use in join */ ++ bss_new_entry->bss_band = band; ++ cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, ++ (u8) bss_new_entry->bss_band, ++ (u16)bss_new_entry->channel); ++ ++ if (cfp) ++ bss_new_entry->freq = cfp->freq; ++ else ++ bss_new_entry->freq = 0; ++ ++ /* Copy the locally created bss_new_entry to the scan table */ ++ memcpy(&adapter->scan_table[bss_idx], bss_new_entry, ++ sizeof(adapter->scan_table[bss_idx])); ++ ++ } ++ ++ dev_dbg(adapter->dev, ++ "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", ++ scan_rsp->number_of_sets, ++ num_in_table - adapter->num_in_scan_table, num_in_table); ++ ++ /* Update the total number of BSSIDs in the scan table */ ++ adapter->num_in_scan_table = num_in_table; ++ ++ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); ++ if (list_empty(&adapter->scan_pending_q)) { ++ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); ++ adapter->scan_processing = false; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); ++ /* ++ * Process the resulting scan table: ++ * - Remove any bad ssids ++ * - Update our current BSS information from scan data ++ */ ++ mwifiex_process_scan_results(priv); ++ ++ /* Need to indicate IOCTL complete */ ++ if (adapter->curr_cmd->wait_q_enabled) { ++ adapter->cmd_wait_q.status = 0; ++ mwifiex_complete_cmd(adapter); ++ } ++ if (priv->report_scan_result) ++ priv->report_scan_result = false; ++ if (priv->scan_pending_on_block) { ++ priv->scan_pending_on_block = false; ++ up(&priv->async_sem); ++ } ++ ++ } else { ++ /* Get scan command from scan_pending_q and put to ++ cmd_pending_q */ ++ cmd_node = list_first_entry(&adapter->scan_pending_q, ++ struct cmd_ctrl_node, list); ++ list_del(&cmd_node->list); ++ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); ++ ++ mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); ++ } ++ ++done: ++ kfree((u8 *) bss_new_entry); ++ return ret; ++} ++ ++/* ++ * This function prepares command for background scan query. ++ * ++ * Preparation includes - ++ * - Setting command ID and proper size ++ * - Setting background scan flush parameter ++ * - Ensuring correct endian-ness ++ */ ++int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd) ++{ ++ struct host_cmd_ds_802_11_bg_scan_query *bg_query = ++ &cmd->params.bg_scan_query; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY); ++ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query) ++ + S_DS_GEN); ++ ++ bg_query->flush = 1; ++ ++ return 0; ++} ++ ++/* ++ * This function finds a SSID in the scan table. ++ * ++ * A BSSID may optionally be provided to qualify the SSID. ++ * For non-Auto mode, further check is made to make sure the ++ * BSS found in the scan table is compatible with the current ++ * settings of the driver. ++ */ ++s32 ++mwifiex_find_ssid_in_list(struct mwifiex_private *priv, ++ struct mwifiex_802_11_ssid *ssid, u8 *bssid, ++ u32 mode) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ s32 net = -1, j; ++ u8 best_rssi = 0; ++ u32 i; ++ ++ dev_dbg(adapter->dev, "info: num of entries in table = %d\n", ++ adapter->num_in_scan_table); ++ ++ /* ++ * Loop through the table until the maximum is reached or until a match ++ * is found based on the bssid field comparison ++ */ ++ for (i = 0; ++ i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0)); ++ i++) { ++ if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) && ++ (!bssid ++ || !memcmp(adapter->scan_table[i].mac_address, bssid, ++ ETH_ALEN)) ++ && ++ (mwifiex_get_cfp_by_band_and_channel_from_cfg80211 ++ (priv, (u8) adapter->scan_table[i].bss_band, ++ (u16) adapter->scan_table[i].channel))) { ++ switch (mode) { ++ case NL80211_IFTYPE_STATION: ++ case NL80211_IFTYPE_ADHOC: ++ j = mwifiex_is_network_compatible(priv, i, ++ mode); ++ ++ if (j >= 0) { ++ if (SCAN_RSSI ++ (adapter->scan_table[i].rssi) > ++ best_rssi) { ++ best_rssi = SCAN_RSSI(adapter-> ++ scan_table ++ [i].rssi); ++ net = i; ++ } ++ } else { ++ if (net == -1) ++ net = j; ++ } ++ break; ++ case NL80211_IFTYPE_UNSPECIFIED: ++ default: ++ /* ++ * Do not check compatibility if the mode ++ * requested is Auto/Unknown. Allows generic ++ * find to work without verifying against the ++ * Adapter security settings ++ */ ++ if (SCAN_RSSI(adapter->scan_table[i].rssi) > ++ best_rssi) { ++ best_rssi = SCAN_RSSI(adapter-> ++ scan_table[i].rssi); ++ net = i; ++ } ++ break; ++ } ++ } ++ } ++ ++ return net; ++} ++ ++/* ++ * This function finds a specific compatible BSSID in the scan list. ++ * ++ * This function loops through the scan table looking for a compatible ++ * match. If a BSSID matches, but the BSS is found to be not compatible ++ * the function ignores it and continues to search through the rest of ++ * the entries in case there is an AP with multiple SSIDs assigned to ++ * the same BSSID. ++ */ ++s32 ++mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, ++ u32 mode) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ s32 net = -1; ++ u32 i; ++ ++ if (!bssid) ++ return -1; ++ ++ dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n", ++ adapter->num_in_scan_table); ++ ++ /* ++ * Look through the scan table for a compatible match. The ret return ++ * variable will be equal to the index in the scan table (greater ++ * than zero) if the network is compatible. The loop will continue ++ * past a matched bssid that is not compatible in case there is an ++ * AP with multiple SSIDs assigned to the same BSSID ++ */ ++ for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) { ++ if (!memcmp ++ (adapter->scan_table[i].mac_address, bssid, ETH_ALEN) ++ && mwifiex_get_cfp_by_band_and_channel_from_cfg80211 ++ (priv, ++ (u8) adapter-> ++ scan_table[i]. ++ bss_band, ++ (u16) adapter-> ++ scan_table[i]. ++ channel)) { ++ switch (mode) { ++ case NL80211_IFTYPE_STATION: ++ case NL80211_IFTYPE_ADHOC: ++ net = mwifiex_is_network_compatible(priv, i, ++ mode); ++ break; ++ default: ++ net = i; ++ break; ++ } ++ } ++ } ++ ++ return net; ++} ++ ++/* ++ * This function inserts scan command node to the scan pending queue. ++ */ ++void ++mwifiex_queue_scan_cmd(struct mwifiex_private *priv, ++ struct cmd_ctrl_node *cmd_node) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ unsigned long flags; ++ ++ cmd_node->wait_q_enabled = true; ++ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); ++ list_add_tail(&cmd_node->list, &adapter->scan_pending_q); ++ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); ++} ++ ++/* ++ * This function finds an AP with specific ssid in the scan list. ++ */ ++int mwifiex_find_best_network(struct mwifiex_private *priv, ++ struct mwifiex_ssid_bssid *req_ssid_bssid) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct mwifiex_bssdescriptor *req_bss; ++ s32 i; ++ ++ memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); ++ ++ i = mwifiex_find_best_network_in_list(priv); ++ ++ if (i >= 0) { ++ req_bss = &adapter->scan_table[i]; ++ memcpy(&req_ssid_bssid->ssid, &req_bss->ssid, ++ sizeof(struct mwifiex_802_11_ssid)); ++ memcpy((u8 *) &req_ssid_bssid->bssid, ++ (u8 *) &req_bss->mac_address, ETH_ALEN); ++ ++ /* Make sure we are in the right mode */ ++ if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) ++ priv->bss_mode = req_bss->bss_mode; ++ } ++ ++ if (!req_ssid_bssid->ssid.ssid_len) ++ return -1; ++ ++ dev_dbg(adapter->dev, "info: Best network found = [%s], " ++ "[%pM]\n", req_ssid_bssid->ssid.ssid, ++ req_ssid_bssid->bssid); ++ ++ return 0; ++} ++ ++/* ++ * This function sends a scan command for all available channels to the ++ * firmware, filtered on a specific SSID. ++ */ ++static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, ++ struct mwifiex_802_11_ssid *req_ssid) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ int ret = 0; ++ struct mwifiex_user_scan_cfg *scan_cfg; ++ ++ if (!req_ssid) ++ return -1; ++ ++ if (adapter->scan_processing) { ++ dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); ++ return ret; ++ } ++ ++ if (priv->scan_block) { ++ dev_dbg(adapter->dev, ++ "cmd: Scan is blocked during association...\n"); ++ return ret; ++ } ++ ++ mwifiex_scan_delete_ssid_table_entry(priv, req_ssid); ++ ++ scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); ++ if (!scan_cfg) { ++ dev_err(adapter->dev, "failed to alloc scan_cfg\n"); ++ return -1; ++ } ++ ++ memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid, ++ req_ssid->ssid_len); ++ scan_cfg->keep_previous_scan = true; ++ ++ ret = mwifiex_scan_networks(priv, scan_cfg); ++ ++ kfree(scan_cfg); ++ return ret; ++} ++ ++/* ++ * Sends IOCTL request to start a scan. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ * ++ * Scan command can be issued for both normal scan and specific SSID ++ * scan, depending upon whether an SSID is provided or not. ++ */ ++int mwifiex_request_scan(struct mwifiex_private *priv, ++ struct mwifiex_802_11_ssid *req_ssid) ++{ ++ int ret = 0; ++ ++ if (down_interruptible(&priv->async_sem)) { ++ dev_err(priv->adapter->dev, "%s: acquire semaphore\n", ++ __func__); ++ return -1; ++ } ++ priv->scan_pending_on_block = true; ++ ++ priv->adapter->cmd_wait_q.condition = false; ++ ++ if (req_ssid && req_ssid->ssid_len != 0) ++ /* Specific SSID scan */ ++ ret = mwifiex_scan_specific_ssid(priv, req_ssid); ++ else ++ /* Normal scan */ ++ ret = mwifiex_scan_networks(priv, NULL); ++ ++ if (!ret) ++ ret = mwifiex_wait_queue_complete(priv->adapter); ++ ++ if (ret == -1) { ++ priv->scan_pending_on_block = false; ++ up(&priv->async_sem); ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function appends the vendor specific IE TLV to a buffer. ++ */ ++int ++mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, ++ u16 vsie_mask, u8 **buffer) ++{ ++ int id, ret_len = 0; ++ struct mwifiex_ie_types_vendor_param_set *vs_param_set; ++ ++ if (!buffer) ++ return 0; ++ if (!(*buffer)) ++ return 0; ++ ++ /* ++ * Traverse through the saved vendor specific IE array and append ++ * the selected(scan/assoc/adhoc) IE as TLV to the command ++ */ ++ for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) { ++ if (priv->vs_ie[id].mask & vsie_mask) { ++ vs_param_set = ++ (struct mwifiex_ie_types_vendor_param_set *) ++ *buffer; ++ vs_param_set->header.type = ++ cpu_to_le16(TLV_TYPE_PASSTHROUGH); ++ vs_param_set->header.len = ++ cpu_to_le16((((u16) priv->vs_ie[id].ie[1]) ++ & 0x00FF) + 2); ++ memcpy(vs_param_set->ie, priv->vs_ie[id].ie, ++ le16_to_cpu(vs_param_set->header.len)); ++ *buffer += le16_to_cpu(vs_param_set->header.len) + ++ sizeof(struct mwifiex_ie_types_header); ++ ret_len += le16_to_cpu(vs_param_set->header.len) + ++ sizeof(struct mwifiex_ie_types_header); ++ } ++ } ++ return ret_len; ++} ++ ++/* ++ * This function saves a beacon buffer of the current BSS descriptor. ++ * ++ * The current beacon buffer is saved so that it can be restored in the ++ * following cases that makes the beacon buffer not to contain the current ++ * ssid's beacon buffer. ++ * - The current ssid was not found somehow in the last scan. ++ * - The current ssid was the last entry of the scan table and overloaded. ++ */ ++void ++mwifiex_save_curr_bcn(struct mwifiex_private *priv) ++{ ++ struct mwifiex_bssdescriptor *curr_bss = ++ &priv->curr_bss_params.bss_descriptor; ++ ++ if (!curr_bss->beacon_buf_size) ++ return; ++ ++ /* allocate beacon buffer at 1st time; or if it's size has changed */ ++ if (!priv->curr_bcn_buf || ++ priv->curr_bcn_size != curr_bss->beacon_buf_size) { ++ priv->curr_bcn_size = curr_bss->beacon_buf_size; ++ ++ kfree(priv->curr_bcn_buf); ++ priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size, ++ GFP_KERNEL); ++ if (!priv->curr_bcn_buf) { ++ dev_err(priv->adapter->dev, ++ "failed to alloc curr_bcn_buf\n"); ++ return; ++ } ++ } ++ ++ memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, ++ curr_bss->beacon_buf_size); ++ dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n", ++ priv->curr_bcn_size); ++} ++ ++/* ++ * This function frees the current BSS descriptor beacon buffer. ++ */ ++void ++mwifiex_free_curr_bcn(struct mwifiex_private *priv) ++{ ++ kfree(priv->curr_bcn_buf); ++ priv->curr_bcn_buf = NULL; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sdio.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sdio.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sdio.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sdio.c 2011-05-05 23:29:45.493441961 +0200 +@@ -0,0 +1,1753 @@ ++/* ++ * Marvell Wireless LAN device driver: SDIO specific handling ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++#include "sdio.h" ++ ++ ++#define SDIO_VERSION "1.0" ++ ++static struct mwifiex_if_ops sdio_ops; ++ ++static struct semaphore add_remove_card_sem; ++ ++/* ++ * SDIO probe. ++ * ++ * This function probes an mwifiex device and registers it. It allocates ++ * the card structure, enables SDIO function number and initiates the ++ * device registration and initialization procedure by adding a logical ++ * interface. ++ */ ++static int ++mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) ++{ ++ int ret = 0; ++ struct sdio_mmc_card *card = NULL; ++ ++ pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n", ++ func->vendor, func->device, func->class, func->num); ++ ++ card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL); ++ if (!card) { ++ pr_err("%s: failed to alloc memory\n", __func__); ++ return -ENOMEM; ++ } ++ ++ card->func = func; ++ ++ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; ++ ++ sdio_claim_host(func); ++ ret = sdio_enable_func(func); ++ sdio_release_host(func); ++ ++ if (ret) { ++ pr_err("%s: failed to enable function\n", __func__); ++ return -EIO; ++ } ++ ++ if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) { ++ pr_err("%s: add card failed\n", __func__); ++ kfree(card); ++ sdio_claim_host(func); ++ ret = sdio_disable_func(func); ++ sdio_release_host(func); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++/* ++ * SDIO remove. ++ * ++ * This function removes the interface and frees up the card structure. ++ */ ++static void ++mwifiex_sdio_remove(struct sdio_func *func) ++{ ++ struct sdio_mmc_card *card; ++ ++ pr_debug("info: SDIO func num=%d\n", func->num); ++ ++ if (func) { ++ card = sdio_get_drvdata(func); ++ if (card) { ++ mwifiex_remove_card(card->adapter, ++ &add_remove_card_sem); ++ kfree(card); ++ } ++ } ++} ++ ++/* ++ * SDIO suspend. ++ * ++ * Kernel needs to suspend all functions separately. Therefore all ++ * registered functions must have drivers with suspend and resume ++ * methods. Failing that the kernel simply removes the whole card. ++ * ++ * If already not suspended, this function allocates and sends a host ++ * sleep activate request to the firmware and turns off the traffic. ++ */ ++static int mwifiex_sdio_suspend(struct device *dev) ++{ ++ struct sdio_func *func = dev_to_sdio_func(dev); ++ struct sdio_mmc_card *card; ++ struct mwifiex_adapter *adapter = NULL; ++ mmc_pm_flag_t pm_flag = 0; ++ int hs_actived = 0; ++ int i; ++ int ret = 0; ++ ++ if (func) { ++ pm_flag = sdio_get_host_pm_caps(func); ++ pr_debug("cmd: %s: suspend: PM flag = 0x%x\n", ++ sdio_func_id(func), pm_flag); ++ if (!(pm_flag & MMC_PM_KEEP_POWER)) { ++ pr_err("%s: cannot remain alive while host is" ++ " suspended\n", sdio_func_id(func)); ++ return -ENOSYS; ++ } ++ ++ card = sdio_get_drvdata(func); ++ if (!card || !card->adapter) { ++ pr_err("suspend: invalid card or adapter\n"); ++ return 0; ++ } ++ } else { ++ pr_err("suspend: sdio_func is not specified\n"); ++ return 0; ++ } ++ ++ adapter = card->adapter; ++ ++ /* Enable the Host Sleep */ ++ hs_actived = mwifiex_enable_hs(adapter); ++ if (hs_actived) { ++ pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n"); ++ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); ++ } ++ ++ /* Indicate device suspended */ ++ adapter->is_suspended = true; ++ ++ for (i = 0; i < adapter->priv_num; i++) ++ netif_carrier_off(adapter->priv[i]->netdev); ++ ++ return ret; ++} ++ ++/* ++ * SDIO resume. ++ * ++ * Kernel needs to suspend all functions separately. Therefore all ++ * registered functions must have drivers with suspend and resume ++ * methods. Failing that the kernel simply removes the whole card. ++ * ++ * If already not resumed, this function turns on the traffic and ++ * sends a host sleep cancel request to the firmware. ++ */ ++static int mwifiex_sdio_resume(struct device *dev) ++{ ++ struct sdio_func *func = dev_to_sdio_func(dev); ++ struct sdio_mmc_card *card; ++ struct mwifiex_adapter *adapter = NULL; ++ mmc_pm_flag_t pm_flag = 0; ++ int i; ++ ++ if (func) { ++ pm_flag = sdio_get_host_pm_caps(func); ++ card = sdio_get_drvdata(func); ++ if (!card || !card->adapter) { ++ pr_err("resume: invalid card or adapter\n"); ++ return 0; ++ } ++ } else { ++ pr_err("resume: sdio_func is not specified\n"); ++ return 0; ++ } ++ ++ adapter = card->adapter; ++ ++ if (!adapter->is_suspended) { ++ dev_warn(adapter->dev, "device already resumed\n"); ++ return 0; ++ } ++ ++ adapter->is_suspended = false; ++ ++ for (i = 0; i < adapter->priv_num; i++) ++ if (adapter->priv[i]->media_connected) ++ netif_carrier_on(adapter->priv[i]->netdev); ++ ++ /* Disable Host Sleep */ ++ mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), ++ MWIFIEX_ASYNC_CMD); ++ ++ return 0; ++} ++ ++/* Device ID for SD8787 */ ++#define SDIO_DEVICE_ID_MARVELL_8787 (0x9119) ++ ++/* WLAN IDs */ ++static const struct sdio_device_id mwifiex_ids[] = { ++ {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(sdio, mwifiex_ids); ++ ++static const struct dev_pm_ops mwifiex_sdio_pm_ops = { ++ .suspend = mwifiex_sdio_suspend, ++ .resume = mwifiex_sdio_resume, ++}; ++ ++static struct sdio_driver mwifiex_sdio = { ++ .name = "mwifiex_sdio", ++ .id_table = mwifiex_ids, ++ .probe = mwifiex_sdio_probe, ++ .remove = mwifiex_sdio_remove, ++ .drv = { ++ .owner = THIS_MODULE, ++ .pm = &mwifiex_sdio_pm_ops, ++ } ++}; ++ ++/* ++ * This function writes data into SDIO card register. ++ */ ++static int ++mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ int ret = -1; ++ ++ sdio_claim_host(card->func); ++ sdio_writeb(card->func, (u8) data, reg, &ret); ++ sdio_release_host(card->func); ++ ++ return ret; ++} ++ ++/* ++ * This function reads data from SDIO card register. ++ */ ++static int ++mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ int ret = -1; ++ u8 val; ++ ++ sdio_claim_host(card->func); ++ val = sdio_readb(card->func, reg, &ret); ++ sdio_release_host(card->func); ++ ++ *data = val; ++ ++ return ret; ++} ++ ++/* ++ * This function writes multiple data into SDIO card memory. ++ * ++ * This does not work in suspended mode. ++ */ ++static int ++mwifiex_write_data_sync(struct mwifiex_adapter *adapter, ++ u8 *buffer, u32 pkt_len, u32 port) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ int ret = -1; ++ u8 blk_mode = ++ (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; ++ u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; ++ u32 blk_cnt = ++ (blk_mode == ++ BLOCK_MODE) ? (pkt_len / ++ MWIFIEX_SDIO_BLOCK_SIZE) : pkt_len; ++ u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); ++ ++ if (adapter->is_suspended) { ++ dev_err(adapter->dev, ++ "%s: not allowed while suspended\n", __func__); ++ return -1; ++ } ++ ++ sdio_claim_host(card->func); ++ ++ if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size)) ++ ret = 0; ++ ++ sdio_release_host(card->func); ++ ++ return ret; ++} ++ ++/* ++ * This function reads multiple data from SDIO card memory. ++ */ ++static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, ++ u32 len, u32 port, u8 claim) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ int ret = -1; ++ u8 blk_mode = ++ (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; ++ u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; ++ u32 blk_cnt = ++ (blk_mode == ++ BLOCK_MODE) ? (len / MWIFIEX_SDIO_BLOCK_SIZE) : len; ++ u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); ++ ++ if (claim) ++ sdio_claim_host(card->func); ++ ++ if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size)) ++ ret = 0; ++ ++ if (claim) ++ sdio_release_host(card->func); ++ ++ return ret; ++} ++ ++/* ++ * This function wakes up the card. ++ * ++ * A host power up command is written to the card configuration ++ * register to wake up the card. ++ */ ++static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) ++{ ++ dev_dbg(adapter->dev, "event: wakeup device...\n"); ++ ++ return mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP); ++} ++ ++/* ++ * This function is called after the card has woken up. ++ * ++ * The card configuration register is reset. ++ */ ++static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) ++{ ++ dev_dbg(adapter->dev, "cmd: wakeup device completed\n"); ++ ++ return mwifiex_write_reg(adapter, CONFIGURATION_REG, 0); ++} ++ ++/* ++ * This function initializes the IO ports. ++ * ++ * The following operations are performed - ++ * - Read the IO ports (0, 1 and 2) ++ * - Set host interrupt Reset-To-Read to clear ++ * - Set auto re-enable interrupt ++ */ ++static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) ++{ ++ u32 reg; ++ ++ adapter->ioport = 0; ++ ++ /* Read the IO port */ ++ if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, ®)) ++ adapter->ioport |= (reg & 0xff); ++ else ++ return -1; ++ ++ if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, ®)) ++ adapter->ioport |= ((reg & 0xff) << 8); ++ else ++ return -1; ++ ++ if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, ®)) ++ adapter->ioport |= ((reg & 0xff) << 16); ++ else ++ return -1; ++ ++ pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); ++ ++ /* Set Host interrupt reset to read to clear */ ++ if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, ®)) ++ mwifiex_write_reg(adapter, HOST_INT_RSR_REG, ++ reg | SDIO_INT_MASK); ++ else ++ return -1; ++ ++ /* Dnld/Upld ready set to auto reset */ ++ if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, ®)) ++ mwifiex_write_reg(adapter, CARD_MISC_CFG_REG, ++ reg | AUTO_RE_ENABLE_INT); ++ else ++ return -1; ++ ++ return 0; ++} ++ ++/* ++ * This function sends data to the card. ++ */ ++static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter, ++ u8 *payload, u32 pkt_len, u32 port) ++{ ++ u32 i = 0; ++ int ret = 0; ++ ++ do { ++ ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port); ++ if (ret) { ++ i++; ++ dev_err(adapter->dev, "host_to_card, write iomem" ++ " (%d) failed: %d\n", i, ret); ++ if (mwifiex_write_reg(adapter, ++ CONFIGURATION_REG, 0x04)) ++ dev_err(adapter->dev, "write CFG reg failed\n"); ++ ++ ret = -1; ++ if (i > MAX_WRITE_IOMEM_RETRY) ++ return ret; ++ } ++ } while (ret == -1); ++ ++ return ret; ++} ++ ++/* ++ * This function gets the read port. ++ * ++ * If control port bit is set in MP read bitmap, the control port ++ * is returned, otherwise the current read port is returned and ++ * the value is increased (provided it does not reach the maximum ++ * limit, in which case it is reset to 1) ++ */ ++static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ u16 rd_bitmap = card->mp_rd_bitmap; ++ ++ dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%04x\n", rd_bitmap); ++ ++ if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK))) ++ return -1; ++ ++ if (card->mp_rd_bitmap & CTRL_PORT_MASK) { ++ card->mp_rd_bitmap &= (u16) (~CTRL_PORT_MASK); ++ *port = CTRL_PORT; ++ dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%04x\n", ++ *port, card->mp_rd_bitmap); ++ } else { ++ if (card->mp_rd_bitmap & (1 << card->curr_rd_port)) { ++ card->mp_rd_bitmap &= ++ (u16) (~(1 << card->curr_rd_port)); ++ *port = card->curr_rd_port; ++ ++ if (++card->curr_rd_port == MAX_PORT) ++ card->curr_rd_port = 1; ++ } else { ++ return -1; ++ } ++ ++ dev_dbg(adapter->dev, ++ "data: port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n", ++ *port, rd_bitmap, card->mp_rd_bitmap); ++ } ++ return 0; ++} ++ ++/* ++ * This function gets the write port for data. ++ * ++ * The current write port is returned if available and the value is ++ * increased (provided it does not reach the maximum limit, in which ++ * case it is reset to 1) ++ */ ++static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ u16 wr_bitmap = card->mp_wr_bitmap; ++ ++ dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%04x\n", wr_bitmap); ++ ++ if (!(wr_bitmap & card->mp_data_port_mask)) ++ return -1; ++ ++ if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { ++ card->mp_wr_bitmap &= (u16) (~(1 << card->curr_wr_port)); ++ *port = card->curr_wr_port; ++ if (++card->curr_wr_port == card->mp_end_port) ++ card->curr_wr_port = 1; ++ } else { ++ adapter->data_sent = true; ++ return -EBUSY; ++ } ++ ++ if (*port == CTRL_PORT) { ++ dev_err(adapter->dev, "invalid data port=%d cur port=%d" ++ " mp_wr_bitmap=0x%04x -> 0x%04x\n", ++ *port, card->curr_wr_port, wr_bitmap, ++ card->mp_wr_bitmap); ++ return -1; ++ } ++ ++ dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n", ++ *port, wr_bitmap, card->mp_wr_bitmap); ++ ++ return 0; ++} ++ ++/* ++ * This function polls the card status. ++ */ ++static int ++mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) ++{ ++ u32 tries; ++ u32 cs = 0; ++ ++ for (tries = 0; tries < MAX_POLL_TRIES; tries++) { ++ if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs)) ++ break; ++ else if ((cs & bits) == bits) ++ return 0; ++ ++ udelay(10); ++ } ++ ++ dev_err(adapter->dev, "poll card status failed, tries = %d\n", ++ tries); ++ return -1; ++} ++ ++/* ++ * This function reads the firmware status. ++ */ ++static int ++mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) ++{ ++ u32 fws0 = 0, fws1 = 0; ++ ++ if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0)) ++ return -1; ++ ++ if (mwifiex_read_reg(adapter, CARD_FW_STATUS1_REG, &fws1)) ++ return -1; ++ ++ *dat = (u16) ((fws1 << 8) | fws0); ++ ++ return 0; ++} ++ ++/* ++ * This function disables the host interrupt. ++ * ++ * The host interrupt mask is read, the disable bit is reset and ++ * written back to the card host interrupt mask register. ++ */ ++static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) ++{ ++ u32 host_int_mask = 0; ++ ++ /* Read back the host_int_mask register */ ++ if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) ++ return -1; ++ ++ /* Update with the mask and write back to the register */ ++ host_int_mask &= ~HOST_INT_DISABLE; ++ ++ if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) { ++ dev_err(adapter->dev, "disable host interrupt failed\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function enables the host interrupt. ++ * ++ * The host interrupt enable mask is written to the card ++ * host interrupt mask register. ++ */ ++static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter) ++{ ++ /* Simply write the mask to the register */ ++ if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, HOST_INT_ENABLE)) { ++ dev_err(adapter->dev, "enable host interrupt failed\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++/* ++ * This function sends a data buffer to the card. ++ */ ++static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, ++ u32 *type, u8 *buffer, ++ u32 npayload, u32 ioport) ++{ ++ int ret = 0; ++ u32 nb; ++ ++ if (!buffer) { ++ dev_err(adapter->dev, "%s: buffer is NULL\n", __func__); ++ return -1; ++ } ++ ++ ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 1); ++ ++ if (ret) { ++ dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__, ++ ret); ++ return -1; ++ } ++ ++ nb = le16_to_cpu(*(__le16 *) (buffer)); ++ if (nb > npayload) { ++ dev_err(adapter->dev, "%s: invalid packet, nb=%d, npayload=%d\n", ++ __func__, nb, npayload); ++ return -1; ++ } ++ ++ *type = le16_to_cpu(*(__le16 *) (buffer + 2)); ++ ++ return ret; ++} ++ ++/* ++ * This function downloads the firmware to the card. ++ * ++ * Firmware is downloaded to the card in blocks. Every block download ++ * is tested for CRC errors, and retried a number of times before ++ * returning failure. ++ */ ++static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, ++ struct mwifiex_fw_image *fw) ++{ ++ int ret = 0; ++ u8 *firmware = fw->fw_buf; ++ u32 firmware_len = fw->fw_len; ++ u32 offset = 0; ++ u32 base0, base1; ++ u8 *fwbuf; ++ u16 len = 0; ++ u32 txlen = 0, tx_blocks = 0, tries = 0; ++ u32 i = 0; ++ ++ if (!firmware_len) { ++ dev_err(adapter->dev, "firmware image not found!" ++ " Terminating download\n"); ++ return -1; ++ } ++ ++ dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n", ++ firmware_len); ++ ++ /* Assume that the allocated buffer is 8-byte aligned */ ++ fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL); ++ if (!fwbuf) { ++ dev_err(adapter->dev, "unable to alloc buffer for firmware." ++ " Terminating download\n"); ++ return -1; ++ } ++ ++ /* Perform firmware data transfer */ ++ do { ++ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY ++ bits */ ++ ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY | ++ DN_LD_CARD_RDY); ++ if (ret) { ++ dev_err(adapter->dev, "FW download with helper:" ++ " poll status timeout @ %d\n", offset); ++ goto done; ++ } ++ ++ /* More data? */ ++ if (offset >= firmware_len) ++ break; ++ ++ for (tries = 0; tries < MAX_POLL_TRIES; tries++) { ++ ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0, ++ &base0); ++ if (ret) { ++ dev_err(adapter->dev, "dev BASE0 register read" ++ " failed: base0=0x%04X(%d). Terminating " ++ "download\n", base0, base0); ++ goto done; ++ } ++ ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1, ++ &base1); ++ if (ret) { ++ dev_err(adapter->dev, "dev BASE1 register read" ++ " failed: base1=0x%04X(%d). Terminating " ++ "download\n", base1, base1); ++ goto done; ++ } ++ len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff)); ++ ++ if (len) ++ break; ++ ++ udelay(10); ++ } ++ ++ if (!len) { ++ break; ++ } else if (len > MWIFIEX_UPLD_SIZE) { ++ dev_err(adapter->dev, "FW download failed @ %d," ++ " invalid length %d\n", offset, len); ++ ret = -1; ++ goto done; ++ } ++ ++ txlen = len; ++ ++ if (len & BIT(0)) { ++ i++; ++ if (i > MAX_WRITE_IOMEM_RETRY) { ++ dev_err(adapter->dev, "FW download failed @" ++ " %d, over max retry count\n", offset); ++ ret = -1; ++ goto done; ++ } ++ dev_err(adapter->dev, "CRC indicated by the helper:" ++ " len = 0x%04X, txlen = %d\n", len, txlen); ++ len &= ~BIT(0); ++ /* Setting this to 0 to resend from same offset */ ++ txlen = 0; ++ } else { ++ i = 0; ++ ++ /* Set blocksize to transfer - checking for last ++ block */ ++ if (firmware_len - offset < txlen) ++ txlen = firmware_len - offset; ++ ++ tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE - ++ 1) / MWIFIEX_SDIO_BLOCK_SIZE; ++ ++ /* Copy payload to buffer */ ++ memmove(fwbuf, &firmware[offset], txlen); ++ } ++ ++ ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks * ++ MWIFIEX_SDIO_BLOCK_SIZE, ++ adapter->ioport); ++ if (ret) { ++ dev_err(adapter->dev, "FW download, write iomem (%d)" ++ " failed @ %d\n", i, offset); ++ if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) ++ dev_err(adapter->dev, "write CFG reg failed\n"); ++ ++ ret = -1; ++ goto done; ++ } ++ ++ offset += txlen; ++ } while (true); ++ ++ dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n", ++ offset); ++ ++ ret = 0; ++done: ++ kfree(fwbuf); ++ return ret; ++} ++ ++/* ++ * This function checks the firmware status in card. ++ * ++ * The winner interface is also determined by this function. ++ */ ++static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, ++ u32 poll_num, int *winner) ++{ ++ int ret = 0; ++ u16 firmware_stat; ++ u32 tries; ++ u32 winner_status; ++ ++ /* Wait for firmware initialization event */ ++ for (tries = 0; tries < poll_num; tries++) { ++ ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); ++ if (ret) ++ continue; ++ if (firmware_stat == FIRMWARE_READY) { ++ ret = 0; ++ break; ++ } else { ++ mdelay(100); ++ ret = -1; ++ } ++ } ++ ++ if (winner && ret) { ++ if (mwifiex_read_reg ++ (adapter, CARD_FW_STATUS0_REG, &winner_status)) ++ winner_status = 0; ++ ++ if (winner_status) ++ *winner = 0; ++ else ++ *winner = 1; ++ } ++ return ret; ++} ++ ++/* ++ * This function reads the interrupt status from card. ++ */ ++static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ u32 sdio_ireg = 0; ++ unsigned long flags; ++ ++ if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS, ++ REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, ++ 0)) { ++ dev_err(adapter->dev, "read mp_regs failed\n"); ++ return; ++ } ++ ++ sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG]; ++ if (sdio_ireg) { ++ /* ++ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS ++ * Clear the interrupt status register ++ */ ++ dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg); ++ spin_lock_irqsave(&adapter->int_lock, flags); ++ adapter->int_status |= sdio_ireg; ++ spin_unlock_irqrestore(&adapter->int_lock, flags); ++ } ++} ++ ++/* ++ * SDIO interrupt handler. ++ * ++ * This function reads the interrupt status from firmware and assigns ++ * the main process in workqueue which will handle the interrupt. ++ */ ++static void ++mwifiex_sdio_interrupt(struct sdio_func *func) ++{ ++ struct mwifiex_adapter *adapter; ++ struct sdio_mmc_card *card; ++ ++ card = sdio_get_drvdata(func); ++ if (!card || !card->adapter) { ++ pr_debug("int: func=%p card=%p adapter=%p\n", ++ func, card, card ? card->adapter : NULL); ++ return; ++ } ++ adapter = card->adapter; ++ ++ if (adapter->surprise_removed) ++ return; ++ ++ if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) ++ adapter->ps_state = PS_STATE_AWAKE; ++ ++ mwifiex_interrupt_status(adapter); ++ queue_work(adapter->workqueue, &adapter->main_work); ++} ++ ++/* ++ * This function decodes a received packet. ++ * ++ * Based on the type, the packet is treated as either a data, or ++ * a command response, or an event, and the correct handler ++ * function is invoked. ++ */ ++static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb, u32 upld_typ) ++{ ++ u8 *cmd_buf; ++ ++ skb_pull(skb, INTF_HEADER_LEN); ++ ++ switch (upld_typ) { ++ case MWIFIEX_TYPE_DATA: ++ dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n"); ++ mwifiex_handle_rx_packet(adapter, skb); ++ break; ++ ++ case MWIFIEX_TYPE_CMD: ++ dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n"); ++ /* take care of curr_cmd = NULL case */ ++ if (!adapter->curr_cmd) { ++ cmd_buf = adapter->upld_buf; ++ ++ if (adapter->ps_state == PS_STATE_SLEEP_CFM) ++ mwifiex_process_sleep_confirm_resp(adapter, ++ skb->data, skb->len); ++ ++ memcpy(cmd_buf, skb->data, min_t(u32, ++ MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); ++ ++ dev_kfree_skb_any(skb); ++ } else { ++ adapter->cmd_resp_received = true; ++ adapter->curr_cmd->resp_skb = skb; ++ } ++ break; ++ ++ case MWIFIEX_TYPE_EVENT: ++ dev_dbg(adapter->dev, "info: --- Rx: Event ---\n"); ++ adapter->event_cause = *(u32 *) skb->data; ++ ++ skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN); ++ ++ if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE)) ++ memcpy(adapter->event_body, skb->data, skb->len); ++ ++ /* event cause has been saved to adapter->event_cause */ ++ adapter->event_received = true; ++ adapter->event_skb = skb; ++ ++ break; ++ ++ default: ++ dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ); ++ dev_kfree_skb_any(skb); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function transfers received packets from card to driver, performing ++ * aggregation if required. ++ * ++ * For data received on control port, or if aggregation is disabled, the ++ * received buffers are uploaded as separate packets. However, if aggregation ++ * is enabled and required, the buffers are copied onto an aggregation buffer, ++ * provided there is space left, processed and finally uploaded. ++ */ ++static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb, u8 port) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ s32 f_do_rx_aggr = 0; ++ s32 f_do_rx_cur = 0; ++ s32 f_aggr_cur = 0; ++ struct sk_buff *skb_deaggr; ++ u32 pind = 0; ++ u32 pkt_len, pkt_type = 0; ++ u8 *curr_ptr; ++ u32 rx_len = skb->len; ++ ++ if (port == CTRL_PORT) { ++ /* Read the command Resp without aggr */ ++ dev_dbg(adapter->dev, "info: %s: no aggregation for cmd " ++ "response\n", __func__); ++ ++ f_do_rx_cur = 1; ++ goto rx_curr_single; ++ } ++ ++ if (!card->mpa_rx.enabled) { ++ dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n", ++ __func__); ++ ++ f_do_rx_cur = 1; ++ goto rx_curr_single; ++ } ++ ++ if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) { ++ /* Some more data RX pending */ ++ dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); ++ ++ if (MP_RX_AGGR_IN_PROGRESS(card)) { ++ if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) { ++ f_aggr_cur = 1; ++ } else { ++ /* No room in Aggr buf, do rx aggr now */ ++ f_do_rx_aggr = 1; ++ f_do_rx_cur = 1; ++ } ++ } else { ++ /* Rx aggr not in progress */ ++ f_aggr_cur = 1; ++ } ++ ++ } else { ++ /* No more data RX pending */ ++ dev_dbg(adapter->dev, "info: %s: last packet\n", __func__); ++ ++ if (MP_RX_AGGR_IN_PROGRESS(card)) { ++ f_do_rx_aggr = 1; ++ if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) ++ f_aggr_cur = 1; ++ else ++ /* No room in Aggr buf, do rx aggr now */ ++ f_do_rx_cur = 1; ++ } else { ++ f_do_rx_cur = 1; ++ } ++ } ++ ++ if (f_aggr_cur) { ++ dev_dbg(adapter->dev, "info: current packet aggregation\n"); ++ /* Curr pkt can be aggregated */ ++ MP_RX_AGGR_SETUP(card, skb, port); ++ ++ if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || ++ MP_RX_AGGR_PORT_LIMIT_REACHED(card)) { ++ dev_dbg(adapter->dev, "info: %s: aggregated packet " ++ "limit reached\n", __func__); ++ /* No more pkts allowed in Aggr buf, rx it */ ++ f_do_rx_aggr = 1; ++ } ++ } ++ ++ if (f_do_rx_aggr) { ++ /* do aggr RX now */ ++ dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n", ++ card->mpa_rx.pkt_cnt); ++ ++ if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, ++ card->mpa_rx.buf_len, ++ (adapter->ioport | 0x1000 | ++ (card->mpa_rx.ports << 4)) + ++ card->mpa_rx.start_port, 1)) ++ return -1; ++ ++ curr_ptr = card->mpa_rx.buf; ++ ++ for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { ++ ++ /* get curr PKT len & type */ ++ pkt_len = *(u16 *) &curr_ptr[0]; ++ pkt_type = *(u16 *) &curr_ptr[2]; ++ ++ /* copy pkt to deaggr buf */ ++ skb_deaggr = card->mpa_rx.skb_arr[pind]; ++ ++ if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <= ++ card->mpa_rx.len_arr[pind])) { ++ ++ memcpy(skb_deaggr->data, curr_ptr, pkt_len); ++ ++ skb_trim(skb_deaggr, pkt_len); ++ ++ /* Process de-aggr packet */ ++ mwifiex_decode_rx_packet(adapter, skb_deaggr, ++ pkt_type); ++ } else { ++ dev_err(adapter->dev, "wrong aggr pkt:" ++ " type=%d len=%d max_len=%d\n", ++ pkt_type, pkt_len, ++ card->mpa_rx.len_arr[pind]); ++ dev_kfree_skb_any(skb_deaggr); ++ } ++ curr_ptr += card->mpa_rx.len_arr[pind]; ++ } ++ MP_RX_AGGR_BUF_RESET(card); ++ } ++ ++rx_curr_single: ++ if (f_do_rx_cur) { ++ dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", ++ port, rx_len); ++ ++ if (mwifiex_sdio_card_to_host(adapter, &pkt_type, ++ skb->data, skb->len, ++ adapter->ioport + port)) ++ return -1; ++ ++ mwifiex_decode_rx_packet(adapter, skb, pkt_type); ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function checks the current interrupt status. ++ * ++ * The following interrupts are checked and handled by this function - ++ * - Data sent ++ * - Command sent ++ * - Packets received ++ * ++ * Since the firmware does not generate download ready interrupt if the ++ * port updated is command port only, command sent interrupt checking ++ * should be done manually, and for every SDIO interrupt. ++ * ++ * In case of Rx packets received, the packets are uploaded from card to ++ * host and processed accordingly. ++ */ ++static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ int ret = 0; ++ u8 sdio_ireg; ++ struct sk_buff *skb = NULL; ++ u8 port = CTRL_PORT; ++ u32 len_reg_l, len_reg_u; ++ u32 rx_blocks; ++ u16 rx_len; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&adapter->int_lock, flags); ++ sdio_ireg = adapter->int_status; ++ adapter->int_status = 0; ++ spin_unlock_irqrestore(&adapter->int_lock, flags); ++ ++ if (!sdio_ireg) ++ return ret; ++ ++ if (sdio_ireg & DN_LD_HOST_INT_STATUS) { ++ card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8; ++ card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L]; ++ dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n", ++ card->mp_wr_bitmap); ++ if (adapter->data_sent && ++ (card->mp_wr_bitmap & card->mp_data_port_mask)) { ++ dev_dbg(adapter->dev, ++ "info: <--- Tx DONE Interrupt --->\n"); ++ adapter->data_sent = false; ++ } ++ } ++ ++ /* As firmware will not generate download ready interrupt if the port ++ updated is command port only, cmd_sent should be done for any SDIO ++ interrupt. */ ++ if (adapter->cmd_sent) { ++ /* Check if firmware has attach buffer at command port and ++ update just that in wr_bit_map. */ ++ card->mp_wr_bitmap |= ++ (u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK; ++ if (card->mp_wr_bitmap & CTRL_PORT_MASK) ++ adapter->cmd_sent = false; ++ } ++ ++ dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n", ++ adapter->cmd_sent, adapter->data_sent); ++ if (sdio_ireg & UP_LD_HOST_INT_STATUS) { ++ card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8; ++ card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L]; ++ dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n", ++ card->mp_rd_bitmap); ++ ++ while (true) { ++ ret = mwifiex_get_rd_port(adapter, &port); ++ if (ret) { ++ dev_dbg(adapter->dev, ++ "info: no more rd_port available\n"); ++ break; ++ } ++ len_reg_l = RD_LEN_P0_L + (port << 1); ++ len_reg_u = RD_LEN_P0_U + (port << 1); ++ rx_len = ((u16) card->mp_regs[len_reg_u]) << 8; ++ rx_len |= (u16) card->mp_regs[len_reg_l]; ++ dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n", ++ port, rx_len); ++ rx_blocks = ++ (rx_len + MWIFIEX_SDIO_BLOCK_SIZE - ++ 1) / MWIFIEX_SDIO_BLOCK_SIZE; ++ if (rx_len <= INTF_HEADER_LEN ++ || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > ++ MWIFIEX_RX_DATA_BUF_SIZE) { ++ dev_err(adapter->dev, "invalid rx_len=%d\n", ++ rx_len); ++ return -1; ++ } ++ rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); ++ ++ skb = dev_alloc_skb(rx_len); ++ ++ if (!skb) { ++ dev_err(adapter->dev, "%s: failed to alloc skb", ++ __func__); ++ return -1; ++ } ++ ++ skb_put(skb, rx_len); ++ ++ dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n", ++ rx_len, skb->len); ++ ++ if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb, ++ port)) { ++ u32 cr = 0; ++ ++ dev_err(adapter->dev, "card_to_host_mpa failed:" ++ " int status=%#x\n", sdio_ireg); ++ if (mwifiex_read_reg(adapter, ++ CONFIGURATION_REG, &cr)) ++ dev_err(adapter->dev, ++ "read CFG reg failed\n"); ++ ++ dev_dbg(adapter->dev, ++ "info: CFG reg val = %d\n", cr); ++ if (mwifiex_write_reg(adapter, ++ CONFIGURATION_REG, ++ (cr | 0x04))) ++ dev_err(adapter->dev, ++ "write CFG reg failed\n"); ++ ++ dev_dbg(adapter->dev, "info: write success\n"); ++ if (mwifiex_read_reg(adapter, ++ CONFIGURATION_REG, &cr)) ++ dev_err(adapter->dev, ++ "read CFG reg failed\n"); ++ ++ dev_dbg(adapter->dev, ++ "info: CFG reg val =%x\n", cr); ++ dev_kfree_skb_any(skb); ++ return -1; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function aggregates transmission buffers in driver and downloads ++ * the aggregated packet to card. ++ * ++ * The individual packets are aggregated by copying into an aggregation ++ * buffer and then downloaded to the card. Previous unsent packets in the ++ * aggregation buffer are pre-copied first before new packets are added. ++ * Aggregation is done till there is space left in the aggregation buffer, ++ * or till new packets are available. ++ * ++ * The function will only download the packet to the card when aggregation ++ * stops, otherwise it will just aggregate the packet in aggregation buffer ++ * and return. ++ */ ++static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, ++ u8 *payload, u32 pkt_len, u8 port, ++ u32 next_pkt_len) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ int ret = 0; ++ s32 f_send_aggr_buf = 0; ++ s32 f_send_cur_buf = 0; ++ s32 f_precopy_cur_buf = 0; ++ s32 f_postcopy_cur_buf = 0; ++ ++ if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) { ++ dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n", ++ __func__); ++ ++ f_send_cur_buf = 1; ++ goto tx_curr_single; ++ } ++ ++ if (next_pkt_len) { ++ /* More pkt in TX queue */ ++ dev_dbg(adapter->dev, "info: %s: more packets in queue.\n", ++ __func__); ++ ++ if (MP_TX_AGGR_IN_PROGRESS(card)) { ++ if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) && ++ MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { ++ f_precopy_cur_buf = 1; ++ ++ if (!(card->mp_wr_bitmap & ++ (1 << card->curr_wr_port)) ++ || !MP_TX_AGGR_BUF_HAS_ROOM( ++ card, next_pkt_len)) ++ f_send_aggr_buf = 1; ++ } else { ++ /* No room in Aggr buf, send it */ ++ f_send_aggr_buf = 1; ++ ++ if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) || ++ !(card->mp_wr_bitmap & ++ (1 << card->curr_wr_port))) ++ f_send_cur_buf = 1; ++ else ++ f_postcopy_cur_buf = 1; ++ } ++ } else { ++ if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len) ++ && (card->mp_wr_bitmap & (1 << card->curr_wr_port))) ++ f_precopy_cur_buf = 1; ++ else ++ f_send_cur_buf = 1; ++ } ++ } else { ++ /* Last pkt in TX queue */ ++ dev_dbg(adapter->dev, "info: %s: Last packet in Tx Queue.\n", ++ __func__); ++ ++ if (MP_TX_AGGR_IN_PROGRESS(card)) { ++ /* some packs in Aggr buf already */ ++ f_send_aggr_buf = 1; ++ ++ if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) ++ f_precopy_cur_buf = 1; ++ else ++ /* No room in Aggr buf, send it */ ++ f_send_cur_buf = 1; ++ } else { ++ f_send_cur_buf = 1; ++ } ++ } ++ ++ if (f_precopy_cur_buf) { ++ dev_dbg(adapter->dev, "data: %s: precopy current buffer\n", ++ __func__); ++ MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); ++ ++ if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) || ++ MP_TX_AGGR_PORT_LIMIT_REACHED(card)) ++ /* No more pkts allowed in Aggr buf, send it */ ++ f_send_aggr_buf = 1; ++ } ++ ++ if (f_send_aggr_buf) { ++ dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n", ++ __func__, ++ card->mpa_tx.start_port, card->mpa_tx.ports); ++ ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, ++ card->mpa_tx.buf_len, ++ (adapter->ioport | 0x1000 | ++ (card->mpa_tx.ports << 4)) + ++ card->mpa_tx.start_port); ++ ++ MP_TX_AGGR_BUF_RESET(card); ++ } ++ ++tx_curr_single: ++ if (f_send_cur_buf) { ++ dev_dbg(adapter->dev, "data: %s: send current buffer %d\n", ++ __func__, port); ++ ret = mwifiex_write_data_to_card(adapter, payload, pkt_len, ++ adapter->ioport + port); ++ } ++ ++ if (f_postcopy_cur_buf) { ++ dev_dbg(adapter->dev, "data: %s: postcopy current buffer\n", ++ __func__); ++ MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function downloads data from driver to card. ++ * ++ * Both commands and data packets are transferred to the card by this ++ * function. ++ * ++ * This function adds the SDIO specific header to the front of the buffer ++ * before transferring. The header contains the length of the packet and ++ * the type. The firmware handles the packets based upon this set type. ++ */ ++static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, ++ u8 type, u8 *payload, u32 pkt_len, ++ struct mwifiex_tx_param *tx_param) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ int ret = 0; ++ u32 buf_block_len; ++ u32 blk_size; ++ u8 port = CTRL_PORT; ++ ++ /* Allocate buffer and copy payload */ ++ blk_size = MWIFIEX_SDIO_BLOCK_SIZE; ++ buf_block_len = (pkt_len + blk_size - 1) / blk_size; ++ *(u16 *) &payload[0] = (u16) pkt_len; ++ *(u16 *) &payload[2] = type; ++ ++ /* ++ * This is SDIO specific header ++ * u16 length, ++ * u16 type (MWIFIEX_TYPE_DATA = 0, MWIFIEX_TYPE_CMD = 1, ++ * MWIFIEX_TYPE_EVENT = 3) ++ */ ++ if (type == MWIFIEX_TYPE_DATA) { ++ ret = mwifiex_get_wr_port_data(adapter, &port); ++ if (ret) { ++ dev_err(adapter->dev, "%s: no wr_port available\n", ++ __func__); ++ return ret; ++ } ++ } else { ++ adapter->cmd_sent = true; ++ /* Type must be MWIFIEX_TYPE_CMD */ ++ ++ if (pkt_len <= INTF_HEADER_LEN || ++ pkt_len > MWIFIEX_UPLD_SIZE) ++ dev_err(adapter->dev, "%s: payload=%p, nb=%d\n", ++ __func__, payload, pkt_len); ++ } ++ ++ /* Transfer data to card */ ++ pkt_len = buf_block_len * blk_size; ++ ++ if (tx_param) ++ ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, ++ port, tx_param->next_pkt_len); ++ else ++ ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, ++ port, 0); ++ ++ if (ret) { ++ if (type == MWIFIEX_TYPE_CMD) ++ adapter->cmd_sent = false; ++ if (type == MWIFIEX_TYPE_DATA) ++ adapter->data_sent = false; ++ } else { ++ if (type == MWIFIEX_TYPE_DATA) { ++ if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port))) ++ adapter->data_sent = true; ++ else ++ adapter->data_sent = false; ++ } ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function allocates the MPA Tx and Rx buffers. ++ */ ++static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, ++ u32 mpa_tx_buf_size, u32 mpa_rx_buf_size) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ int ret = 0; ++ ++ card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL); ++ if (!card->mpa_tx.buf) { ++ dev_err(adapter->dev, "could not alloc buffer for MP-A TX\n"); ++ ret = -1; ++ goto error; ++ } ++ ++ card->mpa_tx.buf_size = mpa_tx_buf_size; ++ ++ card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL); ++ if (!card->mpa_rx.buf) { ++ dev_err(adapter->dev, "could not alloc buffer for MP-A RX\n"); ++ ret = -1; ++ goto error; ++ } ++ ++ card->mpa_rx.buf_size = mpa_rx_buf_size; ++ ++error: ++ if (ret) { ++ kfree(card->mpa_tx.buf); ++ kfree(card->mpa_rx.buf); ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function unregisters the SDIO device. ++ * ++ * The SDIO IRQ is released, the function is disabled and driver ++ * data is set to null. ++ */ ++static void ++mwifiex_unregister_dev(struct mwifiex_adapter *adapter) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ ++ if (adapter->card) { ++ /* Release the SDIO IRQ */ ++ sdio_claim_host(card->func); ++ sdio_release_irq(card->func); ++ sdio_disable_func(card->func); ++ sdio_release_host(card->func); ++ sdio_set_drvdata(card->func, NULL); ++ } ++} ++ ++/* ++ * This function registers the SDIO device. ++ * ++ * SDIO IRQ is claimed, block size is set and driver data is initialized. ++ */ ++static int mwifiex_register_dev(struct mwifiex_adapter *adapter) ++{ ++ int ret = 0; ++ struct sdio_mmc_card *card = adapter->card; ++ struct sdio_func *func = card->func; ++ ++ /* save adapter pointer in card */ ++ card->adapter = adapter; ++ ++ sdio_claim_host(func); ++ ++ /* Request the SDIO IRQ */ ++ ret = sdio_claim_irq(func, mwifiex_sdio_interrupt); ++ if (ret) { ++ pr_err("claim irq failed: ret=%d\n", ret); ++ goto disable_func; ++ } ++ ++ /* Set block size */ ++ ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE); ++ if (ret) { ++ pr_err("cannot set SDIO block size\n"); ++ ret = -1; ++ goto release_irq; ++ } ++ ++ sdio_release_host(func); ++ sdio_set_drvdata(func, card); ++ ++ adapter->dev = &func->dev; ++ ++ return 0; ++ ++release_irq: ++ sdio_release_irq(func); ++disable_func: ++ sdio_disable_func(func); ++ sdio_release_host(func); ++ adapter->card = NULL; ++ ++ return -1; ++} ++ ++/* ++ * This function initializes the SDIO driver. ++ * ++ * The following initializations steps are followed - ++ * - Read the Host interrupt status register to acknowledge ++ * the first interrupt got from bootloader ++ * - Disable host interrupt mask register ++ * - Get SDIO port ++ * - Get revision ID ++ * - Initialize SDIO variables in card ++ * - Allocate MP registers ++ * - Allocate MPA Tx and Rx buffers ++ */ ++static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ int ret; ++ u32 sdio_ireg = 0; ++ ++ /* ++ * Read the HOST_INT_STATUS_REG for ACK the first interrupt got ++ * from the bootloader. If we don't do this we get a interrupt ++ * as soon as we register the irq. ++ */ ++ mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg); ++ ++ /* Disable host interrupt mask register for SDIO */ ++ mwifiex_sdio_disable_host_int(adapter); ++ ++ /* Get SDIO ioport */ ++ mwifiex_init_sdio_ioport(adapter); ++ ++ /* Get revision ID */ ++#define REV_ID_REG 0x5c ++ mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id); ++ ++ /* Initialize SDIO variables in card */ ++ card->mp_rd_bitmap = 0; ++ card->mp_wr_bitmap = 0; ++ card->curr_rd_port = 1; ++ card->curr_wr_port = 1; ++ ++ card->mp_data_port_mask = DATA_PORT_MASK; ++ ++ card->mpa_tx.buf_len = 0; ++ card->mpa_tx.pkt_cnt = 0; ++ card->mpa_tx.start_port = 0; ++ ++ card->mpa_tx.enabled = 0; ++ card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; ++ ++ card->mpa_rx.buf_len = 0; ++ card->mpa_rx.pkt_cnt = 0; ++ card->mpa_rx.start_port = 0; ++ ++ card->mpa_rx.enabled = 0; ++ card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; ++ ++ /* Allocate buffers for SDIO MP-A */ ++ card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL); ++ if (!card->mp_regs) { ++ dev_err(adapter->dev, "failed to alloc mp_regs\n"); ++ return -1; ++ } ++ ++ ret = mwifiex_alloc_sdio_mpa_buffers(adapter, ++ SDIO_MP_TX_AGGR_DEF_BUF_SIZE, ++ SDIO_MP_RX_AGGR_DEF_BUF_SIZE); ++ if (ret) { ++ dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n"); ++ kfree(card->mp_regs); ++ return -1; ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function resets the MPA Tx and Rx buffers. ++ */ ++static void mwifiex_cleanup_mpa_buf(struct mwifiex_adapter *adapter) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ ++ MP_TX_AGGR_BUF_RESET(card); ++ MP_RX_AGGR_BUF_RESET(card); ++} ++ ++/* ++ * This function cleans up the allocated card buffers. ++ * ++ * The following are freed by this function - ++ * - MP registers ++ * - MPA Tx buffer ++ * - MPA Rx buffer ++ */ ++static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ ++ kfree(card->mp_regs); ++ kfree(card->mpa_tx.buf); ++ kfree(card->mpa_rx.buf); ++} ++ ++/* ++ * This function updates the MP end port in card. ++ */ ++static void ++mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) ++{ ++ struct sdio_mmc_card *card = adapter->card; ++ int i; ++ ++ card->mp_end_port = port; ++ ++ card->mp_data_port_mask = DATA_PORT_MASK; ++ ++ for (i = 1; i <= MAX_PORT - card->mp_end_port; i++) ++ card->mp_data_port_mask &= ~(1 << (MAX_PORT - i)); ++ ++ card->curr_wr_port = 1; ++ ++ dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n", ++ port, card->mp_data_port_mask); ++} ++ ++static struct mwifiex_if_ops sdio_ops = { ++ .init_if = mwifiex_init_sdio, ++ .cleanup_if = mwifiex_cleanup_sdio, ++ .check_fw_status = mwifiex_check_fw_status, ++ .prog_fw = mwifiex_prog_fw_w_helper, ++ .register_dev = mwifiex_register_dev, ++ .unregister_dev = mwifiex_unregister_dev, ++ .enable_int = mwifiex_sdio_enable_host_int, ++ .process_int_status = mwifiex_process_int_status, ++ .host_to_card = mwifiex_sdio_host_to_card, ++ .wakeup = mwifiex_pm_wakeup_card, ++ .wakeup_complete = mwifiex_pm_wakeup_card_complete, ++ ++ /* SDIO specific */ ++ .update_mp_end_port = mwifiex_update_mp_end_port, ++ .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, ++}; ++ ++/* ++ * This function initializes the SDIO driver. ++ * ++ * This initiates the semaphore and registers the device with ++ * SDIO bus. ++ */ ++static int ++mwifiex_sdio_init_module(void) ++{ ++ sema_init(&add_remove_card_sem, 1); ++ ++ return sdio_register_driver(&mwifiex_sdio); ++} ++ ++/* ++ * This function cleans up the SDIO driver. ++ * ++ * The following major steps are followed for cleanup - ++ * - Resume the device if its suspended ++ * - Disconnect the device if connected ++ * - Shutdown the firmware ++ * - Unregister the device from SDIO bus. ++ */ ++static void ++mwifiex_sdio_cleanup_module(void) ++{ ++ struct mwifiex_adapter *adapter = g_adapter; ++ int i; ++ ++ if (down_interruptible(&add_remove_card_sem)) ++ goto exit_sem_err; ++ ++ if (!adapter || !adapter->priv_num) ++ goto exit; ++ ++ if (adapter->is_suspended) ++ mwifiex_sdio_resume(adapter->dev); ++ ++ for (i = 0; i < adapter->priv_num; i++) ++ if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && ++ adapter->priv[i]->media_connected) ++ mwifiex_deauthenticate(adapter->priv[i], NULL); ++ ++ if (!adapter->surprise_removed) ++ mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, ++ MWIFIEX_BSS_ROLE_ANY), ++ MWIFIEX_FUNC_SHUTDOWN); ++ ++exit: ++ up(&add_remove_card_sem); ++ ++exit_sem_err: ++ sdio_unregister_driver(&mwifiex_sdio); ++} ++ ++module_init(mwifiex_sdio_init_module); ++module_exit(mwifiex_sdio_cleanup_module); ++ ++MODULE_AUTHOR("Marvell International Ltd."); ++MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION); ++MODULE_VERSION(SDIO_VERSION); ++MODULE_LICENSE("GPL v2"); ++MODULE_FIRMWARE("sd8787.bin"); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sdio.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sdio.h +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sdio.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sdio.h 2011-05-05 23:29:45.494441973 +0200 +@@ -0,0 +1,305 @@ ++/* ++ * Marvell Wireless LAN device driver: SDIO specific definitions ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#ifndef _MWIFIEX_SDIO_H ++#define _MWIFIEX_SDIO_H ++ ++ ++#include ++#include ++#include ++#include ++ ++#include "main.h" ++ ++#define BLOCK_MODE 1 ++#define BYTE_MODE 0 ++ ++#define REG_PORT 0 ++#define RD_BITMAP_L 0x04 ++#define RD_BITMAP_U 0x05 ++#define WR_BITMAP_L 0x06 ++#define WR_BITMAP_U 0x07 ++#define RD_LEN_P0_L 0x08 ++#define RD_LEN_P0_U 0x09 ++ ++#define MWIFIEX_SDIO_IO_PORT_MASK 0xfffff ++ ++#define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000 ++ ++#define CTRL_PORT 0 ++#define CTRL_PORT_MASK 0x0001 ++#define DATA_PORT_MASK 0xfffe ++ ++#define MAX_MP_REGS 64 ++#define MAX_PORT 16 ++ ++#define SDIO_MP_AGGR_DEF_PKT_LIMIT 8 ++ ++#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ ++ ++/* Multi port RX aggregation buffer size */ ++#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ ++ ++/* Misc. Config Register : Auto Re-enable interrupts */ ++#define AUTO_RE_ENABLE_INT BIT(4) ++ ++/* Host Control Registers */ ++/* Host Control Registers : I/O port 0 */ ++#define IO_PORT_0_REG 0x78 ++/* Host Control Registers : I/O port 1 */ ++#define IO_PORT_1_REG 0x79 ++/* Host Control Registers : I/O port 2 */ ++#define IO_PORT_2_REG 0x7A ++ ++/* Host Control Registers : Configuration */ ++#define CONFIGURATION_REG 0x00 ++/* Host Control Registers : Host without Command 53 finish host*/ ++#define HOST_TO_CARD_EVENT (0x1U << 3) ++/* Host Control Registers : Host without Command 53 finish host */ ++#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2) ++/* Host Control Registers : Host power up */ ++#define HOST_POWER_UP (0x1U << 1) ++/* Host Control Registers : Host power down */ ++#define HOST_POWER_DOWN (0x1U << 0) ++ ++/* Host Control Registers : Host interrupt mask */ ++#define HOST_INT_MASK_REG 0x02 ++/* Host Control Registers : Upload host interrupt mask */ ++#define UP_LD_HOST_INT_MASK (0x1U) ++/* Host Control Registers : Download host interrupt mask */ ++#define DN_LD_HOST_INT_MASK (0x2U) ++/* Enable Host interrupt mask */ ++#define HOST_INT_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK) ++/* Disable Host interrupt mask */ ++#define HOST_INT_DISABLE 0xff ++ ++/* Host Control Registers : Host interrupt status */ ++#define HOST_INTSTATUS_REG 0x03 ++/* Host Control Registers : Upload host interrupt status */ ++#define UP_LD_HOST_INT_STATUS (0x1U) ++/* Host Control Registers : Download host interrupt status */ ++#define DN_LD_HOST_INT_STATUS (0x2U) ++ ++/* Host Control Registers : Host interrupt RSR */ ++#define HOST_INT_RSR_REG 0x01 ++/* Host Control Registers : Upload host interrupt RSR */ ++#define UP_LD_HOST_INT_RSR (0x1U) ++#define SDIO_INT_MASK 0x3F ++ ++/* Host Control Registers : Host interrupt status */ ++#define HOST_INT_STATUS_REG 0x28 ++/* Host Control Registers : Upload CRC error */ ++#define UP_LD_CRC_ERR (0x1U << 2) ++/* Host Control Registers : Upload restart */ ++#define UP_LD_RESTART (0x1U << 1) ++/* Host Control Registers : Download restart */ ++#define DN_LD_RESTART (0x1U << 0) ++ ++/* Card Control Registers : Card status register */ ++#define CARD_STATUS_REG 0x30 ++/* Card Control Registers : Card I/O ready */ ++#define CARD_IO_READY (0x1U << 3) ++/* Card Control Registers : CIS card ready */ ++#define CIS_CARD_RDY (0x1U << 2) ++/* Card Control Registers : Upload card ready */ ++#define UP_LD_CARD_RDY (0x1U << 1) ++/* Card Control Registers : Download card ready */ ++#define DN_LD_CARD_RDY (0x1U << 0) ++ ++/* Card Control Registers : Host interrupt mask register */ ++#define HOST_INTERRUPT_MASK_REG 0x34 ++/* Card Control Registers : Host power interrupt mask */ ++#define HOST_POWER_INT_MASK (0x1U << 3) ++/* Card Control Registers : Abort card interrupt mask */ ++#define ABORT_CARD_INT_MASK (0x1U << 2) ++/* Card Control Registers : Upload card interrupt mask */ ++#define UP_LD_CARD_INT_MASK (0x1U << 1) ++/* Card Control Registers : Download card interrupt mask */ ++#define DN_LD_CARD_INT_MASK (0x1U << 0) ++ ++/* Card Control Registers : Card interrupt status register */ ++#define CARD_INTERRUPT_STATUS_REG 0x38 ++/* Card Control Registers : Power up interrupt */ ++#define POWER_UP_INT (0x1U << 4) ++/* Card Control Registers : Power down interrupt */ ++#define POWER_DOWN_INT (0x1U << 3) ++ ++/* Card Control Registers : Card interrupt RSR register */ ++#define CARD_INTERRUPT_RSR_REG 0x3c ++/* Card Control Registers : Power up RSR */ ++#define POWER_UP_RSR (0x1U << 4) ++/* Card Control Registers : Power down RSR */ ++#define POWER_DOWN_RSR (0x1U << 3) ++ ++/* Card Control Registers : Miscellaneous Configuration Register */ ++#define CARD_MISC_CFG_REG 0x6C ++ ++/* Host F1 read base 0 */ ++#define HOST_F1_RD_BASE_0 0x0040 ++/* Host F1 read base 1 */ ++#define HOST_F1_RD_BASE_1 0x0041 ++/* Host F1 card ready */ ++#define HOST_F1_CARD_RDY 0x0020 ++ ++/* Firmware status 0 register */ ++#define CARD_FW_STATUS0_REG 0x60 ++/* Firmware status 1 register */ ++#define CARD_FW_STATUS1_REG 0x61 ++/* Rx length register */ ++#define CARD_RX_LEN_REG 0x62 ++/* Rx unit register */ ++#define CARD_RX_UNIT_REG 0x63 ++ ++/* Event header Len*/ ++#define MWIFIEX_EVENT_HEADER_LEN 8 ++ ++/* Max retry number of CMD53 write */ ++#define MAX_WRITE_IOMEM_RETRY 2 ++ ++/* SDIO Tx aggregation in progress ? */ ++#define MP_TX_AGGR_IN_PROGRESS(a) (a->mpa_tx.pkt_cnt > 0) ++ ++/* SDIO Tx aggregation buffer room for next packet ? */ ++#define MP_TX_AGGR_BUF_HAS_ROOM(a, len) ((a->mpa_tx.buf_len+len) \ ++ <= a->mpa_tx.buf_size) ++ ++/* Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */ ++#define MP_TX_AGGR_BUF_PUT(a, payload, pkt_len, port) do { \ ++ memmove(&a->mpa_tx.buf[a->mpa_tx.buf_len], \ ++ payload, pkt_len); \ ++ a->mpa_tx.buf_len += pkt_len; \ ++ if (!a->mpa_tx.pkt_cnt) \ ++ a->mpa_tx.start_port = port; \ ++ if (a->mpa_tx.start_port <= port) \ ++ a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \ ++ else \ ++ a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - \ ++ a->mp_end_port))); \ ++ a->mpa_tx.pkt_cnt++; \ ++} while (0); ++ ++/* SDIO Tx aggregation limit ? */ ++#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \ ++ (a->mpa_tx.pkt_cnt == a->mpa_tx.pkt_aggr_limit) ++ ++/* SDIO Tx aggregation port limit ? */ ++#define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \ ++ a->mpa_tx.start_port) && (((MAX_PORT - \ ++ a->mpa_tx.start_port) + a->curr_wr_port) >= \ ++ SDIO_MP_AGGR_DEF_PKT_LIMIT)) ++ ++/* Reset SDIO Tx aggregation buffer parameters */ ++#define MP_TX_AGGR_BUF_RESET(a) do { \ ++ a->mpa_tx.pkt_cnt = 0; \ ++ a->mpa_tx.buf_len = 0; \ ++ a->mpa_tx.ports = 0; \ ++ a->mpa_tx.start_port = 0; \ ++} while (0); ++ ++/* SDIO Rx aggregation limit ? */ ++#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \ ++ (a->mpa_rx.pkt_cnt == a->mpa_rx.pkt_aggr_limit) ++ ++/* SDIO Tx aggregation port limit ? */ ++#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \ ++ a->mpa_rx.start_port) && (((MAX_PORT - \ ++ a->mpa_rx.start_port) + a->curr_rd_port) >= \ ++ SDIO_MP_AGGR_DEF_PKT_LIMIT)) ++ ++/* SDIO Rx aggregation in progress ? */ ++#define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt > 0) ++ ++/* SDIO Rx aggregation buffer room for next packet ? */ ++#define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) \ ++ ((a->mpa_rx.buf_len+rx_len) <= a->mpa_rx.buf_size) ++ ++/* Prepare to copy current packet from card to SDIO Rx aggregation buffer */ ++#define MP_RX_AGGR_SETUP(a, skb, port) do { \ ++ a->mpa_rx.buf_len += skb->len; \ ++ if (!a->mpa_rx.pkt_cnt) \ ++ a->mpa_rx.start_port = port; \ ++ if (a->mpa_rx.start_port <= port) \ ++ a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \ ++ else \ ++ a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \ ++ a->mpa_rx.skb_arr[a->mpa_rx.pkt_cnt] = skb; \ ++ a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = skb->len; \ ++ a->mpa_rx.pkt_cnt++; \ ++} while (0); ++ ++/* Reset SDIO Rx aggregation buffer parameters */ ++#define MP_RX_AGGR_BUF_RESET(a) do { \ ++ a->mpa_rx.pkt_cnt = 0; \ ++ a->mpa_rx.buf_len = 0; \ ++ a->mpa_rx.ports = 0; \ ++ a->mpa_rx.start_port = 0; \ ++} while (0); ++ ++ ++/* data structure for SDIO MPA TX */ ++struct mwifiex_sdio_mpa_tx { ++ /* multiport tx aggregation buffer pointer */ ++ u8 *buf; ++ u32 buf_len; ++ u32 pkt_cnt; ++ u16 ports; ++ u16 start_port; ++ u8 enabled; ++ u32 buf_size; ++ u32 pkt_aggr_limit; ++}; ++ ++struct mwifiex_sdio_mpa_rx { ++ u8 *buf; ++ u32 buf_len; ++ u32 pkt_cnt; ++ u16 ports; ++ u16 start_port; ++ ++ struct sk_buff *skb_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT]; ++ u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT]; ++ ++ u8 enabled; ++ u32 buf_size; ++ u32 pkt_aggr_limit; ++}; ++ ++int mwifiex_bus_register(void); ++void mwifiex_bus_unregister(void); ++ ++struct sdio_mmc_card { ++ struct sdio_func *func; ++ struct mwifiex_adapter *adapter; ++ ++ u16 mp_rd_bitmap; ++ u16 mp_wr_bitmap; ++ ++ u16 mp_end_port; ++ u16 mp_data_port_mask; ++ ++ u8 curr_rd_port; ++ u8 curr_wr_port; ++ ++ u8 *mp_regs; ++ ++ struct mwifiex_sdio_mpa_tx mpa_tx; ++ struct mwifiex_sdio_mpa_rx mpa_rx; ++}; ++#endif /* _MWIFIEX_SDIO_H */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sta_cmd.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sta_cmd.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sta_cmd.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sta_cmd.c 2011-05-05 23:29:45.492441949 +0200 +@@ -0,0 +1,1219 @@ ++/* ++ * Marvell Wireless LAN device driver: station command handling ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++ ++/* ++ * This function prepares command to set/get RSSI information. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting data/beacon average factors ++ * - Resetting SNR/NF/RSSI values in private structure ++ * - Ensuring correct endian-ness ++ */ ++static int ++mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, u16 cmd_action) ++{ ++ cmd->command = cpu_to_le16(HostCmd_CMD_RSSI_INFO); ++ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rssi_info) + ++ S_DS_GEN); ++ cmd->params.rssi_info.action = cpu_to_le16(cmd_action); ++ cmd->params.rssi_info.ndata = cpu_to_le16(priv->data_avg_factor); ++ cmd->params.rssi_info.nbcn = cpu_to_le16(priv->bcn_avg_factor); ++ ++ /* Reset SNR/NF/RSSI values in private structure */ ++ priv->data_rssi_last = 0; ++ priv->data_nf_last = 0; ++ priv->data_rssi_avg = 0; ++ priv->data_nf_avg = 0; ++ priv->bcn_rssi_last = 0; ++ priv->bcn_nf_last = 0; ++ priv->bcn_rssi_avg = 0; ++ priv->bcn_nf_avg = 0; ++ ++ return 0; ++} ++ ++/* ++ * This function prepares command to set MAC control. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Ensuring correct endian-ness ++ */ ++static int mwifiex_cmd_mac_control(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ u16 cmd_action, void *data_buf) ++{ ++ struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl; ++ u16 action = *((u16 *) data_buf); ++ ++ if (cmd_action != HostCmd_ACT_GEN_SET) { ++ dev_err(priv->adapter->dev, ++ "mac_control: only support set cmd\n"); ++ return -1; ++ } ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL); ++ cmd->size = ++ cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN); ++ mac_ctrl->action = cpu_to_le16(action); ++ ++ return 0; ++} ++ ++/* ++ * This function prepares command to set/get SNMP MIB. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting SNMP MIB OID number and value ++ * (as required) ++ * - Ensuring correct endian-ness ++ * ++ * The following SNMP MIB OIDs are supported - ++ * - FRAG_THRESH_I : Fragmentation threshold ++ * - RTS_THRESH_I : RTS threshold ++ * - SHORT_RETRY_LIM_I : Short retry limit ++ * - DOT11D_I : 11d support ++ */ ++static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ u16 cmd_action, u32 cmd_oid, ++ void *data_buf) ++{ ++ struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib; ++ u32 ul_temp; ++ ++ dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB); ++ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib) ++ - 1 + S_DS_GEN); ++ ++ if (cmd_action == HostCmd_ACT_GEN_GET) { ++ snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET); ++ snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE); ++ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) ++ + MAX_SNMP_BUF_SIZE); ++ } ++ ++ switch (cmd_oid) { ++ case FRAG_THRESH_I: ++ snmp_mib->oid = cpu_to_le16((u16) FRAG_THRESH_I); ++ if (cmd_action == HostCmd_ACT_GEN_SET) { ++ snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); ++ snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); ++ ul_temp = *((u32 *) data_buf); ++ *((__le16 *) (snmp_mib->value)) = ++ cpu_to_le16((u16) ul_temp); ++ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) ++ + sizeof(u16)); ++ } ++ break; ++ case RTS_THRESH_I: ++ snmp_mib->oid = cpu_to_le16((u16) RTS_THRESH_I); ++ if (cmd_action == HostCmd_ACT_GEN_SET) { ++ snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); ++ snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); ++ ul_temp = *((u32 *) data_buf); ++ *(__le16 *) (snmp_mib->value) = ++ cpu_to_le16((u16) ul_temp); ++ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) ++ + sizeof(u16)); ++ } ++ break; ++ ++ case SHORT_RETRY_LIM_I: ++ snmp_mib->oid = cpu_to_le16((u16) SHORT_RETRY_LIM_I); ++ if (cmd_action == HostCmd_ACT_GEN_SET) { ++ snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); ++ snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); ++ ul_temp = (*(u32 *) data_buf); ++ *((__le16 *) (snmp_mib->value)) = ++ cpu_to_le16((u16) ul_temp); ++ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) ++ + sizeof(u16)); ++ } ++ break; ++ case DOT11D_I: ++ snmp_mib->oid = cpu_to_le16((u16) DOT11D_I); ++ if (cmd_action == HostCmd_ACT_GEN_SET) { ++ snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); ++ snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); ++ ul_temp = *(u32 *) data_buf; ++ *((__le16 *) (snmp_mib->value)) = ++ cpu_to_le16((u16) ul_temp); ++ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) ++ + sizeof(u16)); ++ } ++ break; ++ default: ++ break; ++ } ++ dev_dbg(priv->adapter->dev, ++ "cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x," ++ " Value=0x%x\n", ++ cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size), ++ le16_to_cpu(*(__le16 *) snmp_mib->value)); ++ return 0; ++} ++ ++/* ++ * This function prepares command to get log. ++ * ++ * Preparation includes - ++ * - Setting command ID and proper size ++ * - Ensuring correct endian-ness ++ */ ++static int ++mwifiex_cmd_802_11_get_log(struct host_cmd_ds_command *cmd) ++{ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG); ++ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) + ++ S_DS_GEN); ++ return 0; ++} ++ ++/* ++ * This function prepares command to set/get Tx data rate configuration. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting configuration index, rate scope and rate drop pattern ++ * parameters (as required) ++ * - Ensuring correct endian-ness ++ */ ++static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ u16 cmd_action, void *data_buf) ++{ ++ struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg; ++ struct mwifiex_rate_scope *rate_scope; ++ struct mwifiex_rate_drop_pattern *rate_drop; ++ u16 *pbitmap_rates = (u16 *) data_buf; ++ ++ u32 i; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG); ++ ++ rate_cfg->action = cpu_to_le16(cmd_action); ++ rate_cfg->cfg_index = 0; ++ ++ rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg + ++ sizeof(struct host_cmd_ds_tx_rate_cfg)); ++ rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE); ++ rate_scope->length = cpu_to_le16(sizeof(struct mwifiex_rate_scope) - ++ sizeof(struct mwifiex_ie_types_header)); ++ if (pbitmap_rates != NULL) { ++ rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]); ++ rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]); ++ for (i = 0; ++ i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); ++ i++) ++ rate_scope->ht_mcs_rate_bitmap[i] = ++ cpu_to_le16(pbitmap_rates[2 + i]); ++ } else { ++ rate_scope->hr_dsss_rate_bitmap = ++ cpu_to_le16(priv->bitmap_rates[0]); ++ rate_scope->ofdm_rate_bitmap = ++ cpu_to_le16(priv->bitmap_rates[1]); ++ for (i = 0; ++ i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); ++ i++) ++ rate_scope->ht_mcs_rate_bitmap[i] = ++ cpu_to_le16(priv->bitmap_rates[2 + i]); ++ } ++ ++ rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope + ++ sizeof(struct mwifiex_rate_scope)); ++ rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL); ++ rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode)); ++ rate_drop->rate_drop_mode = 0; ++ ++ cmd->size = ++ cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) + ++ sizeof(struct mwifiex_rate_scope) + ++ sizeof(struct mwifiex_rate_drop_pattern)); ++ ++ return 0; ++} ++ ++/* ++ * This function prepares command to set/get Tx power configuration. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting Tx power mode, power group TLV ++ * (as required) ++ * - Ensuring correct endian-ness ++ */ ++static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd, ++ u16 cmd_action, void *data_buf) ++{ ++ struct mwifiex_types_power_group *pg_tlv = NULL; ++ struct host_cmd_ds_txpwr_cfg *txp = NULL; ++ struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG); ++ cmd->size = ++ cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg)); ++ switch (cmd_action) { ++ case HostCmd_ACT_GEN_SET: ++ txp = (struct host_cmd_ds_txpwr_cfg *) data_buf; ++ if (txp->mode) { ++ pg_tlv = (struct mwifiex_types_power_group ++ *) ((unsigned long) data_buf + ++ sizeof(struct host_cmd_ds_txpwr_cfg)); ++ memmove(cmd_txp_cfg, data_buf, ++ sizeof(struct host_cmd_ds_txpwr_cfg) + ++ sizeof(struct mwifiex_types_power_group) + ++ pg_tlv->length); ++ ++ pg_tlv = (struct mwifiex_types_power_group *) ((u8 *) ++ cmd_txp_cfg + ++ sizeof(struct host_cmd_ds_txpwr_cfg)); ++ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + ++ sizeof(struct mwifiex_types_power_group) + ++ pg_tlv->length); ++ } else { ++ memmove(cmd_txp_cfg, data_buf, ++ sizeof(struct host_cmd_ds_txpwr_cfg)); ++ } ++ cmd_txp_cfg->action = cpu_to_le16(cmd_action); ++ break; ++ case HostCmd_ACT_GEN_GET: ++ cmd_txp_cfg->action = cpu_to_le16(cmd_action); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function prepares command to set Host Sleep configuration. ++ * ++ * Preparation includes - ++ * - Setting command ID and proper size ++ * - Setting Host Sleep action, conditions, ARP filters ++ * (as required) ++ * - Ensuring correct endian-ness ++ */ ++static int mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ u16 cmd_action, ++ struct mwifiex_hs_config_param *data_buf) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg; ++ u16 hs_activate = false; ++ ++ if (data_buf == NULL) ++ /* New Activate command */ ++ hs_activate = true; ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH); ++ ++ if (!hs_activate && ++ (data_buf->conditions ++ != cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) ++ && ((adapter->arp_filter_size > 0) ++ && (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) { ++ dev_dbg(adapter->dev, ++ "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n", ++ adapter->arp_filter_size); ++ memcpy(((u8 *) hs_cfg) + ++ sizeof(struct host_cmd_ds_802_11_hs_cfg_enh), ++ adapter->arp_filter, adapter->arp_filter_size); ++ cmd->size = cpu_to_le16(adapter->arp_filter_size + ++ sizeof(struct host_cmd_ds_802_11_hs_cfg_enh) ++ + S_DS_GEN); ++ } else { ++ cmd->size = cpu_to_le16(S_DS_GEN + sizeof(struct ++ host_cmd_ds_802_11_hs_cfg_enh)); ++ } ++ if (hs_activate) { ++ hs_cfg->action = cpu_to_le16(HS_ACTIVATE); ++ hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED; ++ } else { ++ hs_cfg->action = cpu_to_le16(HS_CONFIGURE); ++ hs_cfg->params.hs_config.conditions = data_buf->conditions; ++ hs_cfg->params.hs_config.gpio = data_buf->gpio; ++ hs_cfg->params.hs_config.gap = data_buf->gap; ++ dev_dbg(adapter->dev, ++ "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n", ++ hs_cfg->params.hs_config.conditions, ++ hs_cfg->params.hs_config.gpio, ++ hs_cfg->params.hs_config.gap); ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function prepares command to set/get MAC address. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting MAC address (for SET only) ++ * - Ensuring correct endian-ness ++ */ ++static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ u16 cmd_action) ++{ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS); ++ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) + ++ S_DS_GEN); ++ cmd->result = 0; ++ ++ cmd->params.mac_addr.action = cpu_to_le16(cmd_action); ++ ++ if (cmd_action == HostCmd_ACT_GEN_SET) ++ memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr, ++ ETH_ALEN); ++ return 0; ++} ++ ++/* ++ * This function prepares command to set MAC multicast address. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting MAC multicast address ++ * - Ensuring correct endian-ness ++ */ ++static int mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd, ++ u16 cmd_action, void *data_buf) ++{ ++ struct mwifiex_multicast_list *mcast_list = ++ (struct mwifiex_multicast_list *) data_buf; ++ struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr; ++ ++ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) + ++ S_DS_GEN); ++ cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR); ++ ++ mcast_addr->action = cpu_to_le16(cmd_action); ++ mcast_addr->num_of_adrs = ++ cpu_to_le16((u16) mcast_list->num_multicast_addr); ++ memcpy(mcast_addr->mac_list, mcast_list->mac_list, ++ mcast_list->num_multicast_addr * ETH_ALEN); ++ ++ return 0; ++} ++ ++/* ++ * This function prepares command to deauthenticate. ++ * ++ * Preparation includes - ++ * - Setting command ID and proper size ++ * - Setting AP MAC address and reason code ++ * - Ensuring correct endian-ness ++ */ ++static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ void *data_buf) ++{ ++ struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE); ++ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate) ++ + S_DS_GEN); ++ ++ /* Set AP MAC address */ ++ memcpy(deauth->mac_addr, (u8 *) data_buf, ETH_ALEN); ++ ++ dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr); ++ ++ deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING); ++ ++ return 0; ++} ++ ++/* ++ * This function prepares command to stop Ad-Hoc network. ++ * ++ * Preparation includes - ++ * - Setting command ID and proper size ++ * - Ensuring correct endian-ness ++ */ ++static int mwifiex_cmd_802_11_ad_hoc_stop(struct host_cmd_ds_command *cmd) ++{ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP); ++ cmd->size = cpu_to_le16(S_DS_GEN); ++ return 0; ++} ++ ++/* ++ * This function sets WEP key(s) to key parameter TLV(s). ++ * ++ * Multi-key parameter TLVs are supported, so we can send multiple ++ * WEP keys in a single buffer. ++ */ ++static int ++mwifiex_set_keyparamset_wep(struct mwifiex_private *priv, ++ struct mwifiex_ie_type_key_param_set *key_param_set, ++ u16 *key_param_len) ++{ ++ int cur_key_param_len = 0; ++ u8 i; ++ ++ /* Multi-key_param_set TLV is supported */ ++ for (i = 0; i < NUM_WEP_KEYS; i++) { ++ if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) || ++ (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) { ++ key_param_set->type = ++ cpu_to_le16(TLV_TYPE_KEY_MATERIAL); ++/* Key_param_set WEP fixed length */ ++#define KEYPARAMSET_WEP_FIXED_LEN 8 ++ key_param_set->length = cpu_to_le16((u16) ++ (priv->wep_key[i]. ++ key_length + ++ KEYPARAMSET_WEP_FIXED_LEN)); ++ key_param_set->key_type_id = ++ cpu_to_le16(KEY_TYPE_ID_WEP); ++ key_param_set->key_info = ++ cpu_to_le16(KEY_ENABLED | KEY_UNICAST | ++ KEY_MCAST); ++ key_param_set->key_len = ++ cpu_to_le16(priv->wep_key[i].key_length); ++ /* Set WEP key index */ ++ key_param_set->key[0] = i; ++ /* Set default Tx key flag */ ++ if (i == ++ (priv-> ++ wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK)) ++ key_param_set->key[1] = 1; ++ else ++ key_param_set->key[1] = 0; ++ memmove(&key_param_set->key[2], ++ priv->wep_key[i].key_material, ++ priv->wep_key[i].key_length); ++ ++ cur_key_param_len = priv->wep_key[i].key_length + ++ KEYPARAMSET_WEP_FIXED_LEN + ++ sizeof(struct mwifiex_ie_types_header); ++ *key_param_len += (u16) cur_key_param_len; ++ key_param_set = ++ (struct mwifiex_ie_type_key_param_set *) ++ ((u8 *)key_param_set + ++ cur_key_param_len); ++ } else if (!priv->wep_key[i].key_length) { ++ continue; ++ } else { ++ dev_err(priv->adapter->dev, ++ "key%d Length = %d is incorrect\n", ++ (i + 1), priv->wep_key[i].key_length); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function prepares command to set/get/reset network key(s). ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting WEP keys, WAPI keys or WPA keys along with required ++ * encryption (TKIP, AES) (as required) ++ * - Ensuring correct endian-ness ++ */ ++static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ u16 cmd_action, ++ u32 cmd_oid, void *data_buf) ++{ ++ struct host_cmd_ds_802_11_key_material *key_material = ++ &cmd->params.key_material; ++ struct mwifiex_ds_encrypt_key *enc_key = ++ (struct mwifiex_ds_encrypt_key *) data_buf; ++ u16 key_param_len = 0; ++ int ret = 0; ++ const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL); ++ key_material->action = cpu_to_le16(cmd_action); ++ ++ if (cmd_action == HostCmd_ACT_GEN_GET) { ++ cmd->size = ++ cpu_to_le16(sizeof(key_material->action) + S_DS_GEN); ++ return ret; ++ } ++ ++ if (!enc_key) { ++ memset(&key_material->key_param_set, 0, ++ (NUM_WEP_KEYS * ++ sizeof(struct mwifiex_ie_type_key_param_set))); ++ ret = mwifiex_set_keyparamset_wep(priv, ++ &key_material->key_param_set, ++ &key_param_len); ++ cmd->size = cpu_to_le16(key_param_len + ++ sizeof(key_material->action) + S_DS_GEN); ++ return ret; ++ } else ++ memset(&key_material->key_param_set, 0, ++ sizeof(struct mwifiex_ie_type_key_param_set)); ++ if (enc_key->is_wapi_key) { ++ dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n"); ++ key_material->key_param_set.key_type_id = ++ cpu_to_le16(KEY_TYPE_ID_WAPI); ++ if (cmd_oid == KEY_INFO_ENABLED) ++ key_material->key_param_set.key_info = ++ cpu_to_le16(KEY_ENABLED); ++ else ++ key_material->key_param_set.key_info = ++ cpu_to_le16(!KEY_ENABLED); ++ ++ key_material->key_param_set.key[0] = enc_key->key_index; ++ if (!priv->sec_info.wapi_key_on) ++ key_material->key_param_set.key[1] = 1; ++ else ++ /* set 0 when re-key */ ++ key_material->key_param_set.key[1] = 0; ++ ++ if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) { ++ /* WAPI pairwise key: unicast */ ++ key_material->key_param_set.key_info |= ++ cpu_to_le16(KEY_UNICAST); ++ } else { /* WAPI group key: multicast */ ++ key_material->key_param_set.key_info |= ++ cpu_to_le16(KEY_MCAST); ++ priv->sec_info.wapi_key_on = true; ++ } ++ ++ key_material->key_param_set.type = ++ cpu_to_le16(TLV_TYPE_KEY_MATERIAL); ++ key_material->key_param_set.key_len = ++ cpu_to_le16(WAPI_KEY_LEN); ++ memcpy(&key_material->key_param_set.key[2], ++ enc_key->key_material, enc_key->key_len); ++ memcpy(&key_material->key_param_set.key[2 + enc_key->key_len], ++ enc_key->wapi_rxpn, WAPI_RXPN_LEN); ++ key_material->key_param_set.length = ++ cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN); ++ ++ key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) + ++ sizeof(struct mwifiex_ie_types_header); ++ cmd->size = cpu_to_le16(key_param_len + ++ sizeof(key_material->action) + S_DS_GEN); ++ return ret; ++ } ++ if (enc_key->key_len == WLAN_KEY_LEN_CCMP) { ++ dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n"); ++ key_material->key_param_set.key_type_id = ++ cpu_to_le16(KEY_TYPE_ID_AES); ++ if (cmd_oid == KEY_INFO_ENABLED) ++ key_material->key_param_set.key_info = ++ cpu_to_le16(KEY_ENABLED); ++ else ++ key_material->key_param_set.key_info = ++ cpu_to_le16(!KEY_ENABLED); ++ ++ if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) ++ /* AES pairwise key: unicast */ ++ key_material->key_param_set.key_info |= ++ cpu_to_le16(KEY_UNICAST); ++ else /* AES group key: multicast */ ++ key_material->key_param_set.key_info |= ++ cpu_to_le16(KEY_MCAST); ++ } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) { ++ dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n"); ++ key_material->key_param_set.key_type_id = ++ cpu_to_le16(KEY_TYPE_ID_TKIP); ++ key_material->key_param_set.key_info = ++ cpu_to_le16(KEY_ENABLED); ++ ++ if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) ++ /* TKIP pairwise key: unicast */ ++ key_material->key_param_set.key_info |= ++ cpu_to_le16(KEY_UNICAST); ++ else /* TKIP group key: multicast */ ++ key_material->key_param_set.key_info |= ++ cpu_to_le16(KEY_MCAST); ++ } ++ ++ if (key_material->key_param_set.key_type_id) { ++ key_material->key_param_set.type = ++ cpu_to_le16(TLV_TYPE_KEY_MATERIAL); ++ key_material->key_param_set.key_len = ++ cpu_to_le16((u16) enc_key->key_len); ++ memcpy(key_material->key_param_set.key, enc_key->key_material, ++ enc_key->key_len); ++ key_material->key_param_set.length = ++ cpu_to_le16((u16) enc_key->key_len + ++ KEYPARAMSET_FIXED_LEN); ++ ++ key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN) ++ + sizeof(struct mwifiex_ie_types_header); ++ ++ cmd->size = cpu_to_le16(key_param_len + ++ sizeof(key_material->action) + S_DS_GEN); ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function prepares command to set/get 11d domain information. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting domain information fields (for SET only) ++ * - Ensuring correct endian-ness ++ */ ++static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ u16 cmd_action) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct host_cmd_ds_802_11d_domain_info *domain_info = ++ &cmd->params.domain_info; ++ struct mwifiex_ietypes_domain_param_set *domain = ++ &domain_info->domain; ++ u8 no_of_triplet = adapter->domain_reg.no_of_triplet; ++ ++ dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet); ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO); ++ domain_info->action = cpu_to_le16(cmd_action); ++ if (cmd_action == HostCmd_ACT_GEN_GET) { ++ cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN); ++ return 0; ++ } ++ ++ /* Set domain info fields */ ++ domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY); ++ memcpy(domain->country_code, adapter->domain_reg.country_code, ++ sizeof(domain->country_code)); ++ ++ domain->header.len = cpu_to_le16((no_of_triplet * ++ sizeof(struct ieee80211_country_ie_triplet)) + ++ sizeof(domain->country_code)); ++ ++ if (no_of_triplet) { ++ memcpy(domain->triplet, adapter->domain_reg.triplet, ++ no_of_triplet * ++ sizeof(struct ieee80211_country_ie_triplet)); ++ ++ cmd->size = cpu_to_le16(sizeof(domain_info->action) + ++ le16_to_cpu(domain->header.len) + ++ sizeof(struct mwifiex_ie_types_header) ++ + S_DS_GEN); ++ } else { ++ cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN); ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function prepares command to set/get RF channel. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting RF type and current RF channel (for SET only) ++ * - Ensuring correct endian-ness ++ */ ++static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *cmd, ++ u16 cmd_action, void *data_buf) ++{ ++ struct host_cmd_ds_802_11_rf_channel *rf_chan = ++ &cmd->params.rf_channel; ++ uint16_t rf_type = le16_to_cpu(rf_chan->rf_type); ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL); ++ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rf_channel) ++ + S_DS_GEN); ++ ++ if (cmd_action == HostCmd_ACT_GEN_SET) { ++ if ((priv->adapter->adhoc_start_band & BAND_A) ++ || (priv->adapter->adhoc_start_band & BAND_AN)) ++ rf_chan->rf_type = ++ cpu_to_le16(HostCmd_SCAN_RADIO_TYPE_A); ++ ++ rf_type = le16_to_cpu(rf_chan->rf_type); ++ SET_SECONDARYCHAN(rf_type, priv->adapter->chan_offset); ++ rf_chan->current_channel = cpu_to_le16(*((u16 *) data_buf)); ++ } ++ rf_chan->action = cpu_to_le16(cmd_action); ++ return 0; ++} ++ ++/* ++ * This function prepares command to set/get IBSS coalescing status. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting status to enable or disable (for SET only) ++ * - Ensuring correct endian-ness ++ */ ++static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd, ++ u16 cmd_action, void *data_buf) ++{ ++ struct host_cmd_ds_802_11_ibss_status *ibss_coal = ++ &(cmd->params.ibss_coalescing); ++ u16 enable = 0; ++ ++ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS); ++ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) + ++ S_DS_GEN); ++ cmd->result = 0; ++ ibss_coal->action = cpu_to_le16(cmd_action); ++ ++ switch (cmd_action) { ++ case HostCmd_ACT_GEN_SET: ++ if (data_buf != NULL) ++ enable = *(u16 *) data_buf; ++ ibss_coal->enable = cpu_to_le16(enable); ++ break; ++ ++ /* In other case.. Nothing to do */ ++ case HostCmd_ACT_GEN_GET: ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function prepares command to set/get register value. ++ * ++ * Preparation includes - ++ * - Setting command ID, action and proper size ++ * - Setting register offset (for both GET and SET) and ++ * register value (for SET only) ++ * - Ensuring correct endian-ness ++ * ++ * The following type of registers can be accessed with this function - ++ * - MAC register ++ * - BBP register ++ * - RF register ++ * - PMIC register ++ * - CAU register ++ * - EEPROM ++ */ ++static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, ++ u16 cmd_action, void *data_buf) ++{ ++ struct mwifiex_ds_reg_rw *reg_rw; ++ ++ reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; ++ switch (le16_to_cpu(cmd->command)) { ++ case HostCmd_CMD_MAC_REG_ACCESS: ++ { ++ struct host_cmd_ds_mac_reg_access *mac_reg; ++ ++ cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN); ++ mac_reg = (struct host_cmd_ds_mac_reg_access *) &cmd-> ++ params.mac_reg; ++ mac_reg->action = cpu_to_le16(cmd_action); ++ mac_reg->offset = ++ cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); ++ mac_reg->value = reg_rw->value; ++ break; ++ } ++ case HostCmd_CMD_BBP_REG_ACCESS: ++ { ++ struct host_cmd_ds_bbp_reg_access *bbp_reg; ++ ++ cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN); ++ bbp_reg = (struct host_cmd_ds_bbp_reg_access *) &cmd-> ++ params.bbp_reg; ++ bbp_reg->action = cpu_to_le16(cmd_action); ++ bbp_reg->offset = ++ cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); ++ bbp_reg->value = (u8) le32_to_cpu(reg_rw->value); ++ break; ++ } ++ case HostCmd_CMD_RF_REG_ACCESS: ++ { ++ struct host_cmd_ds_rf_reg_access *rf_reg; ++ ++ cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN); ++ rf_reg = (struct host_cmd_ds_rf_reg_access *) &cmd-> ++ params.rf_reg; ++ rf_reg->action = cpu_to_le16(cmd_action); ++ rf_reg->offset = ++ cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); ++ rf_reg->value = (u8) le32_to_cpu(reg_rw->value); ++ break; ++ } ++ case HostCmd_CMD_PMIC_REG_ACCESS: ++ { ++ struct host_cmd_ds_pmic_reg_access *pmic_reg; ++ ++ cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN); ++ pmic_reg = (struct host_cmd_ds_pmic_reg_access *) &cmd-> ++ params.pmic_reg; ++ pmic_reg->action = cpu_to_le16(cmd_action); ++ pmic_reg->offset = ++ cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); ++ pmic_reg->value = (u8) le32_to_cpu(reg_rw->value); ++ break; ++ } ++ case HostCmd_CMD_CAU_REG_ACCESS: ++ { ++ struct host_cmd_ds_rf_reg_access *cau_reg; ++ ++ cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN); ++ cau_reg = (struct host_cmd_ds_rf_reg_access *) &cmd-> ++ params.rf_reg; ++ cau_reg->action = cpu_to_le16(cmd_action); ++ cau_reg->offset = ++ cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); ++ cau_reg->value = (u8) le32_to_cpu(reg_rw->value); ++ break; ++ } ++ case HostCmd_CMD_802_11_EEPROM_ACCESS: ++ { ++ struct mwifiex_ds_read_eeprom *rd_eeprom = ++ (struct mwifiex_ds_read_eeprom *) data_buf; ++ struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom = ++ (struct host_cmd_ds_802_11_eeprom_access *) ++ &cmd->params.eeprom; ++ ++ cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN); ++ cmd_eeprom->action = cpu_to_le16(cmd_action); ++ cmd_eeprom->offset = rd_eeprom->offset; ++ cmd_eeprom->byte_count = rd_eeprom->byte_count; ++ cmd_eeprom->value = 0; ++ break; ++ } ++ default: ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function prepares the commands before sending them to the firmware. ++ * ++ * This is a generic function which calls specific command preparation ++ * routines based upon the command number. ++ */ ++int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, ++ u16 cmd_action, u32 cmd_oid, ++ void *data_buf, void *cmd_buf) ++{ ++ struct host_cmd_ds_command *cmd_ptr = ++ (struct host_cmd_ds_command *) cmd_buf; ++ int ret = 0; ++ ++ /* Prepare command */ ++ switch (cmd_no) { ++ case HostCmd_CMD_GET_HW_SPEC: ++ ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr); ++ break; ++ case HostCmd_CMD_MAC_CONTROL: ++ ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action, ++ data_buf); ++ break; ++ case HostCmd_CMD_802_11_MAC_ADDRESS: ++ ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr, ++ cmd_action); ++ break; ++ case HostCmd_CMD_MAC_MULTICAST_ADR: ++ ret = mwifiex_cmd_mac_multicast_adr(cmd_ptr, cmd_action, ++ data_buf); ++ break; ++ case HostCmd_CMD_TX_RATE_CFG: ++ ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action, ++ data_buf); ++ break; ++ case HostCmd_CMD_TXPWR_CFG: ++ ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action, ++ data_buf); ++ break; ++ case HostCmd_CMD_802_11_PS_MODE_ENH: ++ ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action, ++ (uint16_t)cmd_oid, data_buf); ++ break; ++ case HostCmd_CMD_802_11_HS_CFG_ENH: ++ ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action, ++ (struct mwifiex_hs_config_param *) data_buf); ++ break; ++ case HostCmd_CMD_802_11_SCAN: ++ ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf); ++ break; ++ case HostCmd_CMD_802_11_BG_SCAN_QUERY: ++ ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr); ++ break; ++ case HostCmd_CMD_802_11_ASSOCIATE: ++ ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf); ++ break; ++ case HostCmd_CMD_802_11_DEAUTHENTICATE: ++ ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr, ++ data_buf); ++ break; ++ case HostCmd_CMD_802_11_AD_HOC_START: ++ ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr, ++ data_buf); ++ break; ++ case HostCmd_CMD_802_11_GET_LOG: ++ ret = mwifiex_cmd_802_11_get_log(cmd_ptr); ++ break; ++ case HostCmd_CMD_802_11_AD_HOC_JOIN: ++ ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr, ++ data_buf); ++ break; ++ case HostCmd_CMD_802_11_AD_HOC_STOP: ++ ret = mwifiex_cmd_802_11_ad_hoc_stop(cmd_ptr); ++ break; ++ case HostCmd_CMD_RSSI_INFO: ++ ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action); ++ break; ++ case HostCmd_CMD_802_11_SNMP_MIB: ++ ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action, ++ cmd_oid, data_buf); ++ break; ++ case HostCmd_CMD_802_11_TX_RATE_QUERY: ++ cmd_ptr->command = ++ cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY); ++ cmd_ptr->size = ++ cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) + ++ S_DS_GEN); ++ priv->tx_rate = 0; ++ ret = 0; ++ break; ++ case HostCmd_CMD_VERSION_EXT: ++ cmd_ptr->command = cpu_to_le16(cmd_no); ++ cmd_ptr->params.verext.version_str_sel = ++ (u8) (*((u32 *) data_buf)); ++ memcpy(&cmd_ptr->params, data_buf, ++ sizeof(struct host_cmd_ds_version_ext)); ++ cmd_ptr->size = ++ cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) + ++ S_DS_GEN); ++ ret = 0; ++ break; ++ case HostCmd_CMD_802_11_RF_CHANNEL: ++ ret = mwifiex_cmd_802_11_rf_channel(priv, cmd_ptr, cmd_action, ++ data_buf); ++ break; ++ case HostCmd_CMD_FUNC_INIT: ++ if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET) ++ priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY; ++ cmd_ptr->command = cpu_to_le16(cmd_no); ++ cmd_ptr->size = cpu_to_le16(S_DS_GEN); ++ break; ++ case HostCmd_CMD_FUNC_SHUTDOWN: ++ priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET; ++ cmd_ptr->command = cpu_to_le16(cmd_no); ++ cmd_ptr->size = cpu_to_le16(S_DS_GEN); ++ break; ++ case HostCmd_CMD_11N_ADDBA_REQ: ++ ret = mwifiex_cmd_11n_addba_req(cmd_ptr, data_buf); ++ break; ++ case HostCmd_CMD_11N_DELBA: ++ ret = mwifiex_cmd_11n_delba(cmd_ptr, data_buf); ++ break; ++ case HostCmd_CMD_11N_ADDBA_RSP: ++ ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf); ++ break; ++ case HostCmd_CMD_802_11_KEY_MATERIAL: ++ ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr, ++ cmd_action, cmd_oid, ++ data_buf); ++ break; ++ case HostCmd_CMD_802_11D_DOMAIN_INFO: ++ ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr, ++ cmd_action); ++ break; ++ case HostCmd_CMD_RECONFIGURE_TX_BUFF: ++ ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action, ++ data_buf); ++ break; ++ case HostCmd_CMD_AMSDU_AGGR_CTRL: ++ ret = mwifiex_cmd_amsdu_aggr_ctrl(cmd_ptr, cmd_action, ++ data_buf); ++ break; ++ case HostCmd_CMD_11N_CFG: ++ ret = mwifiex_cmd_11n_cfg(cmd_ptr, cmd_action, ++ data_buf); ++ break; ++ case HostCmd_CMD_WMM_GET_STATUS: ++ dev_dbg(priv->adapter->dev, ++ "cmd: WMM: WMM_GET_STATUS cmd sent\n"); ++ cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS); ++ cmd_ptr->size = ++ cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) + ++ S_DS_GEN); ++ ret = 0; ++ break; ++ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: ++ ret = mwifiex_cmd_ibss_coalescing_status(cmd_ptr, cmd_action, ++ data_buf); ++ break; ++ case HostCmd_CMD_MAC_REG_ACCESS: ++ case HostCmd_CMD_BBP_REG_ACCESS: ++ case HostCmd_CMD_RF_REG_ACCESS: ++ case HostCmd_CMD_PMIC_REG_ACCESS: ++ case HostCmd_CMD_CAU_REG_ACCESS: ++ case HostCmd_CMD_802_11_EEPROM_ACCESS: ++ ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf); ++ break; ++ case HostCmd_CMD_SET_BSS_MODE: ++ cmd_ptr->command = cpu_to_le16(cmd_no); ++ if (priv->bss_mode == NL80211_IFTYPE_ADHOC) ++ cmd_ptr->params.bss_mode.con_type = ++ CONNECTION_TYPE_ADHOC; ++ else if (priv->bss_mode == NL80211_IFTYPE_STATION) ++ cmd_ptr->params.bss_mode.con_type = ++ CONNECTION_TYPE_INFRA; ++ cmd_ptr->size = cpu_to_le16(sizeof(struct ++ host_cmd_ds_set_bss_mode) + S_DS_GEN); ++ ret = 0; ++ break; ++ default: ++ dev_err(priv->adapter->dev, ++ "PREP_CMD: unknown cmd- %#x\n", cmd_no); ++ ret = -1; ++ break; ++ } ++ return ret; ++} ++ ++/* ++ * This function issues commands to initialize firmware. ++ * ++ * This is called after firmware download to bring the card to ++ * working state. ++ * ++ * The following commands are issued sequentially - ++ * - Function init (for first interface only) ++ * - Read MAC address (for first interface only) ++ * - Reconfigure Tx buffer size (for first interface only) ++ * - Enable auto deep sleep (for first interface only) ++ * - Get Tx rate ++ * - Get Tx power ++ * - Set IBSS coalescing status ++ * - Set AMSDU aggregation control ++ * - Set 11d control ++ * - Set MAC control (this must be the last command to initialize firmware) ++ */ ++int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) ++{ ++ int ret = 0; ++ u16 enable = true; ++ struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; ++ struct mwifiex_ds_auto_ds auto_ds; ++ enum state_11d_t state_11d; ++ ++ if (first_sta) { ++ ++ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT, ++ HostCmd_ACT_GEN_SET, 0, NULL); ++ if (ret) ++ return -1; ++ /* Read MAC address from HW */ ++ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_GET_HW_SPEC, ++ HostCmd_ACT_GEN_GET, 0, NULL); ++ if (ret) ++ return -1; ++ ++ /* Reconfigure tx buf size */ ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_RECONFIGURE_TX_BUFF, ++ HostCmd_ACT_GEN_SET, 0, ++ &priv->adapter->tx_buf_size); ++ if (ret) ++ return -1; ++ ++ /* Enable IEEE PS by default */ ++ priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_802_11_PS_MODE_ENH, ++ EN_AUTO_PS, BITMAP_STA_PS, NULL); ++ if (ret) ++ return -1; ++ } ++ ++ /* get tx rate */ ++ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TX_RATE_CFG, ++ HostCmd_ACT_GEN_GET, 0, NULL); ++ if (ret) ++ return -1; ++ priv->data_rate = 0; ++ ++ /* get tx power */ ++ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TXPWR_CFG, ++ HostCmd_ACT_GEN_GET, 0, NULL); ++ if (ret) ++ return -1; ++ ++ /* set ibss coalescing_status */ ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, ++ HostCmd_ACT_GEN_SET, 0, &enable); ++ if (ret) ++ return -1; ++ ++ memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl)); ++ amsdu_aggr_ctrl.enable = true; ++ /* Send request to firmware */ ++ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_AMSDU_AGGR_CTRL, ++ HostCmd_ACT_GEN_SET, 0, ++ (void *) &amsdu_aggr_ctrl); ++ if (ret) ++ return -1; ++ /* MAC Control must be the last command in init_fw */ ++ /* set MAC Control */ ++ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, ++ HostCmd_ACT_GEN_SET, 0, ++ &priv->curr_pkt_filter); ++ if (ret) ++ return -1; ++ ++ if (first_sta) { ++ /* Enable auto deep sleep */ ++ auto_ds.auto_ds = DEEP_SLEEP_ON; ++ auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_802_11_PS_MODE_ENH, ++ EN_AUTO_PS, BITMAP_AUTO_DS, ++ &auto_ds); ++ if (ret) ++ return -1; ++ } ++ ++ /* Send cmd to FW to enable/disable 11D function */ ++ state_11d = ENABLE_11D; ++ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB, ++ HostCmd_ACT_GEN_SET, DOT11D_I, &state_11d); ++ if (ret) ++ dev_err(priv->adapter->dev, "11D: failed to enable 11D\n"); ++ ++ /* set last_init_cmd */ ++ priv->adapter->last_init_cmd = HostCmd_CMD_802_11_SNMP_MIB; ++ ret = -EINPROGRESS; ++ ++ return ret; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sta_cmdresp.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sta_cmdresp.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sta_cmdresp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sta_cmdresp.c 2011-05-05 23:29:45.475441743 +0200 +@@ -0,0 +1,972 @@ ++/* ++ * Marvell Wireless LAN device driver: station command response handling ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++ ++ ++/* ++ * This function handles the command response error case. ++ * ++ * For scan response error, the function cancels all the pending ++ * scan commands and generates an event to inform the applications ++ * of the scan completion. ++ * ++ * For Power Save command failure, we do not retry enter PS ++ * command in case of Ad-hoc mode. ++ * ++ * For all other response errors, the current command buffer is freed ++ * and returned to the free command queue. ++ */ ++static void ++mwifiex_process_cmdresp_error(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct host_cmd_ds_802_11_ps_mode_enh *pm; ++ unsigned long flags; ++ ++ dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n", ++ resp->command, resp->result); ++ ++ if (adapter->curr_cmd->wait_q_enabled) ++ adapter->cmd_wait_q.status = -1; ++ ++ switch (le16_to_cpu(resp->command)) { ++ case HostCmd_CMD_802_11_PS_MODE_ENH: ++ pm = &resp->params.psmode_enh; ++ dev_err(adapter->dev, "PS_MODE_ENH cmd failed: " ++ "result=0x%x action=0x%X\n", ++ resp->result, le16_to_cpu(pm->action)); ++ /* We do not re-try enter-ps command in ad-hoc mode. */ ++ if (le16_to_cpu(pm->action) == EN_AUTO_PS && ++ (le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) && ++ priv->bss_mode == NL80211_IFTYPE_ADHOC) ++ adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; ++ ++ break; ++ case HostCmd_CMD_802_11_SCAN: ++ /* Cancel all pending scan command */ ++ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); ++ list_for_each_entry_safe(cmd_node, tmp_node, ++ &adapter->scan_pending_q, list) { ++ list_del(&cmd_node->list); ++ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, ++ flags); ++ mwifiex_insert_cmd_to_free_q(adapter, cmd_node); ++ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); ++ } ++ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); ++ ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); ++ adapter->scan_processing = false; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); ++ if (priv->report_scan_result) ++ priv->report_scan_result = false; ++ if (priv->scan_pending_on_block) { ++ priv->scan_pending_on_block = false; ++ up(&priv->async_sem); ++ } ++ break; ++ ++ case HostCmd_CMD_MAC_CONTROL: ++ break; ++ ++ default: ++ break; ++ } ++ /* Handling errors here */ ++ mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); ++ ++ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); ++ adapter->curr_cmd = NULL; ++ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); ++} ++ ++/* ++ * This function handles the command response of get RSSI info. ++ * ++ * Handling includes changing the header fields into CPU format ++ * and saving the following parameters in driver - ++ * - Last data and beacon RSSI value ++ * - Average data and beacon RSSI value ++ * - Last data and beacon NF value ++ * - Average data and beacon NF value ++ * ++ * The parameters are send to the application as well, along with ++ * calculated SNR values. ++ */ ++static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp, ++ void *data_buf) ++{ ++ struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp = ++ &resp->params.rssi_info_rsp; ++ struct mwifiex_ds_get_signal *signal = NULL; ++ ++ priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last); ++ priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last); ++ ++ priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg); ++ priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg); ++ ++ priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last); ++ priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last); ++ ++ priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg); ++ priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg); ++ ++ /* Need to indicate IOCTL complete */ ++ if (data_buf) { ++ signal = (struct mwifiex_ds_get_signal *) data_buf; ++ memset(signal, 0, sizeof(struct mwifiex_ds_get_signal)); ++ ++ signal->selector = ALL_RSSI_INFO_MASK; ++ ++ /* RSSI */ ++ signal->bcn_rssi_last = priv->bcn_rssi_last; ++ signal->bcn_rssi_avg = priv->bcn_rssi_avg; ++ signal->data_rssi_last = priv->data_rssi_last; ++ signal->data_rssi_avg = priv->data_rssi_avg; ++ ++ /* SNR */ ++ signal->bcn_snr_last = ++ CAL_SNR(priv->bcn_rssi_last, priv->bcn_nf_last); ++ signal->bcn_snr_avg = ++ CAL_SNR(priv->bcn_rssi_avg, priv->bcn_nf_avg); ++ signal->data_snr_last = ++ CAL_SNR(priv->data_rssi_last, priv->data_nf_last); ++ signal->data_snr_avg = ++ CAL_SNR(priv->data_rssi_avg, priv->data_nf_avg); ++ ++ /* NF */ ++ signal->bcn_nf_last = priv->bcn_nf_last; ++ signal->bcn_nf_avg = priv->bcn_nf_avg; ++ signal->data_nf_last = priv->data_nf_last; ++ signal->data_nf_avg = priv->data_nf_avg; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of set/get SNMP ++ * MIB parameters. ++ * ++ * Handling includes changing the header fields into CPU format ++ * and saving the parameter in driver. ++ * ++ * The following parameters are supported - ++ * - Fragmentation threshold ++ * - RTS threshold ++ * - Short retry limit ++ */ ++static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp, ++ void *data_buf) ++{ ++ struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; ++ u16 oid = le16_to_cpu(smib->oid); ++ u16 query_type = le16_to_cpu(smib->query_type); ++ u32 ul_temp; ++ ++ dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x," ++ " query_type = %#x, buf size = %#x\n", ++ oid, query_type, le16_to_cpu(smib->buf_size)); ++ if (query_type == HostCmd_ACT_GEN_GET) { ++ ul_temp = le16_to_cpu(*((__le16 *) (smib->value))); ++ if (data_buf) ++ *(u32 *)data_buf = ul_temp; ++ switch (oid) { ++ case FRAG_THRESH_I: ++ dev_dbg(priv->adapter->dev, ++ "info: SNMP_RESP: FragThsd =%u\n", ul_temp); ++ break; ++ case RTS_THRESH_I: ++ dev_dbg(priv->adapter->dev, ++ "info: SNMP_RESP: RTSThsd =%u\n", ul_temp); ++ break; ++ case SHORT_RETRY_LIM_I: ++ dev_dbg(priv->adapter->dev, ++ "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of get log request ++ * ++ * Handling includes changing the header fields into CPU format ++ * and sending the received parameters to application. ++ */ ++static int mwifiex_ret_get_log(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp, ++ void *data_buf) ++{ ++ struct host_cmd_ds_802_11_get_log *get_log = ++ (struct host_cmd_ds_802_11_get_log *) &resp->params.get_log; ++ struct mwifiex_ds_get_stats *stats = NULL; ++ ++ if (data_buf) { ++ stats = (struct mwifiex_ds_get_stats *) data_buf; ++ stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame); ++ stats->failed = le32_to_cpu(get_log->failed); ++ stats->retry = le32_to_cpu(get_log->retry); ++ stats->multi_retry = le32_to_cpu(get_log->multi_retry); ++ stats->frame_dup = le32_to_cpu(get_log->frame_dup); ++ stats->rts_success = le32_to_cpu(get_log->rts_success); ++ stats->rts_failure = le32_to_cpu(get_log->rts_failure); ++ stats->ack_failure = le32_to_cpu(get_log->ack_failure); ++ stats->rx_frag = le32_to_cpu(get_log->rx_frag); ++ stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame); ++ stats->fcs_error = le32_to_cpu(get_log->fcs_error); ++ stats->tx_frame = le32_to_cpu(get_log->tx_frame); ++ stats->wep_icv_error[0] = ++ le32_to_cpu(get_log->wep_icv_err_cnt[0]); ++ stats->wep_icv_error[1] = ++ le32_to_cpu(get_log->wep_icv_err_cnt[1]); ++ stats->wep_icv_error[2] = ++ le32_to_cpu(get_log->wep_icv_err_cnt[2]); ++ stats->wep_icv_error[3] = ++ le32_to_cpu(get_log->wep_icv_err_cnt[3]); ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of set/get Tx rate ++ * configurations. ++ * ++ * Handling includes changing the header fields into CPU format ++ * and saving the following parameters in driver - ++ * - DSSS rate bitmap ++ * - OFDM rate bitmap ++ * - HT MCS rate bitmaps ++ * ++ * Based on the new rate bitmaps, the function re-evaluates if ++ * auto data rate has been activated. If not, it sends another ++ * query to the firmware to get the current Tx data rate and updates ++ * the driver value. ++ */ ++static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp, ++ void *data_buf) ++{ ++ struct mwifiex_rate_cfg *ds_rate = NULL; ++ struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg; ++ struct mwifiex_rate_scope *rate_scope; ++ struct mwifiex_ie_types_header *head = NULL; ++ u16 tlv, tlv_buf_len; ++ u8 *tlv_buf; ++ u32 i; ++ int ret = 0; ++ ++ tlv_buf = (u8 *) ((u8 *) rate_cfg) + ++ sizeof(struct host_cmd_ds_tx_rate_cfg); ++ tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16)); ++ ++ while (tlv_buf && tlv_buf_len > 0) { ++ tlv = (*tlv_buf); ++ tlv = tlv | (*(tlv_buf + 1) << 8); ++ ++ switch (tlv) { ++ case TLV_TYPE_RATE_SCOPE: ++ rate_scope = (struct mwifiex_rate_scope *) tlv_buf; ++ priv->bitmap_rates[0] = ++ le16_to_cpu(rate_scope->hr_dsss_rate_bitmap); ++ priv->bitmap_rates[1] = ++ le16_to_cpu(rate_scope->ofdm_rate_bitmap); ++ for (i = 0; ++ i < ++ sizeof(rate_scope->ht_mcs_rate_bitmap) / ++ sizeof(u16); i++) ++ priv->bitmap_rates[2 + i] = ++ le16_to_cpu(rate_scope-> ++ ht_mcs_rate_bitmap[i]); ++ break; ++ /* Add RATE_DROP tlv here */ ++ } ++ ++ head = (struct mwifiex_ie_types_header *) tlv_buf; ++ tlv_buf += le16_to_cpu(head->len) + sizeof(*head); ++ tlv_buf_len -= le16_to_cpu(head->len); ++ } ++ ++ priv->is_data_rate_auto = mwifiex_is_rate_auto(priv); ++ ++ if (priv->is_data_rate_auto) ++ priv->data_rate = 0; ++ else ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_802_11_TX_RATE_QUERY, ++ HostCmd_ACT_GEN_GET, 0, NULL); ++ ++ if (data_buf) { ++ ds_rate = (struct mwifiex_rate_cfg *) data_buf; ++ if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) { ++ if (priv->is_data_rate_auto) { ++ ds_rate->is_rate_auto = 1; ++ } else { ++ ds_rate->rate = mwifiex_get_rate_index(priv-> ++ bitmap_rates, ++ sizeof(priv-> ++ bitmap_rates)); ++ if (ds_rate->rate >= ++ MWIFIEX_RATE_BITMAP_OFDM0 ++ && ds_rate->rate <= ++ MWIFIEX_RATE_BITMAP_OFDM7) ++ ds_rate->rate -= ++ (MWIFIEX_RATE_BITMAP_OFDM0 - ++ MWIFIEX_RATE_INDEX_OFDM0); ++ if (ds_rate->rate >= ++ MWIFIEX_RATE_BITMAP_MCS0 ++ && ds_rate->rate <= ++ MWIFIEX_RATE_BITMAP_MCS127) ++ ds_rate->rate -= ++ (MWIFIEX_RATE_BITMAP_MCS0 - ++ MWIFIEX_RATE_INDEX_MCS0); ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function handles the command response of get Tx power level. ++ * ++ * Handling includes saving the maximum and minimum Tx power levels ++ * in driver, as well as sending the values to user. ++ */ ++static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf) ++{ ++ int length = -1, max_power = -1, min_power = -1; ++ struct mwifiex_types_power_group *pg_tlv_hdr = NULL; ++ struct mwifiex_power_group *pg = NULL; ++ ++ if (data_buf) { ++ pg_tlv_hdr = ++ (struct mwifiex_types_power_group *) ((u8 *) data_buf ++ + sizeof(struct host_cmd_ds_txpwr_cfg)); ++ pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr + ++ sizeof(struct mwifiex_types_power_group)); ++ length = pg_tlv_hdr->length; ++ if (length > 0) { ++ max_power = pg->power_max; ++ min_power = pg->power_min; ++ length -= sizeof(struct mwifiex_power_group); ++ } ++ while (length) { ++ pg++; ++ if (max_power < pg->power_max) ++ max_power = pg->power_max; ++ ++ if (min_power > pg->power_min) ++ min_power = pg->power_min; ++ ++ length -= sizeof(struct mwifiex_power_group); ++ } ++ if (pg_tlv_hdr->length > 0) { ++ priv->min_tx_power_level = (u8) min_power; ++ priv->max_tx_power_level = (u8) max_power; ++ } ++ } else { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of set/get Tx power ++ * configurations. ++ * ++ * Handling includes changing the header fields into CPU format ++ * and saving the current Tx power level in driver. ++ */ ++static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp, ++ void *data_buf) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg; ++ struct mwifiex_types_power_group *pg_tlv_hdr = NULL; ++ struct mwifiex_power_group *pg = NULL; ++ u16 action = le16_to_cpu(txp_cfg->action); ++ ++ switch (action) { ++ case HostCmd_ACT_GEN_GET: ++ { ++ pg_tlv_hdr = ++ (struct mwifiex_types_power_group *) ((u8 *) ++ txp_cfg + ++ sizeof ++ (struct ++ host_cmd_ds_txpwr_cfg)); ++ pg = (struct mwifiex_power_group *) ((u8 *) ++ pg_tlv_hdr + ++ sizeof(struct ++ mwifiex_types_power_group)); ++ if (adapter->hw_status == ++ MWIFIEX_HW_STATUS_INITIALIZING) ++ mwifiex_get_power_level(priv, txp_cfg); ++ priv->tx_power_level = (u16) pg->power_min; ++ break; ++ } ++ case HostCmd_ACT_GEN_SET: ++ if (le32_to_cpu(txp_cfg->mode)) { ++ pg_tlv_hdr = ++ (struct mwifiex_types_power_group *) ((u8 *) ++ txp_cfg + ++ sizeof ++ (struct ++ host_cmd_ds_txpwr_cfg)); ++ pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr ++ + ++ sizeof(struct ++ mwifiex_types_power_group)); ++ if (pg->power_max == pg->power_min) ++ priv->tx_power_level = (u16) pg->power_min; ++ } ++ break; ++ default: ++ dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n", ++ action); ++ return 0; ++ } ++ dev_dbg(adapter->dev, ++ "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n", ++ priv->tx_power_level, priv->max_tx_power_level, ++ priv->min_tx_power_level); ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of set/get MAC address. ++ * ++ * Handling includes saving the MAC address in driver. ++ */ ++static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ struct host_cmd_ds_802_11_mac_address *cmd_mac_addr = ++ &resp->params.mac_addr; ++ ++ memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN); ++ ++ dev_dbg(priv->adapter->dev, ++ "info: set mac address: %pM\n", priv->curr_addr); ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of set/get MAC multicast ++ * address. ++ */ ++static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of get Tx rate query. ++ * ++ * Handling includes changing the header fields into CPU format ++ * and saving the Tx rate and HT information parameters in driver. ++ * ++ * Both rate configuration and current data rate can be retrieved ++ * with this request. ++ */ ++static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ priv->tx_rate = resp->params.tx_rate.tx_rate; ++ priv->tx_htinfo = resp->params.tx_rate.ht_info; ++ if (!priv->is_data_rate_auto) ++ priv->data_rate = ++ mwifiex_index_to_data_rate(priv->tx_rate, ++ priv->tx_htinfo); ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of a deauthenticate ++ * command. ++ * ++ * If the deauthenticated MAC matches the current BSS MAC, the connection ++ * state is reset. ++ */ ++static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ ++ adapter->dbg.num_cmd_deauth++; ++ if (!memcmp(resp->params.deauth.mac_addr, ++ &priv->curr_bss_params.bss_descriptor.mac_address, ++ sizeof(resp->params.deauth.mac_addr))) ++ mwifiex_reset_connect_state(priv); ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of ad-hoc stop. ++ * ++ * The function resets the connection state in driver. ++ */ ++static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ mwifiex_reset_connect_state(priv); ++ return 0; ++} ++ ++/* ++ * This function handles the command response of set/get key material. ++ * ++ * Handling includes updating the driver parameters to reflect the ++ * changes. ++ */ ++static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ struct host_cmd_ds_802_11_key_material *key = ++ &resp->params.key_material; ++ ++ if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) { ++ if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) { ++ dev_dbg(priv->adapter->dev, "info: key: GTK is set\n"); ++ priv->wpa_is_gtk_set = true; ++ priv->scan_block = false; ++ } ++ } ++ ++ memset(priv->aes_key.key_param_set.key, 0, ++ sizeof(key->key_param_set.key)); ++ priv->aes_key.key_param_set.key_len = key->key_param_set.key_len; ++ memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key, ++ le16_to_cpu(priv->aes_key.key_param_set.key_len)); ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of get 11d domain information. ++ */ ++static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ struct host_cmd_ds_802_11d_domain_info_rsp *domain_info = ++ &resp->params.domain_info_resp; ++ struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain; ++ u16 action = le16_to_cpu(domain_info->action); ++ u8 no_of_triplet = 0; ++ ++ no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) - ++ IEEE80211_COUNTRY_STRING_LEN) / ++ sizeof(struct ieee80211_country_ie_triplet)); ++ ++ dev_dbg(priv->adapter->dev, "info: 11D Domain Info Resp:" ++ " no_of_triplet=%d\n", no_of_triplet); ++ ++ if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) { ++ dev_warn(priv->adapter->dev, ++ "11D: invalid number of triplets %d " ++ "returned!!\n", no_of_triplet); ++ return -1; ++ } ++ ++ switch (action) { ++ case HostCmd_ACT_GEN_SET: /* Proc Set Action */ ++ break; ++ case HostCmd_ACT_GEN_GET: ++ break; ++ default: ++ dev_err(priv->adapter->dev, ++ "11D: invalid action:%d\n", domain_info->action); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of get RF channel. ++ * ++ * Handling includes changing the header fields into CPU format ++ * and saving the new channel in driver. ++ */ ++static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp, ++ void *data_buf) ++{ ++ struct host_cmd_ds_802_11_rf_channel *rf_channel = ++ &resp->params.rf_channel; ++ u16 new_channel = le16_to_cpu(rf_channel->current_channel); ++ ++ if (priv->curr_bss_params.bss_descriptor.channel != new_channel) { ++ dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n", ++ priv->curr_bss_params.bss_descriptor.channel, ++ new_channel); ++ /* Update the channel again */ ++ priv->curr_bss_params.bss_descriptor.channel = new_channel; ++ } ++ if (data_buf) ++ *((u16 *)data_buf) = new_channel; ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command response of get extended version. ++ * ++ * Handling includes forming the extended version string and sending it ++ * to application. ++ */ ++static int mwifiex_ret_ver_ext(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp, ++ void *data_buf) ++{ ++ struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext; ++ struct host_cmd_ds_version_ext *version_ext = NULL; ++ ++ if (data_buf) { ++ version_ext = (struct host_cmd_ds_version_ext *)data_buf; ++ version_ext->version_str_sel = ver_ext->version_str_sel; ++ memcpy(version_ext->version_str, ver_ext->version_str, ++ sizeof(char) * 128); ++ memcpy(priv->version_str, ver_ext->version_str, 128); ++ } ++ return 0; ++} ++ ++/* ++ * This function handles the command response of register access. ++ * ++ * The register value and offset are returned to the user. For EEPROM ++ * access, the byte count is also returned. ++ */ ++static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp, ++ void *data_buf) ++{ ++ struct mwifiex_ds_reg_rw *reg_rw = NULL; ++ struct mwifiex_ds_read_eeprom *eeprom = NULL; ++ ++ if (data_buf) { ++ reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; ++ eeprom = (struct mwifiex_ds_read_eeprom *) data_buf; ++ switch (type) { ++ case HostCmd_CMD_MAC_REG_ACCESS: ++ { ++ struct host_cmd_ds_mac_reg_access *reg; ++ reg = (struct host_cmd_ds_mac_reg_access *) ++ &resp->params.mac_reg; ++ reg_rw->offset = cpu_to_le32( ++ (u32) le16_to_cpu(reg->offset)); ++ reg_rw->value = reg->value; ++ break; ++ } ++ case HostCmd_CMD_BBP_REG_ACCESS: ++ { ++ struct host_cmd_ds_bbp_reg_access *reg; ++ reg = (struct host_cmd_ds_bbp_reg_access *) ++ &resp->params.bbp_reg; ++ reg_rw->offset = cpu_to_le32( ++ (u32) le16_to_cpu(reg->offset)); ++ reg_rw->value = cpu_to_le32((u32) reg->value); ++ break; ++ } ++ ++ case HostCmd_CMD_RF_REG_ACCESS: ++ { ++ struct host_cmd_ds_rf_reg_access *reg; ++ reg = (struct host_cmd_ds_rf_reg_access *) ++ &resp->params.rf_reg; ++ reg_rw->offset = cpu_to_le32( ++ (u32) le16_to_cpu(reg->offset)); ++ reg_rw->value = cpu_to_le32((u32) reg->value); ++ break; ++ } ++ case HostCmd_CMD_PMIC_REG_ACCESS: ++ { ++ struct host_cmd_ds_pmic_reg_access *reg; ++ reg = (struct host_cmd_ds_pmic_reg_access *) ++ &resp->params.pmic_reg; ++ reg_rw->offset = cpu_to_le32( ++ (u32) le16_to_cpu(reg->offset)); ++ reg_rw->value = cpu_to_le32((u32) reg->value); ++ break; ++ } ++ case HostCmd_CMD_CAU_REG_ACCESS: ++ { ++ struct host_cmd_ds_rf_reg_access *reg; ++ reg = (struct host_cmd_ds_rf_reg_access *) ++ &resp->params.rf_reg; ++ reg_rw->offset = cpu_to_le32( ++ (u32) le16_to_cpu(reg->offset)); ++ reg_rw->value = cpu_to_le32((u32) reg->value); ++ break; ++ } ++ case HostCmd_CMD_802_11_EEPROM_ACCESS: ++ { ++ struct host_cmd_ds_802_11_eeprom_access ++ *cmd_eeprom = ++ (struct host_cmd_ds_802_11_eeprom_access ++ *) &resp->params.eeprom; ++ pr_debug("info: EEPROM read len=%x\n", ++ cmd_eeprom->byte_count); ++ if (le16_to_cpu(eeprom->byte_count) < ++ le16_to_cpu( ++ cmd_eeprom->byte_count)) { ++ eeprom->byte_count = cpu_to_le16(0); ++ pr_debug("info: EEPROM read " ++ "length is too big\n"); ++ return -1; ++ } ++ eeprom->offset = cmd_eeprom->offset; ++ eeprom->byte_count = cmd_eeprom->byte_count; ++ if (le16_to_cpu(eeprom->byte_count) > 0) ++ memcpy(&eeprom->value, ++ &cmd_eeprom->value, ++ le16_to_cpu(eeprom->byte_count)); ++ ++ break; ++ } ++ default: ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * This function handles the command response of get IBSS coalescing status. ++ * ++ * If the received BSSID is different than the current one, the current BSSID, ++ * beacon interval, ATIM window and ERP information are updated, along with ++ * changing the ad-hoc state accordingly. ++ */ ++static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv, ++ struct host_cmd_ds_command *resp) ++{ ++ struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp = ++ &(resp->params.ibss_coalescing); ++ u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; ++ ++ if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET) ++ return 0; ++ ++ dev_dbg(priv->adapter->dev, ++ "info: new BSSID %pM\n", ibss_coal_resp->bssid); ++ ++ /* If rsp has NULL BSSID, Just return..... No Action */ ++ if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) { ++ dev_warn(priv->adapter->dev, "new BSSID is NULL\n"); ++ return 0; ++ } ++ ++ /* If BSSID is diff, modify current BSS parameters */ ++ if (memcmp(priv->curr_bss_params.bss_descriptor.mac_address, ++ ibss_coal_resp->bssid, ETH_ALEN)) { ++ /* BSSID */ ++ memcpy(priv->curr_bss_params.bss_descriptor.mac_address, ++ ibss_coal_resp->bssid, ETH_ALEN); ++ ++ /* Beacon Interval */ ++ priv->curr_bss_params.bss_descriptor.beacon_period ++ = le16_to_cpu(ibss_coal_resp->beacon_interval); ++ ++ /* ERP Information */ ++ priv->curr_bss_params.bss_descriptor.erp_flags = ++ (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect); ++ ++ priv->adhoc_state = ADHOC_COALESCED; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function handles the command responses. ++ * ++ * This is a generic function, which calls command specific ++ * response handlers based on the command ID. ++ */ ++int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, ++ u16 cmdresp_no, void *cmd_buf) ++{ ++ int ret = 0; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct host_cmd_ds_command *resp = ++ (struct host_cmd_ds_command *) cmd_buf; ++ void *data_buf = adapter->curr_cmd->data_buf; ++ ++ /* If the command is not successful, cleanup and return failure */ ++ if (resp->result != HostCmd_RESULT_OK) { ++ mwifiex_process_cmdresp_error(priv, resp); ++ return -1; ++ } ++ /* Command successful, handle response */ ++ switch (cmdresp_no) { ++ case HostCmd_CMD_GET_HW_SPEC: ++ ret = mwifiex_ret_get_hw_spec(priv, resp); ++ break; ++ case HostCmd_CMD_MAC_CONTROL: ++ break; ++ case HostCmd_CMD_802_11_MAC_ADDRESS: ++ ret = mwifiex_ret_802_11_mac_address(priv, resp); ++ break; ++ case HostCmd_CMD_MAC_MULTICAST_ADR: ++ ret = mwifiex_ret_mac_multicast_adr(priv, resp); ++ break; ++ case HostCmd_CMD_TX_RATE_CFG: ++ ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf); ++ break; ++ case HostCmd_CMD_802_11_SCAN: ++ ret = mwifiex_ret_802_11_scan(priv, resp); ++ adapter->curr_cmd->wait_q_enabled = false; ++ break; ++ case HostCmd_CMD_802_11_BG_SCAN_QUERY: ++ ret = mwifiex_ret_802_11_scan(priv, resp); ++ dev_dbg(adapter->dev, ++ "info: CMD_RESP: BG_SCAN result is ready!\n"); ++ break; ++ case HostCmd_CMD_TXPWR_CFG: ++ ret = mwifiex_ret_tx_power_cfg(priv, resp, data_buf); ++ break; ++ case HostCmd_CMD_802_11_PS_MODE_ENH: ++ ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf); ++ break; ++ case HostCmd_CMD_802_11_HS_CFG_ENH: ++ ret = mwifiex_ret_802_11_hs_cfg(priv, resp); ++ break; ++ case HostCmd_CMD_802_11_ASSOCIATE: ++ ret = mwifiex_ret_802_11_associate(priv, resp); ++ break; ++ case HostCmd_CMD_802_11_DEAUTHENTICATE: ++ ret = mwifiex_ret_802_11_deauthenticate(priv, resp); ++ break; ++ case HostCmd_CMD_802_11_AD_HOC_START: ++ case HostCmd_CMD_802_11_AD_HOC_JOIN: ++ ret = mwifiex_ret_802_11_ad_hoc(priv, resp); ++ break; ++ case HostCmd_CMD_802_11_AD_HOC_STOP: ++ ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp); ++ break; ++ case HostCmd_CMD_802_11_GET_LOG: ++ ret = mwifiex_ret_get_log(priv, resp, data_buf); ++ break; ++ case HostCmd_CMD_RSSI_INFO: ++ ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf); ++ break; ++ case HostCmd_CMD_802_11_SNMP_MIB: ++ ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf); ++ break; ++ case HostCmd_CMD_802_11_TX_RATE_QUERY: ++ ret = mwifiex_ret_802_11_tx_rate_query(priv, resp); ++ break; ++ case HostCmd_CMD_802_11_RF_CHANNEL: ++ ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf); ++ break; ++ case HostCmd_CMD_VERSION_EXT: ++ ret = mwifiex_ret_ver_ext(priv, resp, data_buf); ++ break; ++ case HostCmd_CMD_FUNC_INIT: ++ case HostCmd_CMD_FUNC_SHUTDOWN: ++ break; ++ case HostCmd_CMD_802_11_KEY_MATERIAL: ++ ret = mwifiex_ret_802_11_key_material(priv, resp); ++ break; ++ case HostCmd_CMD_802_11D_DOMAIN_INFO: ++ ret = mwifiex_ret_802_11d_domain_info(priv, resp); ++ break; ++ case HostCmd_CMD_11N_ADDBA_REQ: ++ ret = mwifiex_ret_11n_addba_req(priv, resp); ++ break; ++ case HostCmd_CMD_11N_DELBA: ++ ret = mwifiex_ret_11n_delba(priv, resp); ++ break; ++ case HostCmd_CMD_11N_ADDBA_RSP: ++ ret = mwifiex_ret_11n_addba_resp(priv, resp); ++ break; ++ case HostCmd_CMD_RECONFIGURE_TX_BUFF: ++ adapter->tx_buf_size = (u16) le16_to_cpu(resp->params. ++ tx_buf.buff_size); ++ adapter->tx_buf_size = (adapter->tx_buf_size / ++ MWIFIEX_SDIO_BLOCK_SIZE) * ++ MWIFIEX_SDIO_BLOCK_SIZE; ++ adapter->curr_tx_buf_size = adapter->tx_buf_size; ++ dev_dbg(adapter->dev, ++ "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n", ++ adapter->max_tx_buf_size, adapter->tx_buf_size); ++ ++ if (adapter->if_ops.update_mp_end_port) ++ adapter->if_ops.update_mp_end_port(adapter, ++ le16_to_cpu(resp-> ++ params. ++ tx_buf. ++ mp_end_port)); ++ break; ++ case HostCmd_CMD_AMSDU_AGGR_CTRL: ++ ret = mwifiex_ret_amsdu_aggr_ctrl(resp, data_buf); ++ break; ++ case HostCmd_CMD_WMM_GET_STATUS: ++ ret = mwifiex_ret_wmm_get_status(priv, resp); ++ break; ++ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: ++ ret = mwifiex_ret_ibss_coalescing_status(priv, resp); ++ break; ++ case HostCmd_CMD_MAC_REG_ACCESS: ++ case HostCmd_CMD_BBP_REG_ACCESS: ++ case HostCmd_CMD_RF_REG_ACCESS: ++ case HostCmd_CMD_PMIC_REG_ACCESS: ++ case HostCmd_CMD_CAU_REG_ACCESS: ++ case HostCmd_CMD_802_11_EEPROM_ACCESS: ++ ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf); ++ break; ++ case HostCmd_CMD_SET_BSS_MODE: ++ break; ++ case HostCmd_CMD_11N_CFG: ++ ret = mwifiex_ret_11n_cfg(resp, data_buf); ++ break; ++ default: ++ dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", ++ resp->command); ++ break; ++ } ++ ++ return ret; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sta_event.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sta_event.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sta_event.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sta_event.c 2011-05-05 23:29:45.489441913 +0200 +@@ -0,0 +1,406 @@ ++/* ++ * Marvell Wireless LAN device driver: station event handling ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++ ++/* ++ * This function resets the connection state. ++ * ++ * The function is invoked after receiving a disconnect event from firmware, ++ * and performs the following actions - ++ * - Set media status to disconnected ++ * - Clean up Tx and Rx packets ++ * - Resets SNR/NF/RSSI value in driver ++ * - Resets security configurations in driver ++ * - Enables auto data rate ++ * - Saves the previous SSID and BSSID so that they can ++ * be used for re-association, if required ++ * - Erases current SSID and BSSID information ++ * - Sends a disconnect event to upper layers/applications. ++ */ ++void ++mwifiex_reset_connect_state(struct mwifiex_private *priv) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ ++ if (!priv->media_connected) ++ return; ++ ++ dev_dbg(adapter->dev, "info: handles disconnect event\n"); ++ ++ priv->media_connected = false; ++ ++ priv->scan_block = false; ++ ++ /* Free Tx and Rx packets, report disconnect to upper layer */ ++ mwifiex_clean_txrx(priv); ++ ++ /* Reset SNR/NF/RSSI values */ ++ priv->data_rssi_last = 0; ++ priv->data_nf_last = 0; ++ priv->data_rssi_avg = 0; ++ priv->data_nf_avg = 0; ++ priv->bcn_rssi_last = 0; ++ priv->bcn_nf_last = 0; ++ priv->bcn_rssi_avg = 0; ++ priv->bcn_nf_avg = 0; ++ priv->rxpd_rate = 0; ++ priv->rxpd_htinfo = 0; ++ priv->sec_info.wpa_enabled = false; ++ priv->sec_info.wpa2_enabled = false; ++ priv->wpa_ie_len = 0; ++ ++ priv->sec_info.wapi_enabled = false; ++ priv->wapi_ie_len = 0; ++ priv->sec_info.wapi_key_on = false; ++ ++ priv->sec_info.encryption_mode = 0; ++ ++ /* Enable auto data rate */ ++ priv->is_data_rate_auto = true; ++ priv->data_rate = 0; ++ ++ if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { ++ priv->adhoc_state = ADHOC_IDLE; ++ priv->adhoc_is_link_sensed = false; ++ } ++ ++ /* ++ * Memorize the previous SSID and BSSID so ++ * it could be used for re-assoc ++ */ ++ ++ dev_dbg(adapter->dev, "info: previous SSID=%s, SSID len=%u\n", ++ priv->prev_ssid.ssid, priv->prev_ssid.ssid_len); ++ ++ dev_dbg(adapter->dev, "info: current SSID=%s, SSID len=%u\n", ++ priv->curr_bss_params.bss_descriptor.ssid.ssid, ++ priv->curr_bss_params.bss_descriptor.ssid.ssid_len); ++ ++ memcpy(&priv->prev_ssid, ++ &priv->curr_bss_params.bss_descriptor.ssid, ++ sizeof(struct mwifiex_802_11_ssid)); ++ ++ memcpy(priv->prev_bssid, ++ priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN); ++ ++ /* Need to erase the current SSID and BSSID info */ ++ memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params)); ++ ++ adapter->tx_lock_flag = false; ++ adapter->pps_uapsd_mode = false; ++ ++ if (adapter->num_cmd_timeout && adapter->curr_cmd) ++ return; ++ priv->media_connected = false; ++ if (!priv->disconnect) { ++ priv->disconnect = 1; ++ dev_dbg(adapter->dev, "info: successfully disconnected from" ++ " %pM: reason code %d\n", priv->cfg_bssid, ++ WLAN_REASON_DEAUTH_LEAVING); ++ cfg80211_disconnected(priv->netdev, ++ WLAN_REASON_DEAUTH_LEAVING, NULL, 0, ++ GFP_KERNEL); ++ queue_work(priv->workqueue, &priv->cfg_workqueue); ++ } ++ if (!netif_queue_stopped(priv->netdev)) ++ netif_stop_queue(priv->netdev); ++ if (netif_carrier_ok(priv->netdev)) ++ netif_carrier_off(priv->netdev); ++ /* Reset wireless stats signal info */ ++ priv->w_stats.qual.level = 0; ++ priv->w_stats.qual.noise = 0; ++} ++ ++/* ++ * This function handles events generated by firmware. ++ * ++ * This is a generic function and handles all events. ++ * ++ * Event specific routines are called by this function based ++ * upon the generated event cause. ++ * ++ * For the following events, the function just forwards them to upper ++ * layers, optionally recording the change - ++ * - EVENT_LINK_SENSED ++ * - EVENT_MIC_ERR_UNICAST ++ * - EVENT_MIC_ERR_MULTICAST ++ * - EVENT_PORT_RELEASE ++ * - EVENT_RSSI_LOW ++ * - EVENT_SNR_LOW ++ * - EVENT_MAX_FAIL ++ * - EVENT_RSSI_HIGH ++ * - EVENT_SNR_HIGH ++ * - EVENT_DATA_RSSI_LOW ++ * - EVENT_DATA_SNR_LOW ++ * - EVENT_DATA_RSSI_HIGH ++ * - EVENT_DATA_SNR_HIGH ++ * - EVENT_LINK_QUALITY ++ * - EVENT_PRE_BEACON_LOST ++ * - EVENT_IBSS_COALESCED ++ * - EVENT_WEP_ICV_ERR ++ * - EVENT_BW_CHANGE ++ * - EVENT_HOSTWAKE_STAIE ++ * ++ * For the following events, no action is taken - ++ * - EVENT_MIB_CHANGED ++ * - EVENT_INIT_DONE ++ * - EVENT_DUMMY_HOST_WAKEUP_SIGNAL ++ * ++ * Rest of the supported events requires driver handling - ++ * - EVENT_DEAUTHENTICATED ++ * - EVENT_DISASSOCIATED ++ * - EVENT_LINK_LOST ++ * - EVENT_PS_SLEEP ++ * - EVENT_PS_AWAKE ++ * - EVENT_DEEP_SLEEP_AWAKE ++ * - EVENT_HS_ACT_REQ ++ * - EVENT_ADHOC_BCN_LOST ++ * - EVENT_BG_SCAN_REPORT ++ * - EVENT_WMM_STATUS_CHANGE ++ * - EVENT_ADDBA ++ * - EVENT_DELBA ++ * - EVENT_BA_STREAM_TIEMOUT ++ * - EVENT_AMSDU_AGGR_CTRL ++ */ ++int mwifiex_process_sta_event(struct mwifiex_private *priv) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ int ret = 0; ++ u32 eventcause = adapter->event_cause; ++ ++ switch (eventcause) { ++ case EVENT_DUMMY_HOST_WAKEUP_SIGNAL: ++ dev_err(adapter->dev, "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL," ++ " ignoring it\n"); ++ break; ++ case EVENT_LINK_SENSED: ++ dev_dbg(adapter->dev, "event: LINK_SENSED\n"); ++ if (!netif_carrier_ok(priv->netdev)) ++ netif_carrier_on(priv->netdev); ++ if (netif_queue_stopped(priv->netdev)) ++ netif_wake_queue(priv->netdev); ++ break; ++ ++ case EVENT_DEAUTHENTICATED: ++ dev_dbg(adapter->dev, "event: Deauthenticated\n"); ++ adapter->dbg.num_event_deauth++; ++ if (priv->media_connected) ++ mwifiex_reset_connect_state(priv); ++ break; ++ ++ case EVENT_DISASSOCIATED: ++ dev_dbg(adapter->dev, "event: Disassociated\n"); ++ adapter->dbg.num_event_disassoc++; ++ if (priv->media_connected) ++ mwifiex_reset_connect_state(priv); ++ break; ++ ++ case EVENT_LINK_LOST: ++ dev_dbg(adapter->dev, "event: Link lost\n"); ++ adapter->dbg.num_event_link_lost++; ++ if (priv->media_connected) ++ mwifiex_reset_connect_state(priv); ++ break; ++ ++ case EVENT_PS_SLEEP: ++ dev_dbg(adapter->dev, "info: EVENT: SLEEP\n"); ++ ++ adapter->ps_state = PS_STATE_PRE_SLEEP; ++ ++ mwifiex_check_ps_cond(adapter); ++ break; ++ ++ case EVENT_PS_AWAKE: ++ dev_dbg(adapter->dev, "info: EVENT: AWAKE\n"); ++ if (!adapter->pps_uapsd_mode && ++ priv->media_connected && ++ adapter->sleep_period.period) { ++ adapter->pps_uapsd_mode = true; ++ dev_dbg(adapter->dev, ++ "event: PPS/UAPSD mode activated\n"); ++ } ++ adapter->tx_lock_flag = false; ++ if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) { ++ if (mwifiex_check_last_packet_indication(priv)) { ++ if (!adapter->data_sent) { ++ if (!mwifiex_send_null_packet(priv, ++ MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET ++ | ++ MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) ++ adapter->ps_state = ++ PS_STATE_SLEEP; ++ return 0; ++ } ++ } ++ } ++ adapter->ps_state = PS_STATE_AWAKE; ++ adapter->pm_wakeup_card_req = false; ++ adapter->pm_wakeup_fw_try = false; ++ ++ break; ++ ++ case EVENT_DEEP_SLEEP_AWAKE: ++ adapter->if_ops.wakeup_complete(adapter); ++ dev_dbg(adapter->dev, "event: DS_AWAKE\n"); ++ if (adapter->is_deep_sleep) ++ adapter->is_deep_sleep = false; ++ break; ++ ++ case EVENT_HS_ACT_REQ: ++ dev_dbg(adapter->dev, "event: HS_ACT_REQ\n"); ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_802_11_HS_CFG_ENH, ++ 0, 0, NULL); ++ break; ++ ++ case EVENT_MIC_ERR_UNICAST: ++ dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n"); ++ break; ++ ++ case EVENT_MIC_ERR_MULTICAST: ++ dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n"); ++ break; ++ case EVENT_MIB_CHANGED: ++ case EVENT_INIT_DONE: ++ break; ++ ++ case EVENT_ADHOC_BCN_LOST: ++ dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n"); ++ priv->adhoc_is_link_sensed = false; ++ mwifiex_clean_txrx(priv); ++ if (!netif_queue_stopped(priv->netdev)) ++ netif_stop_queue(priv->netdev); ++ if (netif_carrier_ok(priv->netdev)) ++ netif_carrier_off(priv->netdev); ++ break; ++ ++ case EVENT_BG_SCAN_REPORT: ++ dev_dbg(adapter->dev, "event: BGS_REPORT\n"); ++ /* Clear the previous scan result */ ++ memset(adapter->scan_table, 0x00, ++ sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); ++ adapter->num_in_scan_table = 0; ++ adapter->bcn_buf_end = adapter->bcn_buf; ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_802_11_BG_SCAN_QUERY, ++ HostCmd_ACT_GEN_GET, 0, NULL); ++ break; ++ ++ case EVENT_PORT_RELEASE: ++ dev_dbg(adapter->dev, "event: PORT RELEASE\n"); ++ break; ++ ++ case EVENT_WMM_STATUS_CHANGE: ++ dev_dbg(adapter->dev, "event: WMM status changed\n"); ++ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_WMM_GET_STATUS, ++ 0, 0, NULL); ++ break; ++ ++ case EVENT_RSSI_LOW: ++ dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n"); ++ break; ++ case EVENT_SNR_LOW: ++ dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n"); ++ break; ++ case EVENT_MAX_FAIL: ++ dev_dbg(adapter->dev, "event: MAX_FAIL\n"); ++ break; ++ case EVENT_RSSI_HIGH: ++ dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n"); ++ break; ++ case EVENT_SNR_HIGH: ++ dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n"); ++ break; ++ case EVENT_DATA_RSSI_LOW: ++ dev_dbg(adapter->dev, "event: Data RSSI_LOW\n"); ++ break; ++ case EVENT_DATA_SNR_LOW: ++ dev_dbg(adapter->dev, "event: Data SNR_LOW\n"); ++ break; ++ case EVENT_DATA_RSSI_HIGH: ++ dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n"); ++ break; ++ case EVENT_DATA_SNR_HIGH: ++ dev_dbg(adapter->dev, "event: Data SNR_HIGH\n"); ++ break; ++ case EVENT_LINK_QUALITY: ++ dev_dbg(adapter->dev, "event: Link Quality\n"); ++ break; ++ case EVENT_PRE_BEACON_LOST: ++ dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n"); ++ break; ++ case EVENT_IBSS_COALESCED: ++ dev_dbg(adapter->dev, "event: IBSS_COALESCED\n"); ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, ++ HostCmd_ACT_GEN_GET, 0, NULL); ++ break; ++ case EVENT_ADDBA: ++ dev_dbg(adapter->dev, "event: ADDBA Request\n"); ++ mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP, ++ HostCmd_ACT_GEN_SET, 0, ++ adapter->event_body); ++ break; ++ case EVENT_DELBA: ++ dev_dbg(adapter->dev, "event: DELBA Request\n"); ++ mwifiex_11n_delete_ba_stream(priv, adapter->event_body); ++ break; ++ case EVENT_BA_STREAM_TIEMOUT: ++ dev_dbg(adapter->dev, "event: BA Stream timeout\n"); ++ mwifiex_11n_ba_stream_timeout(priv, ++ (struct host_cmd_ds_11n_batimeout ++ *) ++ adapter->event_body); ++ break; ++ case EVENT_AMSDU_AGGR_CTRL: ++ dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ++ *(u16 *) adapter->event_body); ++ adapter->tx_buf_size = ++ min(adapter->curr_tx_buf_size, ++ le16_to_cpu(*(__le16 *) adapter->event_body)); ++ dev_dbg(adapter->dev, "event: tx_buf_size %d\n", ++ adapter->tx_buf_size); ++ break; ++ ++ case EVENT_WEP_ICV_ERR: ++ dev_dbg(adapter->dev, "event: WEP ICV error\n"); ++ break; ++ ++ case EVENT_BW_CHANGE: ++ dev_dbg(adapter->dev, "event: BW Change\n"); ++ break; ++ ++ case EVENT_HOSTWAKE_STAIE: ++ dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause); ++ break; ++ default: ++ dev_dbg(adapter->dev, "event: unknown event id: %#x\n", ++ eventcause); ++ break; ++ } ++ ++ return ret; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sta_ioctl.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sta_ioctl.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sta_ioctl.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sta_ioctl.c 2011-05-05 23:29:45.490441925 +0200 +@@ -0,0 +1,1605 @@ ++/* ++ * Marvell Wireless LAN device driver: functions for station ioctl ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++#include "cfg80211.h" ++ ++/* ++ * Copies the multicast address list from device to driver. ++ * ++ * This function does not validate the destination memory for ++ * size, and the calling function must ensure enough memory is ++ * available. ++ */ ++int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, ++ struct net_device *dev) ++{ ++ int i = 0; ++ struct netdev_hw_addr *ha; ++ ++ netdev_for_each_mc_addr(ha, dev) ++ memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN); ++ ++ return i; ++} ++ ++/* ++ * Wait queue completion handler. ++ * ++ * This function waits on a cmd wait queue. It also cancels the pending ++ * request after waking up, in case of errors. ++ */ ++int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) ++{ ++ bool cancel_flag = false; ++ int status = adapter->cmd_wait_q.status; ++ ++ dev_dbg(adapter->dev, "cmd pending\n"); ++ atomic_inc(&adapter->cmd_pending); ++ ++ /* Status pending, wake up main process */ ++ queue_work(adapter->workqueue, &adapter->main_work); ++ ++ /* Wait for completion */ ++ wait_event_interruptible(adapter->cmd_wait_q.wait, ++ adapter->cmd_wait_q.condition); ++ if (!adapter->cmd_wait_q.condition) ++ cancel_flag = true; ++ ++ if (cancel_flag) { ++ mwifiex_cancel_pending_ioctl(adapter); ++ dev_dbg(adapter->dev, "cmd cancel\n"); ++ } ++ adapter->cmd_wait_q.status = 0; ++ ++ return status; ++} ++ ++/* ++ * This function prepares the correct firmware command and ++ * issues it to set the multicast list. ++ * ++ * This function can be used to enable promiscuous mode, or enable all ++ * multicast packets, or to enable selective multicast. ++ */ ++int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, ++ struct mwifiex_multicast_list *mcast_list) ++{ ++ int ret = 0; ++ u16 old_pkt_filter; ++ ++ old_pkt_filter = priv->curr_pkt_filter; ++ ++ if (mcast_list->mode == MWIFIEX_PROMISC_MODE) { ++ dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n"); ++ priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; ++ priv->curr_pkt_filter &= ++ ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; ++ } else { ++ /* Multicast */ ++ priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; ++ if (mcast_list->mode == MWIFIEX_MULTICAST_MODE) { ++ dev_dbg(priv->adapter->dev, ++ "info: Enabling All Multicast!\n"); ++ priv->curr_pkt_filter |= ++ HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; ++ } else { ++ priv->curr_pkt_filter &= ++ ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; ++ if (mcast_list->num_multicast_addr) { ++ dev_dbg(priv->adapter->dev, ++ "info: Set multicast list=%d\n", ++ mcast_list->num_multicast_addr); ++ /* Set multicast addresses to firmware */ ++ if (old_pkt_filter == priv->curr_pkt_filter) { ++ /* Send request to firmware */ ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_MAC_MULTICAST_ADR, ++ HostCmd_ACT_GEN_SET, 0, ++ mcast_list); ++ } else { ++ /* Send request to firmware */ ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_MAC_MULTICAST_ADR, ++ HostCmd_ACT_GEN_SET, 0, ++ mcast_list); ++ } ++ } ++ } ++ } ++ dev_dbg(priv->adapter->dev, ++ "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n", ++ old_pkt_filter, priv->curr_pkt_filter); ++ if (old_pkt_filter != priv->curr_pkt_filter) { ++ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, ++ HostCmd_ACT_GEN_SET, ++ 0, &priv->curr_pkt_filter); ++ } ++ ++ return ret; ++} ++ ++/* ++ * In Ad-Hoc mode, the IBSS is created if not found in scan list. ++ * In both Ad-Hoc and infra mode, an deauthentication is performed ++ * first. ++ */ ++int mwifiex_bss_start(struct mwifiex_private *priv, ++ struct mwifiex_ssid_bssid *ssid_bssid) ++{ ++ int ret = 0; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ s32 i = -1; ++ ++ priv->scan_block = false; ++ if (!ssid_bssid) ++ return -1; ++ ++ if (priv->bss_mode == NL80211_IFTYPE_STATION) { ++ /* Infra mode */ ++ ret = mwifiex_deauthenticate(priv, NULL); ++ if (ret) ++ return ret; ++ ++ /* Search for the requested SSID in the scan table */ ++ if (ssid_bssid->ssid.ssid_len) ++ i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, ++ NULL, NL80211_IFTYPE_STATION); ++ else ++ i = mwifiex_find_bssid_in_list(priv, ++ (u8 *) &ssid_bssid->bssid, ++ NL80211_IFTYPE_STATION); ++ if (i < 0) ++ return -1; ++ ++ dev_dbg(adapter->dev, ++ "info: SSID found in scan list ... associating...\n"); ++ ++ /* Clear any past association response stored for ++ * application retrieval */ ++ priv->assoc_rsp_size = 0; ++ ret = mwifiex_associate(priv, &adapter->scan_table[i]); ++ if (ret) ++ return ret; ++ } else { ++ /* Adhoc mode */ ++ /* If the requested SSID matches current SSID, return */ ++ if (ssid_bssid->ssid.ssid_len && ++ (!mwifiex_ssid_cmp ++ (&priv->curr_bss_params.bss_descriptor.ssid, ++ &ssid_bssid->ssid))) ++ return 0; ++ ++ /* Exit Adhoc mode first */ ++ dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); ++ ret = mwifiex_deauthenticate(priv, NULL); ++ if (ret) ++ return ret; ++ ++ priv->adhoc_is_link_sensed = false; ++ ++ /* Search for the requested network in the scan table */ ++ if (ssid_bssid->ssid.ssid_len) ++ i = mwifiex_find_ssid_in_list(priv, ++ &ssid_bssid->ssid, NULL, ++ NL80211_IFTYPE_ADHOC); ++ else ++ i = mwifiex_find_bssid_in_list(priv, ++ (u8 *)&ssid_bssid->bssid, ++ NL80211_IFTYPE_ADHOC); ++ ++ if (i >= 0) { ++ dev_dbg(adapter->dev, "info: network found in scan" ++ " list. Joining...\n"); ++ ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]); ++ if (ret) ++ return ret; ++ } else { ++ dev_dbg(adapter->dev, "info: Network not found in " ++ "the list, creating adhoc with ssid = %s\n", ++ ssid_bssid->ssid.ssid); ++ ret = mwifiex_adhoc_start(priv, &ssid_bssid->ssid); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ return ret; ++} ++ ++/* ++ * IOCTL request handler to set host sleep configuration. ++ * ++ * This function prepares the correct firmware command and ++ * issues it. ++ */ ++int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, ++ int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) ++ ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ int status = 0; ++ u32 prev_cond = 0; ++ ++ if (!hs_cfg) ++ return -ENOMEM; ++ ++ switch (action) { ++ case HostCmd_ACT_GEN_SET: ++ if (adapter->pps_uapsd_mode) { ++ dev_dbg(adapter->dev, "info: Host Sleep IOCTL" ++ " is blocked in UAPSD/PPS mode\n"); ++ status = -1; ++ break; ++ } ++ if (hs_cfg->is_invoke_hostcmd) { ++ if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) { ++ if (!adapter->is_hs_configured) ++ /* Already cancelled */ ++ break; ++ /* Save previous condition */ ++ prev_cond = le32_to_cpu(adapter->hs_cfg ++ .conditions); ++ adapter->hs_cfg.conditions = ++ cpu_to_le32(hs_cfg->conditions); ++ } else if (hs_cfg->conditions) { ++ adapter->hs_cfg.conditions = ++ cpu_to_le32(hs_cfg->conditions); ++ adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; ++ if (hs_cfg->gap) ++ adapter->hs_cfg.gap = (u8)hs_cfg->gap; ++ } else if (adapter->hs_cfg.conditions == ++ cpu_to_le32( ++ HOST_SLEEP_CFG_CANCEL)) { ++ /* Return failure if no parameters for HS ++ enable */ ++ status = -1; ++ break; ++ } ++ if (cmd_type == MWIFIEX_SYNC_CMD) ++ status = mwifiex_send_cmd_sync(priv, ++ HostCmd_CMD_802_11_HS_CFG_ENH, ++ HostCmd_ACT_GEN_SET, 0, ++ &adapter->hs_cfg); ++ else ++ status = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_802_11_HS_CFG_ENH, ++ HostCmd_ACT_GEN_SET, 0, ++ &adapter->hs_cfg); ++ if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) ++ /* Restore previous condition */ ++ adapter->hs_cfg.conditions = ++ cpu_to_le32(prev_cond); ++ } else { ++ adapter->hs_cfg.conditions = ++ cpu_to_le32(hs_cfg->conditions); ++ adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; ++ adapter->hs_cfg.gap = (u8)hs_cfg->gap; ++ } ++ break; ++ case HostCmd_ACT_GEN_GET: ++ hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions); ++ hs_cfg->gpio = adapter->hs_cfg.gpio; ++ hs_cfg->gap = adapter->hs_cfg.gap; ++ break; ++ default: ++ status = -1; ++ break; ++ } ++ ++ return status; ++} ++ ++/* ++ * Sends IOCTL request to cancel the existing Host Sleep configuration. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ */ ++int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type) ++{ ++ struct mwifiex_ds_hs_cfg hscfg; ++ ++ hscfg.conditions = HOST_SLEEP_CFG_CANCEL; ++ hscfg.is_invoke_hostcmd = true; ++ ++ return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, ++ cmd_type, &hscfg); ++} ++EXPORT_SYMBOL_GPL(mwifiex_cancel_hs); ++ ++/* ++ * Sends IOCTL request to cancel the existing Host Sleep configuration. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ */ ++int mwifiex_enable_hs(struct mwifiex_adapter *adapter) ++{ ++ struct mwifiex_ds_hs_cfg hscfg; ++ ++ if (adapter->hs_activated) { ++ dev_dbg(adapter->dev, "cmd: HS Already actived\n"); ++ return true; ++ } ++ ++ adapter->hs_activate_wait_q_woken = false; ++ ++ memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param)); ++ hscfg.is_invoke_hostcmd = true; ++ ++ if (mwifiex_set_hs_params(mwifiex_get_priv(adapter, ++ MWIFIEX_BSS_ROLE_STA), ++ HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD, ++ &hscfg)) { ++ dev_err(adapter->dev, "IOCTL request HS enable failed\n"); ++ return false; ++ } ++ ++ wait_event_interruptible(adapter->hs_activate_wait_q, ++ adapter->hs_activate_wait_q_woken); ++ ++ return true; ++} ++EXPORT_SYMBOL_GPL(mwifiex_enable_hs); ++ ++/* ++ * IOCTL request handler to get BSS information. ++ * ++ * This function collates the information from different driver structures ++ * to send to the user. ++ */ ++int mwifiex_get_bss_info(struct mwifiex_private *priv, ++ struct mwifiex_bss_info *info) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct mwifiex_bssdescriptor *bss_desc; ++ s32 tbl_idx = 0; ++ ++ if (!info) ++ return -1; ++ ++ bss_desc = &priv->curr_bss_params.bss_descriptor; ++ ++ info->bss_mode = priv->bss_mode; ++ ++ memcpy(&info->ssid, &bss_desc->ssid, ++ sizeof(struct mwifiex_802_11_ssid)); ++ ++ memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN); ++ ++ info->bss_chan = bss_desc->channel; ++ ++ info->region_code = adapter->region_code; ++ ++ /* Scan table index if connected */ ++ info->scan_table_idx = 0; ++ if (priv->media_connected) { ++ tbl_idx = ++ mwifiex_find_ssid_in_list(priv, &bss_desc->ssid, ++ bss_desc->mac_address, ++ priv->bss_mode); ++ if (tbl_idx >= 0) ++ info->scan_table_idx = tbl_idx; ++ } ++ ++ info->media_connected = priv->media_connected; ++ ++ info->max_power_level = priv->max_tx_power_level; ++ info->min_power_level = priv->min_tx_power_level; ++ ++ info->adhoc_state = priv->adhoc_state; ++ ++ info->bcn_nf_last = priv->bcn_nf_last; ++ ++ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) ++ info->wep_status = true; ++ else ++ info->wep_status = false; ++ ++ info->is_hs_configured = adapter->is_hs_configured; ++ info->is_deep_sleep = adapter->is_deep_sleep; ++ ++ return 0; ++} ++ ++/* ++ * The function sets band configurations. ++ * ++ * it performs extra checks to make sure the Ad-Hoc ++ * band and channel are compatible. Otherwise it returns an error. ++ * ++ */ ++int mwifiex_set_radio_band_cfg(struct mwifiex_private *priv, ++ struct mwifiex_ds_band_cfg *radio_cfg) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ u8 infra_band = 0; ++ u8 adhoc_band = 0; ++ u32 adhoc_channel = 0; ++ ++ infra_band = (u8) radio_cfg->config_bands; ++ adhoc_band = (u8) radio_cfg->adhoc_start_band; ++ adhoc_channel = radio_cfg->adhoc_channel; ++ ++ /* SET Infra band */ ++ if ((infra_band | adapter->fw_bands) & ~adapter->fw_bands) ++ return -1; ++ ++ adapter->config_bands = infra_band; ++ ++ /* SET Ad-hoc Band */ ++ if ((adhoc_band | adapter->fw_bands) & ~adapter->fw_bands) ++ return -1; ++ ++ if (adhoc_band) ++ adapter->adhoc_start_band = adhoc_band; ++ adapter->chan_offset = (u8) radio_cfg->sec_chan_offset; ++ /* ++ * If no adhoc_channel is supplied verify if the existing adhoc ++ * channel compiles with new adhoc_band ++ */ ++ if (!adhoc_channel) { ++ if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 ++ (priv, adapter->adhoc_start_band, ++ priv->adhoc_channel)) { ++ /* Pass back the default channel */ ++ radio_cfg->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; ++ if ((adapter->adhoc_start_band & BAND_A) ++ || (adapter->adhoc_start_band & BAND_AN)) ++ radio_cfg->adhoc_channel = ++ DEFAULT_AD_HOC_CHANNEL_A; ++ } ++ } else { /* Retrurn error if adhoc_band and ++ adhoc_channel combination is invalid */ ++ if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 ++ (priv, adapter->adhoc_start_band, (u16) adhoc_channel)) ++ return -1; ++ priv->adhoc_channel = (u8) adhoc_channel; ++ } ++ if ((adhoc_band & BAND_GN) || (adhoc_band & BAND_AN)) ++ adapter->adhoc_11n_enabled = true; ++ else ++ adapter->adhoc_11n_enabled = false; ++ ++ return 0; ++} ++ ++/* ++ * IOCTL request handler to set/get active channel. ++ * ++ * This function performs validity checking on channel/frequency ++ * compatibility and returns failure if not valid. ++ */ ++int mwifiex_bss_set_channel(struct mwifiex_private *priv, ++ struct mwifiex_chan_freq_power *chan) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct mwifiex_chan_freq_power *cfp = NULL; ++ ++ if (!chan) ++ return -1; ++ ++ if (!chan->channel && !chan->freq) ++ return -1; ++ if (adapter->adhoc_start_band & BAND_AN) ++ adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN; ++ else if (adapter->adhoc_start_band & BAND_A) ++ adapter->adhoc_start_band = BAND_G | BAND_B; ++ if (chan->channel) { ++ if (chan->channel <= MAX_CHANNEL_BAND_BG) ++ cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211 ++ (priv, 0, (u16) chan->channel); ++ if (!cfp) { ++ cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211 ++ (priv, BAND_A, (u16) chan->channel); ++ if (cfp) { ++ if (adapter->adhoc_11n_enabled) ++ adapter->adhoc_start_band = BAND_A ++ | BAND_AN; ++ else ++ adapter->adhoc_start_band = BAND_A; ++ } ++ } ++ } else { ++ if (chan->freq <= MAX_FREQUENCY_BAND_BG) ++ cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211( ++ priv, 0, chan->freq); ++ if (!cfp) { ++ cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211 ++ (priv, BAND_A, chan->freq); ++ if (cfp) { ++ if (adapter->adhoc_11n_enabled) ++ adapter->adhoc_start_band = BAND_A ++ | BAND_AN; ++ else ++ adapter->adhoc_start_band = BAND_A; ++ } ++ } ++ } ++ if (!cfp || !cfp->channel) { ++ dev_err(adapter->dev, "invalid channel/freq\n"); ++ return -1; ++ } ++ priv->adhoc_channel = (u8) cfp->channel; ++ chan->channel = cfp->channel; ++ chan->freq = cfp->freq; ++ ++ return 0; ++} ++ ++/* ++ * IOCTL request handler to set/get Ad-Hoc channel. ++ * ++ * This function prepares the correct firmware command and ++ * issues it to set or get the ad-hoc channel. ++ */ ++static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, ++ u16 action, u16 *channel) ++{ ++ if (action == HostCmd_ACT_GEN_GET) { ++ if (!priv->media_connected) { ++ *channel = priv->adhoc_channel; ++ return 0; ++ } ++ } else { ++ priv->adhoc_channel = (u8) *channel; ++ } ++ ++ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_RF_CHANNEL, ++ action, 0, channel); ++} ++ ++/* ++ * IOCTL request handler to find a particular BSS. ++ * ++ * The BSS can be searched with either a BSSID or a SSID. If none of ++ * these are provided, just the best BSS (best RSSI) is returned. ++ */ ++int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, ++ struct mwifiex_ssid_bssid *ssid_bssid) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct mwifiex_bssdescriptor *bss_desc; ++ u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; ++ u8 mac[ETH_ALEN]; ++ int i = 0; ++ ++ if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) { ++ i = mwifiex_find_bssid_in_list(priv, ++ (u8 *) ssid_bssid->bssid, ++ priv->bss_mode); ++ if (i < 0) { ++ memcpy(mac, ssid_bssid->bssid, sizeof(mac)); ++ dev_err(adapter->dev, "cannot find bssid %pM\n", mac); ++ return -1; ++ } ++ bss_desc = &adapter->scan_table[i]; ++ memcpy(&ssid_bssid->ssid, &bss_desc->ssid, ++ sizeof(struct mwifiex_802_11_ssid)); ++ } else if (ssid_bssid->ssid.ssid_len) { ++ i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL, ++ priv->bss_mode); ++ if (i < 0) { ++ dev_err(adapter->dev, "cannot find ssid %s\n", ++ ssid_bssid->ssid.ssid); ++ return -1; ++ } ++ bss_desc = &adapter->scan_table[i]; ++ memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN); ++ } else { ++ return mwifiex_find_best_network(priv, ssid_bssid); ++ } ++ ++ return 0; ++} ++ ++/* ++ * IOCTL request handler to change Ad-Hoc channel. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ * ++ * The function follows the following steps to perform the change - ++ * - Get current IBSS information ++ * - Get current channel ++ * - If no change is required, return ++ * - If not connected, change channel and return ++ * - If connected, ++ * - Disconnect ++ * - Change channel ++ * - Perform specific SSID scan with same SSID ++ * - Start/Join the IBSS ++ */ ++int ++mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) ++{ ++ int ret = 0; ++ struct mwifiex_bss_info bss_info; ++ struct mwifiex_ssid_bssid ssid_bssid; ++ u16 curr_chan = 0; ++ ++ memset(&bss_info, 0, sizeof(bss_info)); ++ ++ /* Get BSS information */ ++ if (mwifiex_get_bss_info(priv, &bss_info)) ++ return -1; ++ ++ /* Get current channel */ ++ ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_GET, ++ &curr_chan); ++ ++ if (curr_chan == channel) { ++ ret = 0; ++ goto done; ++ } ++ dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n", ++ curr_chan, channel); ++ ++ if (!bss_info.media_connected) { ++ ret = 0; ++ goto done; ++ } ++ ++ /* Do disonnect */ ++ memset(&ssid_bssid, 0, ETH_ALEN); ++ ret = mwifiex_deauthenticate(priv, ssid_bssid.bssid); ++ ++ ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_SET, ++ (u16 *) &channel); ++ ++ /* Do specific SSID scanning */ ++ if (mwifiex_request_scan(priv, &bss_info.ssid)) { ++ ret = -1; ++ goto done; ++ } ++ /* Start/Join Adhoc network */ ++ memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); ++ memcpy(&ssid_bssid.ssid, &bss_info.ssid, ++ sizeof(struct mwifiex_802_11_ssid)); ++ ++ ret = mwifiex_bss_start(priv, &ssid_bssid); ++done: ++ return ret; ++} ++ ++/* ++ * IOCTL request handler to get rate. ++ * ++ * This function prepares the correct firmware command and ++ * issues it to get the current rate if it is connected, ++ * otherwise, the function returns the lowest supported rate ++ * for the band. ++ */ ++static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, ++ struct mwifiex_rate_cfg *rate_cfg) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ ++ rate_cfg->is_rate_auto = priv->is_data_rate_auto; ++ if (!priv->media_connected) { ++ switch (adapter->config_bands) { ++ case BAND_B: ++ /* Return the lowest supported rate for B band */ ++ rate_cfg->rate = supported_rates_b[0] & 0x7f; ++ break; ++ case BAND_G: ++ case BAND_G | BAND_GN: ++ /* Return the lowest supported rate for G band */ ++ rate_cfg->rate = supported_rates_g[0] & 0x7f; ++ break; ++ case BAND_B | BAND_G: ++ case BAND_A | BAND_B | BAND_G: ++ case BAND_A | BAND_B: ++ case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN: ++ case BAND_B | BAND_G | BAND_GN: ++ /* Return the lowest supported rate for BG band */ ++ rate_cfg->rate = supported_rates_bg[0] & 0x7f; ++ break; ++ case BAND_A: ++ case BAND_A | BAND_G: ++ case BAND_A | BAND_G | BAND_AN | BAND_GN: ++ case BAND_A | BAND_AN: ++ /* Return the lowest supported rate for A band */ ++ rate_cfg->rate = supported_rates_a[0] & 0x7f; ++ break; ++ case BAND_GN: ++ /* Return the lowest supported rate for N band */ ++ rate_cfg->rate = supported_rates_n[0] & 0x7f; ++ break; ++ default: ++ dev_warn(adapter->dev, "invalid band %#x\n", ++ adapter->config_bands); ++ break; ++ } ++ } else { ++ return mwifiex_send_cmd_sync(priv, ++ HostCmd_CMD_802_11_TX_RATE_QUERY, ++ HostCmd_ACT_GEN_GET, 0, NULL); ++ } ++ ++ return 0; ++} ++ ++/* ++ * IOCTL request handler to set rate. ++ * ++ * This function prepares the correct firmware command and ++ * issues it to set the current rate. ++ * ++ * The function also performs validation checking on the supplied value. ++ */ ++static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, ++ struct mwifiex_rate_cfg *rate_cfg) ++{ ++ u8 rates[MWIFIEX_SUPPORTED_RATES]; ++ u8 *rate = NULL; ++ int rate_index = 0; ++ u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; ++ u32 i = 0; ++ int ret = 0; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ ++ if (rate_cfg->is_rate_auto) { ++ memset(bitmap_rates, 0, sizeof(bitmap_rates)); ++ /* Support all HR/DSSS rates */ ++ bitmap_rates[0] = 0x000F; ++ /* Support all OFDM rates */ ++ bitmap_rates[1] = 0x00FF; ++ /* Support all HT-MCSs rate */ ++ for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates) - 3; i++) ++ bitmap_rates[i + 2] = 0xFFFF; ++ bitmap_rates[9] = 0x3FFF; ++ } else { ++ memset(rates, 0, sizeof(rates)); ++ mwifiex_get_active_data_rates(priv, rates); ++ rate = rates; ++ for (i = 0; (rate[i] && i < MWIFIEX_SUPPORTED_RATES); i++) { ++ dev_dbg(adapter->dev, "info: rate=%#x wanted=%#x\n", ++ rate[i], rate_cfg->rate); ++ if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f)) ++ break; ++ } ++ if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) { ++ dev_err(adapter->dev, "fixed data rate %#x is out " ++ "of range\n", rate_cfg->rate); ++ return -1; ++ } ++ memset(bitmap_rates, 0, sizeof(bitmap_rates)); ++ ++ rate_index = mwifiex_data_rate_to_index(rate_cfg->rate); ++ ++ /* Only allow b/g rates to be set */ ++ if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 && ++ rate_index <= MWIFIEX_RATE_INDEX_HRDSSS3) { ++ bitmap_rates[0] = 1 << rate_index; ++ } else { ++ rate_index -= 1; /* There is a 0x00 in the table */ ++ if (rate_index >= MWIFIEX_RATE_INDEX_OFDM0 && ++ rate_index <= MWIFIEX_RATE_INDEX_OFDM7) ++ bitmap_rates[1] = 1 << (rate_index - ++ MWIFIEX_RATE_INDEX_OFDM0); ++ } ++ } ++ ++ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG, ++ HostCmd_ACT_GEN_SET, 0, bitmap_rates); ++ ++ return ret; ++} ++ ++/* ++ * IOCTL request handler to set/get rate. ++ * ++ * This function can be used to set/get either the rate value or the ++ * rate index. ++ */ ++static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv, ++ struct mwifiex_rate_cfg *rate_cfg) ++{ ++ int status = 0; ++ ++ if (!rate_cfg) ++ return -1; ++ ++ if (rate_cfg->action == HostCmd_ACT_GEN_GET) ++ status = mwifiex_rate_ioctl_get_rate_value(priv, rate_cfg); ++ else ++ status = mwifiex_rate_ioctl_set_rate_value(priv, rate_cfg); ++ ++ return status; ++} ++ ++/* ++ * Sends IOCTL request to get the data rate. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ */ ++int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, ++ struct mwifiex_rate_cfg *rate) ++{ ++ int ret = 0; ++ ++ memset(rate, 0, sizeof(struct mwifiex_rate_cfg)); ++ rate->action = HostCmd_ACT_GEN_GET; ++ ret = mwifiex_rate_ioctl_cfg(priv, rate); ++ ++ if (!ret) { ++ if (rate && rate->is_rate_auto) ++ rate->rate = mwifiex_index_to_data_rate(priv->tx_rate, ++ priv->tx_htinfo); ++ else if (rate) ++ rate->rate = priv->data_rate; ++ } else { ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++/* ++ * IOCTL request handler to set tx power configuration. ++ * ++ * This function prepares the correct firmware command and ++ * issues it. ++ * ++ * For non-auto power mode, all the following power groups are set - ++ * - Modulation class HR/DSSS ++ * - Modulation class OFDM ++ * - Modulation class HTBW20 ++ * - Modulation class HTBW40 ++ */ ++int mwifiex_set_tx_power(struct mwifiex_private *priv, ++ struct mwifiex_power_cfg *power_cfg) ++{ ++ int ret = 0; ++ struct host_cmd_ds_txpwr_cfg *txp_cfg = NULL; ++ struct mwifiex_types_power_group *pg_tlv = NULL; ++ struct mwifiex_power_group *pg = NULL; ++ u8 *buf = NULL; ++ u16 dbm = 0; ++ ++ if (!power_cfg->is_power_auto) { ++ dbm = (u16) power_cfg->power_level; ++ if ((dbm < priv->min_tx_power_level) || ++ (dbm > priv->max_tx_power_level)) { ++ dev_err(priv->adapter->dev, "txpower value %d dBm" ++ " is out of range (%d dBm-%d dBm)\n", ++ dbm, priv->min_tx_power_level, ++ priv->max_tx_power_level); ++ return -1; ++ } ++ } ++ buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL); ++ if (!buf) { ++ dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n", ++ __func__); ++ return -1; ++ } ++ ++ txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf; ++ txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET); ++ if (!power_cfg->is_power_auto) { ++ txp_cfg->mode = cpu_to_le32(1); ++ pg_tlv = (struct mwifiex_types_power_group *) (buf + ++ sizeof(struct host_cmd_ds_txpwr_cfg)); ++ pg_tlv->type = TLV_TYPE_POWER_GROUP; ++ pg_tlv->length = 4 * sizeof(struct mwifiex_power_group); ++ pg = (struct mwifiex_power_group *) (buf + ++ sizeof(struct host_cmd_ds_txpwr_cfg) + ++ sizeof(struct mwifiex_types_power_group)); ++ /* Power group for modulation class HR/DSSS */ ++ pg->first_rate_code = 0x00; ++ pg->last_rate_code = 0x03; ++ pg->modulation_class = MOD_CLASS_HR_DSSS; ++ pg->power_step = 0; ++ pg->power_min = (s8) dbm; ++ pg->power_max = (s8) dbm; ++ pg++; ++ /* Power group for modulation class OFDM */ ++ pg->first_rate_code = 0x00; ++ pg->last_rate_code = 0x07; ++ pg->modulation_class = MOD_CLASS_OFDM; ++ pg->power_step = 0; ++ pg->power_min = (s8) dbm; ++ pg->power_max = (s8) dbm; ++ pg++; ++ /* Power group for modulation class HTBW20 */ ++ pg->first_rate_code = 0x00; ++ pg->last_rate_code = 0x20; ++ pg->modulation_class = MOD_CLASS_HT; ++ pg->power_step = 0; ++ pg->power_min = (s8) dbm; ++ pg->power_max = (s8) dbm; ++ pg->ht_bandwidth = HT_BW_20; ++ pg++; ++ /* Power group for modulation class HTBW40 */ ++ pg->first_rate_code = 0x00; ++ pg->last_rate_code = 0x20; ++ pg->modulation_class = MOD_CLASS_HT; ++ pg->power_step = 0; ++ pg->power_min = (s8) dbm; ++ pg->power_max = (s8) dbm; ++ pg->ht_bandwidth = HT_BW_40; ++ } ++ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TXPWR_CFG, ++ HostCmd_ACT_GEN_SET, 0, buf); ++ ++ kfree(buf); ++ return ret; ++} ++ ++/* ++ * IOCTL request handler to get power save mode. ++ * ++ * This function prepares the correct firmware command and ++ * issues it. ++ */ ++int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode) ++{ ++ int ret = 0; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ u16 sub_cmd; ++ ++ if (*ps_mode) ++ adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; ++ else ++ adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; ++ sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS; ++ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH, ++ sub_cmd, BITMAP_STA_PS, NULL); ++ if ((!ret) && (sub_cmd == DIS_AUTO_PS)) ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS, ++ 0, NULL); ++ ++ return ret; ++} ++ ++/* ++ * IOCTL request handler to set/reset WPA IE. ++ * ++ * The supplied WPA IE is treated as a opaque buffer. Only the first field ++ * is checked to determine WPA version. If buffer length is zero, the existing ++ * WPA IE is reset. ++ */ ++static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv, ++ u8 *ie_data_ptr, u16 ie_len) ++{ ++ if (ie_len) { ++ if (ie_len > sizeof(priv->wpa_ie)) { ++ dev_err(priv->adapter->dev, ++ "failed to copy WPA IE, too big\n"); ++ return -1; ++ } ++ memcpy(priv->wpa_ie, ie_data_ptr, ie_len); ++ priv->wpa_ie_len = (u8) ie_len; ++ dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n", ++ priv->wpa_ie_len, priv->wpa_ie[0]); ++ ++ if (priv->wpa_ie[0] == WLAN_EID_WPA) { ++ priv->sec_info.wpa_enabled = true; ++ } else if (priv->wpa_ie[0] == WLAN_EID_RSN) { ++ priv->sec_info.wpa2_enabled = true; ++ } else { ++ priv->sec_info.wpa_enabled = false; ++ priv->sec_info.wpa2_enabled = false; ++ } ++ } else { ++ memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie)); ++ priv->wpa_ie_len = 0; ++ dev_dbg(priv->adapter->dev, "info: reset wpa_ie_len=%d IE=%#x\n", ++ priv->wpa_ie_len, priv->wpa_ie[0]); ++ priv->sec_info.wpa_enabled = false; ++ priv->sec_info.wpa2_enabled = false; ++ } ++ ++ return 0; ++} ++ ++/* ++ * IOCTL request handler to set/reset WAPI IE. ++ * ++ * The supplied WAPI IE is treated as a opaque buffer. Only the first field ++ * is checked to internally enable WAPI. If buffer length is zero, the existing ++ * WAPI IE is reset. ++ */ ++static int mwifiex_set_wapi_ie(struct mwifiex_private *priv, ++ u8 *ie_data_ptr, u16 ie_len) ++{ ++ if (ie_len) { ++ if (ie_len > sizeof(priv->wapi_ie)) { ++ dev_dbg(priv->adapter->dev, ++ "info: failed to copy WAPI IE, too big\n"); ++ return -1; ++ } ++ memcpy(priv->wapi_ie, ie_data_ptr, ie_len); ++ priv->wapi_ie_len = ie_len; ++ dev_dbg(priv->adapter->dev, "cmd: Set wapi_ie_len=%d IE=%#x\n", ++ priv->wapi_ie_len, priv->wapi_ie[0]); ++ ++ if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY) ++ priv->sec_info.wapi_enabled = true; ++ } else { ++ memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie)); ++ priv->wapi_ie_len = ie_len; ++ dev_dbg(priv->adapter->dev, ++ "info: Reset wapi_ie_len=%d IE=%#x\n", ++ priv->wapi_ie_len, priv->wapi_ie[0]); ++ priv->sec_info.wapi_enabled = false; ++ } ++ return 0; ++} ++ ++/* ++ * IOCTL request handler to set WAPI key. ++ * ++ * This function prepares the correct firmware command and ++ * issues it. ++ */ ++static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv, ++ struct mwifiex_ds_encrypt_key *encrypt_key) ++{ ++ ++ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL, ++ HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, ++ encrypt_key); ++} ++ ++/* ++ * IOCTL request handler to set WEP network key. ++ * ++ * This function prepares the correct firmware command and ++ * issues it, after validation checks. ++ */ ++static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, ++ struct mwifiex_ds_encrypt_key *encrypt_key) ++{ ++ int ret = 0; ++ struct mwifiex_wep_key *wep_key = NULL; ++ int index; ++ ++ if (priv->wep_key_curr_index >= NUM_WEP_KEYS) ++ priv->wep_key_curr_index = 0; ++ wep_key = &priv->wep_key[priv->wep_key_curr_index]; ++ index = encrypt_key->key_index; ++ if (encrypt_key->key_disable) { ++ priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; ++ } else if (!encrypt_key->key_len) { ++ /* Copy the required key as the current key */ ++ wep_key = &priv->wep_key[index]; ++ if (!wep_key->key_length) { ++ dev_err(priv->adapter->dev, ++ "key not set, so cannot enable it\n"); ++ return -1; ++ } ++ priv->wep_key_curr_index = (u16) index; ++ priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; ++ } else { ++ wep_key = &priv->wep_key[index]; ++ memset(wep_key, 0, sizeof(struct mwifiex_wep_key)); ++ /* Copy the key in the driver */ ++ memcpy(wep_key->key_material, ++ encrypt_key->key_material, ++ encrypt_key->key_len); ++ wep_key->key_index = index; ++ wep_key->key_length = encrypt_key->key_len; ++ priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; ++ } ++ if (wep_key->key_length) { ++ /* Send request to firmware */ ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_802_11_KEY_MATERIAL, ++ HostCmd_ACT_GEN_SET, 0, NULL); ++ if (ret) ++ return ret; ++ } ++ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) ++ priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; ++ else ++ priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; ++ ++ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL, ++ HostCmd_ACT_GEN_SET, 0, ++ &priv->curr_pkt_filter); ++ ++ return ret; ++} ++ ++/* ++ * IOCTL request handler to set WPA key. ++ * ++ * This function prepares the correct firmware command and ++ * issues it, after validation checks. ++ * ++ * Current driver only supports key length of up to 32 bytes. ++ * ++ * This function can also be used to disable a currently set key. ++ */ ++static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv, ++ struct mwifiex_ds_encrypt_key *encrypt_key) ++{ ++ int ret = 0; ++ u8 remove_key = false; ++ struct host_cmd_ds_802_11_key_material *ibss_key; ++ ++ /* Current driver only supports key length of up to 32 bytes */ ++ if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) { ++ dev_err(priv->adapter->dev, "key length too long\n"); ++ return -1; ++ } ++ ++ if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { ++ /* ++ * IBSS/WPA-None uses only one key (Group) for both receiving ++ * and sending unicast and multicast packets. ++ */ ++ /* Send the key as PTK to firmware */ ++ encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; ++ ret = mwifiex_send_cmd_async(priv, ++ HostCmd_CMD_802_11_KEY_MATERIAL, ++ HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, ++ encrypt_key); ++ if (ret) ++ return ret; ++ ++ ibss_key = &priv->aes_key; ++ memset(ibss_key, 0, ++ sizeof(struct host_cmd_ds_802_11_key_material)); ++ /* Copy the key in the driver */ ++ memcpy(ibss_key->key_param_set.key, encrypt_key->key_material, ++ encrypt_key->key_len); ++ memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len, ++ sizeof(ibss_key->key_param_set.key_len)); ++ ibss_key->key_param_set.key_type_id ++ = cpu_to_le16(KEY_TYPE_ID_TKIP); ++ ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED); ++ ++ /* Send the key as GTK to firmware */ ++ encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST; ++ } ++ ++ if (!encrypt_key->key_index) ++ encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; ++ ++ if (remove_key) ++ ret = mwifiex_send_cmd_sync(priv, ++ HostCmd_CMD_802_11_KEY_MATERIAL, ++ HostCmd_ACT_GEN_SET, !(KEY_INFO_ENABLED), ++ encrypt_key); ++ else ++ ret = mwifiex_send_cmd_sync(priv, ++ HostCmd_CMD_802_11_KEY_MATERIAL, ++ HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, ++ encrypt_key); ++ ++ return ret; ++} ++ ++/* ++ * IOCTL request handler to set/get network keys. ++ * ++ * This is a generic key handling function which supports WEP, WPA ++ * and WAPI. ++ */ ++static int ++mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv, ++ struct mwifiex_ds_encrypt_key *encrypt_key) ++{ ++ int status = 0; ++ ++ if (encrypt_key->is_wapi_key) ++ status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key); ++ else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104) ++ status = mwifiex_sec_ioctl_set_wpa_key(priv, encrypt_key); ++ else ++ status = mwifiex_sec_ioctl_set_wep_key(priv, encrypt_key); ++ return status; ++} ++ ++/* ++ * This function returns the driver version. ++ */ ++int ++mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version, ++ int max_len) ++{ ++ union { ++ u32 l; ++ u8 c[4]; ++ } ver; ++ char fw_ver[32]; ++ ++ ver.l = adapter->fw_release_number; ++ sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]); ++ ++ snprintf(version, max_len, driver_version, fw_ver); ++ ++ dev_dbg(adapter->dev, "info: MWIFIEX VERSION: %s\n", version); ++ ++ return 0; ++} ++ ++/* ++ * Sends IOCTL request to get signal information. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ */ ++int mwifiex_get_signal_info(struct mwifiex_private *priv, ++ struct mwifiex_ds_get_signal *signal) ++{ ++ struct mwifiex_ds_get_signal info; ++ int status = 0; ++ ++ memset(&info, 0, sizeof(struct mwifiex_ds_get_signal)); ++ info.selector = ALL_RSSI_INFO_MASK; ++ ++ /* Signal info can be obtained only if connected */ ++ if (!priv->media_connected) { ++ dev_dbg(priv->adapter->dev, ++ "info: Can not get signal in disconnected state\n"); ++ return -1; ++ } ++ ++ status = mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO, ++ HostCmd_ACT_GEN_GET, 0, signal); ++ ++ if (!status) { ++ if (signal) ++ memcpy(signal, &info, ++ sizeof(struct mwifiex_ds_get_signal)); ++ if (info.selector & BCN_RSSI_AVG_MASK) ++ priv->w_stats.qual.level = info.bcn_rssi_avg; ++ if (info.selector & BCN_NF_AVG_MASK) ++ priv->w_stats.qual.noise = info.bcn_nf_avg; ++ } ++ ++ return status; ++} ++ ++/* ++ * Sends IOCTL request to set encoding parameters. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ */ ++int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, ++ int key_len, u8 key_index, int disable) ++{ ++ struct mwifiex_ds_encrypt_key encrypt_key; ++ ++ memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key)); ++ encrypt_key.key_len = key_len; ++ if (!disable) { ++ encrypt_key.key_index = key_index; ++ if (key_len) ++ memcpy(encrypt_key.key_material, key, key_len); ++ } else { ++ encrypt_key.key_disable = true; ++ } ++ ++ return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key); ++} ++ ++/* ++ * Sends IOCTL request to get extended version. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ */ ++int ++mwifiex_get_ver_ext(struct mwifiex_private *priv) ++{ ++ struct mwifiex_ver_ext ver_ext; ++ ++ memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext)); ++ if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_VERSION_EXT, ++ HostCmd_ACT_GEN_GET, 0, &ver_ext)) ++ return -1; ++ ++ return 0; ++} ++ ++/* ++ * Sends IOCTL request to get statistics information. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ */ ++int ++mwifiex_get_stats_info(struct mwifiex_private *priv, ++ struct mwifiex_ds_get_stats *log) ++{ ++ int ret = 0; ++ struct mwifiex_ds_get_stats get_log; ++ ++ memset(&get_log, 0, sizeof(struct mwifiex_ds_get_stats)); ++ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, ++ HostCmd_ACT_GEN_GET, 0, &get_log); ++ ++ if (!ret) { ++ if (log) ++ memcpy(log, &get_log, sizeof(struct ++ mwifiex_ds_get_stats)); ++ priv->w_stats.discard.fragment = get_log.fcs_error; ++ priv->w_stats.discard.retries = get_log.retry; ++ priv->w_stats.discard.misc = get_log.ack_failure; ++ } ++ ++ return ret; ++} ++ ++/* ++ * IOCTL request handler to read/write register. ++ * ++ * This function prepares the correct firmware command and ++ * issues it. ++ * ++ * Access to the following registers are supported - ++ * - MAC ++ * - BBP ++ * - RF ++ * - PMIC ++ * - CAU ++ */ ++static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv, ++ struct mwifiex_ds_reg_rw *reg_rw, ++ u16 action) ++{ ++ u16 cmd_no; ++ ++ switch (le32_to_cpu(reg_rw->type)) { ++ case MWIFIEX_REG_MAC: ++ cmd_no = HostCmd_CMD_MAC_REG_ACCESS; ++ break; ++ case MWIFIEX_REG_BBP: ++ cmd_no = HostCmd_CMD_BBP_REG_ACCESS; ++ break; ++ case MWIFIEX_REG_RF: ++ cmd_no = HostCmd_CMD_RF_REG_ACCESS; ++ break; ++ case MWIFIEX_REG_PMIC: ++ cmd_no = HostCmd_CMD_PMIC_REG_ACCESS; ++ break; ++ case MWIFIEX_REG_CAU: ++ cmd_no = HostCmd_CMD_CAU_REG_ACCESS; ++ break; ++ default: ++ return -1; ++ } ++ ++ return mwifiex_send_cmd_sync(priv, cmd_no, action, 0, reg_rw); ++ ++} ++ ++/* ++ * Sends IOCTL request to write to a register. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ */ ++int ++mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, ++ u32 reg_offset, u32 reg_value) ++{ ++ struct mwifiex_ds_reg_rw reg_rw; ++ ++ reg_rw.type = cpu_to_le32(reg_type); ++ reg_rw.offset = cpu_to_le32(reg_offset); ++ reg_rw.value = cpu_to_le32(reg_value); ++ ++ return mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_SET); ++} ++ ++/* ++ * Sends IOCTL request to read from a register. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ */ ++int ++mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, ++ u32 reg_offset, u32 *value) ++{ ++ int ret = 0; ++ struct mwifiex_ds_reg_rw reg_rw; ++ ++ reg_rw.type = cpu_to_le32(reg_type); ++ reg_rw.offset = cpu_to_le32(reg_offset); ++ ret = mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_GET); ++ ++ if (ret) ++ goto done; ++ ++ *value = le32_to_cpu(reg_rw.value); ++ ++done: ++ return ret; ++} ++ ++/* ++ * Sends IOCTL request to read from EEPROM. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ */ ++int ++mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, ++ u8 *value) ++{ ++ int ret = 0; ++ struct mwifiex_ds_read_eeprom rd_eeprom; ++ ++ rd_eeprom.offset = cpu_to_le16((u16) offset); ++ rd_eeprom.byte_count = cpu_to_le16((u16) bytes); ++ ++ /* Send request to firmware */ ++ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_EEPROM_ACCESS, ++ HostCmd_ACT_GEN_GET, 0, &rd_eeprom); ++ ++ if (!ret) ++ memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA); ++ return ret; ++} ++ ++/* ++ * This function sets a generic IE. In addition to generic IE, it can ++ * also handle WPA, WPA2 and WAPI IEs. ++ */ ++static int ++mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, ++ u16 ie_len) ++{ ++ int ret = 0; ++ struct ieee_types_vendor_header *pvendor_ie; ++ const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 }; ++ const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; ++ ++ /* If the passed length is zero, reset the buffer */ ++ if (!ie_len) { ++ priv->gen_ie_buf_len = 0; ++ priv->wps.session_enable = false; ++ ++ return 0; ++ } else if (!ie_data_ptr) { ++ return -1; ++ } ++ pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; ++ /* Test to see if it is a WPA IE, if not, then it is a gen IE */ ++ if (((pvendor_ie->element_id == WLAN_EID_WPA) ++ && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui)))) ++ || (pvendor_ie->element_id == WLAN_EID_RSN)) { ++ ++ /* IE is a WPA/WPA2 IE so call set_wpa function */ ++ ret = mwifiex_set_wpa_ie_helper(priv, ie_data_ptr, ie_len); ++ priv->wps.session_enable = false; ++ ++ return ret; ++ } else if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) { ++ /* IE is a WAPI IE so call set_wapi function */ ++ ret = mwifiex_set_wapi_ie(priv, ie_data_ptr, ie_len); ++ ++ return ret; ++ } ++ /* ++ * Verify that the passed length is not larger than the ++ * available space remaining in the buffer ++ */ ++ if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) { ++ ++ /* Test to see if it is a WPS IE, if so, enable ++ * wps session flag ++ */ ++ pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; ++ if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) ++ && (!memcmp(pvendor_ie->oui, wps_oui, ++ sizeof(wps_oui)))) { ++ priv->wps.session_enable = true; ++ dev_dbg(priv->adapter->dev, ++ "info: WPS Session Enabled.\n"); ++ } ++ ++ /* Append the passed data to the end of the ++ genIeBuffer */ ++ memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr, ++ ie_len); ++ /* Increment the stored buffer length by the ++ size passed */ ++ priv->gen_ie_buf_len += ie_len; ++ } else { ++ /* Passed data does not fit in the remaining ++ buffer space */ ++ ret = -1; ++ } ++ ++ /* Return 0, or -1 for error case */ ++ return ret; ++} ++ ++/* ++ * IOCTL request handler to set/get generic IE. ++ * ++ * In addition to various generic IEs, this function can also be ++ * used to set the ARP filter. ++ */ ++static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv, ++ struct mwifiex_ds_misc_gen_ie *gen_ie, ++ u16 action) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ ++ switch (gen_ie->type) { ++ case MWIFIEX_IE_TYPE_GEN_IE: ++ if (action == HostCmd_ACT_GEN_GET) { ++ gen_ie->len = priv->wpa_ie_len; ++ memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len); ++ } else { ++ mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data, ++ (u16) gen_ie->len); ++ } ++ break; ++ case MWIFIEX_IE_TYPE_ARP_FILTER: ++ memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter)); ++ if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) { ++ adapter->arp_filter_size = 0; ++ dev_err(adapter->dev, "invalid ARP filter size\n"); ++ return -1; ++ } else { ++ memcpy(adapter->arp_filter, gen_ie->ie_data, ++ gen_ie->len); ++ adapter->arp_filter_size = gen_ie->len; ++ } ++ break; ++ default: ++ dev_err(adapter->dev, "invalid IE type\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++/* ++ * Sends IOCTL request to set a generic IE. ++ * ++ * This function allocates the IOCTL request buffer, fills it ++ * with requisite parameters and calls the IOCTL handler. ++ */ ++int ++mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len) ++{ ++ struct mwifiex_ds_misc_gen_ie gen_ie; ++ ++ if (ie_len > IW_CUSTOM_MAX) ++ return -EFAULT; ++ ++ gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE; ++ gen_ie.len = ie_len; ++ memcpy(gen_ie.ie_data, ie, ie_len); ++ if (mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET)) ++ return -EFAULT; ++ ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sta_rx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sta_rx.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sta_rx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sta_rx.c 2011-05-05 23:29:45.492441949 +0200 +@@ -0,0 +1,182 @@ ++/* ++ * Marvell Wireless LAN device driver: station RX data handling ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "11n_aggr.h" ++#include "11n_rxreorder.h" ++ ++/* ++ * This function processes the received packet and forwards it ++ * to kernel/upper layer. ++ * ++ * This function parses through the received packet and determines ++ * if it is a debug packet or normal packet. ++ * ++ * For non-debug packets, the function chops off unnecessary leading ++ * header bytes, reconstructs the packet as an ethernet frame or ++ * 802.2/llc/snap frame as required, and sends it to kernel/upper layer. ++ * ++ * The completion callback is called after processing in complete. ++ */ ++int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb) ++{ ++ int ret = 0; ++ struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); ++ struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; ++ struct rx_packet_hdr *rx_pkt_hdr; ++ struct rxpd *local_rx_pd; ++ int hdr_chop; ++ struct ethhdr *eth_hdr; ++ u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; ++ ++ local_rx_pd = (struct rxpd *) (skb->data); ++ ++ rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd + ++ local_rx_pd->rx_pkt_offset); ++ ++ if (!memcmp(&rx_pkt_hdr->rfc1042_hdr, ++ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) { ++ /* ++ * Replace the 803 header and rfc1042 header (llc/snap) with an ++ * EthernetII header, keep the src/dst and snap_type ++ * (ethertype). ++ * The firmware only passes up SNAP frames converting ++ * all RX Data from 802.11 to 802.2/LLC/SNAP frames. ++ * To create the Ethernet II, just move the src, dst address ++ * right before the snap_type. ++ */ ++ eth_hdr = (struct ethhdr *) ++ ((u8 *) &rx_pkt_hdr->eth803_hdr ++ + sizeof(rx_pkt_hdr->eth803_hdr) + ++ sizeof(rx_pkt_hdr->rfc1042_hdr) ++ - sizeof(rx_pkt_hdr->eth803_hdr.h_dest) ++ - sizeof(rx_pkt_hdr->eth803_hdr.h_source) ++ - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type)); ++ ++ memcpy(eth_hdr->h_source, rx_pkt_hdr->eth803_hdr.h_source, ++ sizeof(eth_hdr->h_source)); ++ memcpy(eth_hdr->h_dest, rx_pkt_hdr->eth803_hdr.h_dest, ++ sizeof(eth_hdr->h_dest)); ++ ++ /* Chop off the rxpd + the excess memory from the 802.2/llc/snap ++ header that was removed. */ ++ hdr_chop = (u8 *) eth_hdr - (u8 *) local_rx_pd; ++ } else { ++ /* Chop off the rxpd */ ++ hdr_chop = (u8 *) &rx_pkt_hdr->eth803_hdr - ++ (u8 *) local_rx_pd; ++ } ++ ++ /* Chop off the leading header bytes so the it points to the start of ++ either the reconstructed EthII frame or the 802.2/llc/snap frame */ ++ skb_pull(skb, hdr_chop); ++ ++ priv->rxpd_rate = local_rx_pd->rx_rate; ++ ++ priv->rxpd_htinfo = local_rx_pd->ht_info; ++ ++ ret = mwifiex_recv_packet(adapter, skb); ++ if (ret == -1) ++ dev_err(adapter->dev, "recv packet failed\n"); ++ ++ return ret; ++} ++ ++/* ++ * This function processes the received buffer. ++ * ++ * The function looks into the RxPD and performs sanity tests on the ++ * received buffer to ensure its a valid packet, before processing it ++ * further. If the packet is determined to be aggregated, it is ++ * de-aggregated accordingly. Non-unicast packets are sent directly to ++ * the kernel/upper layers. Unicast packets are handed over to the ++ * Rx reordering routine if 11n is enabled. ++ * ++ * The completion callback is called after processing in complete. ++ */ ++int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb) ++{ ++ int ret = 0; ++ struct rxpd *local_rx_pd; ++ struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); ++ struct rx_packet_hdr *rx_pkt_hdr; ++ u8 ta[ETH_ALEN]; ++ u16 rx_pkt_type = 0; ++ struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; ++ ++ local_rx_pd = (struct rxpd *) (skb->data); ++ rx_pkt_type = local_rx_pd->rx_pkt_type; ++ ++ rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd + ++ local_rx_pd->rx_pkt_offset); ++ ++ if ((local_rx_pd->rx_pkt_offset + local_rx_pd->rx_pkt_length) > ++ (u16) skb->len) { ++ dev_err(adapter->dev, "wrong rx packet: len=%d," ++ " rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len, ++ local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length); ++ priv->stats.rx_dropped++; ++ dev_kfree_skb_any(skb); ++ return ret; ++ } ++ if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) { ++ mwifiex_11n_deaggregate_pkt(priv, skb); ++ return ret; ++ } ++ /* ++ * If the packet is not an unicast packet then send the packet ++ * directly to os. Don't pass thru rx reordering ++ */ ++ if (!IS_11N_ENABLED(priv) || ++ memcmp(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN)) { ++ mwifiex_process_rx_packet(adapter, skb); ++ return ret; ++ } ++ ++ if (mwifiex_queuing_ra_based(priv)) { ++ memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN); ++ } else { ++ if (rx_pkt_type != PKT_TYPE_BAR) ++ priv->rx_seq[local_rx_pd->priority] = ++ local_rx_pd->seq_num; ++ memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address, ++ ETH_ALEN); ++ } ++ ++ /* Reorder and send to OS */ ++ ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num, ++ local_rx_pd->priority, ta, ++ (u8) local_rx_pd->rx_pkt_type, ++ (void *) skb); ++ ++ if (ret || (rx_pkt_type == PKT_TYPE_BAR)) { ++ if (priv && (ret == -1)) ++ priv->stats.rx_dropped++; ++ ++ dev_kfree_skb_any(skb); ++ } ++ ++ return ret; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sta_tx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sta_tx.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/sta_tx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/sta_tx.c 2011-05-05 23:29:45.471441695 +0200 +@@ -0,0 +1,198 @@ ++/* ++ * Marvell Wireless LAN device driver: station TX data handling ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++ ++/* ++ * This function fills the TxPD for tx packets. ++ * ++ * The Tx buffer received by this function should already have the ++ * header space allocated for TxPD. ++ * ++ * This function inserts the TxPD in between interface header and actual ++ * data and adjusts the buffer pointers accordingly. ++ * ++ * The following TxPD fields are set by this function, as required - ++ * - BSS number ++ * - Tx packet length and offset ++ * - Priority ++ * - Packet delay ++ * - Priority specific Tx control ++ * - Flags ++ */ ++void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, ++ struct sk_buff *skb) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct txpd *local_tx_pd; ++ struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); ++ ++ if (!skb->len) { ++ dev_err(adapter->dev, "Tx: bad packet length: %d\n", ++ skb->len); ++ tx_info->status_code = -1; ++ return skb->data; ++ } ++ ++ BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN)); ++ skb_push(skb, sizeof(*local_tx_pd)); ++ ++ local_tx_pd = (struct txpd *) skb->data; ++ memset(local_tx_pd, 0, sizeof(struct txpd)); ++ local_tx_pd->bss_num = priv->bss_num; ++ local_tx_pd->bss_type = priv->bss_type; ++ local_tx_pd->tx_pkt_length = cpu_to_le16((u16) (skb->len - ++ sizeof(struct txpd))); ++ ++ local_tx_pd->priority = (u8) skb->priority; ++ local_tx_pd->pkt_delay_2ms = ++ mwifiex_wmm_compute_drv_pkt_delay(priv, skb); ++ ++ if (local_tx_pd->priority < ++ ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) ++ /* ++ * Set the priority specific tx_control field, setting of 0 will ++ * cause the default value to be used later in this function ++ */ ++ local_tx_pd->tx_control = ++ cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[local_tx_pd-> ++ priority]); ++ ++ if (adapter->pps_uapsd_mode) { ++ if (mwifiex_check_last_packet_indication(priv)) { ++ adapter->tx_lock_flag = true; ++ local_tx_pd->flags = ++ MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; ++ } ++ } ++ ++ /* Offset of actual data */ ++ local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); ++ ++ /* make space for INTF_HEADER_LEN */ ++ skb_push(skb, INTF_HEADER_LEN); ++ ++ if (!local_tx_pd->tx_control) ++ /* TxCtrl set by user or default */ ++ local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); ++ ++ return skb->data; ++} ++ ++/* ++ * This function tells firmware to send a NULL data packet. ++ * ++ * The function creates a NULL data packet with TxPD and sends to the ++ * firmware for transmission, with highest priority setting. ++ */ ++int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct txpd *local_tx_pd; ++/* sizeof(struct txpd) + Interface specific header */ ++#define NULL_PACKET_HDR 64 ++ u32 data_len = NULL_PACKET_HDR; ++ struct sk_buff *skb = NULL; ++ int ret = 0; ++ struct mwifiex_txinfo *tx_info = NULL; ++ ++ if (adapter->surprise_removed) ++ return -1; ++ ++ if (!priv->media_connected) ++ return -1; ++ ++ if (adapter->data_sent) ++ return -1; ++ ++ skb = dev_alloc_skb(data_len); ++ if (!skb) ++ return -1; ++ ++ tx_info = MWIFIEX_SKB_TXCB(skb); ++ tx_info->bss_index = priv->bss_index; ++ skb_reserve(skb, sizeof(struct txpd) + INTF_HEADER_LEN); ++ skb_push(skb, sizeof(struct txpd)); ++ ++ local_tx_pd = (struct txpd *) skb->data; ++ local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); ++ local_tx_pd->flags = flags; ++ local_tx_pd->priority = WMM_HIGHEST_PRIORITY; ++ local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); ++ local_tx_pd->bss_num = priv->bss_num; ++ local_tx_pd->bss_type = priv->bss_type; ++ ++ skb_push(skb, INTF_HEADER_LEN); ++ ++ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, ++ skb->data, skb->len, NULL); ++ switch (ret) { ++ case -EBUSY: ++ adapter->data_sent = true; ++ /* Fall through FAILURE handling */ ++ case -1: ++ dev_kfree_skb_any(skb); ++ dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n", ++ __func__, ret); ++ adapter->dbg.num_tx_host_to_card_failure++; ++ break; ++ case 0: ++ dev_kfree_skb_any(skb); ++ dev_dbg(adapter->dev, "data: %s: host_to_card succeeded\n", ++ __func__); ++ adapter->tx_lock_flag = true; ++ break; ++ case -EINPROGRESS: ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++/* ++ * This function checks if we need to send last packet indication. ++ */ ++u8 ++mwifiex_check_last_packet_indication(struct mwifiex_private *priv) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ u8 ret = false; ++ ++ if (!adapter->sleep_period.period) ++ return ret; ++ if (mwifiex_wmm_lists_empty(adapter)) ++ ret = true; ++ ++ if (ret && !adapter->cmd_sent && !adapter->curr_cmd ++ && !is_command_pending(adapter)) { ++ adapter->delay_null_pkt = false; ++ ret = true; ++ } else { ++ ret = false; ++ adapter->delay_null_pkt = true; ++ } ++ return ret; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/txrx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/txrx.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/txrx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/txrx.c 2011-05-05 23:29:45.439441309 +0200 +@@ -0,0 +1,200 @@ ++/* ++ * Marvell Wireless LAN device driver: generic TX/RX data handling ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++ ++/* ++ * This function processes the received buffer. ++ * ++ * Main responsibility of this function is to parse the RxPD to ++ * identify the correct interface this packet is headed for and ++ * forwarding it to the associated handling function, where the ++ * packet will be further processed and sent to kernel/upper layer ++ * if required. ++ */ ++int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb) ++{ ++ struct mwifiex_private *priv = ++ mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); ++ struct rxpd *local_rx_pd; ++ struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); ++ ++ local_rx_pd = (struct rxpd *) (skb->data); ++ /* Get the BSS number from rxpd, get corresponding priv */ ++ priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num & ++ BSS_NUM_MASK, local_rx_pd->bss_type); ++ if (!priv) ++ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); ++ ++ rx_info->bss_index = priv->bss_index; ++ ++ return mwifiex_process_sta_rx_packet(adapter, skb); ++} ++EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); ++ ++/* ++ * This function sends a packet to device. ++ * ++ * It processes the packet to add the TxPD, checks condition and ++ * sends the processed packet to firmware for transmission. ++ * ++ * On successful completion, the function calls the completion callback ++ * and logs the time. ++ */ ++int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, ++ struct mwifiex_tx_param *tx_param) ++{ ++ int ret = -1; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ u8 *head_ptr = NULL; ++ struct txpd *local_tx_pd = NULL; ++ ++ head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb); ++ if (head_ptr) { ++ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) ++ local_tx_pd = ++ (struct txpd *) (head_ptr + INTF_HEADER_LEN); ++ ++ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, ++ skb->data, skb->len, tx_param); ++ } ++ ++ switch (ret) { ++ case -EBUSY: ++ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && ++ (adapter->pps_uapsd_mode) && ++ (adapter->tx_lock_flag)) { ++ priv->adapter->tx_lock_flag = false; ++ local_tx_pd->flags = 0; ++ } ++ dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); ++ break; ++ case -1: ++ adapter->data_sent = false; ++ dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n", ++ ret); ++ adapter->dbg.num_tx_host_to_card_failure++; ++ mwifiex_write_data_complete(adapter, skb, ret); ++ break; ++ case -EINPROGRESS: ++ adapter->data_sent = false; ++ break; ++ case 0: ++ mwifiex_write_data_complete(adapter, skb, ret); ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++/* ++ * Packet send completion callback handler. ++ * ++ * It either frees the buffer directly or forwards it to another ++ * completion callback which checks conditions, updates statistics, ++ * wakes up stalled traffic queue if required, and then frees the buffer. ++ */ ++int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb, int status) ++{ ++ struct mwifiex_private *priv = NULL, *tpriv = NULL; ++ struct mwifiex_txinfo *tx_info = NULL; ++ int i; ++ ++ if (!skb) ++ return 0; ++ ++ tx_info = MWIFIEX_SKB_TXCB(skb); ++ priv = mwifiex_bss_index_to_priv(adapter, tx_info->bss_index); ++ if (!priv) ++ goto done; ++ ++ priv->netdev->trans_start = jiffies; ++ if (!status) { ++ priv->stats.tx_packets++; ++ priv->stats.tx_bytes += skb->len; ++ } else { ++ priv->stats.tx_errors++; ++ } ++ atomic_dec(&adapter->tx_pending); ++ ++ for (i = 0; i < adapter->priv_num; i++) { ++ ++ tpriv = adapter->priv[i]; ++ ++ if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA) ++ && (tpriv->media_connected)) { ++ if (netif_queue_stopped(tpriv->netdev)) ++ netif_wake_queue(tpriv->netdev); ++ } ++ } ++done: ++ dev_kfree_skb_any(skb); ++ ++ return 0; ++} ++ ++/* ++ * Packet receive completion callback handler. ++ * ++ * This function calls another completion callback handler which ++ * updates the statistics, and optionally updates the parent buffer ++ * use count before freeing the received packet. ++ */ ++int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb, int status) ++{ ++ struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); ++ struct mwifiex_rxinfo *rx_info_parent = NULL; ++ struct mwifiex_private *priv; ++ struct sk_buff *skb_parent = NULL; ++ unsigned long flags; ++ ++ priv = adapter->priv[rx_info->bss_index]; ++ ++ if (priv && (status == -1)) ++ priv->stats.rx_dropped++; ++ ++ if (rx_info->parent) { ++ skb_parent = rx_info->parent; ++ rx_info_parent = MWIFIEX_SKB_RXCB(skb_parent); ++ ++ spin_lock_irqsave(&priv->rx_pkt_lock, flags); ++ --rx_info_parent->use_count; ++ ++ if (!rx_info_parent->use_count) { ++ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); ++ dev_kfree_skb_any(skb_parent); ++ } else { ++ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); ++ } ++ } else { ++ dev_kfree_skb_any(skb); ++ } ++ ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/util.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/util.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/util.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/util.c 2011-05-05 23:29:45.453441477 +0200 +@@ -0,0 +1,227 @@ ++/* ++ * Marvell Wireless LAN device driver: utility functions ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++ ++/* ++ * Firmware initialization complete callback handler. ++ * ++ * This function wakes up the function waiting on the init ++ * wait queue for the firmware initialization to complete. ++ */ ++int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter) ++{ ++ ++ adapter->init_wait_q_woken = true; ++ wake_up_interruptible(&adapter->init_wait_q); ++ return 0; ++} ++ ++/* ++ * Firmware shutdown complete callback handler. ++ * ++ * This function sets the hardware status to not ready and wakes up ++ * the function waiting on the init wait queue for the firmware ++ * shutdown to complete. ++ */ ++int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter) ++{ ++ adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY; ++ adapter->init_wait_q_woken = true; ++ wake_up_interruptible(&adapter->init_wait_q); ++ return 0; ++} ++ ++/* ++ * This function sends init/shutdown command ++ * to firmware. ++ */ ++int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, ++ u32 func_init_shutdown) ++{ ++ u16 cmd; ++ ++ if (func_init_shutdown == MWIFIEX_FUNC_INIT) { ++ cmd = HostCmd_CMD_FUNC_INIT; ++ } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) { ++ cmd = HostCmd_CMD_FUNC_SHUTDOWN; ++ } else { ++ dev_err(priv->adapter->dev, "unsupported parameter\n"); ++ return -1; ++ } ++ ++ return mwifiex_send_cmd_sync(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL); ++} ++EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw); ++ ++/* ++ * IOCTL request handler to set/get debug information. ++ * ++ * This function collates/sets the information from/to different driver ++ * structures. ++ */ ++int mwifiex_get_debug_info(struct mwifiex_private *priv, ++ struct mwifiex_debug_info *info) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ ++ if (info) { ++ memcpy(info->packets_out, ++ priv->wmm.packets_out, ++ sizeof(priv->wmm.packets_out)); ++ info->max_tx_buf_size = (u32) adapter->max_tx_buf_size; ++ info->tx_buf_size = (u32) adapter->tx_buf_size; ++ info->rx_tbl_num = mwifiex_get_rx_reorder_tbl( ++ priv, info->rx_tbl); ++ info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl( ++ priv, info->tx_tbl); ++ info->ps_mode = adapter->ps_mode; ++ info->ps_state = adapter->ps_state; ++ info->is_deep_sleep = adapter->is_deep_sleep; ++ info->pm_wakeup_card_req = adapter->pm_wakeup_card_req; ++ info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try; ++ info->is_hs_configured = adapter->is_hs_configured; ++ info->hs_activated = adapter->hs_activated; ++ info->num_cmd_host_to_card_failure ++ = adapter->dbg.num_cmd_host_to_card_failure; ++ info->num_cmd_sleep_cfm_host_to_card_failure ++ = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure; ++ info->num_tx_host_to_card_failure ++ = adapter->dbg.num_tx_host_to_card_failure; ++ info->num_event_deauth = adapter->dbg.num_event_deauth; ++ info->num_event_disassoc = adapter->dbg.num_event_disassoc; ++ info->num_event_link_lost = adapter->dbg.num_event_link_lost; ++ info->num_cmd_deauth = adapter->dbg.num_cmd_deauth; ++ info->num_cmd_assoc_success = ++ adapter->dbg.num_cmd_assoc_success; ++ info->num_cmd_assoc_failure = ++ adapter->dbg.num_cmd_assoc_failure; ++ info->num_tx_timeout = adapter->dbg.num_tx_timeout; ++ info->num_cmd_timeout = adapter->dbg.num_cmd_timeout; ++ info->timeout_cmd_id = adapter->dbg.timeout_cmd_id; ++ info->timeout_cmd_act = adapter->dbg.timeout_cmd_act; ++ memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id, ++ sizeof(adapter->dbg.last_cmd_id)); ++ memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act, ++ sizeof(adapter->dbg.last_cmd_act)); ++ info->last_cmd_index = adapter->dbg.last_cmd_index; ++ memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id, ++ sizeof(adapter->dbg.last_cmd_resp_id)); ++ info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index; ++ memcpy(info->last_event, adapter->dbg.last_event, ++ sizeof(adapter->dbg.last_event)); ++ info->last_event_index = adapter->dbg.last_event_index; ++ info->data_sent = adapter->data_sent; ++ info->cmd_sent = adapter->cmd_sent; ++ info->cmd_resp_received = adapter->cmd_resp_received; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function processes the received packet before sending it to the ++ * kernel. ++ * ++ * It extracts the SKB from the received buffer and sends it to kernel. ++ * In case the received buffer does not contain the data in SKB format, ++ * the function creates a blank SKB, fills it with the data from the ++ * received buffer and then sends this new SKB to the kernel. ++ */ ++int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) ++{ ++ struct mwifiex_rxinfo *rx_info = NULL; ++ struct mwifiex_private *priv = NULL; ++ ++ if (!skb) ++ return -1; ++ ++ rx_info = MWIFIEX_SKB_RXCB(skb); ++ priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index); ++ if (!priv) ++ return -1; ++ ++ skb->dev = priv->netdev; ++ skb->protocol = eth_type_trans(skb, priv->netdev); ++ skb->ip_summed = CHECKSUM_NONE; ++ priv->stats.rx_bytes += skb->len; ++ priv->stats.rx_packets++; ++ if (in_interrupt()) ++ netif_rx(skb); ++ else ++ netif_rx_ni(skb); ++ ++ return 0; ++} ++ ++/* ++ * Receive packet completion callback handler. ++ * ++ * This function updates the statistics and frees the buffer SKB. ++ */ ++int mwifiex_recv_complete(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb, int status) ++{ ++ struct mwifiex_private *priv = NULL; ++ struct mwifiex_rxinfo *rx_info = NULL; ++ ++ if (!skb) ++ return 0; ++ ++ rx_info = MWIFIEX_SKB_RXCB(skb); ++ priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index); ++ ++ if (priv && (status == -1)) ++ priv->stats.rx_dropped++; ++ ++ dev_kfree_skb_any(skb); ++ ++ return 0; ++} ++ ++/* ++ * IOCTL completion callback handler. ++ * ++ * This function is called when a pending IOCTL is completed. ++ * ++ * If work queue support is enabled, the function wakes up the ++ * corresponding waiting function. Otherwise, it processes the ++ * IOCTL response and frees the response buffer. ++ */ ++int mwifiex_complete_cmd(struct mwifiex_adapter *adapter) ++{ ++ atomic_dec(&adapter->cmd_pending); ++ dev_dbg(adapter->dev, "cmd completed: status=%d\n", ++ adapter->cmd_wait_q.status); ++ ++ adapter->cmd_wait_q.condition = true; ++ ++ if (adapter->cmd_wait_q.status == -ETIMEDOUT) ++ dev_err(adapter->dev, "cmd timeout\n"); ++ else ++ wake_up_interruptible(&adapter->cmd_wait_q.wait); ++ ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/util.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/util.h +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/util.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/util.h 2011-05-05 23:29:45.489441913 +0200 +@@ -0,0 +1,32 @@ ++/* ++ * Marvell Wireless LAN device driver: utility functions ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#ifndef _MWIFIEX_UTIL_H_ ++#define _MWIFIEX_UTIL_H_ ++ ++static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) ++{ ++ return (struct mwifiex_rxinfo *)skb->cb; ++} ++ ++static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb) ++{ ++ return (struct mwifiex_txinfo *)skb->cb; ++} ++#endif /* !_MWIFIEX_UTIL_H_ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/wmm.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/wmm.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/wmm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/wmm.c 2011-05-05 23:29:45.472441707 +0200 +@@ -0,0 +1,1231 @@ ++/* ++ * Marvell Wireless LAN device driver: WMM ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#include "decl.h" ++#include "ioctl.h" ++#include "util.h" ++#include "fw.h" ++#include "main.h" ++#include "wmm.h" ++#include "11n.h" ++ ++ ++/* Maximum value FW can accept for driver delay in packet transmission */ ++#define DRV_PKT_DELAY_TO_FW_MAX 512 ++ ++ ++#define WMM_QUEUED_PACKET_LOWER_LIMIT 180 ++ ++#define WMM_QUEUED_PACKET_UPPER_LIMIT 200 ++ ++/* Offset for TOS field in the IP header */ ++#define IPTOS_OFFSET 5 ++ ++/* WMM information IE */ ++static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07, ++ 0x00, 0x50, 0xf2, 0x02, ++ 0x00, 0x01, 0x00 ++}; ++ ++static const u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE, ++ WMM_AC_BK, ++ WMM_AC_VI, ++ WMM_AC_VO ++}; ++ ++static u8 tos_to_tid[] = { ++ /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */ ++ 0x01, /* 0 1 0 AC_BK */ ++ 0x02, /* 0 0 0 AC_BK */ ++ 0x00, /* 0 0 1 AC_BE */ ++ 0x03, /* 0 1 1 AC_BE */ ++ 0x04, /* 1 0 0 AC_VI */ ++ 0x05, /* 1 0 1 AC_VI */ ++ 0x06, /* 1 1 0 AC_VO */ ++ 0x07 /* 1 1 1 AC_VO */ ++}; ++ ++/* ++ * This table inverses the tos_to_tid operation to get a priority ++ * which is in sequential order, and can be compared. ++ * Use this to compare the priority of two different TIDs. ++ */ ++static u8 tos_to_tid_inv[] = { ++ 0x02, /* from tos_to_tid[2] = 0 */ ++ 0x00, /* from tos_to_tid[0] = 1 */ ++ 0x01, /* from tos_to_tid[1] = 2 */ ++ 0x03, ++ 0x04, ++ 0x05, ++ 0x06, ++ 0x07}; ++ ++static u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} }; ++ ++/* ++ * This function debug prints the priority parameters for a WMM AC. ++ */ ++static void ++mwifiex_wmm_ac_debug_print(const struct ieee_types_wmm_ac_parameters *ac_param) ++{ ++ const char *ac_str[] = { "BK", "BE", "VI", "VO" }; ++ ++ pr_debug("info: WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, " ++ "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n", ++ ac_str[wmm_aci_to_qidx_map[(ac_param->aci_aifsn_bitmap ++ & MWIFIEX_ACI) >> 5]], ++ (ac_param->aci_aifsn_bitmap & MWIFIEX_ACI) >> 5, ++ (ac_param->aci_aifsn_bitmap & MWIFIEX_ACM) >> 4, ++ ac_param->aci_aifsn_bitmap & MWIFIEX_AIFSN, ++ ac_param->ecw_bitmap & MWIFIEX_ECW_MIN, ++ (ac_param->ecw_bitmap & MWIFIEX_ECW_MAX) >> 4, ++ le16_to_cpu(ac_param->tx_op_limit)); ++} ++ ++/* ++ * This function allocates a route address list. ++ * ++ * The function also initializes the list with the provided RA. ++ */ ++static struct mwifiex_ra_list_tbl * ++mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra) ++{ ++ struct mwifiex_ra_list_tbl *ra_list; ++ ++ ra_list = kzalloc(sizeof(struct mwifiex_ra_list_tbl), GFP_ATOMIC); ++ ++ if (!ra_list) { ++ dev_err(adapter->dev, "%s: failed to alloc ra_list\n", ++ __func__); ++ return NULL; ++ } ++ INIT_LIST_HEAD(&ra_list->list); ++ skb_queue_head_init(&ra_list->skb_head); ++ ++ memcpy(ra_list->ra, ra, ETH_ALEN); ++ ++ ra_list->total_pkts_size = 0; ++ ++ dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list); ++ ++ return ra_list; ++} ++ ++/* ++ * This function allocates and adds a RA list for all TIDs ++ * with the given RA. ++ */ ++void ++mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra) ++{ ++ int i; ++ struct mwifiex_ra_list_tbl *ra_list; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ ++ for (i = 0; i < MAX_NUM_TID; ++i) { ++ ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra); ++ dev_dbg(adapter->dev, "info: created ra_list %p\n", ra_list); ++ ++ if (!ra_list) ++ break; ++ ++ if (!mwifiex_queuing_ra_based(priv)) ++ ra_list->is_11n_enabled = IS_11N_ENABLED(priv); ++ else ++ ra_list->is_11n_enabled = false; ++ ++ dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n", ++ ra_list, ra_list->is_11n_enabled); ++ ++ list_add_tail(&ra_list->list, ++ &priv->wmm.tid_tbl_ptr[i].ra_list); ++ ++ if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr) ++ priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list; ++ } ++} ++ ++/* ++ * This function sets the WMM queue priorities to their default values. ++ */ ++static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv) ++{ ++ /* Default queue priorities: VO->VI->BE->BK */ ++ priv->wmm.queue_priority[0] = WMM_AC_VO; ++ priv->wmm.queue_priority[1] = WMM_AC_VI; ++ priv->wmm.queue_priority[2] = WMM_AC_BE; ++ priv->wmm.queue_priority[3] = WMM_AC_BK; ++} ++ ++/* ++ * This function map ACs to TIDs. ++ */ ++static void ++mwifiex_wmm_queue_priorities_tid(u8 queue_priority[]) ++{ ++ int i; ++ ++ for (i = 0; i < 4; ++i) { ++ tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1]; ++ tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0]; ++ } ++} ++ ++/* ++ * This function initializes WMM priority queues. ++ */ ++void ++mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, ++ struct ieee_types_wmm_parameter *wmm_ie) ++{ ++ u16 cw_min, avg_back_off, tmp[4]; ++ u32 i, j, num_ac; ++ u8 ac_idx; ++ ++ if (!wmm_ie || !priv->wmm_enabled) { ++ /* WMM is not enabled, just set the defaults and return */ ++ mwifiex_wmm_default_queue_priorities(priv); ++ return; ++ } ++ ++ dev_dbg(priv->adapter->dev, "info: WMM Parameter IE: version=%d, " ++ "qos_info Parameter Set Count=%d, Reserved=%#x\n", ++ wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap & ++ IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK, ++ wmm_ie->reserved); ++ ++ for (num_ac = 0; num_ac < ARRAY_SIZE(wmm_ie->ac_params); num_ac++) { ++ cw_min = (1 << (wmm_ie->ac_params[num_ac].ecw_bitmap & ++ MWIFIEX_ECW_MIN)) - 1; ++ avg_back_off = (cw_min >> 1) + ++ (wmm_ie->ac_params[num_ac].aci_aifsn_bitmap & ++ MWIFIEX_AIFSN); ++ ++ ac_idx = wmm_aci_to_qidx_map[(wmm_ie->ac_params[num_ac]. ++ aci_aifsn_bitmap & ++ MWIFIEX_ACI) >> 5]; ++ priv->wmm.queue_priority[ac_idx] = ac_idx; ++ tmp[ac_idx] = avg_back_off; ++ ++ dev_dbg(priv->adapter->dev, "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n", ++ (1 << ((wmm_ie->ac_params[num_ac].ecw_bitmap & ++ MWIFIEX_ECW_MAX) >> 4)) - 1, ++ cw_min, avg_back_off); ++ mwifiex_wmm_ac_debug_print(&wmm_ie->ac_params[num_ac]); ++ } ++ ++ /* Bubble sort */ ++ for (i = 0; i < num_ac; i++) { ++ for (j = 1; j < num_ac - i; j++) { ++ if (tmp[j - 1] > tmp[j]) { ++ swap(tmp[j - 1], tmp[j]); ++ swap(priv->wmm.queue_priority[j - 1], ++ priv->wmm.queue_priority[j]); ++ } else if (tmp[j - 1] == tmp[j]) { ++ if (priv->wmm.queue_priority[j - 1] ++ < priv->wmm.queue_priority[j]) ++ swap(priv->wmm.queue_priority[j - 1], ++ priv->wmm.queue_priority[j]); ++ } ++ } ++ } ++ ++ mwifiex_wmm_queue_priorities_tid(priv->wmm.queue_priority); ++} ++ ++/* ++ * This function evaluates whether or not an AC is to be downgraded. ++ * ++ * In case the AC is not enabled, the highest AC is returned that is ++ * enabled and does not require admission control. ++ */ ++static enum mwifiex_wmm_ac_e ++mwifiex_wmm_eval_downgrade_ac(struct mwifiex_private *priv, ++ enum mwifiex_wmm_ac_e eval_ac) ++{ ++ int down_ac; ++ enum mwifiex_wmm_ac_e ret_ac; ++ struct mwifiex_wmm_ac_status *ac_status; ++ ++ ac_status = &priv->wmm.ac_status[eval_ac]; ++ ++ if (!ac_status->disabled) ++ /* Okay to use this AC, its enabled */ ++ return eval_ac; ++ ++ /* Setup a default return value of the lowest priority */ ++ ret_ac = WMM_AC_BK; ++ ++ /* ++ * Find the highest AC that is enabled and does not require ++ * admission control. The spec disallows downgrading to an AC, ++ * which is enabled due to a completed admission control. ++ * Unadmitted traffic is not to be sent on an AC with admitted ++ * traffic. ++ */ ++ for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) { ++ ac_status = &priv->wmm.ac_status[down_ac]; ++ ++ if (!ac_status->disabled && !ac_status->flow_required) ++ /* AC is enabled and does not require admission ++ control */ ++ ret_ac = (enum mwifiex_wmm_ac_e) down_ac; ++ } ++ ++ return ret_ac; ++} ++ ++/* ++ * This function downgrades WMM priority queue. ++ */ ++void ++mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv) ++{ ++ int ac_val; ++ ++ dev_dbg(priv->adapter->dev, "info: WMM: AC Priorities:" ++ "BK(0), BE(1), VI(2), VO(3)\n"); ++ ++ if (!priv->wmm_enabled) { ++ /* WMM is not enabled, default priorities */ ++ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) ++ priv->wmm.ac_down_graded_vals[ac_val] = ++ (enum mwifiex_wmm_ac_e) ac_val; ++ } else { ++ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) { ++ priv->wmm.ac_down_graded_vals[ac_val] ++ = mwifiex_wmm_eval_downgrade_ac(priv, ++ (enum mwifiex_wmm_ac_e) ac_val); ++ dev_dbg(priv->adapter->dev, "info: WMM: AC PRIO %d maps to %d\n", ++ ac_val, priv->wmm.ac_down_graded_vals[ac_val]); ++ } ++ } ++} ++ ++/* ++ * This function converts the IP TOS field to an WMM AC ++ * Queue assignment. ++ */ ++static enum mwifiex_wmm_ac_e ++mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos) ++{ ++ /* Map of TOS UP values to WMM AC */ ++ const enum mwifiex_wmm_ac_e tos_to_ac[] = { WMM_AC_BE, ++ WMM_AC_BK, ++ WMM_AC_BK, ++ WMM_AC_BE, ++ WMM_AC_VI, ++ WMM_AC_VI, ++ WMM_AC_VO, ++ WMM_AC_VO ++ }; ++ ++ if (tos >= ARRAY_SIZE(tos_to_ac)) ++ return WMM_AC_BE; ++ ++ return tos_to_ac[tos]; ++} ++ ++/* ++ * This function evaluates a given TID and downgrades it to a lower ++ * TID if the WMM Parameter IE received from the AP indicates that the ++ * AP is disabled (due to call admission control (ACM bit). Mapping ++ * of TID to AC is taken care of internally. ++ */ ++static u8 ++mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid) ++{ ++ enum mwifiex_wmm_ac_e ac, ac_down; ++ u8 new_tid; ++ ++ ac = mwifiex_wmm_convert_tos_to_ac(priv->adapter, tid); ++ ac_down = priv->wmm.ac_down_graded_vals[ac]; ++ ++ /* Send the index to tid array, picking from the array will be ++ * taken care by dequeuing function ++ */ ++ new_tid = ac_to_tid[ac_down][tid % 2]; ++ ++ return new_tid; ++} ++ ++/* ++ * This function initializes the WMM state information and the ++ * WMM data path queues. ++ */ ++void ++mwifiex_wmm_init(struct mwifiex_adapter *adapter) ++{ ++ int i, j; ++ struct mwifiex_private *priv; ++ ++ for (j = 0; j < adapter->priv_num; ++j) { ++ priv = adapter->priv[j]; ++ if (!priv) ++ continue; ++ ++ for (i = 0; i < MAX_NUM_TID; ++i) { ++ priv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i]; ++ priv->aggr_prio_tbl[i].ampdu_ap = tos_to_tid_inv[i]; ++ priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i]; ++ priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL; ++ } ++ ++ priv->aggr_prio_tbl[6].amsdu ++ = priv->aggr_prio_tbl[6].ampdu_ap ++ = priv->aggr_prio_tbl[6].ampdu_user ++ = BA_STREAM_NOT_ALLOWED; ++ ++ priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap ++ = priv->aggr_prio_tbl[7].ampdu_user ++ = BA_STREAM_NOT_ALLOWED; ++ ++ priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT; ++ priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE; ++ priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE; ++ } ++} ++ ++/* ++ * This function checks if WMM Tx queue is empty. ++ */ ++int ++mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter) ++{ ++ int i, j; ++ struct mwifiex_private *priv; ++ ++ for (j = 0; j < adapter->priv_num; ++j) { ++ priv = adapter->priv[j]; ++ if (priv) { ++ for (i = 0; i < MAX_NUM_TID; i++) ++ if (!mwifiex_wmm_is_ra_list_empty( ++ &priv->wmm.tid_tbl_ptr[i].ra_list)) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++/* ++ * This function deletes all packets in an RA list node. ++ * ++ * The packet sent completion callback handler are called with ++ * status failure, after they are dequeued to ensure proper ++ * cleanup. The RA list node itself is freed at the end. ++ */ ++static void ++mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv, ++ struct mwifiex_ra_list_tbl *ra_list) ++{ ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct sk_buff *skb, *tmp; ++ ++ skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) ++ mwifiex_write_data_complete(adapter, skb, -1); ++} ++ ++/* ++ * This function deletes all packets in an RA list. ++ * ++ * Each nodes in the RA list are freed individually first, and then ++ * the RA list itself is freed. ++ */ ++static void ++mwifiex_wmm_del_pkts_in_ralist(struct mwifiex_private *priv, ++ struct list_head *ra_list_head) ++{ ++ struct mwifiex_ra_list_tbl *ra_list; ++ ++ list_for_each_entry(ra_list, ra_list_head, list) ++ mwifiex_wmm_del_pkts_in_ralist_node(priv, ra_list); ++} ++ ++/* ++ * This function deletes all packets in all RA lists. ++ */ ++static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_NUM_TID; i++) ++ mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i]. ++ ra_list); ++} ++ ++/* ++ * This function deletes all route addresses from all RA lists. ++ */ ++static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv) ++{ ++ struct mwifiex_ra_list_tbl *ra_list, *tmp_node; ++ int i; ++ ++ for (i = 0; i < MAX_NUM_TID; ++i) { ++ dev_dbg(priv->adapter->dev, ++ "info: ra_list: freeing buf for tid %d\n", i); ++ list_for_each_entry_safe(ra_list, tmp_node, ++ &priv->wmm.tid_tbl_ptr[i].ra_list, list) { ++ list_del(&ra_list->list); ++ kfree(ra_list); ++ } ++ ++ INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[i].ra_list); ++ ++ priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL; ++ } ++} ++ ++/* ++ * This function cleans up the Tx and Rx queues. ++ * ++ * Cleanup includes - ++ * - All packets in RA lists ++ * - All entries in Rx reorder table ++ * - All entries in Tx BA stream table ++ * - MPA buffer (if required) ++ * - All RA lists ++ */ ++void ++mwifiex_clean_txrx(struct mwifiex_private *priv) ++{ ++ unsigned long flags; ++ ++ mwifiex_11n_cleanup_reorder_tbl(priv); ++ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); ++ ++ mwifiex_wmm_cleanup_queues(priv); ++ mwifiex_11n_delete_all_tx_ba_stream_tbl(priv); ++ ++ if (priv->adapter->if_ops.cleanup_mpa_buf) ++ priv->adapter->if_ops.cleanup_mpa_buf(priv->adapter); ++ ++ mwifiex_wmm_delete_all_ralist(priv); ++ memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); ++ ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); ++} ++ ++/* ++ * This function retrieves a particular RA list node, matching with the ++ * given TID and RA address. ++ */ ++static struct mwifiex_ra_list_tbl * ++mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, ++ u8 *ra_addr) ++{ ++ struct mwifiex_ra_list_tbl *ra_list; ++ ++ list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[tid].ra_list, ++ list) { ++ if (!memcmp(ra_list->ra, ra_addr, ETH_ALEN)) ++ return ra_list; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * This function retrieves an RA list node for a given TID and ++ * RA address pair. ++ * ++ * If no such node is found, a new node is added first and then ++ * retrieved. ++ */ ++static struct mwifiex_ra_list_tbl * ++mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr) ++{ ++ struct mwifiex_ra_list_tbl *ra_list; ++ ++ ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra_addr); ++ if (ra_list) ++ return ra_list; ++ mwifiex_ralist_add(priv, ra_addr); ++ ++ return mwifiex_wmm_get_ralist_node(priv, tid, ra_addr); ++} ++ ++/* ++ * This function checks if a particular RA list node exists in a given TID ++ * table index. ++ */ ++int ++mwifiex_is_ralist_valid(struct mwifiex_private *priv, ++ struct mwifiex_ra_list_tbl *ra_list, int ptr_index) ++{ ++ struct mwifiex_ra_list_tbl *rlist; ++ ++ list_for_each_entry(rlist, &priv->wmm.tid_tbl_ptr[ptr_index].ra_list, ++ list) { ++ if (rlist == ra_list) ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++ * This function adds a packet to WMM queue. ++ * ++ * In disconnected state the packet is immediately dropped and the ++ * packet send completion callback is called with status failure. ++ * ++ * Otherwise, the correct RA list node is located and the packet ++ * is queued at the list tail. ++ */ ++void ++mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb) ++{ ++ struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); ++ struct mwifiex_private *priv = adapter->priv[tx_info->bss_index]; ++ u32 tid; ++ struct mwifiex_ra_list_tbl *ra_list; ++ u8 ra[ETH_ALEN], tid_down; ++ unsigned long flags; ++ ++ if (!priv->media_connected) { ++ dev_dbg(adapter->dev, "data: drop packet in disconnect\n"); ++ mwifiex_write_data_complete(adapter, skb, -1); ++ return; ++ } ++ ++ tid = skb->priority; ++ ++ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); ++ ++ tid_down = mwifiex_wmm_downgrade_tid(priv, tid); ++ ++ /* In case of infra as we have already created the list during ++ association we just don't have to call get_queue_raptr, we will ++ have only 1 raptr for a tid in case of infra */ ++ if (!mwifiex_queuing_ra_based(priv)) { ++ if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list)) ++ ra_list = list_first_entry( ++ &priv->wmm.tid_tbl_ptr[tid_down].ra_list, ++ struct mwifiex_ra_list_tbl, list); ++ else ++ ra_list = NULL; ++ } else { ++ memcpy(ra, skb->data, ETH_ALEN); ++ ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); ++ } ++ ++ if (!ra_list) { ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); ++ mwifiex_write_data_complete(adapter, skb, -1); ++ return; ++ } ++ ++ skb_queue_tail(&ra_list->skb_head, skb); ++ ++ ra_list->total_pkts_size += skb->len; ++ ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); ++} ++ ++/* ++ * This function processes the get WMM status command response from firmware. ++ * ++ * The response may contain multiple TLVs - ++ * - AC Queue status TLVs ++ * - Current WMM Parameter IE TLV ++ * - Admission Control action frame TLVs ++ * ++ * This function parses the TLVs and then calls further specific functions ++ * to process any changes in the queue prioritize or state. ++ */ ++int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, ++ const struct host_cmd_ds_command *resp) ++{ ++ u8 *curr = (u8 *) &resp->params.get_wmm_status; ++ uint16_t resp_len = le16_to_cpu(resp->size), tlv_len; ++ int valid = true; ++ ++ struct mwifiex_ie_types_data *tlv_hdr; ++ struct mwifiex_ie_types_wmm_queue_status *tlv_wmm_qstatus; ++ struct ieee_types_wmm_parameter *wmm_param_ie = NULL; ++ struct mwifiex_wmm_ac_status *ac_status; ++ ++ dev_dbg(priv->adapter->dev, "info: WMM: WMM_GET_STATUS cmdresp received: %d\n", ++ resp_len); ++ ++ while ((resp_len >= sizeof(tlv_hdr->header)) && valid) { ++ tlv_hdr = (struct mwifiex_ie_types_data *) curr; ++ tlv_len = le16_to_cpu(tlv_hdr->header.len); ++ ++ switch (le16_to_cpu(tlv_hdr->header.type)) { ++ case TLV_TYPE_WMMQSTATUS: ++ tlv_wmm_qstatus = ++ (struct mwifiex_ie_types_wmm_queue_status *) ++ tlv_hdr; ++ dev_dbg(priv->adapter->dev, ++ "info: CMD_RESP: WMM_GET_STATUS:" ++ " QSTATUS TLV: %d, %d, %d\n", ++ tlv_wmm_qstatus->queue_index, ++ tlv_wmm_qstatus->flow_required, ++ tlv_wmm_qstatus->disabled); ++ ++ ac_status = &priv->wmm.ac_status[tlv_wmm_qstatus-> ++ queue_index]; ++ ac_status->disabled = tlv_wmm_qstatus->disabled; ++ ac_status->flow_required = ++ tlv_wmm_qstatus->flow_required; ++ ac_status->flow_created = tlv_wmm_qstatus->flow_created; ++ break; ++ ++ case WLAN_EID_VENDOR_SPECIFIC: ++ /* ++ * Point the regular IEEE IE 2 bytes into the Marvell IE ++ * and setup the IEEE IE type and length byte fields ++ */ ++ ++ wmm_param_ie = ++ (struct ieee_types_wmm_parameter *) (curr + ++ 2); ++ wmm_param_ie->vend_hdr.len = (u8) tlv_len; ++ wmm_param_ie->vend_hdr.element_id = ++ WLAN_EID_VENDOR_SPECIFIC; ++ ++ dev_dbg(priv->adapter->dev, ++ "info: CMD_RESP: WMM_GET_STATUS:" ++ " WMM Parameter Set Count: %d\n", ++ wmm_param_ie->qos_info_bitmap & ++ IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK); ++ ++ memcpy((u8 *) &priv->curr_bss_params.bss_descriptor. ++ wmm_ie, wmm_param_ie, ++ wmm_param_ie->vend_hdr.len + 2); ++ ++ break; ++ ++ default: ++ valid = false; ++ break; ++ } ++ ++ curr += (tlv_len + sizeof(tlv_hdr->header)); ++ resp_len -= (tlv_len + sizeof(tlv_hdr->header)); ++ } ++ ++ mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie); ++ mwifiex_wmm_setup_ac_downgrade(priv); ++ ++ return 0; ++} ++ ++/* ++ * Callback handler from the command module to allow insertion of a WMM TLV. ++ * ++ * If the BSS we are associating to supports WMM, this function adds the ++ * required WMM Information IE to the association request command buffer in ++ * the form of a Marvell extended IEEE IE. ++ */ ++u32 ++mwifiex_wmm_process_association_req(struct mwifiex_private *priv, ++ u8 **assoc_buf, ++ struct ieee_types_wmm_parameter *wmm_ie, ++ struct ieee80211_ht_cap *ht_cap) ++{ ++ struct mwifiex_ie_types_wmm_param_set *wmm_tlv; ++ u32 ret_len = 0; ++ ++ /* Null checks */ ++ if (!assoc_buf) ++ return 0; ++ if (!(*assoc_buf)) ++ return 0; ++ ++ if (!wmm_ie) ++ return 0; ++ ++ dev_dbg(priv->adapter->dev, "info: WMM: process assoc req:" ++ "bss->wmmIe=0x%x\n", ++ wmm_ie->vend_hdr.element_id); ++ ++ if ((priv->wmm_required ++ || (ht_cap && (priv->adapter->config_bands & BAND_GN ++ || priv->adapter->config_bands & BAND_AN)) ++ ) ++ && wmm_ie->vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) { ++ wmm_tlv = (struct mwifiex_ie_types_wmm_param_set *) *assoc_buf; ++ wmm_tlv->header.type = cpu_to_le16((u16) wmm_info_ie[0]); ++ wmm_tlv->header.len = cpu_to_le16((u16) wmm_info_ie[1]); ++ memcpy(wmm_tlv->wmm_ie, &wmm_info_ie[2], ++ le16_to_cpu(wmm_tlv->header.len)); ++ if (wmm_ie->qos_info_bitmap & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ++ memcpy((u8 *) (wmm_tlv->wmm_ie ++ + le16_to_cpu(wmm_tlv->header.len) ++ - sizeof(priv->wmm_qosinfo)), ++ &priv->wmm_qosinfo, ++ sizeof(priv->wmm_qosinfo)); ++ ++ ret_len = sizeof(wmm_tlv->header) ++ + le16_to_cpu(wmm_tlv->header.len); ++ ++ *assoc_buf += ret_len; ++ } ++ ++ return ret_len; ++} ++ ++/* ++ * This function computes the time delay in the driver queues for a ++ * given packet. ++ * ++ * When the packet is received at the OS/Driver interface, the current ++ * time is set in the packet structure. The difference between the present ++ * time and that received time is computed in this function and limited ++ * based on pre-compiled limits in the driver. ++ */ ++u8 ++mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, ++ const struct sk_buff *skb) ++{ ++ u8 ret_val = 0; ++ struct timeval out_tstamp, in_tstamp; ++ u32 queue_delay; ++ ++ do_gettimeofday(&out_tstamp); ++ in_tstamp = ktime_to_timeval(skb->tstamp); ++ ++ queue_delay = (out_tstamp.tv_sec - in_tstamp.tv_sec) * 1000; ++ queue_delay += (out_tstamp.tv_usec - in_tstamp.tv_usec) / 1000; ++ ++ /* ++ * Queue delay is passed as a uint8 in units of 2ms (ms shifted ++ * by 1). Min value (other than 0) is therefore 2ms, max is 510ms. ++ * ++ * Pass max value if queue_delay is beyond the uint8 range ++ */ ++ ret_val = (u8) (min(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1); ++ ++ dev_dbg(priv->adapter->dev, "data: WMM: Pkt Delay: %d ms," ++ " %d ms sent to FW\n", queue_delay, ret_val); ++ ++ return ret_val; ++} ++ ++/* ++ * This function retrieves the highest priority RA list table pointer. ++ */ ++static struct mwifiex_ra_list_tbl * ++mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, ++ struct mwifiex_private **priv, int *tid) ++{ ++ struct mwifiex_private *priv_tmp; ++ struct mwifiex_ra_list_tbl *ptr, *head; ++ struct mwifiex_bss_prio_node *bssprio_node, *bssprio_head; ++ struct mwifiex_tid_tbl *tid_ptr; ++ int is_list_empty; ++ unsigned long flags; ++ int i, j; ++ ++ for (j = adapter->priv_num - 1; j >= 0; --j) { ++ spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock, ++ flags); ++ is_list_empty = list_empty(&adapter->bss_prio_tbl[j] ++ .bss_prio_head); ++ spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock, ++ flags); ++ if (is_list_empty) ++ continue; ++ ++ if (adapter->bss_prio_tbl[j].bss_prio_cur == ++ (struct mwifiex_bss_prio_node *) ++ &adapter->bss_prio_tbl[j].bss_prio_head) { ++ bssprio_node = ++ list_first_entry(&adapter->bss_prio_tbl[j] ++ .bss_prio_head, ++ struct mwifiex_bss_prio_node, ++ list); ++ bssprio_head = bssprio_node; ++ } else { ++ bssprio_node = adapter->bss_prio_tbl[j].bss_prio_cur; ++ bssprio_head = bssprio_node; ++ } ++ ++ do { ++ priv_tmp = bssprio_node->priv; ++ ++ for (i = HIGH_PRIO_TID; i >= LOW_PRIO_TID; --i) { ++ ++ tid_ptr = &(priv_tmp)->wmm. ++ tid_tbl_ptr[tos_to_tid[i]]; ++ ++ spin_lock_irqsave(&tid_ptr->tid_tbl_lock, ++ flags); ++ is_list_empty = ++ list_empty(&adapter->bss_prio_tbl[j] ++ .bss_prio_head); ++ spin_unlock_irqrestore(&tid_ptr->tid_tbl_lock, ++ flags); ++ if (is_list_empty) ++ continue; ++ ++ /* ++ * Always choose the next ra we transmitted ++ * last time, this way we pick the ra's in ++ * round robin fashion. ++ */ ++ ptr = list_first_entry( ++ &tid_ptr->ra_list_curr->list, ++ struct mwifiex_ra_list_tbl, ++ list); ++ ++ head = ptr; ++ if (ptr == (struct mwifiex_ra_list_tbl *) ++ &tid_ptr->ra_list) { ++ /* Get next ra */ ++ ptr = list_first_entry(&ptr->list, ++ struct mwifiex_ra_list_tbl, list); ++ head = ptr; ++ } ++ ++ do { ++ is_list_empty = ++ skb_queue_empty(&ptr->skb_head); ++ if (!is_list_empty) { ++ *priv = priv_tmp; ++ *tid = tos_to_tid[i]; ++ return ptr; ++ } ++ /* Get next ra */ ++ ptr = list_first_entry(&ptr->list, ++ struct mwifiex_ra_list_tbl, ++ list); ++ if (ptr == ++ (struct mwifiex_ra_list_tbl *) ++ &tid_ptr->ra_list) ++ ptr = list_first_entry( ++ &ptr->list, ++ struct mwifiex_ra_list_tbl, ++ list); ++ } while (ptr != head); ++ } ++ ++ /* Get next bss priority node */ ++ bssprio_node = list_first_entry(&bssprio_node->list, ++ struct mwifiex_bss_prio_node, ++ list); ++ ++ if (bssprio_node == ++ (struct mwifiex_bss_prio_node *) ++ &adapter->bss_prio_tbl[j].bss_prio_head) ++ /* Get next bss priority node */ ++ bssprio_node = list_first_entry( ++ &bssprio_node->list, ++ struct mwifiex_bss_prio_node, ++ list); ++ } while (bssprio_node != bssprio_head); ++ } ++ return NULL; ++} ++ ++/* ++ * This function gets the number of packets in the Tx queue of a ++ * particular RA list. ++ */ ++static int ++mwifiex_num_pkts_in_txq(struct mwifiex_private *priv, ++ struct mwifiex_ra_list_tbl *ptr, int max_buf_size) ++{ ++ int count = 0, total_size = 0; ++ struct sk_buff *skb, *tmp; ++ ++ skb_queue_walk_safe(&ptr->skb_head, skb, tmp) { ++ total_size += skb->len; ++ if (total_size < max_buf_size) ++ ++count; ++ else ++ break; ++ } ++ ++ return count; ++} ++ ++/* ++ * This function sends a single packet to firmware for transmission. ++ */ ++static void ++mwifiex_send_single_packet(struct mwifiex_private *priv, ++ struct mwifiex_ra_list_tbl *ptr, int ptr_index, ++ unsigned long ra_list_flags) ++ __releases(&priv->wmm.ra_list_spinlock) ++{ ++ struct sk_buff *skb, *skb_next; ++ struct mwifiex_tx_param tx_param; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ struct mwifiex_txinfo *tx_info; ++ ++ if (skb_queue_empty(&ptr->skb_head)) { ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ dev_dbg(adapter->dev, "data: nothing to send\n"); ++ return; ++ } ++ ++ skb = skb_dequeue(&ptr->skb_head); ++ ++ tx_info = MWIFIEX_SKB_TXCB(skb); ++ dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb); ++ ++ ptr->total_pkts_size -= skb->len; ++ ++ if (!skb_queue_empty(&ptr->skb_head)) ++ skb_next = skb_peek(&ptr->skb_head); ++ else ++ skb_next = NULL; ++ ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); ++ ++ tx_param.next_pkt_len = ((skb_next) ? skb_next->len + ++ sizeof(struct txpd) : 0); ++ ++ if (mwifiex_process_tx(priv, skb, &tx_param) == -EBUSY) { ++ /* Queue the packet back at the head */ ++ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); ++ ++ if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ mwifiex_write_data_complete(adapter, skb, -1); ++ return; ++ } ++ ++ skb_queue_tail(&ptr->skb_head, skb); ++ ++ ptr->total_pkts_size += skb->len; ++ tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ } else { ++ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); ++ if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { ++ priv->wmm.packets_out[ptr_index]++; ++ priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr; ++ } ++ adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = ++ list_first_entry( ++ &adapter->bss_prio_tbl[priv->bss_priority] ++ .bss_prio_cur->list, ++ struct mwifiex_bss_prio_node, ++ list); ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ } ++} ++ ++/* ++ * This function checks if the first packet in the given RA list ++ * is already processed or not. ++ */ ++static int ++mwifiex_is_ptr_processed(struct mwifiex_private *priv, ++ struct mwifiex_ra_list_tbl *ptr) ++{ ++ struct sk_buff *skb; ++ struct mwifiex_txinfo *tx_info; ++ ++ if (skb_queue_empty(&ptr->skb_head)) ++ return false; ++ ++ skb = skb_peek(&ptr->skb_head); ++ ++ tx_info = MWIFIEX_SKB_TXCB(skb); ++ if (tx_info->flags & MWIFIEX_BUF_FLAG_REQUEUED_PKT) ++ return true; ++ ++ return false; ++} ++ ++/* ++ * This function sends a single processed packet to firmware for ++ * transmission. ++ */ ++static void ++mwifiex_send_processed_packet(struct mwifiex_private *priv, ++ struct mwifiex_ra_list_tbl *ptr, int ptr_index, ++ unsigned long ra_list_flags) ++ __releases(&priv->wmm.ra_list_spinlock) ++{ ++ struct mwifiex_tx_param tx_param; ++ struct mwifiex_adapter *adapter = priv->adapter; ++ int ret = -1; ++ struct sk_buff *skb, *skb_next; ++ struct mwifiex_txinfo *tx_info; ++ ++ if (skb_queue_empty(&ptr->skb_head)) { ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ return; ++ } ++ ++ skb = skb_dequeue(&ptr->skb_head); ++ ++ if (!skb_queue_empty(&ptr->skb_head)) ++ skb_next = skb_peek(&ptr->skb_head); ++ else ++ skb_next = NULL; ++ ++ tx_info = MWIFIEX_SKB_TXCB(skb); ++ ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); ++ tx_param.next_pkt_len = ++ ((skb_next) ? skb_next->len + ++ sizeof(struct txpd) : 0); ++ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, ++ skb->data, skb->len, &tx_param); ++ switch (ret) { ++ case -EBUSY: ++ dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); ++ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); ++ ++ if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ mwifiex_write_data_complete(adapter, skb, -1); ++ return; ++ } ++ ++ skb_queue_tail(&ptr->skb_head, skb); ++ ++ tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ break; ++ case -1: ++ adapter->data_sent = false; ++ dev_err(adapter->dev, "host_to_card failed: %#x\n", ret); ++ adapter->dbg.num_tx_host_to_card_failure++; ++ mwifiex_write_data_complete(adapter, skb, ret); ++ break; ++ case -EINPROGRESS: ++ adapter->data_sent = false; ++ default: ++ break; ++ } ++ if (ret != -EBUSY) { ++ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); ++ if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { ++ priv->wmm.packets_out[ptr_index]++; ++ priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr; ++ } ++ adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = ++ list_first_entry( ++ &adapter->bss_prio_tbl[priv->bss_priority] ++ .bss_prio_cur->list, ++ struct mwifiex_bss_prio_node, ++ list); ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ++ ra_list_flags); ++ } ++} ++ ++/* ++ * This function dequeues a packet from the highest priority list ++ * and transmits it. ++ */ ++static int ++mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) ++{ ++ struct mwifiex_ra_list_tbl *ptr; ++ struct mwifiex_private *priv = NULL; ++ int ptr_index = 0; ++ u8 ra[ETH_ALEN]; ++ int tid_del = 0, tid = 0; ++ unsigned long flags; ++ ++ ptr = mwifiex_wmm_get_highest_priolist_ptr(adapter, &priv, &ptr_index); ++ if (!ptr) ++ return -1; ++ ++ tid = mwifiex_get_tid(ptr); ++ ++ dev_dbg(adapter->dev, "data: tid=%d\n", tid); ++ ++ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); ++ if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { ++ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); ++ return -1; ++ } ++ ++ if (mwifiex_is_ptr_processed(priv, ptr)) { ++ mwifiex_send_processed_packet(priv, ptr, ptr_index, flags); ++ /* ra_list_spinlock has been freed in ++ mwifiex_send_processed_packet() */ ++ return 0; ++ } ++ ++ if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid) ++ || ((priv->sec_info.wpa_enabled ++ || priv->sec_info.wpa2_enabled) && !priv->wpa_is_gtk_set) ++ ) { ++ mwifiex_send_single_packet(priv, ptr, ptr_index, flags); ++ /* ra_list_spinlock has been freed in ++ mwifiex_send_single_packet() */ ++ } else { ++ if (mwifiex_is_ampdu_allowed(priv, tid)) { ++ if (mwifiex_space_avail_for_new_ba_stream(adapter)) { ++ mwifiex_11n_create_tx_ba_stream_tbl(priv, ++ ptr->ra, tid, ++ BA_STREAM_SETUP_INPROGRESS); ++ mwifiex_send_addba(priv, tid, ptr->ra); ++ } else if (mwifiex_find_stream_to_delete ++ (priv, tid, &tid_del, ra)) { ++ mwifiex_11n_create_tx_ba_stream_tbl(priv, ++ ptr->ra, tid, ++ BA_STREAM_SETUP_INPROGRESS); ++ mwifiex_send_delba(priv, tid_del, ra, 1); ++ } ++ } ++/* Minimum number of AMSDU */ ++#define MIN_NUM_AMSDU 2 ++ if (mwifiex_is_amsdu_allowed(priv, tid) && ++ (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >= ++ MIN_NUM_AMSDU)) ++ mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ++ ptr_index, flags); ++ /* ra_list_spinlock has been freed in ++ mwifiex_11n_aggregate_pkt() */ ++ else ++ mwifiex_send_single_packet(priv, ptr, ptr_index, flags); ++ /* ra_list_spinlock has been freed in ++ mwifiex_send_single_packet() */ ++ } ++ return 0; ++} ++ ++/* ++ * This function transmits the highest priority packet awaiting in the ++ * WMM Queues. ++ */ ++void ++mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter) ++{ ++ do { ++ /* Check if busy */ ++ if (adapter->data_sent || adapter->tx_lock_flag) ++ break; ++ ++ if (mwifiex_dequeue_tx_packet(adapter)) ++ break; ++ } while (true); ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwifiex/wmm.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/wmm.h +--- linux-2.6.39-rc6/drivers/net/wireless/mwifiex/wmm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwifiex/wmm.h 2011-05-05 23:29:45.466441635 +0200 +@@ -0,0 +1,110 @@ ++/* ++ * Marvell Wireless LAN device driver: WMM ++ * ++ * Copyright (C) 2011, Marvell International Ltd. ++ * ++ * This software file (the "File") is distributed by Marvell International ++ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 ++ * (the "License"). You may use, redistribute and/or modify this File in ++ * accordance with the terms and conditions of the License, a copy of which ++ * is available by writing to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the ++ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. ++ * ++ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ++ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about ++ * this warranty disclaimer. ++ */ ++ ++#ifndef _MWIFIEX_WMM_H_ ++#define _MWIFIEX_WMM_H_ ++ ++enum ieee_types_wmm_aciaifsn_bitmasks { ++ MWIFIEX_AIFSN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)), ++ MWIFIEX_ACM = BIT(4), ++ MWIFIEX_ACI = (BIT(5) | BIT(6)), ++}; ++ ++enum ieee_types_wmm_ecw_bitmasks { ++ MWIFIEX_ECW_MIN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)), ++ MWIFIEX_ECW_MAX = (BIT(4) | BIT(5) | BIT(6) | BIT(7)), ++}; ++ ++/* ++ * This function retrieves the TID of the given RA list. ++ */ ++static inline int ++mwifiex_get_tid(struct mwifiex_ra_list_tbl *ptr) ++{ ++ struct sk_buff *skb; ++ ++ if (skb_queue_empty(&ptr->skb_head)) ++ return 0; ++ ++ skb = skb_peek(&ptr->skb_head); ++ ++ return skb->priority; ++} ++ ++/* ++ * This function gets the length of a list. ++ */ ++static inline int ++mwifiex_wmm_list_len(struct list_head *head) ++{ ++ struct list_head *pos; ++ int count = 0; ++ ++ list_for_each(pos, head) ++ ++count; ++ ++ return count; ++} ++ ++/* ++ * This function checks if a RA list is empty or not. ++ */ ++static inline u8 ++mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead) ++{ ++ struct mwifiex_ra_list_tbl *ra_list; ++ int is_list_empty; ++ ++ list_for_each_entry(ra_list, ra_list_hhead, list) { ++ is_list_empty = skb_queue_empty(&ra_list->skb_head); ++ if (!is_list_empty) ++ return false; ++ } ++ ++ return true; ++} ++ ++void mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, ++ struct sk_buff *skb); ++void mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra); ++ ++int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter); ++void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter); ++int mwifiex_is_ralist_valid(struct mwifiex_private *priv, ++ struct mwifiex_ra_list_tbl *ra_list, int tid); ++ ++u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, ++ const struct sk_buff *skb); ++void mwifiex_wmm_init(struct mwifiex_adapter *adapter); ++ ++extern u32 mwifiex_wmm_process_association_req(struct mwifiex_private *priv, ++ u8 **assoc_buf, ++ struct ieee_types_wmm_parameter ++ *wmmie, ++ struct ieee80211_ht_cap ++ *htcap); ++ ++void mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, ++ struct ieee_types_wmm_parameter ++ *wmm_ie); ++void mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv); ++extern int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, ++ const struct host_cmd_ds_command *resp); ++ ++#endif /* !_MWIFIEX_WMM_H_ */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/mwl8k.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwl8k.c +--- linux-2.6.39-rc6/drivers/net/wireless/mwl8k.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/mwl8k.c 2011-05-05 23:29:49.217486955 +0200 +@@ -63,6 +63,7 @@ + #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 + #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c + #define MWL8K_A2H_INT_DUMMY (1 << 20) ++#define MWL8K_A2H_INT_BA_WATCHDOG (1 << 14) + #define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) + #define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) + #define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) +@@ -73,6 +74,14 @@ + #define MWL8K_A2H_INT_RX_READY (1 << 1) + #define MWL8K_A2H_INT_TX_DONE (1 << 0) + ++/* HW micro second timer register ++ * located at offset 0xA600. This ++ * will be used to timestamp tx ++ * packets. ++ */ ++ ++#define MWL8K_HW_TIMER_REGISTER 0x0000a600 ++ + #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ + MWL8K_A2H_INT_CHNL_SWITCHED | \ + MWL8K_A2H_INT_QUEUE_EMPTY | \ +@@ -82,10 +91,14 @@ + MWL8K_A2H_INT_MAC_EVENT | \ + MWL8K_A2H_INT_OPC_DONE | \ + MWL8K_A2H_INT_RX_READY | \ +- MWL8K_A2H_INT_TX_DONE) ++ MWL8K_A2H_INT_TX_DONE | \ ++ MWL8K_A2H_INT_BA_WATCHDOG) + + #define MWL8K_RX_QUEUES 1 +-#define MWL8K_TX_QUEUES 4 ++#define MWL8K_TX_WMM_QUEUES 4 ++#define MWL8K_MAX_AMPDU_QUEUES 8 ++#define MWL8K_MAX_TX_QUEUES (MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES) ++#define mwl8k_tx_queues(priv) (MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues) + + struct rxd_ops { + int rxd_size; +@@ -134,6 +147,21 @@ + struct sk_buff **skb; + }; + ++enum { ++ AMPDU_NO_STREAM, ++ AMPDU_STREAM_NEW, ++ AMPDU_STREAM_IN_PROGRESS, ++ AMPDU_STREAM_ACTIVE, ++}; ++ ++struct mwl8k_ampdu_stream { ++ struct ieee80211_sta *sta; ++ u8 tid; ++ u8 state; ++ u8 idx; ++ u8 txq_idx; /* index of this stream in priv->txq */ ++}; ++ + struct mwl8k_priv { + struct ieee80211_hw *hw; + struct pci_dev *pdev; +@@ -160,6 +188,12 @@ + u32 ap_macids_supported; + u32 sta_macids_supported; + ++ /* Ampdu stream information */ ++ u8 num_ampdu_queues; ++ spinlock_t stream_lock; ++ struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES]; ++ struct work_struct watchdog_ba_handle; ++ + /* firmware access */ + struct mutex fw_mutex; + struct task_struct *fw_mutex_owner; +@@ -191,7 +225,8 @@ + int pending_tx_pkts; + + struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; +- struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; ++ struct mwl8k_tx_queue txq[MWL8K_MAX_TX_QUEUES]; ++ u32 txq_offset[MWL8K_MAX_TX_QUEUES]; + + bool radio_on; + bool radio_short_preamble; +@@ -224,7 +259,7 @@ + * preserve the queue configurations so they can be restored if/when + * the firmware image is swapped. + */ +- struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES]; ++ struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_WMM_QUEUES]; + + /* async firmware loading state */ + unsigned fw_state; +@@ -262,9 +297,17 @@ + #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) + #define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) + ++struct tx_traffic_info { ++ u32 start_time; ++ u32 pkts; ++}; ++ ++#define MWL8K_MAX_TID 8 + struct mwl8k_sta { + /* Index into station database. Returned by UPDATE_STADB. */ + u8 peer_id; ++ u8 is_ampdu_allowed; ++ struct tx_traffic_info tx_stats[MWL8K_MAX_TID]; + }; + #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) + +@@ -352,10 +395,12 @@ + #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 + #define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ + #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 ++#define MWL8K_CMD_GET_WATCHDOG_BITMAP 0x0205 + #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ + #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ + #define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ + #define MWL8K_CMD_UPDATE_STADB 0x1123 ++#define MWL8K_CMD_BASTREAM 0x1125 + + static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) + { +@@ -395,6 +440,8 @@ + MWL8K_CMDNAME(SET_NEW_STN); + MWL8K_CMDNAME(UPDATE_ENCRYPTION); + MWL8K_CMDNAME(UPDATE_STADB); ++ MWL8K_CMDNAME(BASTREAM); ++ MWL8K_CMDNAME(GET_WATCHDOG_BITMAP); + default: + snprintf(buf, bufsize, "0x%x", cmd); + } +@@ -669,7 +716,7 @@ + "helper image\n", pci_name(priv->pdev)); + return rc; + } +- msleep(5); ++ msleep(20); + + rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); + } else { +@@ -734,8 +781,10 @@ + skb_pull(skb, sizeof(*tr) - hdrlen); + } + ++#define REDUCED_TX_HEADROOM 8 ++ + static void +-mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) ++mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, int tail_pad) + { + struct ieee80211_hdr *wh; + int hdrlen; +@@ -751,6 +800,22 @@ + wh = (struct ieee80211_hdr *)skb->data; + + hdrlen = ieee80211_hdrlen(wh->frame_control); ++ ++ /* ++ * Check if skb_resize is required because of ++ * tx_headroom adjustment. ++ */ ++ if (priv->ap_fw && (hdrlen < (sizeof(struct ieee80211_cts) ++ + REDUCED_TX_HEADROOM))) { ++ if (pskb_expand_head(skb, REDUCED_TX_HEADROOM, 0, GFP_ATOMIC)) { ++ ++ wiphy_err(priv->hw->wiphy, ++ "Failed to reallocate TX buffer\n"); ++ return; ++ } ++ skb->truesize += REDUCED_TX_HEADROOM; ++ } ++ + reqd_hdrlen = sizeof(*tr); + + if (hdrlen != reqd_hdrlen) +@@ -773,7 +838,8 @@ + tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); + } + +-static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) ++static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, ++ struct sk_buff *skb) + { + struct ieee80211_hdr *wh; + struct ieee80211_tx_info *tx_info; +@@ -791,8 +857,8 @@ + /* + * Make sure the packet header is in the DMA header format (4-address + * without QoS), the necessary crypto padding between the header and the +- * payload has already been provided by mac80211, but it doesn't add tail +- * padding when HW crypto is enabled. ++ * payload has already been provided by mac80211, but it doesn't add ++ * tail padding when HW crypto is enabled. + * + * We have the following trailer padding requirements: + * - WEP: 4 trailer bytes (ICV) +@@ -814,7 +880,7 @@ + break; + } + } +- mwl8k_add_dma_header(skb, data_pad); ++ mwl8k_add_dma_header(priv, skb, data_pad); + } + + /* +@@ -1127,6 +1193,9 @@ + struct mwl8k_rx_queue *rxq = priv->rxq + index; + int i; + ++ if (rxq->rxd == NULL) ++ return; ++ + for (i = 0; i < MWL8K_RX_DESCS; i++) { + if (rxq->buf[i].skb != NULL) { + pci_unmap_single(priv->pdev, +@@ -1319,7 +1388,7 @@ + __le16 pkt_len; + __u8 dest_MAC_addr[ETH_ALEN]; + __le32 next_txd_phys_addr; +- __le32 reserved; ++ __le32 timestamp; + __le16 rate_info; + __u8 peer_id; + __u8 tx_frag_cnt; +@@ -1383,7 +1452,7 @@ + struct mwl8k_priv *priv = hw->priv; + int i; + +- for (i = 0; i < MWL8K_TX_QUEUES; i++) { ++ for (i = 0; i < mwl8k_tx_queues(priv); i++) { + struct mwl8k_tx_queue *txq = priv->txq + i; + int fw_owned = 0; + int drv_owned = 0; +@@ -1452,9 +1521,8 @@ + + if (timeout) { + WARN_ON(priv->pending_tx_pkts); +- if (retry) { ++ if (retry) + wiphy_notice(hw->wiphy, "tx rings drained\n"); +- } + break; + } + +@@ -1484,6 +1552,41 @@ + MWL8K_TXD_STATUS_OK_RETRY | \ + MWL8K_TXD_STATUS_OK_MORE_RETRY)) + ++static int mwl8k_tid_queue_mapping(u8 tid) ++{ ++ BUG_ON(tid > 7); ++ ++ switch (tid) { ++ case 0: ++ case 3: ++ return IEEE80211_AC_BE; ++ break; ++ case 1: ++ case 2: ++ return IEEE80211_AC_BK; ++ break; ++ case 4: ++ case 5: ++ return IEEE80211_AC_VI; ++ break; ++ case 6: ++ case 7: ++ return IEEE80211_AC_VO; ++ break; ++ default: ++ return -1; ++ break; ++ } ++} ++ ++/* The firmware will fill in the rate information ++ * for each packet that gets queued in the hardware ++ * and these macros will interpret that info. ++ */ ++ ++#define RI_FORMAT(a) (a & 0x0001) ++#define RI_RATE_ID_MCS(a) ((a & 0x01f8) >> 3) ++ + static int + mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) + { +@@ -1500,6 +1603,10 @@ + struct sk_buff *skb; + struct ieee80211_tx_info *info; + u32 status; ++ struct ieee80211_sta *sta; ++ struct mwl8k_sta *sta_info = NULL; ++ u16 rate_info; ++ struct ieee80211_hdr *wh; + + tx = txq->head; + tx_desc = txq->txd + tx; +@@ -1528,18 +1635,40 @@ + + mwl8k_remove_dma_header(skb, tx_desc->qos_control); + ++ wh = (struct ieee80211_hdr *) skb->data; ++ + /* Mark descriptor as unused */ + tx_desc->pkt_phys_addr = 0; + tx_desc->pkt_len = 0; + + info = IEEE80211_SKB_CB(skb); ++ if (ieee80211_is_data(wh->frame_control)) { ++ sta = info->control.sta; ++ if (sta) { ++ sta_info = MWL8K_STA(sta); ++ BUG_ON(sta_info == NULL); ++ rate_info = le16_to_cpu(tx_desc->rate_info); ++ /* If rate is < 6.5 Mpbs for an ht station ++ * do not form an ampdu. If the station is a ++ * legacy station (format = 0), do not form an ++ * ampdu ++ */ ++ if (RI_RATE_ID_MCS(rate_info) < 1 || ++ RI_FORMAT(rate_info) == 0) { ++ sta_info->is_ampdu_allowed = false; ++ } else { ++ sta_info->is_ampdu_allowed = true; ++ } ++ } ++ } ++ + ieee80211_tx_info_clear_status(info); + + /* Rate control is happening in the firmware. + * Ensure no tx rate is being reported. + */ +- info->status.rates[0].idx = -1; +- info->status.rates[0].count = 1; ++ info->status.rates[0].idx = -1; ++ info->status.rates[0].count = 1; + + if (MWL8K_TXD_SUCCESS(status)) + info->flags |= IEEE80211_TX_STAT_ACK; +@@ -1549,9 +1678,6 @@ + processed++; + } + +- if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) +- ieee80211_wake_queue(hw, index); +- + return processed; + } + +@@ -1561,6 +1687,9 @@ + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_tx_queue *txq = priv->txq + index; + ++ if (txq->txd == NULL) ++ return; ++ + mwl8k_txq_reclaim(hw, index, INT_MAX, 1); + + kfree(txq->skb); +@@ -1572,12 +1701,116 @@ + txq->txd = NULL; + } + ++/* caller must hold priv->stream_lock when calling the stream functions */ ++static struct mwl8k_ampdu_stream * ++mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) ++{ ++ struct mwl8k_ampdu_stream *stream; ++ struct mwl8k_priv *priv = hw->priv; ++ int i; ++ ++ for (i = 0; i < priv->num_ampdu_queues; i++) { ++ stream = &priv->ampdu[i]; ++ if (stream->state == AMPDU_NO_STREAM) { ++ stream->sta = sta; ++ stream->state = AMPDU_STREAM_NEW; ++ stream->tid = tid; ++ stream->idx = i; ++ stream->txq_idx = MWL8K_TX_WMM_QUEUES + i; ++ wiphy_debug(hw->wiphy, "Added a new stream for %pM %d", ++ sta->addr, tid); ++ return stream; ++ } ++ } ++ return NULL; ++} ++ ++static int ++mwl8k_start_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) ++{ ++ int ret; ++ ++ /* if the stream has already been started, don't start it again */ ++ if (stream->state != AMPDU_STREAM_NEW) ++ return 0; ++ ret = ieee80211_start_tx_ba_session(stream->sta, stream->tid, 0); ++ if (ret) ++ wiphy_debug(hw->wiphy, "Failed to start stream for %pM %d: " ++ "%d\n", stream->sta->addr, stream->tid, ret); ++ else ++ wiphy_debug(hw->wiphy, "Started stream for %pM %d\n", ++ stream->sta->addr, stream->tid); ++ return ret; ++} ++ ++static void ++mwl8k_remove_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) ++{ ++ wiphy_debug(hw->wiphy, "Remove stream for %pM %d\n", stream->sta->addr, ++ stream->tid); ++ memset(stream, 0, sizeof(*stream)); ++} ++ ++static struct mwl8k_ampdu_stream * ++mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid) ++{ ++ struct mwl8k_priv *priv = hw->priv; ++ int i; ++ ++ for (i = 0 ; i < priv->num_ampdu_queues; i++) { ++ struct mwl8k_ampdu_stream *stream; ++ stream = &priv->ampdu[i]; ++ if (stream->state == AMPDU_NO_STREAM) ++ continue; ++ if (!memcmp(stream->sta->addr, addr, ETH_ALEN) && ++ stream->tid == tid) ++ return stream; ++ } ++ return NULL; ++} ++ ++#define MWL8K_AMPDU_PACKET_THRESHOLD 64 ++static inline bool mwl8k_ampdu_allowed(struct ieee80211_sta *sta, u8 tid) ++{ ++ struct mwl8k_sta *sta_info = MWL8K_STA(sta); ++ struct tx_traffic_info *tx_stats; ++ ++ BUG_ON(tid >= MWL8K_MAX_TID); ++ tx_stats = &sta_info->tx_stats[tid]; ++ ++ return sta_info->is_ampdu_allowed && ++ tx_stats->pkts > MWL8K_AMPDU_PACKET_THRESHOLD; ++} ++ ++static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid) ++{ ++ struct mwl8k_sta *sta_info = MWL8K_STA(sta); ++ struct tx_traffic_info *tx_stats; ++ ++ BUG_ON(tid >= MWL8K_MAX_TID); ++ tx_stats = &sta_info->tx_stats[tid]; ++ ++ if (tx_stats->start_time == 0) ++ tx_stats->start_time = jiffies; ++ ++ /* reset the packet count after each second elapses. If the number of ++ * packets ever exceeds the ampdu_min_traffic threshold, we will allow ++ * an ampdu stream to be started. ++ */ ++ if (jiffies - tx_stats->start_time > HZ) { ++ tx_stats->pkts = 0; ++ tx_stats->start_time = 0; ++ } else ++ tx_stats->pkts++; ++} ++ + static void + mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) + { + struct mwl8k_priv *priv = hw->priv; + struct ieee80211_tx_info *tx_info; + struct mwl8k_vif *mwl8k_vif; ++ struct ieee80211_sta *sta; + struct ieee80211_hdr *wh; + struct mwl8k_tx_queue *txq; + struct mwl8k_tx_desc *tx; +@@ -1585,6 +1818,12 @@ + u32 txstatus; + u8 txdatarate; + u16 qos; ++ int txpriority; ++ u8 tid = 0; ++ struct mwl8k_ampdu_stream *stream = NULL; ++ bool start_ba_session = false; ++ bool mgmtframe = false; ++ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + + wh = (struct ieee80211_hdr *)skb->data; + if (ieee80211_is_data_qos(wh->frame_control)) +@@ -1592,14 +1831,18 @@ + else + qos = 0; + ++ if (ieee80211_is_mgmt(wh->frame_control)) ++ mgmtframe = true; ++ + if (priv->ap_fw) +- mwl8k_encapsulate_tx_frame(skb); ++ mwl8k_encapsulate_tx_frame(priv, skb); + else +- mwl8k_add_dma_header(skb, 0); ++ mwl8k_add_dma_header(priv, skb, 0); + + wh = &((struct mwl8k_dma_data *)skb->data)->wh; + + tx_info = IEEE80211_SKB_CB(skb); ++ sta = tx_info->control.sta; + mwl8k_vif = MWL8K_VIF(tx_info->control.vif); + + if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { +@@ -1627,12 +1870,91 @@ + qos |= MWL8K_QOS_ACK_POLICY_NORMAL; + } + ++ /* Queue ADDBA request in the respective data queue. While setting up ++ * the ampdu stream, mac80211 queues further packets for that ++ * particular ra/tid pair. However, packets piled up in the hardware ++ * for that ra/tid pair will still go out. ADDBA request and the ++ * related data packets going out from different queues asynchronously ++ * will cause a shift in the receiver window which might result in ++ * ampdu packets getting dropped at the receiver after the stream has ++ * been setup. ++ */ ++ if (unlikely(ieee80211_is_action(wh->frame_control) && ++ mgmt->u.action.category == WLAN_CATEGORY_BACK && ++ mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ && ++ priv->ap_fw)) { ++ u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); ++ tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; ++ index = mwl8k_tid_queue_mapping(tid); ++ } ++ ++ txpriority = index; ++ ++ if (ieee80211_is_data_qos(wh->frame_control) && ++ skb->protocol != cpu_to_be16(ETH_P_PAE) && ++ sta->ht_cap.ht_supported && priv->ap_fw) { ++ tid = qos & 0xf; ++ mwl8k_tx_count_packet(sta, tid); ++ spin_lock(&priv->stream_lock); ++ stream = mwl8k_lookup_stream(hw, sta->addr, tid); ++ if (stream != NULL) { ++ if (stream->state == AMPDU_STREAM_ACTIVE) { ++ txpriority = stream->txq_idx; ++ index = stream->txq_idx; ++ } else if (stream->state == AMPDU_STREAM_NEW) { ++ /* We get here if the driver sends us packets ++ * after we've initiated a stream, but before ++ * our ampdu_action routine has been called ++ * with IEEE80211_AMPDU_TX_START to get the SSN ++ * for the ADDBA request. So this packet can ++ * go out with no risk of sequence number ++ * mismatch. No special handling is required. ++ */ ++ } else { ++ /* Drop packets that would go out after the ++ * ADDBA request was sent but before the ADDBA ++ * response is received. If we don't do this, ++ * the recipient would probably receive it ++ * after the ADDBA request with SSN 0. This ++ * will cause the recipient's BA receive window ++ * to shift, which would cause the subsequent ++ * packets in the BA stream to be discarded. ++ * mac80211 queues our packets for us in this ++ * case, so this is really just a safety check. ++ */ ++ wiphy_warn(hw->wiphy, ++ "Cannot send packet while ADDBA " ++ "dialog is underway.\n"); ++ spin_unlock(&priv->stream_lock); ++ dev_kfree_skb(skb); ++ return; ++ } ++ } else { ++ /* Defer calling mwl8k_start_stream so that the current ++ * skb can go out before the ADDBA request. This ++ * prevents sequence number mismatch at the recepient ++ * as described above. ++ */ ++ if (mwl8k_ampdu_allowed(sta, tid)) { ++ stream = mwl8k_add_stream(hw, sta, tid); ++ if (stream != NULL) ++ start_ba_session = true; ++ } ++ } ++ spin_unlock(&priv->stream_lock); ++ } ++ + dma = pci_map_single(priv->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + + if (pci_dma_mapping_error(priv->pdev, dma)) { + wiphy_debug(hw->wiphy, + "failed to dma map skb, dropping TX frame.\n"); ++ if (start_ba_session) { ++ spin_lock(&priv->stream_lock); ++ mwl8k_remove_stream(hw, stream); ++ spin_unlock(&priv->stream_lock); ++ } + dev_kfree_skb(skb); + return; + } +@@ -1641,12 +1963,34 @@ + + txq = priv->txq + index; + ++ /* Mgmt frames that go out frequently are probe ++ * responses. Other mgmt frames got out relatively ++ * infrequently. Hence reserve 2 buffers so that ++ * other mgmt frames do not get dropped due to an ++ * already queued probe response in one of the ++ * reserved buffers. ++ */ ++ ++ if (txq->len >= MWL8K_TX_DESCS - 2) { ++ if (mgmtframe == false || ++ txq->len == MWL8K_TX_DESCS) { ++ if (start_ba_session) { ++ spin_lock(&priv->stream_lock); ++ mwl8k_remove_stream(hw, stream); ++ spin_unlock(&priv->stream_lock); ++ } ++ spin_unlock_bh(&priv->tx_lock); ++ dev_kfree_skb(skb); ++ return; ++ } ++ } ++ + BUG_ON(txq->skb[txq->tail] != NULL); + txq->skb[txq->tail] = skb; + + tx = txq->txd + txq->tail; + tx->data_rate = txdatarate; +- tx->tx_priority = index; ++ tx->tx_priority = txpriority; + tx->qos_control = cpu_to_le16(qos); + tx->pkt_phys_addr = cpu_to_le32(dma); + tx->pkt_len = cpu_to_le16(skb->len); +@@ -1655,6 +1999,11 @@ + tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; + else + tx->peer_id = 0; ++ ++ if (priv->ap_fw) ++ tx->timestamp = cpu_to_le32(ioread32(priv->regs + ++ MWL8K_HW_TIMER_REGISTER)); ++ + wmb(); + tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); + +@@ -1665,12 +2014,17 @@ + if (txq->tail == MWL8K_TX_DESCS) + txq->tail = 0; + +- if (txq->head == txq->tail) +- ieee80211_stop_queue(hw, index); +- + mwl8k_tx_start(priv); + + spin_unlock_bh(&priv->tx_lock); ++ ++ /* Initiate the ampdu session here */ ++ if (start_ba_session) { ++ spin_lock(&priv->stream_lock); ++ if (mwl8k_start_stream(hw, stream)) ++ mwl8k_remove_stream(hw, stream); ++ spin_unlock(&priv->stream_lock); ++ } + } + + +@@ -1868,7 +2222,7 @@ + __u8 mcs_bitmap[16]; + __le32 rx_queue_ptr; + __le32 num_tx_queues; +- __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; ++ __le32 tx_queue_ptrs[MWL8K_TX_WMM_QUEUES]; + __le32 caps2; + __le32 num_tx_desc_per_queue; + __le32 total_rxd; +@@ -1974,8 +2328,8 @@ + memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); + cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); + cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); +- cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); +- for (i = 0; i < MWL8K_TX_QUEUES; i++) ++ cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); ++ for (i = 0; i < mwl8k_tx_queues(priv); i++) + cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); + cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); + cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); +@@ -2017,13 +2371,16 @@ + __le32 wcbbase2; + __le32 wcbbase3; + __le32 fw_api_version; ++ __le32 caps; ++ __le32 num_of_ampdu_queues; ++ __le32 wcbbase_ampdu[MWL8K_MAX_AMPDU_QUEUES]; + } __packed; + + static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) + { + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_cmd_get_hw_spec_ap *cmd; +- int rc; ++ int rc, i; + u32 api_version; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); +@@ -2055,27 +2412,31 @@ + priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); + priv->fw_rev = le32_to_cpu(cmd->fw_rev); + priv->hw_rev = cmd->hw_rev; +- mwl8k_setup_2ghz_band(hw); ++ mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); + priv->ap_macids_supported = 0x000000ff; + priv->sta_macids_supported = 0x00000000; +- +- off = le32_to_cpu(cmd->wcbbase0) & 0xffff; +- iowrite32(priv->txq[0].txd_dma, priv->sram + off); +- ++ priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); ++ if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { ++ wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" ++ " but we only support %d.\n", ++ priv->num_ampdu_queues, ++ MWL8K_MAX_AMPDU_QUEUES); ++ priv->num_ampdu_queues = MWL8K_MAX_AMPDU_QUEUES; ++ } + off = le32_to_cpu(cmd->rxwrptr) & 0xffff; + iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); + + off = le32_to_cpu(cmd->rxrdptr) & 0xffff; + iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); + +- off = le32_to_cpu(cmd->wcbbase1) & 0xffff; +- iowrite32(priv->txq[1].txd_dma, priv->sram + off); +- +- off = le32_to_cpu(cmd->wcbbase2) & 0xffff; +- iowrite32(priv->txq[2].txd_dma, priv->sram + off); +- +- off = le32_to_cpu(cmd->wcbbase3) & 0xffff; +- iowrite32(priv->txq[3].txd_dma, priv->sram + off); ++ priv->txq_offset[0] = le32_to_cpu(cmd->wcbbase0) & 0xffff; ++ priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff; ++ priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff; ++ priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff; ++ ++ for (i = 0; i < priv->num_ampdu_queues; i++) ++ priv->txq_offset[i + MWL8K_TX_WMM_QUEUES] = ++ le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff; + } + + done: +@@ -2098,12 +2459,20 @@ + __le32 caps; + __le32 rx_queue_ptr; + __le32 num_tx_queues; +- __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; ++ __le32 tx_queue_ptrs[MWL8K_MAX_TX_QUEUES]; + __le32 flags; + __le32 num_tx_desc_per_queue; + __le32 total_rxd; + } __packed; + ++/* If enabled, MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY will cause ++ * packets to expire 500 ms after the timestamp in the tx descriptor. That is, ++ * the packets that are queued for more than 500ms, will be dropped in the ++ * hardware. This helps minimizing the issues caused due to head-of-line ++ * blocking where a slow client can hog the bandwidth and affect traffic to a ++ * faster client. ++ */ ++#define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400 + #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 + #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 + #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 +@@ -2124,7 +2493,7 @@ + + cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); + cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); +- cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); ++ cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); + + /* + * Mac80211 stack has Q0 as highest priority and Q3 as lowest in +@@ -2132,14 +2501,15 @@ + * in that order. Map Q3 of mac80211 to Q0 of firmware so that the + * priority is interpreted the right way in firmware. + */ +- for (i = 0; i < MWL8K_TX_QUEUES; i++) { +- int j = MWL8K_TX_QUEUES - 1 - i; ++ for (i = 0; i < mwl8k_tx_queues(priv); i++) { ++ int j = mwl8k_tx_queues(priv) - 1 - i; + cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma); + } + + cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | + MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | +- MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON); ++ MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON | ++ MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY); + cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); + cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); + +@@ -2356,7 +2726,7 @@ + __le16 bw; + __le16 sub_ch; + __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; +-} __attribute__((packed)); ++} __packed; + + static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, + struct ieee80211_conf *conf, +@@ -3123,6 +3493,65 @@ + } + + /* ++ * CMD_GET_WATCHDOG_BITMAP. ++ */ ++struct mwl8k_cmd_get_watchdog_bitmap { ++ struct mwl8k_cmd_pkt header; ++ u8 bitmap; ++} __packed; ++ ++static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap) ++{ ++ struct mwl8k_cmd_get_watchdog_bitmap *cmd; ++ int rc; ++ ++ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); ++ if (cmd == NULL) ++ return -ENOMEM; ++ ++ cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_WATCHDOG_BITMAP); ++ cmd->header.length = cpu_to_le16(sizeof(*cmd)); ++ ++ rc = mwl8k_post_cmd(hw, &cmd->header); ++ if (!rc) ++ *bitmap = cmd->bitmap; ++ ++ kfree(cmd); ++ ++ return rc; ++} ++ ++#define INVALID_BA 0xAA ++static void mwl8k_watchdog_ba_events(struct work_struct *work) ++{ ++ int rc; ++ u8 bitmap = 0, stream_index; ++ struct mwl8k_ampdu_stream *streams; ++ struct mwl8k_priv *priv = ++ container_of(work, struct mwl8k_priv, watchdog_ba_handle); ++ ++ rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap); ++ if (rc) ++ return; ++ ++ if (bitmap == INVALID_BA) ++ return; ++ ++ /* the bitmap is the hw queue number. Map it to the ampdu queue. */ ++ stream_index = bitmap - MWL8K_TX_WMM_QUEUES; ++ ++ BUG_ON(stream_index >= priv->num_ampdu_queues); ++ ++ streams = &priv->ampdu[stream_index]; ++ ++ if (streams->state == AMPDU_STREAM_ACTIVE) ++ ieee80211_stop_tx_ba_session(streams->sta, streams->tid); ++ ++ return; ++} ++ ++ ++/* + * CMD_BSS_START. + */ + struct mwl8k_cmd_bss_start { +@@ -3151,6 +3580,152 @@ + } + + /* ++ * CMD_BASTREAM. ++ */ ++ ++/* ++ * UPSTREAM is tx direction ++ */ ++#define BASTREAM_FLAG_DIRECTION_UPSTREAM 0x00 ++#define BASTREAM_FLAG_IMMEDIATE_TYPE 0x01 ++ ++enum ba_stream_action_type { ++ MWL8K_BA_CREATE, ++ MWL8K_BA_UPDATE, ++ MWL8K_BA_DESTROY, ++ MWL8K_BA_FLUSH, ++ MWL8K_BA_CHECK, ++}; ++ ++ ++struct mwl8k_create_ba_stream { ++ __le32 flags; ++ __le32 idle_thrs; ++ __le32 bar_thrs; ++ __le32 window_size; ++ u8 peer_mac_addr[6]; ++ u8 dialog_token; ++ u8 tid; ++ u8 queue_id; ++ u8 param_info; ++ __le32 ba_context; ++ u8 reset_seq_no_flag; ++ __le16 curr_seq_no; ++ u8 sta_src_mac_addr[6]; ++} __packed; ++ ++struct mwl8k_destroy_ba_stream { ++ __le32 flags; ++ __le32 ba_context; ++} __packed; ++ ++struct mwl8k_cmd_bastream { ++ struct mwl8k_cmd_pkt header; ++ __le32 action; ++ union { ++ struct mwl8k_create_ba_stream create_params; ++ struct mwl8k_destroy_ba_stream destroy_params; ++ }; ++} __packed; ++ ++static int ++mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) ++{ ++ struct mwl8k_cmd_bastream *cmd; ++ int rc; ++ ++ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); ++ if (cmd == NULL) ++ return -ENOMEM; ++ ++ cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); ++ cmd->header.length = cpu_to_le16(sizeof(*cmd)); ++ ++ cmd->action = cpu_to_le32(MWL8K_BA_CHECK); ++ ++ cmd->create_params.queue_id = stream->idx; ++ memcpy(&cmd->create_params.peer_mac_addr[0], stream->sta->addr, ++ ETH_ALEN); ++ cmd->create_params.tid = stream->tid; ++ ++ cmd->create_params.flags = ++ cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) | ++ cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM); ++ ++ rc = mwl8k_post_cmd(hw, &cmd->header); ++ ++ kfree(cmd); ++ ++ return rc; ++} ++ ++static int ++mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, ++ u8 buf_size) ++{ ++ struct mwl8k_cmd_bastream *cmd; ++ int rc; ++ ++ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); ++ if (cmd == NULL) ++ return -ENOMEM; ++ ++ ++ cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); ++ cmd->header.length = cpu_to_le16(sizeof(*cmd)); ++ ++ cmd->action = cpu_to_le32(MWL8K_BA_CREATE); ++ ++ cmd->create_params.bar_thrs = cpu_to_le32((u32)buf_size); ++ cmd->create_params.window_size = cpu_to_le32((u32)buf_size); ++ cmd->create_params.queue_id = stream->idx; ++ ++ memcpy(cmd->create_params.peer_mac_addr, stream->sta->addr, ETH_ALEN); ++ cmd->create_params.tid = stream->tid; ++ cmd->create_params.curr_seq_no = cpu_to_le16(0); ++ cmd->create_params.reset_seq_no_flag = 1; ++ ++ cmd->create_params.param_info = ++ (stream->sta->ht_cap.ampdu_factor & ++ IEEE80211_HT_AMPDU_PARM_FACTOR) | ++ ((stream->sta->ht_cap.ampdu_density << 2) & ++ IEEE80211_HT_AMPDU_PARM_DENSITY); ++ ++ cmd->create_params.flags = ++ cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE | ++ BASTREAM_FLAG_DIRECTION_UPSTREAM); ++ ++ rc = mwl8k_post_cmd(hw, &cmd->header); ++ ++ wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n", ++ stream->sta->addr, stream->tid); ++ kfree(cmd); ++ ++ return rc; ++} ++ ++static void mwl8k_destroy_ba(struct ieee80211_hw *hw, ++ struct mwl8k_ampdu_stream *stream) ++{ ++ struct mwl8k_cmd_bastream *cmd; ++ ++ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); ++ if (cmd == NULL) ++ return; ++ ++ cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); ++ cmd->header.length = cpu_to_le16(sizeof(*cmd)); ++ cmd->action = cpu_to_le32(MWL8K_BA_DESTROY); ++ ++ cmd->destroy_params.ba_context = cpu_to_le32(stream->idx); ++ mwl8k_post_cmd(hw, &cmd->header); ++ ++ wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx); ++ ++ kfree(cmd); ++} ++ ++/* + * CMD_SET_NEW_STN. + */ + struct mwl8k_cmd_set_new_stn { +@@ -3274,7 +3849,7 @@ + __u8 mac_addr[6]; + __u8 encr_type; + +-} __attribute__((packed)); ++} __packed; + + struct mwl8k_cmd_set_key { + struct mwl8k_cmd_pkt header; +@@ -3294,7 +3869,7 @@ + __le16 tkip_tsc_low; + __le32 tkip_tsc_high; + __u8 mac_addr[6]; +-} __attribute__((packed)); ++} __packed; + + enum { + MWL8K_ENCR_ENABLE, +@@ -3671,6 +4246,11 @@ + tasklet_schedule(&priv->poll_rx_task); + } + ++ if (status & MWL8K_A2H_INT_BA_WATCHDOG) { ++ status &= ~MWL8K_A2H_INT_BA_WATCHDOG; ++ ieee80211_queue_work(hw, &priv->watchdog_ba_handle); ++ } ++ + if (status) + iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); + +@@ -3699,7 +4279,7 @@ + + spin_lock_bh(&priv->tx_lock); + +- for (i = 0; i < MWL8K_TX_QUEUES; i++) ++ for (i = 0; i < mwl8k_tx_queues(priv); i++) + limit -= mwl8k_txq_reclaim(hw, i, limit, 0); + + if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { +@@ -3774,6 +4354,8 @@ + + /* Enable interrupts */ + iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); ++ iowrite32(MWL8K_A2H_EVENTS, ++ priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); + + rc = mwl8k_fw_lock(hw); + if (!rc) { +@@ -3829,6 +4411,7 @@ + + /* Stop finalize join worker */ + cancel_work_sync(&priv->finalize_join_worker); ++ cancel_work_sync(&priv->watchdog_ba_handle); + if (priv->beacon_skb != NULL) + dev_kfree_skb(priv->beacon_skb); + +@@ -3837,7 +4420,7 @@ + tasklet_disable(&priv->poll_rx_task); + + /* Return all skbs to mac80211 */ +- for (i = 0; i < MWL8K_TX_QUEUES; i++) ++ for (i = 0; i < mwl8k_tx_queues(priv); i++) + mwl8k_txq_reclaim(hw, i, INT_MAX, 1); + } + +@@ -3958,9 +4541,12 @@ + conf->power_level = 18; + + if (priv->ap_fw) { +- rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); +- if (rc) +- goto out; ++ ++ if (conf->flags & IEEE80211_CONF_CHANGE_POWER) { ++ rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); ++ if (rc) ++ goto out; ++ } + + rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); + if (rc) +@@ -3987,7 +4573,7 @@ + struct ieee80211_bss_conf *info, u32 changed) + { + struct mwl8k_priv *priv = hw->priv; +- u32 ap_legacy_rates; ++ u32 ap_legacy_rates = 0; + u8 ap_mcs_rates[16]; + int rc; + +@@ -4312,6 +4898,8 @@ + ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); + if (ret >= 0) { + MWL8K_STA(sta)->peer_id = ret; ++ if (sta->ht_cap.ht_supported) ++ MWL8K_STA(sta)->is_ampdu_allowed = true; + ret = 0; + } + +@@ -4335,14 +4923,14 @@ + + rc = mwl8k_fw_lock(hw); + if (!rc) { +- BUG_ON(queue > MWL8K_TX_QUEUES - 1); ++ BUG_ON(queue > MWL8K_TX_WMM_QUEUES - 1); + memcpy(&priv->wmm_params[queue], params, sizeof(*params)); + + if (!priv->wmm_enabled) + rc = mwl8k_cmd_set_wmm_mode(hw, 1); + + if (!rc) { +- int q = MWL8K_TX_QUEUES - 1 - queue; ++ int q = MWL8K_TX_WMM_QUEUES - 1 - queue; + rc = mwl8k_cmd_set_edca_params(hw, q, + params->cw_min, + params->cw_max, +@@ -4378,21 +4966,118 @@ + return 0; + } + ++#define MAX_AMPDU_ATTEMPTS 5 ++ + static int + mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) + { ++ ++ int i, rc = 0; ++ struct mwl8k_priv *priv = hw->priv; ++ struct mwl8k_ampdu_stream *stream; ++ u8 *addr = sta->addr; ++ ++ if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) ++ return -ENOTSUPP; ++ ++ spin_lock(&priv->stream_lock); ++ stream = mwl8k_lookup_stream(hw, addr, tid); ++ + switch (action) { + case IEEE80211_AMPDU_RX_START: + case IEEE80211_AMPDU_RX_STOP: +- if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) +- return -ENOTSUPP; +- return 0; ++ break; ++ case IEEE80211_AMPDU_TX_START: ++ /* By the time we get here the hw queues may contain outgoing ++ * packets for this RA/TID that are not part of this BA ++ * session. The hw will assign sequence numbers to these ++ * packets as they go out. So if we query the hw for its next ++ * sequence number and use that for the SSN here, it may end up ++ * being wrong, which will lead to sequence number mismatch at ++ * the recipient. To avoid this, we reset the sequence number ++ * to O for the first MPDU in this BA stream. ++ */ ++ *ssn = 0; ++ if (stream == NULL) { ++ /* This means that somebody outside this driver called ++ * ieee80211_start_tx_ba_session. This is unexpected ++ * because we do our own rate control. Just warn and ++ * move on. ++ */ ++ wiphy_warn(hw->wiphy, "Unexpected call to %s. " ++ "Proceeding anyway.\n", __func__); ++ stream = mwl8k_add_stream(hw, sta, tid); ++ } ++ if (stream == NULL) { ++ wiphy_debug(hw->wiphy, "no free AMPDU streams\n"); ++ rc = -EBUSY; ++ break; ++ } ++ stream->state = AMPDU_STREAM_IN_PROGRESS; ++ ++ /* Release the lock before we do the time consuming stuff */ ++ spin_unlock(&priv->stream_lock); ++ for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) { ++ rc = mwl8k_check_ba(hw, stream); ++ ++ if (!rc) ++ break; ++ /* ++ * HW queues take time to be flushed, give them ++ * sufficient time ++ */ ++ ++ msleep(1000); ++ } ++ spin_lock(&priv->stream_lock); ++ if (rc) { ++ wiphy_err(hw->wiphy, "Stream for tid %d busy after %d" ++ " attempts\n", tid, MAX_AMPDU_ATTEMPTS); ++ mwl8k_remove_stream(hw, stream); ++ rc = -EBUSY; ++ break; ++ } ++ ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); ++ break; ++ case IEEE80211_AMPDU_TX_STOP: ++ if (stream == NULL) ++ break; ++ if (stream->state == AMPDU_STREAM_ACTIVE) { ++ spin_unlock(&priv->stream_lock); ++ mwl8k_destroy_ba(hw, stream); ++ spin_lock(&priv->stream_lock); ++ } ++ mwl8k_remove_stream(hw, stream); ++ ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); ++ break; ++ case IEEE80211_AMPDU_TX_OPERATIONAL: ++ BUG_ON(stream == NULL); ++ BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS); ++ spin_unlock(&priv->stream_lock); ++ rc = mwl8k_create_ba(hw, stream, buf_size); ++ spin_lock(&priv->stream_lock); ++ if (!rc) ++ stream->state = AMPDU_STREAM_ACTIVE; ++ else { ++ spin_unlock(&priv->stream_lock); ++ mwl8k_destroy_ba(hw, stream); ++ spin_lock(&priv->stream_lock); ++ wiphy_debug(hw->wiphy, ++ "Failed adding stream for sta %pM tid %d\n", ++ addr, tid); ++ mwl8k_remove_stream(hw, stream); ++ } ++ break; ++ + default: +- return -ENOTSUPP; ++ rc = -ENOTSUPP; + } ++ ++ spin_unlock(&priv->stream_lock); ++ return rc; + } + + static const struct ieee80211_ops mwl8k_ops = { +@@ -4441,7 +5126,7 @@ + MWL8366, + }; + +-#define MWL8K_8366_AP_FW_API 1 ++#define MWL8K_8366_AP_FW_API 2 + #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" + #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) + +@@ -4607,6 +5292,23 @@ + return rc; + } + ++static int mwl8k_init_txqs(struct ieee80211_hw *hw) ++{ ++ struct mwl8k_priv *priv = hw->priv; ++ int rc = 0; ++ int i; ++ ++ for (i = 0; i < mwl8k_tx_queues(priv); i++) { ++ rc = mwl8k_txq_init(hw, i); ++ if (rc) ++ break; ++ if (priv->ap_fw) ++ iowrite32(priv->txq[i].txd_dma, ++ priv->sram + priv->txq_offset[i]); ++ } ++ return rc; ++} ++ + /* initialize hw after successfully loading a firmware image */ + static int mwl8k_probe_hw(struct ieee80211_hw *hw) + { +@@ -4634,17 +5336,26 @@ + goto err_stop_firmware; + rxq_refill(hw, 0, INT_MAX); + +- for (i = 0; i < MWL8K_TX_QUEUES; i++) { +- rc = mwl8k_txq_init(hw, i); ++ /* For the sta firmware, we need to know the dma addresses of tx queues ++ * before sending MWL8K_CMD_GET_HW_SPEC. So we must initialize them ++ * prior to issuing this command. But for the AP case, we learn the ++ * total number of queues from the result CMD_GET_HW_SPEC, so for this ++ * case we must initialize the tx queues after. ++ */ ++ priv->num_ampdu_queues = 0; ++ if (!priv->ap_fw) { ++ rc = mwl8k_init_txqs(hw); + if (rc) + goto err_free_queues; + } + + iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); + iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); +- iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, ++ iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY| ++ MWL8K_A2H_INT_BA_WATCHDOG, + priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); +- iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); ++ iowrite32(MWL8K_A2H_INT_OPC_DONE, ++ priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); + + rc = request_irq(priv->pdev->irq, mwl8k_interrupt, + IRQF_SHARED, MWL8K_NAME, hw); +@@ -4653,6 +5364,8 @@ + goto err_free_queues; + } + ++ memset(priv->ampdu, 0, sizeof(priv->ampdu)); ++ + /* + * Temporarily enable interrupts. Initial firmware host + * commands use interrupts and avoid polling. Disable +@@ -4664,6 +5377,8 @@ + if (priv->ap_fw) { + rc = mwl8k_cmd_get_hw_spec_ap(hw); + if (!rc) ++ rc = mwl8k_init_txqs(hw); ++ if (!rc) + rc = mwl8k_cmd_set_hw_spec(hw); + } else { + rc = mwl8k_cmd_get_hw_spec_sta(hw); +@@ -4705,7 +5420,7 @@ + free_irq(priv->pdev->irq, hw); + + err_free_queues: +- for (i = 0; i < MWL8K_TX_QUEUES; i++) ++ for (i = 0; i < mwl8k_tx_queues(priv); i++) + mwl8k_txq_deinit(hw, i); + mwl8k_rxq_deinit(hw, 0); + +@@ -4727,7 +5442,7 @@ + mwl8k_stop(hw); + mwl8k_rxq_deinit(hw, 0); + +- for (i = 0; i < MWL8K_TX_QUEUES; i++) ++ for (i = 0; i < mwl8k_tx_queues(priv); i++) + mwl8k_txq_deinit(hw, i); + + rc = mwl8k_init_firmware(hw, fw_image, false); +@@ -4746,7 +5461,7 @@ + if (rc) + goto fail; + +- for (i = 0; i < MWL8K_TX_QUEUES; i++) { ++ for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { + rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); + if (rc) + goto fail; +@@ -4778,9 +5493,11 @@ + hw->extra_tx_headroom = + sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); + ++ hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0; ++ + hw->channel_change_time = 10; + +- hw->queues = MWL8K_TX_QUEUES; ++ hw->queues = MWL8K_TX_WMM_QUEUES; + + /* Set rssi values to dBm */ + hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; +@@ -4796,6 +5513,8 @@ + + /* Finalize join worker */ + INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); ++ /* Handle watchdog ba events */ ++ INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events); + + /* TX reclaim and RX tasklets. */ + tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); +@@ -4815,6 +5534,8 @@ + + spin_lock_init(&priv->tx_lock); + ++ spin_lock_init(&priv->stream_lock); ++ + priv->tx_wait = NULL; + + rc = mwl8k_probe_hw(hw); +@@ -4836,7 +5557,7 @@ + return 0; + + err_unprobe_hw: +- for (i = 0; i < MWL8K_TX_QUEUES; i++) ++ for (i = 0; i < mwl8k_tx_queues(priv); i++) + mwl8k_txq_deinit(hw, i); + mwl8k_rxq_deinit(hw, 0); + +@@ -4995,10 +5716,10 @@ + mwl8k_hw_reset(priv); + + /* Return all skbs to mac80211 */ +- for (i = 0; i < MWL8K_TX_QUEUES; i++) ++ for (i = 0; i < mwl8k_tx_queues(priv); i++) + mwl8k_txq_reclaim(hw, i, INT_MAX, 1); + +- for (i = 0; i < MWL8K_TX_QUEUES; i++) ++ for (i = 0; i < mwl8k_tx_queues(priv); i++) + mwl8k_txq_deinit(hw, i); + + mwl8k_rxq_deinit(hw, 0); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/p54/eeprom.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/p54/eeprom.c +--- linux-2.6.39-rc6/drivers/net/wireless/p54/eeprom.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/p54/eeprom.c 2011-05-05 23:29:45.614443423 +0200 +@@ -491,7 +491,7 @@ + struct pda_rssi_cal_entry *cal = (void *) &data[offset]; + + for (i = 0; i < entries; i++) { +- u16 freq; ++ u16 freq = 0; + switch (i) { + case IEEE80211_BAND_2GHZ: + freq = 2437; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/p54/fwio.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/p54/fwio.c +--- linux-2.6.39-rc6/drivers/net/wireless/p54/fwio.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/p54/fwio.c 2011-05-05 23:29:45.605443315 +0200 +@@ -727,3 +727,34 @@ + p54_tx(priv, skb); + return 0; + } ++ ++int p54_set_groupfilter(struct p54_common *priv) ++{ ++ struct p54_group_address_table *grp; ++ struct sk_buff *skb; ++ bool on = false; ++ ++ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*grp), ++ P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE, GFP_KERNEL); ++ if (!skb) ++ return -ENOMEM; ++ ++ grp = (struct p54_group_address_table *)skb_put(skb, sizeof(*grp)); ++ ++ on = !(priv->filter_flags & FIF_ALLMULTI) && ++ (priv->mc_maclist_num > 0 && ++ priv->mc_maclist_num <= MC_FILTER_ADDRESS_NUM); ++ ++ if (on) { ++ grp->filter_enable = cpu_to_le16(1); ++ grp->num_address = cpu_to_le16(priv->mc_maclist_num); ++ memcpy(grp->mac_list, priv->mc_maclist, sizeof(grp->mac_list)); ++ } else { ++ grp->filter_enable = cpu_to_le16(0); ++ grp->num_address = cpu_to_le16(0); ++ memset(grp->mac_list, 0, sizeof(grp->mac_list)); ++ } ++ ++ p54_tx(priv, skb); ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/p54/lmac.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/p54/lmac.h +--- linux-2.6.39-rc6/drivers/net/wireless/p54/lmac.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/p54/lmac.h 2011-05-05 23:29:45.617443459 +0200 +@@ -540,6 +540,7 @@ + int p54_setup_mac(struct p54_common *priv); + int p54_set_ps(struct p54_common *priv); + int p54_fetch_statistics(struct p54_common *priv); ++int p54_set_groupfilter(struct p54_common *priv); + + /* e/v DCF setup */ + int p54_set_edcf(struct p54_common *priv); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/p54/main.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/p54/main.c +--- linux-2.6.39-rc6/drivers/net/wireless/p54/main.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/p54/main.c 2011-05-05 23:29:45.619443483 +0200 +@@ -308,6 +308,31 @@ + return ret; + } + ++static u64 p54_prepare_multicast(struct ieee80211_hw *dev, ++ struct netdev_hw_addr_list *mc_list) ++{ ++ struct p54_common *priv = dev->priv; ++ struct netdev_hw_addr *ha; ++ int i; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(priv->mc_maclist) != ++ ARRAY_SIZE(((struct p54_group_address_table *)NULL)->mac_list)); ++ /* ++ * The first entry is reserved for the global broadcast MAC. ++ * Otherwise the firmware will drop it and ARP will no longer work. ++ */ ++ i = 1; ++ priv->mc_maclist_num = netdev_hw_addr_list_count(mc_list) + i; ++ netdev_hw_addr_list_for_each(ha, mc_list) { ++ memcpy(&priv->mc_maclist[i], ha->addr, ETH_ALEN); ++ i++; ++ if (i >= ARRAY_SIZE(priv->mc_maclist)) ++ break; ++ } ++ ++ return 1; /* update */ ++} ++ + static void p54_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, +@@ -316,12 +341,16 @@ + struct p54_common *priv = dev->priv; + + *total_flags &= FIF_PROMISC_IN_BSS | ++ FIF_ALLMULTI | + FIF_OTHER_BSS; + + priv->filter_flags = *total_flags; + + if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) + p54_setup_mac(priv); ++ ++ if (changed_flags & FIF_ALLMULTI || multicast) ++ p54_set_groupfilter(priv); + } + + static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, +@@ -591,6 +620,7 @@ + .config = p54_config, + .flush = p54_flush, + .bss_info_changed = p54_bss_info_changed, ++ .prepare_multicast = p54_prepare_multicast, + .configure_filter = p54_configure_filter, + .conf_tx = p54_conf_tx, + .get_stats = p54_get_stats, +@@ -660,6 +690,7 @@ + init_completion(&priv->beacon_comp); + INIT_DELAYED_WORK(&priv->work, p54_work); + ++ memset(&priv->mc_maclist[0], ~0, ETH_ALEN); + return dev; + } + EXPORT_SYMBOL_GPL(p54_init_common); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/p54/p54.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/p54/p54.h +--- linux-2.6.39-rc6/drivers/net/wireless/p54/p54.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/p54/p54.h 2011-05-05 23:29:45.619443483 +0200 +@@ -211,8 +211,10 @@ + /* BBP/MAC state */ + u8 mac_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; ++ u8 mc_maclist[4][ETH_ALEN]; + u16 wakeup_timer; + unsigned int filter_flags; ++ int mc_maclist_num; + int mode; + u32 tsf_low32, tsf_high32; + u32 basic_rate_mask; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/Kconfig linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/Kconfig +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/Kconfig 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/Kconfig 2011-05-05 23:29:46.104449343 +0200 +@@ -59,7 +59,6 @@ + select RT2800_LIB + select RT2X00_LIB_PCI if PCI + select RT2X00_LIB_SOC if RALINK_RT288X || RALINK_RT305X +- select RT2X00_LIB_HT + select RT2X00_LIB_FIRMWARE + select RT2X00_LIB_CRYPTO + select CRC_CCITT +@@ -74,17 +73,13 @@ + if RT2800PCI + + config RT2800PCI_RT33XX +- bool "rt2800pci - Include support for rt33xx devices (EXPERIMENTAL)" +- depends on EXPERIMENTAL +- default n ++ bool "rt2800pci - Include support for rt33xx devices" ++ default y + ---help--- + This adds support for rt33xx wireless chipset family to the + rt2800pci driver. + Supported chips: RT3390 + +- Support for these devices is non-functional at the moment and is +- intended for testers and developers. +- + config RT2800PCI_RT35XX + bool "rt2800pci - Include support for rt35xx devices (EXPERIMENTAL)" + depends on EXPERIMENTAL +@@ -100,15 +95,12 @@ + config RT2800PCI_RT53XX + bool "rt2800-pci - Include support for rt53xx devices (EXPERIMENTAL)" + depends on EXPERIMENTAL +- default n ++ default y + ---help--- + This adds support for rt53xx wireless chipset family to the + rt2800pci driver. + Supported chips: RT5390 + +- Support for these devices is non-functional at the moment and is +- intended for testers and developers. +- + endif + + config RT2500USB +@@ -140,7 +132,6 @@ + depends on USB + select RT2800_LIB + select RT2X00_LIB_USB +- select RT2X00_LIB_HT + select RT2X00_LIB_FIRMWARE + select RT2X00_LIB_CRYPTO + select CRC_CCITT +@@ -153,17 +144,13 @@ + if RT2800USB + + config RT2800USB_RT33XX +- bool "rt2800usb - Include support for rt33xx devices (EXPERIMENTAL)" +- depends on EXPERIMENTAL +- default n ++ bool "rt2800usb - Include support for rt33xx devices" ++ default y + ---help--- + This adds support for rt33xx wireless chipset family to the + rt2800usb driver. + Supported chips: RT3370 + +- Support for these devices is non-functional at the moment and is +- intended for testers and developers. +- + config RT2800USB_RT35XX + bool "rt2800usb - Include support for rt35xx devices (EXPERIMENTAL)" + depends on EXPERIMENTAL +@@ -207,9 +194,6 @@ + config RT2X00_LIB + tristate + +-config RT2X00_LIB_HT +- boolean +- + config RT2X00_LIB_FIRMWARE + boolean + select FW_LOADER +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/Makefile linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/Makefile +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/Makefile 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/Makefile 2011-05-05 23:29:46.071448945 +0200 +@@ -7,7 +7,6 @@ + rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o + rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o + rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o +-rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o + + obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o + obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2400pci.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2400pci.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2400pci.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2400pci.c 2011-05-05 23:29:46.105449355 +0200 +@@ -1314,8 +1314,8 @@ + } + } + +-static void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, +- struct rt2x00_field32 irq_field) ++static inline void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, ++ struct rt2x00_field32 irq_field) + { + u32 reg; + +@@ -1368,8 +1368,10 @@ + static void rt2400pci_rxdone_tasklet(unsigned long data) + { + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; +- rt2x00pci_rxdone(rt2x00dev); +- rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); ++ if (rt2x00pci_rxdone(rt2x00dev)) ++ tasklet_schedule(&rt2x00dev->rxdone_tasklet); ++ else ++ rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); + } + + static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) +@@ -1534,13 +1536,13 @@ + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) +- __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); + + /* + * Check if the BBP tuning should be enabled. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING)) +- __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); + + return 0; + } +@@ -1638,9 +1640,9 @@ + /* + * This device requires the atim queue and DMA-mapped skbs. + */ +- __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); ++ __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); + + /* + * Set the rssi offset. +@@ -1718,6 +1720,9 @@ + .tx_last_beacon = rt2400pci_tx_last_beacon, + .rfkill_poll = rt2x00mac_rfkill_poll, + .flush = rt2x00mac_flush, ++ .set_antenna = rt2x00mac_set_antenna, ++ .get_antenna = rt2x00mac_get_antenna, ++ .get_ringparam = rt2x00mac_get_ringparam, + }; + + static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { +@@ -1738,6 +1743,7 @@ + .start_queue = rt2400pci_start_queue, + .kick_queue = rt2400pci_kick_queue, + .stop_queue = rt2400pci_stop_queue, ++ .flush_queue = rt2x00pci_flush_queue, + .write_tx_desc = rt2400pci_write_tx_desc, + .write_beacon = rt2400pci_write_beacon, + .fill_rxdone = rt2400pci_fill_rxdone, +@@ -1799,10 +1805,11 @@ + * RT2400pci module information. + */ + static DEFINE_PCI_DEVICE_TABLE(rt2400pci_device_table) = { +- { PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) }, ++ { PCI_DEVICE(0x1814, 0x0101) }, + { 0, } + }; + ++ + MODULE_AUTHOR(DRV_PROJECT); + MODULE_VERSION(DRV_VERSION); + MODULE_DESCRIPTION("Ralink RT2400 PCI & PCMCIA Wireless LAN driver."); +@@ -1810,10 +1817,16 @@ + MODULE_DEVICE_TABLE(pci, rt2400pci_device_table); + MODULE_LICENSE("GPL"); + ++static int rt2400pci_probe(struct pci_dev *pci_dev, ++ const struct pci_device_id *id) ++{ ++ return rt2x00pci_probe(pci_dev, &rt2400pci_ops); ++} ++ + static struct pci_driver rt2400pci_driver = { + .name = KBUILD_MODNAME, + .id_table = rt2400pci_device_table, +- .probe = rt2x00pci_probe, ++ .probe = rt2400pci_probe, + .remove = __devexit_p(rt2x00pci_remove), + .suspend = rt2x00pci_suspend, + .resume = rt2x00pci_resume, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2500pci.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2500pci.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2500pci.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2500pci.c 2011-05-05 23:29:46.070448933 +0200 +@@ -1446,8 +1446,8 @@ + } + } + +-static void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, +- struct rt2x00_field32 irq_field) ++static inline void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, ++ struct rt2x00_field32 irq_field) + { + u32 reg; + +@@ -1500,8 +1500,10 @@ + static void rt2500pci_rxdone_tasklet(unsigned long data) + { + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; +- rt2x00pci_rxdone(rt2x00dev); +- rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); ++ if (rt2x00pci_rxdone(rt2x00dev)) ++ tasklet_schedule(&rt2x00dev->rxdone_tasklet); ++ else ++ rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); + } + + static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) +@@ -1685,14 +1687,14 @@ + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) +- __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); + + /* + * Check if the BBP tuning should be enabled. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + if (!rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE)) +- __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); + + /* + * Read the RSSI <-> dBm offset information. +@@ -1956,9 +1958,9 @@ + /* + * This device requires the atim queue and DMA-mapped skbs. + */ +- __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); ++ __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); + + /* + * Set the rssi offset. +@@ -2011,6 +2013,9 @@ + .tx_last_beacon = rt2500pci_tx_last_beacon, + .rfkill_poll = rt2x00mac_rfkill_poll, + .flush = rt2x00mac_flush, ++ .set_antenna = rt2x00mac_set_antenna, ++ .get_antenna = rt2x00mac_get_antenna, ++ .get_ringparam = rt2x00mac_get_ringparam, + }; + + static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { +@@ -2031,6 +2036,7 @@ + .start_queue = rt2500pci_start_queue, + .kick_queue = rt2500pci_kick_queue, + .stop_queue = rt2500pci_stop_queue, ++ .flush_queue = rt2x00pci_flush_queue, + .write_tx_desc = rt2500pci_write_tx_desc, + .write_beacon = rt2500pci_write_beacon, + .fill_rxdone = rt2500pci_fill_rxdone, +@@ -2092,7 +2098,7 @@ + * RT2500pci module information. + */ + static DEFINE_PCI_DEVICE_TABLE(rt2500pci_device_table) = { +- { PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) }, ++ { PCI_DEVICE(0x1814, 0x0201) }, + { 0, } + }; + +@@ -2103,10 +2109,16 @@ + MODULE_DEVICE_TABLE(pci, rt2500pci_device_table); + MODULE_LICENSE("GPL"); + ++static int rt2500pci_probe(struct pci_dev *pci_dev, ++ const struct pci_device_id *id) ++{ ++ return rt2x00pci_probe(pci_dev, &rt2500pci_ops); ++} ++ + static struct pci_driver rt2500pci_driver = { + .name = KBUILD_MODNAME, + .id_table = rt2500pci_device_table, +- .probe = rt2x00pci_probe, ++ .probe = rt2500pci_probe, + .remove = __devexit_p(rt2x00pci_remove), + .suspend = rt2x00pci_suspend, + .resume = rt2x00pci_resume, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2500usb.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2500usb.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2500usb.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2500usb.c 2011-05-05 23:29:46.087449138 +0200 +@@ -1519,7 +1519,7 @@ + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) +- __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); + + /* + * Read the RSSI <-> dBm offset information. +@@ -1790,14 +1790,14 @@ + /* + * This device requires the atim queue + */ +- __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); ++ __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags); + if (!modparam_nohwcrypt) { +- __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_COPY_IV, &rt2x00dev->cap_flags); + } +- __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); ++ __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); + + /* + * Set the rssi offset. +@@ -1824,6 +1824,9 @@ + .conf_tx = rt2x00mac_conf_tx, + .rfkill_poll = rt2x00mac_rfkill_poll, + .flush = rt2x00mac_flush, ++ .set_antenna = rt2x00mac_set_antenna, ++ .get_antenna = rt2x00mac_get_antenna, ++ .get_ringparam = rt2x00mac_get_ringparam, + }; + + static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { +@@ -1905,58 +1908,54 @@ + */ + static struct usb_device_id rt2500usb_device_table[] = { + /* ASUS */ +- { USB_DEVICE(0x0b05, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x0b05, 0x1707), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x0b05, 0x1706) }, ++ { USB_DEVICE(0x0b05, 0x1707) }, + /* Belkin */ +- { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x050d, 0x7050) }, ++ { USB_DEVICE(0x050d, 0x7051) }, + /* Cisco Systems */ +- { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) }, +- /* CNet */ +- { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x13b1, 0x000d) }, ++ { USB_DEVICE(0x13b1, 0x0011) }, ++ { USB_DEVICE(0x13b1, 0x001a) }, + /* Conceptronic */ +- { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x14b2, 0x3c02) }, + /* D-LINK */ +- { USB_DEVICE(0x2001, 0x3c00), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x2001, 0x3c00) }, + /* Gigabyte */ +- { USB_DEVICE(0x1044, 0x8001), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x1044, 0x8007), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x1044, 0x8001) }, ++ { USB_DEVICE(0x1044, 0x8007) }, + /* Hercules */ +- { USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x06f8, 0xe000) }, + /* Melco */ +- { USB_DEVICE(0x0411, 0x005e), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x0411, 0x005e) }, ++ { USB_DEVICE(0x0411, 0x0066) }, ++ { USB_DEVICE(0x0411, 0x0067) }, ++ { USB_DEVICE(0x0411, 0x008b) }, ++ { USB_DEVICE(0x0411, 0x0097) }, + /* MSI */ +- { USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x0db0, 0x6869), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x0db0, 0x6861) }, ++ { USB_DEVICE(0x0db0, 0x6865) }, ++ { USB_DEVICE(0x0db0, 0x6869) }, + /* Ralink */ +- { USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) }, +- { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x148f, 0x1706) }, ++ { USB_DEVICE(0x148f, 0x2570) }, ++ { USB_DEVICE(0x148f, 0x9020) }, + /* Sagem */ +- { USB_DEVICE(0x079b, 0x004b), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x079b, 0x004b) }, + /* Siemens */ +- { USB_DEVICE(0x0681, 0x3c06), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x0681, 0x3c06) }, + /* SMC */ +- { USB_DEVICE(0x0707, 0xee13), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x0707, 0xee13) }, + /* Spairon */ +- { USB_DEVICE(0x114b, 0x0110), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x114b, 0x0110) }, + /* SURECOM */ +- { USB_DEVICE(0x0769, 0x11f3), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x0769, 0x11f3) }, + /* Trust */ +- { USB_DEVICE(0x0eb0, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x0eb0, 0x9020) }, + /* VTech */ +- { USB_DEVICE(0x0f88, 0x3012), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x0f88, 0x3012) }, + /* Zinwell */ +- { USB_DEVICE(0x5a57, 0x0260), USB_DEVICE_DATA(&rt2500usb_ops) }, ++ { USB_DEVICE(0x5a57, 0x0260) }, + { 0, } + }; + +@@ -1967,10 +1966,16 @@ + MODULE_DEVICE_TABLE(usb, rt2500usb_device_table); + MODULE_LICENSE("GPL"); + ++static int rt2500usb_probe(struct usb_interface *usb_intf, ++ const struct usb_device_id *id) ++{ ++ return rt2x00usb_probe(usb_intf, &rt2500usb_ops); ++} ++ + static struct usb_driver rt2500usb_driver = { + .name = KBUILD_MODNAME, + .id_table = rt2500usb_device_table, +- .probe = rt2x00usb_probe, ++ .probe = rt2500usb_probe, + .disconnect = rt2x00usb_disconnect, + .suspend = rt2x00usb_suspend, + .resume = rt2x00usb_resume, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2800.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2800.h +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2800.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2800.h 2011-05-05 23:29:46.082449077 +0200 +@@ -2104,6 +2104,59 @@ + #define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) + + /* ++ * EEPROM temperature compensation boundaries 802.11BG ++ * MINUS4: If the actual TSSI is below this boundary, tx power needs to be ++ * reduced by (agc_step * -4) ++ * MINUS3: If the actual TSSI is below this boundary, tx power needs to be ++ * reduced by (agc_step * -3) ++ */ ++#define EEPROM_TSSI_BOUND_BG1 0x0037 ++#define EEPROM_TSSI_BOUND_BG1_MINUS4 FIELD16(0x00ff) ++#define EEPROM_TSSI_BOUND_BG1_MINUS3 FIELD16(0xff00) ++ ++/* ++ * EEPROM temperature compensation boundaries 802.11BG ++ * MINUS2: If the actual TSSI is below this boundary, tx power needs to be ++ * reduced by (agc_step * -2) ++ * MINUS1: If the actual TSSI is below this boundary, tx power needs to be ++ * reduced by (agc_step * -1) ++ */ ++#define EEPROM_TSSI_BOUND_BG2 0x0038 ++#define EEPROM_TSSI_BOUND_BG2_MINUS2 FIELD16(0x00ff) ++#define EEPROM_TSSI_BOUND_BG2_MINUS1 FIELD16(0xff00) ++ ++/* ++ * EEPROM temperature compensation boundaries 802.11BG ++ * REF: Reference TSSI value, no tx power changes needed ++ * PLUS1: If the actual TSSI is above this boundary, tx power needs to be ++ * increased by (agc_step * 1) ++ */ ++#define EEPROM_TSSI_BOUND_BG3 0x0039 ++#define EEPROM_TSSI_BOUND_BG3_REF FIELD16(0x00ff) ++#define EEPROM_TSSI_BOUND_BG3_PLUS1 FIELD16(0xff00) ++ ++/* ++ * EEPROM temperature compensation boundaries 802.11BG ++ * PLUS2: If the actual TSSI is above this boundary, tx power needs to be ++ * increased by (agc_step * 2) ++ * PLUS3: If the actual TSSI is above this boundary, tx power needs to be ++ * increased by (agc_step * 3) ++ */ ++#define EEPROM_TSSI_BOUND_BG4 0x003a ++#define EEPROM_TSSI_BOUND_BG4_PLUS2 FIELD16(0x00ff) ++#define EEPROM_TSSI_BOUND_BG4_PLUS3 FIELD16(0xff00) ++ ++/* ++ * EEPROM temperature compensation boundaries 802.11BG ++ * PLUS4: If the actual TSSI is above this boundary, tx power needs to be ++ * increased by (agc_step * 4) ++ * AGC_STEP: Temperature compensation step. ++ */ ++#define EEPROM_TSSI_BOUND_BG5 0x003b ++#define EEPROM_TSSI_BOUND_BG5_PLUS4 FIELD16(0x00ff) ++#define EEPROM_TSSI_BOUND_BG5_AGC_STEP FIELD16(0xff00) ++ ++/* + * EEPROM TXPOWER 802.11A + */ + #define EEPROM_TXPOWER_A1 0x003c +@@ -2113,6 +2166,59 @@ + #define EEPROM_TXPOWER_A_2 FIELD16(0xff00) + + /* ++ * EEPROM temperature compensation boundaries 802.11A ++ * MINUS4: If the actual TSSI is below this boundary, tx power needs to be ++ * reduced by (agc_step * -4) ++ * MINUS3: If the actual TSSI is below this boundary, tx power needs to be ++ * reduced by (agc_step * -3) ++ */ ++#define EEPROM_TSSI_BOUND_A1 0x006a ++#define EEPROM_TSSI_BOUND_A1_MINUS4 FIELD16(0x00ff) ++#define EEPROM_TSSI_BOUND_A1_MINUS3 FIELD16(0xff00) ++ ++/* ++ * EEPROM temperature compensation boundaries 802.11A ++ * MINUS2: If the actual TSSI is below this boundary, tx power needs to be ++ * reduced by (agc_step * -2) ++ * MINUS1: If the actual TSSI is below this boundary, tx power needs to be ++ * reduced by (agc_step * -1) ++ */ ++#define EEPROM_TSSI_BOUND_A2 0x006b ++#define EEPROM_TSSI_BOUND_A2_MINUS2 FIELD16(0x00ff) ++#define EEPROM_TSSI_BOUND_A2_MINUS1 FIELD16(0xff00) ++ ++/* ++ * EEPROM temperature compensation boundaries 802.11A ++ * REF: Reference TSSI value, no tx power changes needed ++ * PLUS1: If the actual TSSI is above this boundary, tx power needs to be ++ * increased by (agc_step * 1) ++ */ ++#define EEPROM_TSSI_BOUND_A3 0x006c ++#define EEPROM_TSSI_BOUND_A3_REF FIELD16(0x00ff) ++#define EEPROM_TSSI_BOUND_A3_PLUS1 FIELD16(0xff00) ++ ++/* ++ * EEPROM temperature compensation boundaries 802.11A ++ * PLUS2: If the actual TSSI is above this boundary, tx power needs to be ++ * increased by (agc_step * 2) ++ * PLUS3: If the actual TSSI is above this boundary, tx power needs to be ++ * increased by (agc_step * 3) ++ */ ++#define EEPROM_TSSI_BOUND_A4 0x006d ++#define EEPROM_TSSI_BOUND_A4_PLUS2 FIELD16(0x00ff) ++#define EEPROM_TSSI_BOUND_A4_PLUS3 FIELD16(0xff00) ++ ++/* ++ * EEPROM temperature compensation boundaries 802.11A ++ * PLUS4: If the actual TSSI is above this boundary, tx power needs to be ++ * increased by (agc_step * 4) ++ * AGC_STEP: Temperature compensation step. ++ */ ++#define EEPROM_TSSI_BOUND_A5 0x006e ++#define EEPROM_TSSI_BOUND_A5_PLUS4 FIELD16(0x00ff) ++#define EEPROM_TSSI_BOUND_A5_AGC_STEP FIELD16(0xff00) ++ ++/* + * EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode + */ + #define EEPROM_TXPOWER_BYRATE 0x006f +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2800lib.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2800lib.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2800lib.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2800lib.c 2011-05-05 23:29:46.076449005 +0200 +@@ -687,6 +687,9 @@ + mcs = real_mcs; + } + ++ if (aggr == 1 || ampdu == 1) ++ __set_bit(TXDONE_AMPDU, &txdesc.flags); ++ + /* + * Ralink has a retry mechanism using a global fallback + * table. We setup this fallback table to try the immediate +@@ -727,34 +730,20 @@ + struct data_queue *queue; + struct queue_entry *entry; + u32 reg; +- u8 pid; +- int i; ++ u8 qid; + +- /* +- * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO +- * at most X times and also stop processing once the TX_STA_FIFO_VALID +- * flag is not set anymore. +- * +- * The legacy drivers use X=TX_RING_SIZE but state in a comment +- * that the TX_STA_FIFO stack has a size of 16. We stick to our +- * tx ring size for now. +- */ +- for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) { +- rt2800_register_read(rt2x00dev, TX_STA_FIFO, ®); +- if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID)) +- break; ++ while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { + +- /* +- * Skip this entry when it contains an invalid +- * queue identication number. ++ /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus ++ * qid is guaranteed to be one of the TX QIDs + */ +- pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); +- if (pid >= QID_RX) +- continue; +- +- queue = rt2x00queue_get_tx_queue(rt2x00dev, pid); +- if (unlikely(!queue)) ++ qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); ++ queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); ++ if (unlikely(!queue)) { ++ WARNING(rt2x00dev, "Got TX status for an unavailable " ++ "queue %u, dropping\n", qid); + continue; ++ } + + /* + * Inside each queue, we process each entry in a chronological +@@ -946,25 +935,49 @@ + unsigned int ledmode = + rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, + EEPROM_FREQ_LED_MODE); ++ u32 reg; ++ ++ /* Check for SoC (SOC devices don't support MCU requests) */ ++ if (rt2x00_is_soc(led->rt2x00dev)) { ++ rt2800_register_read(led->rt2x00dev, LED_CFG, ®); ++ ++ /* Set LED Polarity */ ++ rt2x00_set_field32(®, LED_CFG_LED_POLAR, polarity); ++ ++ /* Set LED Mode */ ++ if (led->type == LED_TYPE_RADIO) { ++ rt2x00_set_field32(®, LED_CFG_G_LED_MODE, ++ enabled ? 3 : 0); ++ } else if (led->type == LED_TYPE_ASSOC) { ++ rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, ++ enabled ? 3 : 0); ++ } else if (led->type == LED_TYPE_QUALITY) { ++ rt2x00_set_field32(®, LED_CFG_R_LED_MODE, ++ enabled ? 3 : 0); ++ } ++ ++ rt2800_register_write(led->rt2x00dev, LED_CFG, reg); + +- if (led->type == LED_TYPE_RADIO) { +- rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, +- enabled ? 0x20 : 0); +- } else if (led->type == LED_TYPE_ASSOC) { +- rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, +- enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); +- } else if (led->type == LED_TYPE_QUALITY) { +- /* +- * The brightness is divided into 6 levels (0 - 5), +- * The specs tell us the following levels: +- * 0, 1 ,3, 7, 15, 31 +- * to determine the level in a simple way we can simply +- * work with bitshifting: +- * (1 << level) - 1 +- */ +- rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, +- (1 << brightness / (LED_FULL / 6)) - 1, +- polarity); ++ } else { ++ if (led->type == LED_TYPE_RADIO) { ++ rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, ++ enabled ? 0x20 : 0); ++ } else if (led->type == LED_TYPE_ASSOC) { ++ rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, ++ enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); ++ } else if (led->type == LED_TYPE_QUALITY) { ++ /* ++ * The brightness is divided into 6 levels (0 - 5), ++ * The specs tell us the following levels: ++ * 0, 1 ,3, 7, 15, 31 ++ * to determine the level in a simple way we can simply ++ * work with bitshifting: ++ * (1 << level) - 1 ++ */ ++ rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, ++ (1 << brightness / (LED_FULL / 6)) - 1, ++ polarity); ++ } + } + } + +@@ -1218,6 +1231,25 @@ + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); ++ ++ if (conf->sync == TSF_SYNC_AP_NONE) { ++ /* ++ * Tune beacon queue transmit parameters for AP mode ++ */ ++ rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, ®); ++ rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 0); ++ rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 1); ++ rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32); ++ rt2x00_set_field32(®, TBTT_SYNC_CFG_TBTT_ADJUST, 0); ++ rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg); ++ } else { ++ rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, ®); ++ rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 4); ++ rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 2); ++ rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32); ++ rt2x00_set_field32(®, TBTT_SYNC_CFG_TBTT_ADJUST, 16); ++ rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg); ++ } + } + + if (flags & CONFIG_UPDATE_MAC) { +@@ -1608,7 +1640,6 @@ + struct channel_info *info) + { + u8 rfcsr; +- u16 eeprom; + + rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); + rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); +@@ -1638,11 +1669,10 @@ + rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); + rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); + +- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + if (rf->channel <= 14) { + int idx = rf->channel-1; + +- if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) { ++ if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) { + /* r55/r59 value array of channel 1~14 */ + static const char r55_bt_rev[] = {0x83, 0x83, +@@ -1736,8 +1766,8 @@ + + if (rf->channel <= 14) { + if (!rt2x00_rt(rt2x00dev, RT5390)) { +- if (test_bit(CONFIG_EXTERNAL_LNA_BG, +- &rt2x00dev->flags)) { ++ if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, ++ &rt2x00dev->cap_flags)) { + rt2800_bbp_write(rt2x00dev, 82, 0x62); + rt2800_bbp_write(rt2x00dev, 75, 0x46); + } else { +@@ -1748,7 +1778,7 @@ + } else { + rt2800_bbp_write(rt2x00dev, 82, 0xf2); + +- if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) ++ if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) + rt2800_bbp_write(rt2x00dev, 75, 0x46); + else + rt2800_bbp_write(rt2x00dev, 75, 0x50); +@@ -1813,17 +1843,131 @@ + rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, ®); + } + ++static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) ++{ ++ u8 tssi_bounds[9]; ++ u8 current_tssi; ++ u16 eeprom; ++ u8 step; ++ int i; ++ ++ /* ++ * Read TSSI boundaries for temperature compensation from ++ * the EEPROM. ++ * ++ * Array idx 0 1 2 3 4 5 6 7 8 ++ * Matching Delta value -4 -3 -2 -1 0 +1 +2 +3 +4 ++ * Example TSSI bounds 0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00 ++ */ ++ if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom); ++ tssi_bounds[0] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_BG1_MINUS4); ++ tssi_bounds[1] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_BG1_MINUS3); ++ ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom); ++ tssi_bounds[2] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_BG2_MINUS2); ++ tssi_bounds[3] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_BG2_MINUS1); ++ ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom); ++ tssi_bounds[4] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_BG3_REF); ++ tssi_bounds[5] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_BG3_PLUS1); ++ ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom); ++ tssi_bounds[6] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_BG4_PLUS2); ++ tssi_bounds[7] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_BG4_PLUS3); ++ ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom); ++ tssi_bounds[8] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_BG5_PLUS4); ++ ++ step = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_BG5_AGC_STEP); ++ } else { ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom); ++ tssi_bounds[0] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_A1_MINUS4); ++ tssi_bounds[1] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_A1_MINUS3); ++ ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom); ++ tssi_bounds[2] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_A2_MINUS2); ++ tssi_bounds[3] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_A2_MINUS1); ++ ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom); ++ tssi_bounds[4] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_A3_REF); ++ tssi_bounds[5] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_A3_PLUS1); ++ ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom); ++ tssi_bounds[6] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_A4_PLUS2); ++ tssi_bounds[7] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_A4_PLUS3); ++ ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom); ++ tssi_bounds[8] = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_A5_PLUS4); ++ ++ step = rt2x00_get_field16(eeprom, ++ EEPROM_TSSI_BOUND_A5_AGC_STEP); ++ } ++ ++ /* ++ * Check if temperature compensation is supported. ++ */ ++ if (tssi_bounds[4] == 0xff) ++ return 0; ++ ++ /* ++ * Read current TSSI (BBP 49). ++ */ ++ rt2800_bbp_read(rt2x00dev, 49, ¤t_tssi); ++ ++ /* ++ * Compare TSSI value (BBP49) with the compensation boundaries ++ * from the EEPROM and increase or decrease tx power. ++ */ ++ for (i = 0; i <= 3; i++) { ++ if (current_tssi > tssi_bounds[i]) ++ break; ++ } ++ ++ if (i == 4) { ++ for (i = 8; i >= 5; i--) { ++ if (current_tssi < tssi_bounds[i]) ++ break; ++ } ++ } ++ ++ return (i - 4) * step; ++} ++ + static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, + enum ieee80211_band band) + { + u16 eeprom; + u8 comp_en; + u8 comp_type; +- int comp_value; ++ int comp_value = 0; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom); + +- if (eeprom == 0xffff) ++ /* ++ * HT40 compensation not required. ++ */ ++ if (eeprom == 0xffff || ++ !test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) + return 0; + + if (band == IEEE80211_BAND_2GHZ) { +@@ -1853,11 +1997,9 @@ + return comp_value; + } + +-static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, +- int is_rate_b, +- enum ieee80211_band band, +- int power_level, +- u8 txpower) ++static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, ++ enum ieee80211_band band, int power_level, ++ u8 txpower, int delta) + { + u32 reg; + u16 eeprom; +@@ -1865,15 +2007,11 @@ + u8 eirp_txpower; + u8 eirp_txpower_criterion; + u8 reg_limit; +- int bw_comp = 0; + + if (!((band == IEEE80211_BAND_5GHZ) && is_rate_b)) + return txpower; + +- if (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) +- bw_comp = rt2800_get_txpower_bw_comp(rt2x00dev, band); +- +- if (test_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags)) { ++ if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags)) { + /* + * Check if eirp txpower exceed txpower_limit. + * We use OFDM 6M as criterion and its eirp txpower +@@ -1895,18 +2033,19 @@ + EEPROM_EIRP_MAX_TX_POWER_5GHZ); + + eirp_txpower = eirp_txpower_criterion + (txpower - criterion) + +- (is_rate_b ? 4 : 0) + bw_comp; ++ (is_rate_b ? 4 : 0) + delta; + + reg_limit = (eirp_txpower > power_level) ? + (eirp_txpower - power_level) : 0; + } else + reg_limit = 0; + +- return txpower + bw_comp - reg_limit; ++ return txpower + delta - reg_limit; + } + + static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, +- struct ieee80211_conf *conf) ++ enum ieee80211_band band, ++ int power_level) + { + u8 txpower; + u16 eeprom; +@@ -1914,8 +2053,17 @@ + u32 reg; + u8 r1; + u32 offset; +- enum ieee80211_band band = conf->channel->band; +- int power_level = conf->power_level; ++ int delta; ++ ++ /* ++ * Calculate HT40 compensation delta ++ */ ++ delta = rt2800_get_txpower_bw_comp(rt2x00dev, band); ++ ++ /* ++ * calculate temperature compensation delta ++ */ ++ delta += rt2800_get_gain_calibration_delta(rt2x00dev); + + /* + * set to normal bbp tx power control mode: +/- 0dBm +@@ -1944,8 +2092,8 @@ + */ + txpower = rt2x00_get_field16(eeprom, + EEPROM_TXPOWER_BYRATE_RATE0); +- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, +- power_level, txpower); ++ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, ++ power_level, txpower, delta); + rt2x00_set_field32(®, TX_PWR_CFG_RATE0, txpower); + + /* +@@ -1955,8 +2103,8 @@ + */ + txpower = rt2x00_get_field16(eeprom, + EEPROM_TXPOWER_BYRATE_RATE1); +- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, +- power_level, txpower); ++ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, ++ power_level, txpower, delta); + rt2x00_set_field32(®, TX_PWR_CFG_RATE1, txpower); + + /* +@@ -1966,8 +2114,8 @@ + */ + txpower = rt2x00_get_field16(eeprom, + EEPROM_TXPOWER_BYRATE_RATE2); +- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, +- power_level, txpower); ++ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, ++ power_level, txpower, delta); + rt2x00_set_field32(®, TX_PWR_CFG_RATE2, txpower); + + /* +@@ -1977,8 +2125,8 @@ + */ + txpower = rt2x00_get_field16(eeprom, + EEPROM_TXPOWER_BYRATE_RATE3); +- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, +- power_level, txpower); ++ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, ++ power_level, txpower, delta); + rt2x00_set_field32(®, TX_PWR_CFG_RATE3, txpower); + + /* read the next four txpower values */ +@@ -1993,8 +2141,8 @@ + */ + txpower = rt2x00_get_field16(eeprom, + EEPROM_TXPOWER_BYRATE_RATE0); +- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, +- power_level, txpower); ++ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, ++ power_level, txpower, delta); + rt2x00_set_field32(®, TX_PWR_CFG_RATE4, txpower); + + /* +@@ -2004,8 +2152,8 @@ + */ + txpower = rt2x00_get_field16(eeprom, + EEPROM_TXPOWER_BYRATE_RATE1); +- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, +- power_level, txpower); ++ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, ++ power_level, txpower, delta); + rt2x00_set_field32(®, TX_PWR_CFG_RATE5, txpower); + + /* +@@ -2015,8 +2163,8 @@ + */ + txpower = rt2x00_get_field16(eeprom, + EEPROM_TXPOWER_BYRATE_RATE2); +- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, +- power_level, txpower); ++ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, ++ power_level, txpower, delta); + rt2x00_set_field32(®, TX_PWR_CFG_RATE6, txpower); + + /* +@@ -2026,8 +2174,8 @@ + */ + txpower = rt2x00_get_field16(eeprom, + EEPROM_TXPOWER_BYRATE_RATE3); +- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, +- power_level, txpower); ++ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, ++ power_level, txpower, delta); + rt2x00_set_field32(®, TX_PWR_CFG_RATE7, txpower); + + rt2800_register_write(rt2x00dev, offset, reg); +@@ -2037,6 +2185,13 @@ + } + } + ++void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev) ++{ ++ rt2800_config_txpower(rt2x00dev, rt2x00dev->curr_band, ++ rt2x00dev->tx_power); ++} ++EXPORT_SYMBOL_GPL(rt2800_gain_calibration); ++ + static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) + { +@@ -2090,10 +2245,12 @@ + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) { + rt2800_config_channel(rt2x00dev, libconf->conf, + &libconf->rf, &libconf->channel); +- rt2800_config_txpower(rt2x00dev, libconf->conf); ++ rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band, ++ libconf->conf->power_level); + } + if (flags & IEEE80211_CONF_CHANGE_POWER) +- rt2800_config_txpower(rt2x00dev, libconf->conf); ++ rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band, ++ libconf->conf->power_level); + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt2800_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_PS) +@@ -2254,7 +2411,7 @@ + } else if (rt2800_is_305x_soc(rt2x00dev)) { + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); + rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); +- rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000001f); ++ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000030); + } else if (rt2x00_rt(rt2x00dev, RT5390)) { + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); + rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); +@@ -2758,8 +2915,7 @@ + ant = (div_mode == 3) ? 1 : 0; + + /* check if this is a Bluetooth combo card */ +- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); +- if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) { ++ if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { + u32 reg; + + rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); +@@ -3155,8 +3311,8 @@ + rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || + rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) || + rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) { +- if (!test_bit(CONFIG_EXTERNAL_LNA_BG, +- &rt2x00dev->flags)) ++ if (!test_bit(CAPABILITY_EXTERNAL_LNA_BG, ++ &rt2x00dev->cap_flags)) + rt2x00_set_field8(&rfcsr, RFCSR17_R, 1); + } + rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &eeprom); +@@ -3568,26 +3724,30 @@ + } + + /* +- * Read frequency offset and RF programming sequence. ++ * Determine external LNA informations. + */ +- rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); +- rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); +- +- /* +- * Read external LNA informations. +- */ +- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); +- + if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G)) +- __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); + if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G)) +- __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); + + /* + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_HW_RADIO)) +- __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); ++ ++ /* ++ * Detect if this device has Bluetooth co-existence. ++ */ ++ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) ++ __set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags); ++ ++ /* ++ * Read frequency offset and RF programming sequence. ++ */ ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); ++ rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); + + /* + * Store led settings, for correct led behaviour. +@@ -3597,7 +3757,7 @@ + rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); + rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); + +- rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg); ++ rt2x00dev->led_mcu_reg = eeprom; + #endif /* CONFIG_RT2X00_LIB_LEDS */ + + /* +@@ -3607,7 +3767,7 @@ + + if (rt2x00_get_field16(eeprom, EEPROM_EIRP_MAX_TX_POWER_2GHZ) < + EIRP_MAX_TX_POWER_LIMIT) +- __set_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags); + + return 0; + } +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2800lib.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2800lib.h +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2800lib.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2800lib.h 2011-05-05 23:29:46.059448799 +0200 +@@ -181,6 +181,7 @@ + void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); + void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, + const u32 count); ++void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev); + + int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev); + void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2800pci.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2800pci.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2800pci.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2800pci.c 2011-05-05 23:29:46.103449331 +0200 +@@ -66,7 +66,7 @@ + return; + + for (i = 0; i < 200; i++) { +- rt2800_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); ++ rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); + + if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) || + (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) || +@@ -80,8 +80,8 @@ + if (i == 200) + ERROR(rt2x00dev, "MCU request failed, no response from hardware\n"); + +- rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); +- rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); + } + + #if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +@@ -105,7 +105,7 @@ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg; + +- rt2800_register_read(rt2x00dev, E2PROM_CSR, ®); ++ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); + + eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); + eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); +@@ -127,7 +127,7 @@ + rt2x00_set_field32(®, E2PROM_CSR_CHIP_SELECT, + !!eeprom->reg_chip_select); + +- rt2800_register_write(rt2x00dev, E2PROM_CSR, reg); ++ rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg); + } + + static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) +@@ -135,7 +135,7 @@ + struct eeprom_93cx6 eeprom; + u32 reg; + +- rt2800_register_read(rt2x00dev, E2PROM_CSR, ®); ++ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); + + eeprom.data = rt2x00dev; + eeprom.register_read = rt2800pci_eepromregister_read; +@@ -195,9 +195,9 @@ + + switch (queue->qid) { + case QID_RX: +- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); ++ rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); +- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); ++ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + break; + case QID_BEACON: + /* +@@ -207,15 +207,15 @@ + tasklet_enable(&rt2x00dev->tbtt_tasklet); + tasklet_enable(&rt2x00dev->pretbtt_tasklet); + +- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); ++ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); +- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); ++ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); + +- rt2800_register_read(rt2x00dev, INT_TIMER_EN, ®); ++ rt2x00pci_register_read(rt2x00dev, INT_TIMER_EN, ®); + rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 1); +- rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg); ++ rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg); + break; + default: + break; +@@ -233,11 +233,13 @@ + case QID_AC_BE: + case QID_AC_BK: + entry = rt2x00queue_get_entry(queue, Q_INDEX); +- rt2800_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), entry->entry_idx); ++ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), ++ entry->entry_idx); + break; + case QID_MGMT: + entry = rt2x00queue_get_entry(queue, Q_INDEX); +- rt2800_register_write(rt2x00dev, TX_CTX_IDX(5), entry->entry_idx); ++ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(5), ++ entry->entry_idx); + break; + default: + break; +@@ -251,20 +253,20 @@ + + switch (queue->qid) { + case QID_RX: +- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); ++ rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); +- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); ++ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + break; + case QID_BEACON: +- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); ++ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); +- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); ++ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); + +- rt2800_register_read(rt2x00dev, INT_TIMER_EN, ®); ++ rt2x00pci_register_read(rt2x00dev, INT_TIMER_EN, ®); + rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 0); +- rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg); ++ rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg); + + /* + * Wait for tbtt tasklets to finish. +@@ -295,19 +297,19 @@ + */ + reg = 0; + rt2x00_set_field32(®, PBF_SYS_CTRL_HOST_RAM_WRITE, 1); +- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg); ++ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, reg); + + /* + * Write firmware to device. + */ +- rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, +- data, len); ++ rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, ++ data, len); + +- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); +- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); ++ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); ++ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); + +- rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); +- rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); ++ rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0); ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + + return 0; + } +@@ -351,7 +353,7 @@ + * Set RX IDX in register to inform hardware that we have + * handled this entry and it is available for reuse again. + */ +- rt2800_register_write(rt2x00dev, RX_CRX_IDX, ++ rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, + entry->entry_idx); + } else { + rt2x00_desc_read(entry_priv->desc, 1, &word); +@@ -369,45 +371,51 @@ + * Initialize registers. + */ + entry_priv = rt2x00dev->tx[0].entries[0].priv_data; +- rt2800_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma); +- rt2800_register_write(rt2x00dev, TX_MAX_CNT0, rt2x00dev->tx[0].limit); +- rt2800_register_write(rt2x00dev, TX_CTX_IDX0, 0); +- rt2800_register_write(rt2x00dev, TX_DTX_IDX0, 0); ++ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma); ++ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT0, ++ rt2x00dev->tx[0].limit); ++ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX0, 0); ++ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX0, 0); + + entry_priv = rt2x00dev->tx[1].entries[0].priv_data; +- rt2800_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma); +- rt2800_register_write(rt2x00dev, TX_MAX_CNT1, rt2x00dev->tx[1].limit); +- rt2800_register_write(rt2x00dev, TX_CTX_IDX1, 0); +- rt2800_register_write(rt2x00dev, TX_DTX_IDX1, 0); ++ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma); ++ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT1, ++ rt2x00dev->tx[1].limit); ++ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX1, 0); ++ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX1, 0); + + entry_priv = rt2x00dev->tx[2].entries[0].priv_data; +- rt2800_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma); +- rt2800_register_write(rt2x00dev, TX_MAX_CNT2, rt2x00dev->tx[2].limit); +- rt2800_register_write(rt2x00dev, TX_CTX_IDX2, 0); +- rt2800_register_write(rt2x00dev, TX_DTX_IDX2, 0); ++ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma); ++ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT2, ++ rt2x00dev->tx[2].limit); ++ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX2, 0); ++ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX2, 0); + + entry_priv = rt2x00dev->tx[3].entries[0].priv_data; +- rt2800_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma); +- rt2800_register_write(rt2x00dev, TX_MAX_CNT3, rt2x00dev->tx[3].limit); +- rt2800_register_write(rt2x00dev, TX_CTX_IDX3, 0); +- rt2800_register_write(rt2x00dev, TX_DTX_IDX3, 0); ++ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma); ++ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT3, ++ rt2x00dev->tx[3].limit); ++ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX3, 0); ++ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX3, 0); + + entry_priv = rt2x00dev->rx->entries[0].priv_data; +- rt2800_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma); +- rt2800_register_write(rt2x00dev, RX_MAX_CNT, rt2x00dev->rx[0].limit); +- rt2800_register_write(rt2x00dev, RX_CRX_IDX, rt2x00dev->rx[0].limit - 1); +- rt2800_register_write(rt2x00dev, RX_DRX_IDX, 0); ++ rt2x00pci_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma); ++ rt2x00pci_register_write(rt2x00dev, RX_MAX_CNT, ++ rt2x00dev->rx[0].limit); ++ rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, ++ rt2x00dev->rx[0].limit - 1); ++ rt2x00pci_register_write(rt2x00dev, RX_DRX_IDX, 0); + + /* + * Enable global DMA configuration + */ +- rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); ++ rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); +- rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); ++ rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + +- rt2800_register_write(rt2x00dev, DELAY_INT_CFG, 0); ++ rt2x00pci_register_write(rt2x00dev, DELAY_INT_CFG, 0); + + return 0; + } +@@ -427,8 +435,8 @@ + * should clear the register to assure a clean state. + */ + if (state == STATE_RADIO_IRQ_ON) { +- rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); +- rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg); ++ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); ++ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + + /* + * Enable tasklets. The beacon related tasklets are +@@ -440,7 +448,7 @@ + } + + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); +- rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); ++ rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00_set_field32(®, INT_MASK_CSR_RXDELAYINT, 0); + rt2x00_set_field32(®, INT_MASK_CSR_TXDELAYINT, 0); + rt2x00_set_field32(®, INT_MASK_CSR_RX_DONE, mask); +@@ -459,7 +467,7 @@ + rt2x00_set_field32(®, INT_MASK_CSR_GPTIMER, 0); + rt2x00_set_field32(®, INT_MASK_CSR_RX_COHERENT, 0); + rt2x00_set_field32(®, INT_MASK_CSR_TX_COHERENT, 0); +- rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); ++ rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + + if (state == STATE_RADIO_IRQ_OFF) { +@@ -480,7 +488,7 @@ + /* + * Reset DMA indexes + */ +- rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, ®); ++ rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, ®); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1); +@@ -488,26 +496,26 @@ + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1); +- rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg); ++ rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg); + +- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); +- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); ++ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); ++ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); + + if (rt2x00_rt(rt2x00dev, RT5390)) { +- rt2800_register_read(rt2x00dev, AUX_CTRL, ®); ++ rt2x00pci_register_read(rt2x00dev, AUX_CTRL, ®); + rt2x00_set_field32(®, AUX_CTRL_FORCE_PCIE_CLK, 1); + rt2x00_set_field32(®, AUX_CTRL_WAKE_PCIE_EN, 1); +- rt2800_register_write(rt2x00dev, AUX_CTRL, reg); ++ rt2x00pci_register_write(rt2x00dev, AUX_CTRL, reg); + } + +- rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); ++ rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + +- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); ++ rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); +- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); ++ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + +- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); ++ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + + return 0; + } +@@ -525,8 +533,8 @@ + { + if (rt2x00_is_soc(rt2x00dev)) { + rt2800_disable_radio(rt2x00dev); +- rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); +- rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); ++ rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0); ++ rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, 0); + } + } + +@@ -537,8 +545,10 @@ + rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02); + rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP); + } else if (state == STATE_SLEEP) { +- rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, 0xffffffff); +- rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, 0xffffffff); ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ++ 0xffffffff); ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ++ 0xffffffff); + rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01); + } + +@@ -717,12 +727,13 @@ + rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); + } + +-static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) ++static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) + { + struct data_queue *queue; + struct queue_entry *entry; + u32 status; + u8 qid; ++ int max_tx_done = 16; + + while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) { + qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); +@@ -759,11 +770,16 @@ + + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + rt2800_txdone_entry(entry, status); ++ ++ if (--max_tx_done == 0) ++ break; + } ++ ++ return !max_tx_done; + } + +-static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, +- struct rt2x00_field32 irq_field) ++static inline void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, ++ struct rt2x00_field32 irq_field) + { + u32 reg; + +@@ -772,15 +788,17 @@ + * access needs locking. + */ + spin_lock_irq(&rt2x00dev->irqmask_lock); +- rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); ++ rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00_set_field32(®, irq_field, 1); +- rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); ++ rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); + spin_unlock_irq(&rt2x00dev->irqmask_lock); + } + + static void rt2800pci_txstatus_tasklet(unsigned long data) + { +- rt2800pci_txdone((struct rt2x00_dev *)data); ++ struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; ++ if (rt2800pci_txdone(rt2x00dev)) ++ tasklet_schedule(&rt2x00dev->txstatus_tasklet); + + /* + * No need to enable the tx status interrupt here as we always +@@ -806,8 +824,10 @@ + static void rt2800pci_rxdone_tasklet(unsigned long data) + { + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; +- rt2x00pci_rxdone(rt2x00dev); +- rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); ++ if (rt2x00pci_rxdone(rt2x00dev)) ++ tasklet_schedule(&rt2x00dev->rxdone_tasklet); ++ else ++ rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); + } + + static void rt2800pci_autowake_tasklet(unsigned long data) +@@ -841,7 +861,7 @@ + * need to lock the kfifo. + */ + for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) { +- rt2800_register_read(rt2x00dev, TX_STA_FIFO, &status); ++ rt2x00pci_register_read(rt2x00dev, TX_STA_FIFO, &status); + + if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID)) + break; +@@ -863,8 +883,8 @@ + u32 reg, mask; + + /* Read status and ACK all interrupts */ +- rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); +- rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg); ++ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); ++ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + + if (!reg) + return IRQ_NONE; +@@ -904,9 +924,9 @@ + * the tasklet will reenable the appropriate interrupts. + */ + spin_lock(&rt2x00dev->irqmask_lock); +- rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); ++ rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg &= mask; +- rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); ++ rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); + spin_unlock(&rt2x00dev->irqmask_lock); + + return IRQ_HANDLED; +@@ -956,28 +976,28 @@ + * This device has multiple filters for control frames + * and has a separate filter for PS Poll frames. + */ +- __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); +- __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); ++ __set_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags); + + /* + * This device has a pre tbtt interrupt and thus fetches + * a new beacon directly prior to transmission. + */ +- __set_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_PRE_TBTT_INTERRUPT, &rt2x00dev->cap_flags); + + /* + * This device requires firmware. + */ + if (!rt2x00_is_soc(rt2x00dev)) +- __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags); ++ __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags); + if (!modparam_nohwcrypt) +- __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); +- __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); ++ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); + + /* + * Set the rssi offset. +@@ -1008,6 +1028,7 @@ + .ampdu_action = rt2800_ampdu_action, + .flush = rt2x00mac_flush, + .get_survey = rt2800_get_survey, ++ .get_ringparam = rt2x00mac_get_ringparam, + }; + + static const struct rt2800_ops rt2800pci_rt2800_ops = { +@@ -1043,9 +1064,11 @@ + .link_stats = rt2800_link_stats, + .reset_tuner = rt2800_reset_tuner, + .link_tuner = rt2800_link_tuner, ++ .gain_calibration = rt2800_gain_calibration, + .start_queue = rt2800pci_start_queue, + .kick_queue = rt2800pci_kick_queue, + .stop_queue = rt2800pci_stop_queue, ++ .flush_queue = rt2x00pci_flush_queue, + .write_tx_desc = rt2800pci_write_tx_desc, + .write_tx_data = rt2800_write_tx_data, + .write_beacon = rt2800_write_beacon, +@@ -1105,36 +1128,36 @@ + */ + #ifdef CONFIG_PCI + static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { +- { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1432, 0x7738), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) }, ++ { PCI_DEVICE(0x1814, 0x0601) }, ++ { PCI_DEVICE(0x1814, 0x0681) }, ++ { PCI_DEVICE(0x1814, 0x0701) }, ++ { PCI_DEVICE(0x1814, 0x0781) }, ++ { PCI_DEVICE(0x1814, 0x3090) }, ++ { PCI_DEVICE(0x1814, 0x3091) }, ++ { PCI_DEVICE(0x1814, 0x3092) }, ++ { PCI_DEVICE(0x1432, 0x7708) }, ++ { PCI_DEVICE(0x1432, 0x7727) }, ++ { PCI_DEVICE(0x1432, 0x7728) }, ++ { PCI_DEVICE(0x1432, 0x7738) }, ++ { PCI_DEVICE(0x1432, 0x7748) }, ++ { PCI_DEVICE(0x1432, 0x7758) }, ++ { PCI_DEVICE(0x1432, 0x7768) }, ++ { PCI_DEVICE(0x1462, 0x891a) }, ++ { PCI_DEVICE(0x1a3b, 0x1059) }, + #ifdef CONFIG_RT2800PCI_RT33XX +- { PCI_DEVICE(0x1814, 0x3390), PCI_DEVICE_DATA(&rt2800pci_ops) }, ++ { PCI_DEVICE(0x1814, 0x3390) }, + #endif + #ifdef CONFIG_RT2800PCI_RT35XX +- { PCI_DEVICE(0x1432, 0x7711), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1432, 0x7722), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) }, +- { PCI_DEVICE(0x1814, 0x3593), PCI_DEVICE_DATA(&rt2800pci_ops) }, ++ { PCI_DEVICE(0x1432, 0x7711) }, ++ { PCI_DEVICE(0x1432, 0x7722) }, ++ { PCI_DEVICE(0x1814, 0x3060) }, ++ { PCI_DEVICE(0x1814, 0x3062) }, ++ { PCI_DEVICE(0x1814, 0x3562) }, ++ { PCI_DEVICE(0x1814, 0x3592) }, ++ { PCI_DEVICE(0x1814, 0x3593) }, + #endif + #ifdef CONFIG_RT2800PCI_RT53XX +- { PCI_DEVICE(0x1814, 0x5390), PCI_DEVICE_DATA(&rt2800pci_ops) }, ++ { PCI_DEVICE(0x1814, 0x5390) }, + #endif + { 0, } + }; +@@ -1170,10 +1193,16 @@ + #endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ + + #ifdef CONFIG_PCI ++static int rt2800pci_probe(struct pci_dev *pci_dev, ++ const struct pci_device_id *id) ++{ ++ return rt2x00pci_probe(pci_dev, &rt2800pci_ops); ++} ++ + static struct pci_driver rt2800pci_driver = { + .name = KBUILD_MODNAME, + .id_table = rt2800pci_device_table, +- .probe = rt2x00pci_probe, ++ .probe = rt2800pci_probe, + .remove = __devexit_p(rt2x00pci_remove), + .suspend = rt2x00pci_suspend, + .resume = rt2x00pci_resume, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2800usb.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2800usb.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2800usb.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2800usb.c 2011-05-05 23:29:46.077449017 +0200 +@@ -59,16 +59,16 @@ + + switch (queue->qid) { + case QID_RX: +- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); ++ rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); +- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); ++ rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + break; + case QID_BEACON: +- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); ++ rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); +- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); ++ rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + break; + default: + break; +@@ -82,16 +82,16 @@ + + switch (queue->qid) { + case QID_RX: +- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); ++ rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); +- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); ++ rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + break; + case QID_BEACON: +- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); ++ rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); +- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); ++ rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + break; + default: + break; +@@ -99,6 +99,63 @@ + } + + /* ++ * test if there is an entry in any TX queue for which DMA is done ++ * but the TX status has not been returned yet ++ */ ++static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev) ++{ ++ struct data_queue *queue; ++ ++ tx_queue_for_each(rt2x00dev, queue) { ++ if (rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE) != ++ rt2x00queue_get_entry(queue, Q_INDEX_DONE)) ++ return true; ++ } ++ return false; ++} ++ ++static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, ++ int urb_status, u32 tx_status) ++{ ++ if (urb_status) { ++ WARNING(rt2x00dev, "rt2x00usb_register_read_async failed: %d\n", urb_status); ++ return false; ++ } ++ ++ /* try to read all TX_STA_FIFO entries before scheduling txdone_work */ ++ if (rt2x00_get_field32(tx_status, TX_STA_FIFO_VALID)) { ++ if (!kfifo_put(&rt2x00dev->txstatus_fifo, &tx_status)) { ++ WARNING(rt2x00dev, "TX status FIFO overrun, " ++ "drop tx status report.\n"); ++ queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); ++ } else ++ return true; ++ } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) { ++ queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); ++ } else if (rt2800usb_txstatus_pending(rt2x00dev)) { ++ mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); ++ } ++ ++ return false; ++} ++ ++static void rt2800usb_tx_dma_done(struct queue_entry *entry) ++{ ++ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; ++ ++ rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO, ++ rt2800usb_tx_sta_fifo_read_completed); ++} ++ ++static void rt2800usb_tx_sta_fifo_timeout(unsigned long data) ++{ ++ struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; ++ ++ rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO, ++ rt2800usb_tx_sta_fifo_read_completed); ++} ++ ++/* + * Firmware functions + */ + static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev) +@@ -129,11 +186,11 @@ + /* + * Write firmware to device. + */ +- rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, +- data + offset, length); ++ rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, ++ data + offset, length); + +- rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); +- rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); ++ rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); ++ rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); + + /* + * Send firmware request to device to load firmware, +@@ -148,7 +205,7 @@ + } + + msleep(10); +- rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); ++ rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + + return 0; + } +@@ -166,22 +223,22 @@ + if (rt2800_wait_csr_ready(rt2x00dev)) + return -EBUSY; + +- rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); +- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); ++ rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, ®); ++ rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); + +- rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); ++ rt2x00usb_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + +- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); ++ rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); +- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); ++ rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + +- rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); ++ rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, + USB_MODE_RESET, REGISTER_TIMEOUT); + +- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); ++ rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + + return 0; + } +@@ -193,7 +250,7 @@ + if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev))) + return -EIO; + +- rt2800_register_read(rt2x00dev, USB_DMA_CFG, ®); ++ rt2x00usb_register_read(rt2x00dev, USB_DMA_CFG, ®); + rt2x00_set_field32(®, USB_DMA_CFG_PHY_CLEAR, 0); + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, 0); + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128); +@@ -206,7 +263,7 @@ + / 1024) - 3); + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_EN, 1); + rt2x00_set_field32(®, USB_DMA_CFG_TX_BULK_EN, 1); +- rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg); ++ rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, reg); + + return rt2800_enable_radio(rt2x00dev); + } +@@ -282,12 +339,12 @@ + unsigned int i; + u32 reg; + +- rt2800_register_read(rt2x00dev, TXRXQ_PCNT, ®); ++ rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, ®); + if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q)) { + WARNING(rt2x00dev, "TX HW queue 0 timed out," + " invoke forced kick\n"); + +- rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40012); ++ rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40012); + + for (i = 0; i < 10; i++) { + udelay(10); +@@ -295,15 +352,15 @@ + break; + } + +- rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); ++ rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006); + } + +- rt2800_register_read(rt2x00dev, TXRXQ_PCNT, ®); ++ rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, ®); + if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q)) { + WARNING(rt2x00dev, "TX HW queue 1 timed out," + " invoke forced kick\n"); + +- rt2800_register_write(rt2x00dev, PBF_CFG, 0xf4000a); ++ rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf4000a); + + for (i = 0; i < 10; i++) { + udelay(10); +@@ -311,7 +368,7 @@ + break; + } + +- rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); ++ rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006); + } + + rt2x00usb_watchdog(rt2x00dev); +@@ -420,13 +477,24 @@ + while (!rt2x00queue_empty(queue)) { + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + +- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || +- !test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) ++ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) ++ break; ++ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) ++ rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); ++ else if (rt2x00queue_status_timeout(entry)) ++ rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); ++ else + break; +- +- rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); + } + } ++ ++ /* ++ * The hw may delay sending the packet after DMA complete ++ * if the medium is busy, thus the TX_STA_FIFO entry is ++ * also delayed -> use a timer to retrieve it. ++ */ ++ if (rt2800usb_txstatus_pending(rt2x00dev)) ++ mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); + } + + /* +@@ -553,19 +621,24 @@ + * This device has multiple filters for control frames + * and has a separate filter for PS Poll frames. + */ +- __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); +- __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); ++ __set_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags); + + /* + * This device requires firmware. + */ +- __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); ++ __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags); + if (!modparam_nohwcrypt) +- __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); +- __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); +- __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); ++ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); ++ ++ setup_timer(&rt2x00dev->txstatus_timer, ++ rt2800usb_tx_sta_fifo_timeout, ++ (unsigned long) rt2x00dev); + + /* + * Set the rssi offset. +@@ -602,6 +675,7 @@ + .ampdu_action = rt2800_ampdu_action, + .flush = rt2x00mac_flush, + .get_survey = rt2800_get_survey, ++ .get_ringparam = rt2x00mac_get_ringparam, + }; + + static const struct rt2800_ops rt2800usb_rt2800_ops = { +@@ -630,11 +704,13 @@ + .link_stats = rt2800_link_stats, + .reset_tuner = rt2800_reset_tuner, + .link_tuner = rt2800_link_tuner, ++ .gain_calibration = rt2800_gain_calibration, + .watchdog = rt2800usb_watchdog, + .start_queue = rt2800usb_start_queue, + .kick_queue = rt2x00usb_kick_queue, + .stop_queue = rt2800usb_stop_queue, + .flush_queue = rt2x00usb_flush_queue, ++ .tx_dma_done = rt2800usb_tx_dma_done, + .write_tx_desc = rt2800usb_write_tx_desc, + .write_tx_data = rt2800usb_write_tx_data, + .write_beacon = rt2800_write_beacon, +@@ -695,294 +771,332 @@ + */ + static struct usb_device_id rt2800usb_device_table[] = { + /* Abocom */ +- { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x07b8, 0x2870) }, ++ { USB_DEVICE(0x07b8, 0x2770) }, ++ { USB_DEVICE(0x07b8, 0x3070) }, ++ { USB_DEVICE(0x07b8, 0x3071) }, ++ { USB_DEVICE(0x07b8, 0x3072) }, ++ { USB_DEVICE(0x1482, 0x3c09) }, + /* AirTies */ +- { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1eda, 0x2012) }, ++ { USB_DEVICE(0x1eda, 0x2310) }, + /* Allwin */ +- { USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x8516, 0x2070) }, ++ { USB_DEVICE(0x8516, 0x2770) }, ++ { USB_DEVICE(0x8516, 0x2870) }, ++ { USB_DEVICE(0x8516, 0x3070) }, ++ { USB_DEVICE(0x8516, 0x3071) }, ++ { USB_DEVICE(0x8516, 0x3072) }, ++ /* Alpha Networks */ ++ { USB_DEVICE(0x14b2, 0x3c06) }, ++ { USB_DEVICE(0x14b2, 0x3c07) }, ++ { USB_DEVICE(0x14b2, 0x3c09) }, ++ { USB_DEVICE(0x14b2, 0x3c12) }, ++ { USB_DEVICE(0x14b2, 0x3c23) }, ++ { USB_DEVICE(0x14b2, 0x3c25) }, ++ { USB_DEVICE(0x14b2, 0x3c27) }, ++ { USB_DEVICE(0x14b2, 0x3c28) }, ++ { USB_DEVICE(0x14b2, 0x3c2c) }, + /* Amit */ +- { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x15c5, 0x0008) }, + /* Askey */ +- { USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1690, 0x0740) }, + /* ASUS */ +- { USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0b05, 0x1731) }, ++ { USB_DEVICE(0x0b05, 0x1732) }, ++ { USB_DEVICE(0x0b05, 0x1742) }, ++ { USB_DEVICE(0x0b05, 0x1784) }, ++ { USB_DEVICE(0x1761, 0x0b05) }, + /* AzureWave */ +- { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x13d3, 0x3307), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x13d3, 0x3321), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x13d3, 0x3247) }, ++ { USB_DEVICE(0x13d3, 0x3273) }, ++ { USB_DEVICE(0x13d3, 0x3305) }, ++ { USB_DEVICE(0x13d3, 0x3307) }, ++ { USB_DEVICE(0x13d3, 0x3321) }, + /* Belkin */ +- { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x050d, 0x825b), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x050d, 0x935a), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x050d, 0x935b), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x050d, 0x8053) }, ++ { USB_DEVICE(0x050d, 0x805c) }, ++ { USB_DEVICE(0x050d, 0x815c) }, ++ { USB_DEVICE(0x050d, 0x825b) }, ++ { USB_DEVICE(0x050d, 0x935a) }, ++ { USB_DEVICE(0x050d, 0x935b) }, + /* Buffalo */ +- { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0411, 0x016f), USB_DEVICE_DATA(&rt2800usb_ops) }, +- /* Conceptronic */ +- { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x14b2, 0x3c28), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0411, 0x00e8) }, ++ { USB_DEVICE(0x0411, 0x016f) }, ++ { USB_DEVICE(0x0411, 0x01a2) }, + /* Corega */ +- { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x07aa, 0x002f) }, ++ { USB_DEVICE(0x07aa, 0x003c) }, ++ { USB_DEVICE(0x07aa, 0x003f) }, ++ { USB_DEVICE(0x18c5, 0x0012) }, + /* D-Link */ +- { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x07d1, 0x3c09) }, ++ { USB_DEVICE(0x07d1, 0x3c0a) }, ++ { USB_DEVICE(0x07d1, 0x3c0d) }, ++ { USB_DEVICE(0x07d1, 0x3c0e) }, ++ { USB_DEVICE(0x07d1, 0x3c0f) }, ++ { USB_DEVICE(0x07d1, 0x3c11) }, ++ { USB_DEVICE(0x07d1, 0x3c16) }, + /* Draytek */ +- { USB_DEVICE(0x07fa, 0x7712), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x07fa, 0x7712) }, + /* Edimax */ +- { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x7392, 0x7711) }, ++ { USB_DEVICE(0x7392, 0x7717) }, ++ { USB_DEVICE(0x7392, 0x7718) }, + /* Encore */ +- { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x203d, 0x1480) }, ++ { USB_DEVICE(0x203d, 0x14a9) }, + /* EnGenius */ +- { USB_DEVICE(0x1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1740, 0x9701) }, ++ { USB_DEVICE(0x1740, 0x9702) }, ++ { USB_DEVICE(0x1740, 0x9703) }, ++ { USB_DEVICE(0x1740, 0x9705) }, ++ { USB_DEVICE(0x1740, 0x9706) }, ++ { USB_DEVICE(0x1740, 0x9707) }, ++ { USB_DEVICE(0x1740, 0x9708) }, ++ { USB_DEVICE(0x1740, 0x9709) }, ++ /* Gemtek */ ++ { USB_DEVICE(0x15a9, 0x0012) }, + /* Gigabyte */ +- { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1044, 0x800b) }, ++ { USB_DEVICE(0x1044, 0x800d) }, + /* Hawking */ +- { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0e66, 0x0013), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0e66, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0e66, 0x0018), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0e66, 0x0001) }, ++ { USB_DEVICE(0x0e66, 0x0003) }, ++ { USB_DEVICE(0x0e66, 0x0009) }, ++ { USB_DEVICE(0x0e66, 0x000b) }, ++ { USB_DEVICE(0x0e66, 0x0013) }, ++ { USB_DEVICE(0x0e66, 0x0017) }, ++ { USB_DEVICE(0x0e66, 0x0018) }, + /* I-O DATA */ +- { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x04bb, 0x0945) }, ++ { USB_DEVICE(0x04bb, 0x0947) }, ++ { USB_DEVICE(0x04bb, 0x0948) }, + /* Linksys */ +- { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x13b1, 0x0031) }, ++ { USB_DEVICE(0x1737, 0x0070) }, ++ { USB_DEVICE(0x1737, 0x0071) }, + /* Logitec */ +- { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0789, 0x0166), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0789, 0x0162) }, ++ { USB_DEVICE(0x0789, 0x0163) }, ++ { USB_DEVICE(0x0789, 0x0164) }, ++ { USB_DEVICE(0x0789, 0x0166) }, + /* Motorola */ +- { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x100d, 0x9031) }, + /* MSI */ +- { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x822b), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x822c), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x871b), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x871c), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0db0, 0x3820) }, ++ { USB_DEVICE(0x0db0, 0x3821) }, ++ { USB_DEVICE(0x0db0, 0x3822) }, ++ { USB_DEVICE(0x0db0, 0x3870) }, ++ { USB_DEVICE(0x0db0, 0x3871) }, ++ { USB_DEVICE(0x0db0, 0x6899) }, ++ { USB_DEVICE(0x0db0, 0x821a) }, ++ { USB_DEVICE(0x0db0, 0x822a) }, ++ { USB_DEVICE(0x0db0, 0x822b) }, ++ { USB_DEVICE(0x0db0, 0x822c) }, ++ { USB_DEVICE(0x0db0, 0x870a) }, ++ { USB_DEVICE(0x0db0, 0x871a) }, ++ { USB_DEVICE(0x0db0, 0x871b) }, ++ { USB_DEVICE(0x0db0, 0x871c) }, ++ { USB_DEVICE(0x0db0, 0x899a) }, + /* Para */ +- { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x20b8, 0x8888) }, + /* Pegatron */ +- { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1d4d, 0x000c) }, ++ { USB_DEVICE(0x1d4d, 0x000e) }, ++ { USB_DEVICE(0x1d4d, 0x0011) }, + /* Philips */ +- { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0471, 0x200f) }, + /* Planex */ +- { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x2019, 0xab25) }, ++ { USB_DEVICE(0x2019, 0xed06) }, + /* Quanta */ +- { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1a32, 0x0304) }, + /* Ralink */ +- { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x148f, 0x2070) }, ++ { USB_DEVICE(0x148f, 0x2770) }, ++ { USB_DEVICE(0x148f, 0x2870) }, ++ { USB_DEVICE(0x148f, 0x3070) }, ++ { USB_DEVICE(0x148f, 0x3071) }, ++ { USB_DEVICE(0x148f, 0x3072) }, + /* Samsung */ +- { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x04e8, 0x2018) }, + /* Siemens */ +- { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x129b, 0x1828) }, + /* Sitecom */ +- { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0df6, 0x0017) }, ++ { USB_DEVICE(0x0df6, 0x002b) }, ++ { USB_DEVICE(0x0df6, 0x002c) }, ++ { USB_DEVICE(0x0df6, 0x002d) }, ++ { USB_DEVICE(0x0df6, 0x0039) }, ++ { USB_DEVICE(0x0df6, 0x003b) }, ++ { USB_DEVICE(0x0df6, 0x003d) }, ++ { USB_DEVICE(0x0df6, 0x003e) }, ++ { USB_DEVICE(0x0df6, 0x003f) }, ++ { USB_DEVICE(0x0df6, 0x0040) }, ++ { USB_DEVICE(0x0df6, 0x0042) }, ++ { USB_DEVICE(0x0df6, 0x0047) }, ++ { USB_DEVICE(0x0df6, 0x0048) }, ++ { USB_DEVICE(0x0df6, 0x0051) }, ++ { USB_DEVICE(0x0df6, 0x005f) }, + /* SMC */ +- { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x083a, 0xa703), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x083a, 0x6618) }, ++ { USB_DEVICE(0x083a, 0x7511) }, ++ { USB_DEVICE(0x083a, 0x7512) }, ++ { USB_DEVICE(0x083a, 0x7522) }, ++ { USB_DEVICE(0x083a, 0x8522) }, ++ { USB_DEVICE(0x083a, 0xa618) }, ++ { USB_DEVICE(0x083a, 0xa701) }, ++ { USB_DEVICE(0x083a, 0xa702) }, ++ { USB_DEVICE(0x083a, 0xa703) }, ++ { USB_DEVICE(0x083a, 0xb522) }, + /* Sparklan */ +- { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x15a9, 0x0006) }, + /* Sweex */ +- { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, +- /* U-Media*/ +- { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x177f, 0x0302) }, ++ /* U-Media */ ++ { USB_DEVICE(0x157e, 0x300e) }, ++ { USB_DEVICE(0x157e, 0x3013) }, + /* ZCOM */ +- { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0cde, 0x0022) }, ++ { USB_DEVICE(0x0cde, 0x0025) }, + /* Zinwell */ +- { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x5a57, 0x0280) }, ++ { USB_DEVICE(0x5a57, 0x0282) }, ++ { USB_DEVICE(0x5a57, 0x0283) }, ++ { USB_DEVICE(0x5a57, 0x5257) }, + /* Zyxel */ +- { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0586, 0x3416) }, ++ { USB_DEVICE(0x0586, 0x3418) }, ++ { USB_DEVICE(0x0586, 0x341e) }, ++ { USB_DEVICE(0x0586, 0x343e) }, + #ifdef CONFIG_RT2800USB_RT33XX + /* Ralink */ +- { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x148f, 0x3370) }, ++ { USB_DEVICE(0x148f, 0x8070) }, + /* Sitecom */ +- { USB_DEVICE(0x0df6, 0x0050), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0df6, 0x0050) }, + #endif + #ifdef CONFIG_RT2800USB_RT35XX + /* Allwin */ +- { USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x8516, 0x3572) }, + /* Askey */ +- { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1690, 0x0744) }, + /* Cisco */ +- { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x167b, 0x4001) }, + /* EnGenius */ +- { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1740, 0x9801) }, + /* I-O DATA */ +- { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x04bb, 0x0944) }, ++ /* Linksys */ ++ { USB_DEVICE(0x13b1, 0x002f) }, ++ { USB_DEVICE(0x1737, 0x0079) }, + /* Ralink */ +- { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x148f, 0x3572) }, + /* Sitecom */ +- { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0df6, 0x0041) }, + /* Toshiba */ +- { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0930, 0x0a07) }, + /* Zinwell */ +- { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x5a57, 0x0284) }, + #endif + #ifdef CONFIG_RT2800USB_UNKNOWN + /* + * Unclear what kind of devices these are (they aren't supported by the + * vendor linux driver). + */ ++ /* Abocom */ ++ { USB_DEVICE(0x07b8, 0x3073) }, ++ { USB_DEVICE(0x07b8, 0x3074) }, ++ /* Alpha Networks */ ++ { USB_DEVICE(0x14b2, 0x3c08) }, ++ { USB_DEVICE(0x14b2, 0x3c11) }, + /* Amigo */ +- { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0e0b, 0x9031) }, ++ { USB_DEVICE(0x0e0b, 0x9041) }, + /* ASUS */ +- { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0b05, 0x166a) }, ++ { USB_DEVICE(0x0b05, 0x1760) }, ++ { USB_DEVICE(0x0b05, 0x1761) }, ++ { USB_DEVICE(0x0b05, 0x1790) }, ++ { USB_DEVICE(0x0b05, 0x179d) }, + /* AzureWave */ +- { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x13d3, 0x3322), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x13d3, 0x3262) }, ++ { USB_DEVICE(0x13d3, 0x3284) }, ++ { USB_DEVICE(0x13d3, 0x3322) }, + /* Belkin */ +- { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x050d, 0x1003) }, ++ { USB_DEVICE(0x050d, 0x825a) }, + /* Buffalo */ +- { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0411, 0x0148), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0411, 0x0150), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x0411, 0x015d), USB_DEVICE_DATA(&rt2800usb_ops) }, +- /* Conceptronic */ +- { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0411, 0x012e) }, ++ { USB_DEVICE(0x0411, 0x0148) }, ++ { USB_DEVICE(0x0411, 0x0150) }, ++ { USB_DEVICE(0x0411, 0x015d) }, + /* Corega */ +- { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x07aa, 0x0041) }, ++ { USB_DEVICE(0x07aa, 0x0042) }, ++ { USB_DEVICE(0x18c5, 0x0008) }, + /* D-Link */ +- { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x07d1, 0x3c17), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x07d1, 0x3c0b) }, ++ { USB_DEVICE(0x07d1, 0x3c13) }, ++ { USB_DEVICE(0x07d1, 0x3c15) }, ++ { USB_DEVICE(0x07d1, 0x3c17) }, ++ { USB_DEVICE(0x2001, 0x3c17) }, + /* Edimax */ +- { USB_DEVICE(0x7392, 0x4085), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x7392, 0x4085) }, ++ { USB_DEVICE(0x7392, 0x7722) }, + /* Encore */ +- { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x203d, 0x14a1) }, + /* Gemtek */ +- { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x15a9, 0x0010) }, + /* Gigabyte */ +- { USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1044, 0x800c) }, ++ /* Huawei */ ++ { USB_DEVICE(0x148f, 0xf101) }, ++ /* I-O DATA */ ++ { USB_DEVICE(0x04bb, 0x094b) }, + /* LevelOne */ +- { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1740, 0x0605) }, ++ { USB_DEVICE(0x1740, 0x0615) }, + /* Linksys */ +- { USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1737, 0x0078), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1737, 0x0077) }, ++ { USB_DEVICE(0x1737, 0x0078) }, ++ /* Logitec */ ++ { USB_DEVICE(0x0789, 0x0168) }, ++ { USB_DEVICE(0x0789, 0x0169) }, + /* Motorola */ +- { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x100d, 0x9032) }, + /* Ovislink */ +- { USB_DEVICE(0x1b75, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1b75, 0x3071) }, ++ { USB_DEVICE(0x1b75, 0x3072) }, + /* Pegatron */ +- { USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x05a6, 0x0101) }, ++ { USB_DEVICE(0x1d4d, 0x0002) }, ++ { USB_DEVICE(0x1d4d, 0x0010) }, + /* Planex */ +- { USB_DEVICE(0x2019, 0x5201), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x2019, 0x5201) }, ++ { USB_DEVICE(0x2019, 0xab24) }, + /* Qcom */ +- { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x18e8, 0x6259) }, ++ /* RadioShack */ ++ { USB_DEVICE(0x08b9, 0x1197) }, ++ /* Sitecom */ ++ { USB_DEVICE(0x0df6, 0x003c) }, ++ { USB_DEVICE(0x0df6, 0x004a) }, ++ { USB_DEVICE(0x0df6, 0x004d) }, ++ { USB_DEVICE(0x0df6, 0x0053) }, ++ { USB_DEVICE(0x0df6, 0x0060) }, ++ { USB_DEVICE(0x0df6, 0x0062) }, + /* SMC */ +- { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x083a, 0xd522), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x083a, 0xf511), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x083a, 0xa512) }, ++ { USB_DEVICE(0x083a, 0xc522) }, ++ { USB_DEVICE(0x083a, 0xd522) }, ++ { USB_DEVICE(0x083a, 0xf511) }, + /* Sweex */ +- { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) }, +- { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x177f, 0x0153) }, ++ { USB_DEVICE(0x177f, 0x0313) }, + /* Zyxel */ +- { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0586, 0x341a) }, + #endif + { 0, } + }; +@@ -995,10 +1109,16 @@ + MODULE_FIRMWARE(FIRMWARE_RT2870); + MODULE_LICENSE("GPL"); + ++static int rt2800usb_probe(struct usb_interface *usb_intf, ++ const struct usb_device_id *id) ++{ ++ return rt2x00usb_probe(usb_intf, &rt2800usb_ops); ++} ++ + static struct usb_driver rt2800usb_driver = { + .name = KBUILD_MODNAME, + .id_table = rt2800usb_device_table, +- .probe = rt2x00usb_probe, ++ .probe = rt2800usb_probe, + .disconnect = rt2x00usb_disconnect, + .suspend = rt2x00usb_suspend, + .resume = rt2x00usb_resume, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00config.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00config.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00config.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00config.c 2011-05-05 23:29:46.061448823 +0200 +@@ -100,6 +100,10 @@ + erp.basic_rates = bss_conf->basic_rates; + erp.beacon_int = bss_conf->beacon_int; + ++ /* Update the AID, this is needed for dynamic PS support */ ++ rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0; ++ rt2x00dev->last_beacon = bss_conf->timestamp; ++ + /* Update global beacon interval time, this is needed for PS support */ + rt2x00dev->beacon_int = bss_conf->beacon_int; + +@@ -109,15 +113,6 @@ + rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp, changed); + } + +-static inline +-enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant, +- enum antenna default_ant) +-{ +- if (current_ant != ANTENNA_SW_DIVERSITY) +- return current_ant; +- return (default_ant != ANTENNA_SW_DIVERSITY) ? default_ant : ANTENNA_B; +-} +- + void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, + struct antenna_setup config) + { +@@ -126,19 +121,35 @@ + struct antenna_setup *active = &rt2x00dev->link.ant.active; + + /* +- * Failsafe: Make sure we are not sending the +- * ANTENNA_SW_DIVERSITY state to the driver. +- * If that happens, fallback to hardware defaults, +- * or our own default. +- */ +- if (!(ant->flags & ANTENNA_RX_DIVERSITY)) +- config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx); +- else if (config.rx == ANTENNA_SW_DIVERSITY) ++ * When the caller tries to send the SW diversity, ++ * we must update the ANTENNA_RX_DIVERSITY flag to ++ * enable the antenna diversity in the link tuner. ++ * ++ * Secondly, we must guarentee we never send the ++ * software antenna diversity command to the driver. ++ */ ++ if (!(ant->flags & ANTENNA_RX_DIVERSITY)) { ++ if (config.rx == ANTENNA_SW_DIVERSITY) { ++ ant->flags |= ANTENNA_RX_DIVERSITY; ++ ++ if (def->rx == ANTENNA_SW_DIVERSITY) ++ config.rx = ANTENNA_B; ++ else ++ config.rx = def->rx; ++ } ++ } else if (config.rx == ANTENNA_SW_DIVERSITY) + config.rx = active->rx; + +- if (!(ant->flags & ANTENNA_TX_DIVERSITY)) +- config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx); +- else if (config.tx == ANTENNA_SW_DIVERSITY) ++ if (!(ant->flags & ANTENNA_TX_DIVERSITY)) { ++ if (config.tx == ANTENNA_SW_DIVERSITY) { ++ ant->flags |= ANTENNA_TX_DIVERSITY; ++ ++ if (def->tx == ANTENNA_SW_DIVERSITY) ++ config.tx = ANTENNA_B; ++ else ++ config.tx = def->tx; ++ } ++ } else if (config.tx == ANTENNA_SW_DIVERSITY) + config.tx = active->tx; + + /* +@@ -163,12 +174,43 @@ + rt2x00queue_start_queue(rt2x00dev->rx); + } + ++static u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, ++ struct ieee80211_conf *conf) ++{ ++ struct hw_mode_spec *spec = &rt2x00dev->spec; ++ int center_channel; ++ u16 i; ++ ++ /* ++ * Initialize center channel to current channel. ++ */ ++ center_channel = spec->channels[conf->channel->hw_value].channel; ++ ++ /* ++ * Adjust center channel to HT40+ and HT40- operation. ++ */ ++ if (conf_is_ht40_plus(conf)) ++ center_channel += 2; ++ else if (conf_is_ht40_minus(conf)) ++ center_channel -= (center_channel == 14) ? 1 : 2; ++ ++ for (i = 0; i < spec->num_channels; i++) ++ if (spec->channels[i].channel == center_channel) ++ return i; ++ ++ WARN_ON(1); ++ return conf->channel->hw_value; ++} ++ + void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + unsigned int ieee80211_flags) + { + struct rt2x00lib_conf libconf; + u16 hw_value; ++ u16 autowake_timeout; ++ u16 beacon_int; ++ u16 beacon_diff; + + memset(&libconf, 0, sizeof(libconf)); + +@@ -176,10 +218,10 @@ + + if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { + if (conf_is_ht40(conf)) { +- __set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); ++ set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); + hw_value = rt2x00ht_center_channel(rt2x00dev, conf); + } else { +- __clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); ++ clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); + hw_value = conf->channel->hw_value; + } + +@@ -192,6 +234,10 @@ + sizeof(libconf.channel)); + } + ++ if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && ++ (ieee80211_flags & IEEE80211_CONF_CHANGE_PS)) ++ cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); ++ + /* + * Start configuration. + */ +@@ -204,6 +250,26 @@ + if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) + rt2x00link_reset_tuner(rt2x00dev, false); + ++ if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && ++ (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) && ++ (conf->flags & IEEE80211_CONF_PS)) { ++ beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon; ++ beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int); ++ ++ if (beacon_diff > beacon_int) ++ beacon_diff = 0; ++ ++ autowake_timeout = (conf->max_sleep_period * beacon_int) - beacon_diff; ++ queue_delayed_work(rt2x00dev->workqueue, ++ &rt2x00dev->autowakeup_work, ++ autowake_timeout - 15); ++ } ++ ++ if (conf->flags & IEEE80211_CONF_PS) ++ set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); ++ else ++ clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); ++ + rt2x00dev->curr_band = conf->channel->band; + rt2x00dev->curr_freq = conf->channel->center_freq; + rt2x00dev->tx_power = conf->power_level; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00crypto.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00crypto.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00crypto.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00crypto.c 2011-05-05 23:29:46.088449151 +0200 +@@ -52,7 +52,7 @@ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; + +- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key) ++ if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !hw_key) + return; + + __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); +@@ -80,7 +80,7 @@ + struct ieee80211_key_conf *key = tx_info->control.hw_key; + unsigned int overhead = 0; + +- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key) ++ if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !key) + return overhead; + + /* +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00debug.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00debug.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00debug.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00debug.c 2011-05-05 23:29:46.105449355 +0200 +@@ -63,7 +63,8 @@ + * - driver folder + * - driver file + * - chipset file +- * - device flags file ++ * - device state flags file ++ * - device capability flags file + * - register folder + * - csr offset/value files + * - eeprom offset/value files +@@ -78,6 +79,7 @@ + struct dentry *driver_entry; + struct dentry *chipset_entry; + struct dentry *dev_flags; ++ struct dentry *cap_flags; + struct dentry *register_folder; + struct dentry *csr_off_entry; + struct dentry *csr_val_entry; +@@ -553,6 +555,35 @@ + .llseek = default_llseek, + }; + ++static ssize_t rt2x00debug_read_cap_flags(struct file *file, ++ char __user *buf, ++ size_t length, ++ loff_t *offset) ++{ ++ struct rt2x00debug_intf *intf = file->private_data; ++ char line[16]; ++ size_t size; ++ ++ if (*offset) ++ return 0; ++ ++ size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->cap_flags); ++ ++ if (copy_to_user(buf, line, size)) ++ return -EFAULT; ++ ++ *offset += size; ++ return size; ++} ++ ++static const struct file_operations rt2x00debug_fop_cap_flags = { ++ .owner = THIS_MODULE, ++ .read = rt2x00debug_read_cap_flags, ++ .open = rt2x00debug_file_open, ++ .release = rt2x00debug_file_release, ++ .llseek = default_llseek, ++}; ++ + static struct dentry *rt2x00debug_create_file_driver(const char *name, + struct rt2x00debug_intf + *intf, +@@ -568,7 +599,6 @@ + blob->data = data; + data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name); + data += sprintf(data, "version:\t%s\n", DRV_VERSION); +- data += sprintf(data, "compiled:\t%s %s\n", __DATE__, __TIME__); + blob->size = strlen(blob->data); + + return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob); +@@ -653,6 +683,12 @@ + if (IS_ERR(intf->dev_flags) || !intf->dev_flags) + goto exit; + ++ intf->cap_flags = debugfs_create_file("cap_flags", S_IRUSR, ++ intf->driver_folder, intf, ++ &rt2x00debug_fop_cap_flags); ++ if (IS_ERR(intf->cap_flags) || !intf->cap_flags) ++ goto exit; ++ + intf->register_folder = + debugfs_create_dir("register", intf->driver_folder); + if (IS_ERR(intf->register_folder) || !intf->register_folder) +@@ -706,7 +742,7 @@ + intf, &rt2x00debug_fop_queue_stats); + + #ifdef CONFIG_RT2X00_LIB_CRYPTO +- if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) ++ if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) + intf->crypto_stats_entry = + debugfs_create_file("crypto", S_IRUGO, intf->queue_folder, + intf, &rt2x00debug_fop_crypto_stats); +@@ -744,6 +780,7 @@ + debugfs_remove(intf->csr_off_entry); + debugfs_remove(intf->register_folder); + debugfs_remove(intf->dev_flags); ++ debugfs_remove(intf->cap_flags); + debugfs_remove(intf->chipset_entry); + debugfs_remove(intf->driver_entry); + debugfs_remove(intf->driver_folder); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00dev.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00dev.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00dev.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00dev.c 2011-05-05 23:29:46.084449101 +0200 +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include "rt2x00.h" + #include "rt2x00lib.h" +@@ -70,6 +71,7 @@ + */ + rt2x00queue_start_queues(rt2x00dev); + rt2x00link_start_tuner(rt2x00dev); ++ rt2x00link_start_agc(rt2x00dev); + + /* + * Start watchdog monitoring. +@@ -92,6 +94,7 @@ + /* + * Stop all queues + */ ++ rt2x00link_stop_agc(rt2x00dev); + rt2x00link_stop_tuner(rt2x00dev); + rt2x00queue_stop_queues(rt2x00dev); + rt2x00queue_flush_queues(rt2x00dev, true); +@@ -138,6 +141,16 @@ + rt2x00dev); + } + ++static void rt2x00lib_autowakeup(struct work_struct *work) ++{ ++ struct rt2x00_dev *rt2x00dev = ++ container_of(work, struct rt2x00_dev, autowakeup_work.work); ++ ++ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) ++ ERROR(rt2x00dev, "Device failed to wakeup.\n"); ++ clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); ++} ++ + /* + * Interrupt context handlers. + */ +@@ -197,7 +210,7 @@ + * here as they will fetch the next beacon directly prior to + * transmission. + */ +- if (test_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags)) ++ if (test_bit(CAPABILITY_PRE_TBTT_INTERRUPT, &rt2x00dev->cap_flags)) + return; + + /* fetch next beacon */ +@@ -222,7 +235,7 @@ + void rt2x00lib_dmastart(struct queue_entry *entry) + { + set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); +- rt2x00queue_index_inc(entry->queue, Q_INDEX); ++ rt2x00queue_index_inc(entry, Q_INDEX); + } + EXPORT_SYMBOL_GPL(rt2x00lib_dmastart); + +@@ -230,7 +243,7 @@ + { + set_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags); + clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); +- rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE); ++ rt2x00queue_index_inc(entry, Q_INDEX_DMA_DONE); + } + EXPORT_SYMBOL_GPL(rt2x00lib_dmadone); + +@@ -268,7 +281,7 @@ + /* + * Remove L2 padding which was added during + */ +- if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) ++ if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags)) + rt2x00queue_remove_l2pad(entry->skb, header_length); + + /* +@@ -277,7 +290,7 @@ + * mac80211 will expect the same data to be present it the + * frame as it was passed to us. + */ +- if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) ++ if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) + rt2x00crypto_tx_insert_iv(entry->skb, header_length); + + /* +@@ -350,10 +363,14 @@ + * which would allow the rc algorithm to better decide on + * which rates are suitable. + */ +- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { ++ if (test_bit(TXDONE_AMPDU, &txdesc->flags) || ++ tx_info->flags & IEEE80211_TX_CTL_AMPDU) { + tx_info->flags |= IEEE80211_TX_STAT_AMPDU; + tx_info->status.ampdu_len = 1; + tx_info->status.ampdu_ack_len = success ? 1 : 0; ++ ++ if (!success) ++ tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + } + + if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { +@@ -370,7 +387,7 @@ + * send the status report back. + */ + if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) { +- if (test_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags)) ++ if (test_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags)) + ieee80211_tx_status(rt2x00dev->hw, entry->skb); + else + ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb); +@@ -385,7 +402,7 @@ + + rt2x00dev->ops->lib->clear_entry(entry); + +- rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); ++ rt2x00queue_index_inc(entry, Q_INDEX_DONE); + + /* + * If the data queue was below the threshold before the txdone +@@ -409,6 +426,77 @@ + } + EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo); + ++static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie) ++{ ++ struct ieee80211_mgmt *mgmt = (void *)data; ++ u8 *pos, *end; ++ ++ pos = (u8 *)mgmt->u.beacon.variable; ++ end = data + len; ++ while (pos < end) { ++ if (pos + 2 + pos[1] > end) ++ return NULL; ++ ++ if (pos[0] == ie) ++ return pos; ++ ++ pos += 2 + pos[1]; ++ } ++ ++ return NULL; ++} ++ ++static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, ++ struct sk_buff *skb, ++ struct rxdone_entry_desc *rxdesc) ++{ ++ struct ieee80211_hdr *hdr = (void *) skb->data; ++ struct ieee80211_tim_ie *tim_ie; ++ u8 *tim; ++ u8 tim_len; ++ bool cam; ++ ++ /* If this is not a beacon, or if mac80211 has no powersaving ++ * configured, or if the device is already in powersaving mode ++ * we can exit now. */ ++ if (likely(!ieee80211_is_beacon(hdr->frame_control) || ++ !(rt2x00dev->hw->conf.flags & IEEE80211_CONF_PS))) ++ return; ++ ++ /* min. beacon length + FCS_LEN */ ++ if (skb->len <= 40 + FCS_LEN) ++ return; ++ ++ /* and only beacons from the associated BSSID, please */ ++ if (!(rxdesc->dev_flags & RXDONE_MY_BSS) || ++ !rt2x00dev->aid) ++ return; ++ ++ rt2x00dev->last_beacon = jiffies; ++ ++ tim = rt2x00lib_find_ie(skb->data, skb->len - FCS_LEN, WLAN_EID_TIM); ++ if (!tim) ++ return; ++ ++ if (tim[1] < sizeof(*tim_ie)) ++ return; ++ ++ tim_len = tim[1]; ++ tim_ie = (struct ieee80211_tim_ie *) &tim[2]; ++ ++ /* Check whenever the PHY can be turned off again. */ ++ ++ /* 1. What about buffered unicast traffic for our AID? */ ++ cam = ieee80211_check_tim(tim_ie, tim_len, rt2x00dev->aid); ++ ++ /* 2. Maybe the AP wants to send multicast/broadcast data? */ ++ cam |= (tim_ie->bitmap_ctrl & 0x01); ++ ++ if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) ++ rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, ++ IEEE80211_CONF_CHANGE_PS); ++} ++ + static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, + struct rxdone_entry_desc *rxdesc) + { +@@ -511,8 +599,6 @@ + (rxdesc.size > header_length) && + (rxdesc.dev_flags & RXDONE_L2PAD)) + rt2x00queue_remove_l2pad(entry->skb, header_length); +- else +- rt2x00queue_align_payload(entry->skb, header_length); + + /* Trim buffer to correct size */ + skb_trim(entry->skb, rxdesc.size); +@@ -526,6 +612,12 @@ + rxdesc.flags |= RX_FLAG_HT; + + /* ++ * Check if this is a beacon, and more frames have been ++ * buffered while we were in powersaving mode. ++ */ ++ rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc); ++ ++ /* + * Update extra components + */ + rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc); +@@ -554,7 +646,7 @@ + + submit_entry: + entry->flags = 0; +- rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); ++ rt2x00queue_index_inc(entry, Q_INDEX_DONE); + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2x00dev->ops->lib->clear_entry(entry); +@@ -801,23 +893,28 @@ + /* + * Take TX headroom required for alignment into account. + */ +- if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) ++ if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags)) + rt2x00dev->hw->extra_tx_headroom += RT2X00_L2PAD_SIZE; +- else if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) ++ else if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) + rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE; + + /* + * Allocate tx status FIFO for driver use. + */ +- if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) { ++ if (test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags)) { + /* +- * Allocate txstatus fifo and tasklet, we use a size of 512 +- * for the kfifo which is big enough to store 512/4=128 tx +- * status reports. In the worst case (tx status for all tx +- * queues gets reported before we've got a chance to handle +- * them) 24*4=384 tx status reports need to be cached. ++ * Allocate the txstatus fifo. In the worst case the tx ++ * status fifo has to hold the tx status of all entries ++ * in all tx queues. Hence, calculate the kfifo size as ++ * tx_queues * entry_num and round up to the nearest ++ * power of 2. + */ +- status = kfifo_alloc(&rt2x00dev->txstatus_fifo, 512, ++ int kfifo_size = ++ roundup_pow_of_two(rt2x00dev->ops->tx_queues * ++ rt2x00dev->ops->tx->entry_num * ++ sizeof(u32)); ++ ++ status = kfifo_alloc(&rt2x00dev->txstatus_fifo, kfifo_size, + GFP_KERNEL); + if (status) + return status; +@@ -1007,6 +1104,7 @@ + } + + INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); ++ INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); + + /* + * Let the driver probe the device to detect the capabilities. +@@ -1061,6 +1159,7 @@ + /* + * Stop all work. + */ ++ del_timer_sync(&rt2x00dev->txstatus_timer); + cancel_work_sync(&rt2x00dev->intf_work); + if (rt2x00_is_usb(rt2x00dev)) { + cancel_work_sync(&rt2x00dev->rxdone_work); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00firmware.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00firmware.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00firmware.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00firmware.c 2011-05-05 23:29:46.042448595 +0200 +@@ -99,7 +99,7 @@ + { + int retval; + +- if (!test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) ++ if (!test_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags)) + return 0; + + if (!rt2x00dev->fw) { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00.h +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00.h 2011-05-05 23:29:46.060448811 +0200 +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #include + +@@ -348,6 +349,11 @@ + * to bring the device/driver back into the desired state. + */ + struct delayed_work watchdog_work; ++ ++ /* ++ * Work structure for scheduling periodic AGC adjustments. ++ */ ++ struct delayed_work agc_work; + }; + + enum rt2x00_delayed_flags { +@@ -556,6 +562,7 @@ + struct link_qual *qual); + void (*link_tuner) (struct rt2x00_dev *rt2x00dev, + struct link_qual *qual, const u32 count); ++ void (*gain_calibration) (struct rt2x00_dev *rt2x00dev); + + /* + * Data queue handlers. +@@ -564,7 +571,8 @@ + void (*start_queue) (struct data_queue *queue); + void (*kick_queue) (struct data_queue *queue); + void (*stop_queue) (struct data_queue *queue); +- void (*flush_queue) (struct data_queue *queue); ++ void (*flush_queue) (struct data_queue *queue, bool drop); ++ void (*tx_dma_done) (struct queue_entry *entry); + + /* + * TX control handlers +@@ -637,11 +645,11 @@ + }; + + /* +- * rt2x00 device flags ++ * rt2x00 state flags + */ +-enum rt2x00_flags { ++enum rt2x00_state_flags { + /* +- * Device state flags ++ * Device flags + */ + DEVICE_STATE_PRESENT, + DEVICE_STATE_REGISTERED_HW, +@@ -651,40 +659,47 @@ + DEVICE_STATE_SCANNING, + + /* +- * Driver requirements ++ * Driver configuration + */ +- DRIVER_REQUIRE_FIRMWARE, +- DRIVER_REQUIRE_BEACON_GUARD, +- DRIVER_REQUIRE_ATIM_QUEUE, +- DRIVER_REQUIRE_DMA, +- DRIVER_REQUIRE_COPY_IV, +- DRIVER_REQUIRE_L2PAD, +- DRIVER_REQUIRE_TXSTATUS_FIFO, +- DRIVER_REQUIRE_TASKLET_CONTEXT, +- DRIVER_REQUIRE_SW_SEQNO, +- DRIVER_REQUIRE_HT_TX_DESC, +- +- /* +- * Driver features +- */ +- CONFIG_SUPPORT_HW_BUTTON, +- CONFIG_SUPPORT_HW_CRYPTO, +- CONFIG_SUPPORT_POWER_LIMIT, +- DRIVER_SUPPORT_CONTROL_FILTERS, +- DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, +- DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, +- DRIVER_SUPPORT_LINK_TUNING, +- DRIVER_SUPPORT_WATCHDOG, ++ CONFIG_CHANNEL_HT40, ++ CONFIG_POWERSAVING, ++}; + ++/* ++ * rt2x00 capability flags ++ */ ++enum rt2x00_capability_flags { + /* +- * Driver configuration ++ * Requirements + */ +- CONFIG_FRAME_TYPE, +- CONFIG_RF_SEQUENCE, +- CONFIG_EXTERNAL_LNA_A, +- CONFIG_EXTERNAL_LNA_BG, +- CONFIG_DOUBLE_ANTENNA, +- CONFIG_CHANNEL_HT40, ++ REQUIRE_FIRMWARE, ++ REQUIRE_BEACON_GUARD, ++ REQUIRE_ATIM_QUEUE, ++ REQUIRE_DMA, ++ REQUIRE_COPY_IV, ++ REQUIRE_L2PAD, ++ REQUIRE_TXSTATUS_FIFO, ++ REQUIRE_TASKLET_CONTEXT, ++ REQUIRE_SW_SEQNO, ++ REQUIRE_HT_TX_DESC, ++ REQUIRE_PS_AUTOWAKE, ++ ++ /* ++ * Capabilities ++ */ ++ CAPABILITY_HW_BUTTON, ++ CAPABILITY_HW_CRYPTO, ++ CAPABILITY_POWER_LIMIT, ++ CAPABILITY_CONTROL_FILTERS, ++ CAPABILITY_CONTROL_FILTER_PSPOLL, ++ CAPABILITY_PRE_TBTT_INTERRUPT, ++ CAPABILITY_LINK_TUNING, ++ CAPABILITY_FRAME_TYPE, ++ CAPABILITY_RF_SEQUENCE, ++ CAPABILITY_EXTERNAL_LNA_A, ++ CAPABILITY_EXTERNAL_LNA_BG, ++ CAPABILITY_DOUBLE_ANTENNA, ++ CAPABILITY_BT_COEXIST, + }; + + /* +@@ -733,13 +748,20 @@ + #endif /* CONFIG_RT2X00_LIB_LEDS */ + + /* +- * Device flags. +- * In these flags the current status and some +- * of the device capabilities are stored. ++ * Device state flags. ++ * In these flags the current status is stored. ++ * Access to these flags should occur atomically. + */ + unsigned long flags; + + /* ++ * Device capabiltiy flags. ++ * In these flags the device/driver capabilities are stored. ++ * Access to these flags should occur non-atomically. ++ */ ++ unsigned long cap_flags; ++ ++ /* + * Device information, Bus IRQ and name (PCI, SoC) + */ + int irq; +@@ -855,10 +877,20 @@ + u8 calibration[2]; + + /* ++ * Association id. ++ */ ++ u16 aid; ++ ++ /* + * Beacon interval. + */ + u16 beacon_int; + ++ /** ++ * Timestamp of last received beacon ++ */ ++ unsigned long last_beacon; ++ + /* + * Low level statistics which will have + * to be kept up to date while device is running. +@@ -887,6 +919,11 @@ + struct work_struct txdone_work; + + /* ++ * Powersaving work ++ */ ++ struct delayed_work autowakeup_work; ++ ++ /* + * Data queue arrays for RX, TX, Beacon and ATIM. + */ + unsigned int data_queues; +@@ -906,6 +943,11 @@ + DECLARE_KFIFO_PTR(txstatus_fifo, u32); + + /* ++ * Timer to ensure tx status reports are read (rt2800usb). ++ */ ++ struct timer_list txstatus_timer; ++ ++ /* + * Tasklet for processing tx status reports (rt2800pci). + */ + struct tasklet_struct txstatus_tasklet; +@@ -1230,6 +1272,10 @@ + const struct ieee80211_tx_queue_params *params); + void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); + void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop); ++int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); ++int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); ++void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, ++ u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); + + /* + * Driver allocation handlers. +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00ht.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00ht.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00ht.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00ht.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,133 +0,0 @@ +-/* +- Copyright (C) 2004 - 2009 Ivo van Doorn +- +- +- 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. +- */ +- +-/* +- Module: rt2x00lib +- Abstract: rt2x00 HT specific routines. +- */ +- +-#include +-#include +- +-#include "rt2x00.h" +-#include "rt2x00lib.h" +- +-void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, +- struct txentry_desc *txdesc, +- const struct rt2x00_rate *hwrate) +-{ +- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); +- struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; +- +- if (tx_info->control.sta) +- txdesc->u.ht.mpdu_density = +- tx_info->control.sta->ht_cap.ampdu_density; +- +- txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ +- +- txdesc->u.ht.stbc = +- (tx_info->flags & IEEE80211_TX_CTL_STBC) >> IEEE80211_TX_CTL_STBC_SHIFT; +- +- /* +- * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the +- * mcs rate to be used +- */ +- if (txrate->flags & IEEE80211_TX_RC_MCS) { +- txdesc->u.ht.mcs = txrate->idx; +- +- /* +- * MIMO PS should be set to 1 for STA's using dynamic SM PS +- * when using more then one tx stream (>MCS7). +- */ +- if (tx_info->control.sta && txdesc->u.ht.mcs > 7 && +- ((tx_info->control.sta->ht_cap.cap & +- IEEE80211_HT_CAP_SM_PS) >> +- IEEE80211_HT_CAP_SM_PS_SHIFT) == +- WLAN_HT_CAP_SM_PS_DYNAMIC) +- __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); +- } else { +- txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); +- if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) +- txdesc->u.ht.mcs |= 0x08; +- } +- +- /* +- * This frame is eligible for an AMPDU, however, don't aggregate +- * frames that are intended to probe a specific tx rate. +- */ +- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU && +- !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) +- __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags); +- +- /* +- * Set 40Mhz mode if necessary (for legacy rates this will +- * duplicate the frame to both channels). +- */ +- if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH || +- txrate->flags & IEEE80211_TX_RC_DUP_DATA) +- __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags); +- if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) +- __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags); +- +- /* +- * Determine IFS values +- * - Use TXOP_BACKOFF for management frames +- * - Use TXOP_SIFS for fragment bursts +- * - Use TXOP_HTTXOP for everything else +- * +- * Note: rt2800 devices won't use CTS protection (if used) +- * for frames not transmitted with TXOP_HTTXOP +- */ +- if (ieee80211_is_mgmt(hdr->frame_control)) +- txdesc->u.ht.txop = TXOP_BACKOFF; +- else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)) +- txdesc->u.ht.txop = TXOP_SIFS; +- else +- txdesc->u.ht.txop = TXOP_HTTXOP; +-} +- +-u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, +- struct ieee80211_conf *conf) +-{ +- struct hw_mode_spec *spec = &rt2x00dev->spec; +- int center_channel; +- u16 i; +- +- /* +- * Initialize center channel to current channel. +- */ +- center_channel = spec->channels[conf->channel->hw_value].channel; +- +- /* +- * Adjust center channel to HT40+ and HT40- operation. +- */ +- if (conf_is_ht40_plus(conf)) +- center_channel += 2; +- else if (conf_is_ht40_minus(conf)) +- center_channel -= (center_channel == 14) ? 1 : 2; +- +- for (i = 0; i < spec->num_channels; i++) +- if (spec->channels[i].channel == center_channel) +- return i; +- +- WARN_ON(1); +- return conf->channel->hw_value; +-} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00lib.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00lib.h +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00lib.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00lib.h 2011-05-05 23:29:46.080449053 +0200 +@@ -32,6 +32,7 @@ + */ + #define WATCHDOG_INTERVAL round_jiffies_relative(HZ) + #define LINK_TUNE_INTERVAL round_jiffies_relative(HZ) ++#define AGC_INTERVAL round_jiffies_relative(4 * HZ) + + /* + * rt2x00_rate: Per rate device information +@@ -119,16 +120,6 @@ + void rt2x00queue_align_frame(struct sk_buff *skb); + + /** +- * rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary +- * @skb: The skb to align +- * @header_length: Length of 802.11 header +- * +- * Align the 802.11 payload to a 4-byte boundary, this could +- * mean the header is not aligned properly though. +- */ +-void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length); +- +-/** + * rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary + * @skb: The skb to align + * @header_length: Length of 802.11 header +@@ -184,14 +175,14 @@ + + /** + * rt2x00queue_index_inc - Index incrementation function +- * @queue: Queue (&struct data_queue) to perform the action on. ++ * @entry: Queue entry (&struct queue_entry) to perform the action on. + * @index: Index type (&enum queue_index) to perform the action on. + * +- * This function will increase the requested index on the queue, ++ * This function will increase the requested index on the entry's queue, + * it will grab the appropriate locks and handle queue overflow events by + * resetting the index to the start of the queue. + */ +-void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); ++void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index); + + /** + * rt2x00queue_init_queues - Initialize all data queues +@@ -281,6 +272,18 @@ + void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev); + + /** ++ * rt2x00link_start_agc - Start periodic gain calibration ++ * @rt2x00dev: Pointer to &struct rt2x00_dev. ++ */ ++void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev); ++ ++/** ++ * rt2x00link_stop_agc - Stop periodic gain calibration ++ * @rt2x00dev: Pointer to &struct rt2x00_dev. ++ */ ++void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev); ++ ++/** + * rt2x00link_register - Initialize link tuning & watchdog functionality + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * +@@ -385,41 +388,17 @@ + #endif /* CONFIG_RT2X00_LIB_CRYPTO */ + + /* +- * HT handlers. +- */ +-#ifdef CONFIG_RT2X00_LIB_HT +-void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, +- struct txentry_desc *txdesc, +- const struct rt2x00_rate *hwrate); +- +-u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, +- struct ieee80211_conf *conf); +-#else +-static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, +- struct txentry_desc *txdesc, +- const struct rt2x00_rate *hwrate) +-{ +-} +- +-static inline u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, +- struct ieee80211_conf *conf) +-{ +- return conf->channel->hw_value; +-} +-#endif /* CONFIG_RT2X00_LIB_HT */ +- +-/* + * RFkill handlers. + */ + static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) + { +- if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) ++ if (test_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags)) + wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy); + } + + static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) + { +- if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) ++ if (test_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags)) + wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy); + } + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00link.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00link.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00link.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00link.c 2011-05-05 23:29:46.067448897 +0200 +@@ -192,17 +192,7 @@ + /* + * Determine if software diversity is enabled for + * either the TX or RX antenna (or both). +- * Always perform this check since within the link +- * tuner interval the configuration might have changed. + */ +- ant->flags &= ~ANTENNA_RX_DIVERSITY; +- ant->flags &= ~ANTENNA_TX_DIVERSITY; +- +- if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) +- ant->flags |= ANTENNA_RX_DIVERSITY; +- if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) +- ant->flags |= ANTENNA_TX_DIVERSITY; +- + if (!(ant->flags & ANTENNA_RX_DIVERSITY) && + !(ant->flags & ANTENNA_TX_DIVERSITY)) { + ant->flags = 0; +@@ -383,7 +373,7 @@ + * do not support link tuning at all, while other devices can disable + * the feature from the EEPROM. + */ +- if (test_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags)) ++ if (test_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags)) + rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count); + + /* +@@ -413,12 +403,11 @@ + { + struct link *link = &rt2x00dev->link; + +- if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || +- !test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags)) +- return; +- +- ieee80211_queue_delayed_work(rt2x00dev->hw, +- &link->watchdog_work, WATCHDOG_INTERVAL); ++ if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && ++ rt2x00dev->ops->lib->watchdog) ++ ieee80211_queue_delayed_work(rt2x00dev->hw, ++ &link->watchdog_work, ++ WATCHDOG_INTERVAL); + } + + void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev) +@@ -447,8 +436,46 @@ + WATCHDOG_INTERVAL); + } + ++void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev) ++{ ++ struct link *link = &rt2x00dev->link; ++ ++ if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && ++ rt2x00dev->ops->lib->gain_calibration) ++ ieee80211_queue_delayed_work(rt2x00dev->hw, ++ &link->agc_work, ++ AGC_INTERVAL); ++} ++ ++void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev) ++{ ++ cancel_delayed_work_sync(&rt2x00dev->link.agc_work); ++} ++ ++static void rt2x00link_agc(struct work_struct *work) ++{ ++ struct rt2x00_dev *rt2x00dev = ++ container_of(work, struct rt2x00_dev, link.agc_work.work); ++ struct link *link = &rt2x00dev->link; ++ ++ /* ++ * When the radio is shutting down we should ++ * immediately cease the watchdog monitoring. ++ */ ++ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) ++ return; ++ ++ rt2x00dev->ops->lib->gain_calibration(rt2x00dev); ++ ++ if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) ++ ieee80211_queue_delayed_work(rt2x00dev->hw, ++ &link->agc_work, ++ AGC_INTERVAL); ++} ++ + void rt2x00link_register(struct rt2x00_dev *rt2x00dev) + { ++ INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc); + INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog); + INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner); + } +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00mac.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00mac.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00mac.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00mac.c 2011-05-05 23:29:46.038448546 +0200 +@@ -119,7 +119,7 @@ + * Use the ATIM queue if appropriate and present. + */ + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && +- test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) ++ test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) + qid = QID_ATIM; + + queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); +@@ -158,7 +158,7 @@ + return; + + exit_fail: +- ieee80211_stop_queue(rt2x00dev->hw, qid); ++ rt2x00queue_pause_queue(queue); + dev_kfree_skb_any(skb); + } + EXPORT_SYMBOL_GPL(rt2x00mac_tx); +@@ -411,11 +411,11 @@ + * of different types, but has no a separate filter for PS Poll frames, + * FIF_CONTROL flag implies FIF_PSPOLL. + */ +- if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags)) { ++ if (!test_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags)) { + if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL) + *total_flags |= FIF_CONTROL | FIF_PSPOLL; + } +- if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags)) { ++ if (!test_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags)) { + if (*total_flags & FIF_CONTROL) + *total_flags |= FIF_PSPOLL; + } +@@ -496,7 +496,7 @@ + + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return 0; +- else if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) ++ else if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) + return -EOPNOTSUPP; + else if (key->keylen > 32) + return -ENOSPC; +@@ -562,7 +562,7 @@ + void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw) + { + struct rt2x00_dev *rt2x00dev = hw->priv; +- __set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); ++ set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); + rt2x00link_stop_tuner(rt2x00dev); + } + EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start); +@@ -570,7 +570,7 @@ + void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw) + { + struct rt2x00_dev *rt2x00dev = hw->priv; +- __clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); ++ clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); + rt2x00link_start_tuner(rt2x00dev); + } + EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_complete); +@@ -737,3 +737,84 @@ + rt2x00queue_flush_queue(queue, drop); + } + EXPORT_SYMBOL_GPL(rt2x00mac_flush); ++ ++int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) ++{ ++ struct rt2x00_dev *rt2x00dev = hw->priv; ++ struct link_ant *ant = &rt2x00dev->link.ant; ++ struct antenna_setup *def = &rt2x00dev->default_ant; ++ struct antenna_setup setup; ++ ++ // The antenna value is not supposed to be 0, ++ // or exceed the maximum number of antenna's. ++ if (!tx_ant || (tx_ant & ~3) || !rx_ant || (rx_ant & ~3)) ++ return -EINVAL; ++ ++ // When the client tried to configure the antenna to or from ++ // diversity mode, we must reset the default antenna as well ++ // as that controls the diversity switch. ++ if (ant->flags & ANTENNA_TX_DIVERSITY && tx_ant != 3) ++ ant->flags &= ~ANTENNA_TX_DIVERSITY; ++ if (ant->flags & ANTENNA_RX_DIVERSITY && rx_ant != 3) ++ ant->flags &= ~ANTENNA_RX_DIVERSITY; ++ ++ // If diversity is being enabled, check if we need hardware ++ // or software diversity. In the latter case, reset the value, ++ // and make sure we update the antenna flags to have the ++ // link tuner pick up the diversity tuning. ++ if (tx_ant == 3 && def->tx == ANTENNA_SW_DIVERSITY) { ++ tx_ant = ANTENNA_SW_DIVERSITY; ++ ant->flags |= ANTENNA_TX_DIVERSITY; ++ } ++ ++ if (rx_ant == 3 && def->rx == ANTENNA_SW_DIVERSITY) { ++ rx_ant = ANTENNA_SW_DIVERSITY; ++ ant->flags |= ANTENNA_RX_DIVERSITY; ++ } ++ ++ setup.tx = tx_ant; ++ setup.rx = rx_ant; ++ ++ rt2x00lib_config_antenna(rt2x00dev, setup); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(rt2x00mac_set_antenna); ++ ++int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) ++{ ++ struct rt2x00_dev *rt2x00dev = hw->priv; ++ struct link_ant *ant = &rt2x00dev->link.ant; ++ struct antenna_setup *active = &rt2x00dev->link.ant.active; ++ ++ // When software diversity is active, we must report this to the ++ // client and not the current active antenna state. ++ if (ant->flags & ANTENNA_TX_DIVERSITY) ++ *tx_ant = ANTENNA_HW_DIVERSITY; ++ else ++ *tx_ant = active->tx; ++ ++ if (ant->flags & ANTENNA_RX_DIVERSITY) ++ *rx_ant = ANTENNA_HW_DIVERSITY; ++ else ++ *rx_ant = active->rx; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(rt2x00mac_get_antenna); ++ ++void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, ++ u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) ++{ ++ struct rt2x00_dev *rt2x00dev = hw->priv; ++ struct data_queue *queue; ++ ++ tx_queue_for_each(rt2x00dev, queue) { ++ *tx += queue->length; ++ *tx_max += queue->limit; ++ } ++ ++ *rx = rt2x00dev->rx->length; ++ *rx_max = rt2x00dev->rx->limit; ++} ++EXPORT_SYMBOL_GPL(rt2x00mac_get_ringparam); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00pci.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00pci.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00pci.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00pci.c 2011-05-05 23:29:46.023448365 +0200 +@@ -60,14 +60,15 @@ + } + EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); + +-void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) ++bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) + { + struct data_queue *queue = rt2x00dev->rx; + struct queue_entry *entry; + struct queue_entry_priv_pci *entry_priv; + struct skb_frame_desc *skbdesc; ++ int max_rx = 16; + +- while (1) { ++ while (--max_rx) { + entry = rt2x00queue_get_entry(queue, Q_INDEX); + entry_priv = entry->priv_data; + +@@ -93,9 +94,20 @@ + */ + rt2x00lib_rxdone(entry); + } ++ ++ return !max_rx; + } + EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); + ++void rt2x00pci_flush_queue(struct data_queue *queue, bool drop) ++{ ++ unsigned int i; ++ ++ for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++) ++ msleep(10); ++} ++EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue); ++ + /* + * Device initialization handlers. + */ +@@ -239,9 +251,8 @@ + return -ENOMEM; + } + +-int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) ++int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops) + { +- struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data; + struct ieee80211_hw *hw; + struct rt2x00_dev *rt2x00dev; + int retval; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00pci.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00pci.h +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00pci.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00pci.h 2011-05-05 23:29:46.072448957 +0200 +@@ -101,8 +101,21 @@ + /** + * rt2x00pci_rxdone - Handle RX done events + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. ++ * ++ * Returns true if there are still rx frames pending and false if all ++ * pending rx frames were processed. + */ +-void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); ++bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); ++ ++/** ++ * rt2x00pci_flush_queue - Flush data queue ++ * @queue: Data queue to stop ++ * @drop: True to drop all pending frames. ++ * ++ * This will wait for a maximum of 100ms, waiting for the queues ++ * to become empty. ++ */ ++void rt2x00pci_flush_queue(struct data_queue *queue, bool drop); + + /* + * Device initialization handlers. +@@ -113,7 +126,7 @@ + /* + * PCI driver handlers. + */ +-int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id); ++int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops); + void rt2x00pci_remove(struct pci_dev *pci_dev); + #ifdef CONFIG_PM + int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00queue.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00queue.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00queue.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00queue.c 2011-05-05 23:29:46.088449151 +0200 +@@ -60,7 +60,7 @@ + * at least 8 bytes bytes available in headroom for IV/EIV + * and 8 bytes for ICV data as tailroon. + */ +- if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { ++ if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) { + head_size += 8; + tail_size += 8; + } +@@ -86,7 +86,7 @@ + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->entry = entry; + +- if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) { ++ if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) { + skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, + skb->data, + skb->len, +@@ -148,19 +148,6 @@ + skb_trim(skb, frame_length); + } + +-void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length) +-{ +- unsigned int frame_length = skb->len; +- unsigned int align = ALIGN_SIZE(skb, header_length); +- +- if (!align) +- return; +- +- skb_push(skb, align); +- memmove(skb->data, skb->data + align, frame_length); +- skb_trim(skb, frame_length); +-} +- + void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) + { + unsigned int payload_length = skb->len - header_length; +@@ -226,7 +213,7 @@ + + __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); + +- if (!test_bit(DRIVER_REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->flags)) ++ if (!test_bit(REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->cap_flags)) + return; + + /* +@@ -315,6 +302,85 @@ + } + } + ++static void rt2x00queue_create_tx_descriptor_ht(struct queue_entry *entry, ++ struct txentry_desc *txdesc, ++ const struct rt2x00_rate *hwrate) ++{ ++ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); ++ struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; ++ ++ if (tx_info->control.sta) ++ txdesc->u.ht.mpdu_density = ++ tx_info->control.sta->ht_cap.ampdu_density; ++ ++ txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ ++ ++ /* ++ * Only one STBC stream is supported for now. ++ */ ++ if (tx_info->flags & IEEE80211_TX_CTL_STBC) ++ txdesc->u.ht.stbc = 1; ++ ++ /* ++ * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the ++ * mcs rate to be used ++ */ ++ if (txrate->flags & IEEE80211_TX_RC_MCS) { ++ txdesc->u.ht.mcs = txrate->idx; ++ ++ /* ++ * MIMO PS should be set to 1 for STA's using dynamic SM PS ++ * when using more then one tx stream (>MCS7). ++ */ ++ if (tx_info->control.sta && txdesc->u.ht.mcs > 7 && ++ ((tx_info->control.sta->ht_cap.cap & ++ IEEE80211_HT_CAP_SM_PS) >> ++ IEEE80211_HT_CAP_SM_PS_SHIFT) == ++ WLAN_HT_CAP_SM_PS_DYNAMIC) ++ __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); ++ } else { ++ txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); ++ if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ++ txdesc->u.ht.mcs |= 0x08; ++ } ++ ++ /* ++ * This frame is eligible for an AMPDU, however, don't aggregate ++ * frames that are intended to probe a specific tx rate. ++ */ ++ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU && ++ !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) ++ __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags); ++ ++ /* ++ * Set 40Mhz mode if necessary (for legacy rates this will ++ * duplicate the frame to both channels). ++ */ ++ if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH || ++ txrate->flags & IEEE80211_TX_RC_DUP_DATA) ++ __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags); ++ if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) ++ __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags); ++ ++ /* ++ * Determine IFS values ++ * - Use TXOP_BACKOFF for management frames except beacons ++ * - Use TXOP_SIFS for fragment bursts ++ * - Use TXOP_HTTXOP for everything else ++ * ++ * Note: rt2800 devices won't use CTS protection (if used) ++ * for frames not transmitted with TXOP_HTTXOP ++ */ ++ if (ieee80211_is_mgmt(hdr->frame_control) && ++ !ieee80211_is_beacon(hdr->frame_control)) ++ txdesc->u.ht.txop = TXOP_BACKOFF; ++ else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)) ++ txdesc->u.ht.txop = TXOP_SIFS; ++ else ++ txdesc->u.ht.txop = TXOP_HTTXOP; ++} ++ + static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc) + { +@@ -409,8 +475,8 @@ + rt2x00crypto_create_tx_descriptor(entry, txdesc); + rt2x00queue_create_tx_descriptor_seq(entry, txdesc); + +- if (test_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags)) +- rt2x00ht_create_tx_descriptor(entry, txdesc, hwrate); ++ if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags)) ++ rt2x00queue_create_tx_descriptor_ht(entry, txdesc, hwrate); + else + rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate); + } +@@ -449,7 +515,7 @@ + /* + * Map the skb to DMA. + */ +- if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) ++ if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) + rt2x00queue_map_txskb(entry); + + return 0; +@@ -495,8 +561,11 @@ + struct skb_frame_desc *skbdesc; + u8 rate_idx, rate_flags; + +- if (unlikely(rt2x00queue_full(queue))) ++ if (unlikely(rt2x00queue_full(queue))) { ++ ERROR(queue->rt2x00dev, ++ "Dropping frame due to full tx queue %d.\n", queue->qid); + return -ENOBUFS; ++ } + + if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, + &entry->flags))) { +@@ -539,7 +608,7 @@ + */ + if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && + !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { +- if (test_bit(DRIVER_REQUIRE_COPY_IV, &queue->rt2x00dev->flags)) ++ if (test_bit(REQUIRE_COPY_IV, &queue->rt2x00dev->cap_flags)) + rt2x00crypto_tx_copy_iv(skb, &txdesc); + else + rt2x00crypto_tx_remove_iv(skb, &txdesc); +@@ -553,9 +622,9 @@ + * PCI and USB devices, while header alignment only is valid + * for PCI devices. + */ +- if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) ++ if (test_bit(REQUIRE_L2PAD, &queue->rt2x00dev->cap_flags)) + rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length); +- else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) ++ else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags)) + rt2x00queue_align_frame(entry->skb); + + /* +@@ -571,7 +640,7 @@ + + set_bit(ENTRY_DATA_PENDING, &entry->flags); + +- rt2x00queue_index_inc(queue, Q_INDEX); ++ rt2x00queue_index_inc(entry, Q_INDEX); + rt2x00queue_write_tx_descriptor(entry, &txdesc); + rt2x00queue_kick_tx_queue(queue, &txdesc); + +@@ -660,10 +729,12 @@ + return ret; + } + +-void rt2x00queue_for_each_entry(struct data_queue *queue, ++bool rt2x00queue_for_each_entry(struct data_queue *queue, + enum queue_index start, + enum queue_index end, +- void (*fn)(struct queue_entry *entry)) ++ void *data, ++ bool (*fn)(struct queue_entry *entry, ++ void *data)) + { + unsigned long irqflags; + unsigned int index_start; +@@ -674,7 +745,7 @@ + ERROR(queue->rt2x00dev, + "Entry requested from invalid index range (%d - %d)\n", + start, end); +- return; ++ return true; + } + + /* +@@ -693,15 +764,23 @@ + * send out all frames in the correct order. + */ + if (index_start < index_end) { +- for (i = index_start; i < index_end; i++) +- fn(&queue->entries[i]); ++ for (i = index_start; i < index_end; i++) { ++ if (fn(&queue->entries[i], data)) ++ return true; ++ } + } else { +- for (i = index_start; i < queue->limit; i++) +- fn(&queue->entries[i]); ++ for (i = index_start; i < queue->limit; i++) { ++ if (fn(&queue->entries[i], data)) ++ return true; ++ } + +- for (i = 0; i < index_end; i++) +- fn(&queue->entries[i]); ++ for (i = 0; i < index_end; i++) { ++ if (fn(&queue->entries[i], data)) ++ return true; ++ } + } ++ ++ return false; + } + EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry); + +@@ -727,8 +806,9 @@ + } + EXPORT_SYMBOL_GPL(rt2x00queue_get_entry); + +-void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) ++void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index) + { ++ struct data_queue *queue = entry->queue; + unsigned long irqflags; + + if (unlikely(index >= Q_INDEX_MAX)) { +@@ -743,7 +823,7 @@ + if (queue->index[index] >= queue->limit) + queue->index[index] = 0; + +- queue->last_action[index] = jiffies; ++ entry->last_action = jiffies; + + if (index == Q_INDEX) { + queue->length++; +@@ -848,7 +928,6 @@ + + void rt2x00queue_flush_queue(struct data_queue *queue, bool drop) + { +- unsigned int i; + bool started; + bool tx_queue = + (queue->qid == QID_AC_VO) || +@@ -883,20 +962,12 @@ + } + + /* +- * Check if driver supports flushing, we can only guarantee +- * full support for flushing if the driver is able +- * to cancel all pending frames (drop = true). +- */ +- if (drop && queue->rt2x00dev->ops->lib->flush_queue) +- queue->rt2x00dev->ops->lib->flush_queue(queue); +- +- /* +- * When we don't want to drop any frames, or when +- * the driver doesn't fully flush the queue correcly, +- * we must wait for the queue to become empty. ++ * Check if driver supports flushing, if that is the case we can ++ * defer the flushing to the driver. Otherwise we must use the ++ * alternative which just waits for the queue to become empty. + */ +- for (i = 0; !rt2x00queue_empty(queue) && i < 100; i++) +- msleep(10); ++ if (likely(queue->rt2x00dev->ops->lib->flush_queue)) ++ queue->rt2x00dev->ops->lib->flush_queue(queue, drop); + + /* + * The queue flush has failed... +@@ -969,10 +1040,8 @@ + queue->count = 0; + queue->length = 0; + +- for (i = 0; i < Q_INDEX_MAX; i++) { ++ for (i = 0; i < Q_INDEX_MAX; i++) + queue->index[i] = 0; +- queue->last_action[i] = jiffies; +- } + + spin_unlock_irqrestore(&queue->index_lock, irqflags); + } +@@ -1079,7 +1148,7 @@ + if (status) + goto exit; + +- if (test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) { ++ if (test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) { + status = rt2x00queue_alloc_entries(rt2x00dev->atim, + rt2x00dev->ops->atim); + if (status) +@@ -1131,7 +1200,7 @@ + struct data_queue *queue; + enum data_queue_qid qid; + unsigned int req_atim = +- !!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); ++ !!test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); + + /* + * We need the following queues: +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00queue.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00queue.h +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00queue.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00queue.h 2011-05-05 23:29:46.104449343 +0200 +@@ -217,6 +217,7 @@ + TXDONE_FALLBACK, + TXDONE_FAILURE, + TXDONE_EXCESSIVE_RETRY, ++ TXDONE_AMPDU, + }; + + /** +@@ -363,6 +364,7 @@ + * struct queue_entry: Entry inside the &struct data_queue + * + * @flags: Entry flags, see &enum queue_entry_flags. ++ * @last_action: Timestamp of last change. + * @queue: The data queue (&struct data_queue) to which this entry belongs. + * @skb: The buffer which is currently being transmitted (for TX queue), + * or used to directly receive data in (for RX queue). +@@ -372,6 +374,7 @@ + */ + struct queue_entry { + unsigned long flags; ++ unsigned long last_action; + + struct data_queue *queue; + +@@ -462,7 +465,6 @@ + unsigned short threshold; + unsigned short length; + unsigned short index[Q_INDEX_MAX]; +- unsigned long last_action[Q_INDEX_MAX]; + + unsigned short txop; + unsigned short aifs; +@@ -579,16 +581,22 @@ + * @queue: Pointer to @data_queue + * @start: &enum queue_index Pointer to start index + * @end: &enum queue_index Pointer to end index ++ * @data: Data to pass to the callback function + * @fn: The function to call for each &struct queue_entry + * + * This will walk through all entries in the queue, in chronological + * order. This means it will start at the current @start pointer + * and will walk through the queue until it reaches the @end pointer. ++ * ++ * If fn returns true for an entry rt2x00queue_for_each_entry will stop ++ * processing and return true as well. + */ +-void rt2x00queue_for_each_entry(struct data_queue *queue, ++bool rt2x00queue_for_each_entry(struct data_queue *queue, + enum queue_index start, + enum queue_index end, +- void (*fn)(struct queue_entry *entry)); ++ void *data, ++ bool (*fn)(struct queue_entry *entry, ++ void *data)); + + /** + * rt2x00queue_empty - Check if the queue is empty. +@@ -628,22 +636,24 @@ + + /** + * rt2x00queue_status_timeout - Check if a timeout occurred for STATUS reports +- * @queue: Queue to check. ++ * @entry: Queue entry to check. + */ +-static inline int rt2x00queue_status_timeout(struct data_queue *queue) ++static inline int rt2x00queue_status_timeout(struct queue_entry *entry) + { +- return time_after(queue->last_action[Q_INDEX_DMA_DONE], +- queue->last_action[Q_INDEX_DONE] + (HZ / 10)); ++ if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) ++ return false; ++ return time_after(jiffies, entry->last_action + msecs_to_jiffies(100)); + } + + /** +- * rt2x00queue_timeout - Check if a timeout occurred for DMA transfers +- * @queue: Queue to check. ++ * rt2x00queuedma__timeout - Check if a timeout occurred for DMA transfers ++ * @entry: Queue entry to check. + */ +-static inline int rt2x00queue_dma_timeout(struct data_queue *queue) ++static inline int rt2x00queue_dma_timeout(struct queue_entry *entry) + { +- return time_after(queue->last_action[Q_INDEX], +- queue->last_action[Q_INDEX_DMA_DONE] + (HZ / 10)); ++ if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) ++ return false; ++ return time_after(jiffies, entry->last_action + msecs_to_jiffies(100)); + } + + /** +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00usb.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00usb.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00usb.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00usb.c 2011-05-05 23:29:46.078449029 +0200 +@@ -165,6 +165,59 @@ + } + EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read); + ++ ++struct rt2x00_async_read_data { ++ __le32 reg; ++ struct usb_ctrlrequest cr; ++ struct rt2x00_dev *rt2x00dev; ++ bool (*callback)(struct rt2x00_dev *, int, u32); ++}; ++ ++static void rt2x00usb_register_read_async_cb(struct urb *urb) ++{ ++ struct rt2x00_async_read_data *rd = urb->context; ++ if (rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg))) { ++ if (usb_submit_urb(urb, GFP_ATOMIC) < 0) ++ kfree(rd); ++ } else ++ kfree(rd); ++} ++ ++void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, ++ const unsigned int offset, ++ bool (*callback)(struct rt2x00_dev*, int, u32)) ++{ ++ struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); ++ struct urb *urb; ++ struct rt2x00_async_read_data *rd; ++ ++ rd = kmalloc(sizeof(*rd), GFP_ATOMIC); ++ if (!rd) ++ return; ++ ++ urb = usb_alloc_urb(0, GFP_ATOMIC); ++ if (!urb) { ++ kfree(rd); ++ return; ++ } ++ ++ rd->rt2x00dev = rt2x00dev; ++ rd->callback = callback; ++ rd->cr.bRequestType = USB_VENDOR_REQUEST_IN; ++ rd->cr.bRequest = USB_MULTI_READ; ++ rd->cr.wValue = 0; ++ rd->cr.wIndex = cpu_to_le16(offset); ++ rd->cr.wLength = cpu_to_le16(sizeof(u32)); ++ ++ usb_fill_control_urb(urb, usb_dev, usb_rcvctrlpipe(usb_dev, 0), ++ (unsigned char *)(&rd->cr), &rd->reg, sizeof(rd->reg), ++ rt2x00usb_register_read_async_cb, rd); ++ if (usb_submit_urb(urb, GFP_ATOMIC) < 0) ++ kfree(rd); ++ usb_free_urb(urb); ++} ++EXPORT_SYMBOL_GPL(rt2x00usb_register_read_async); ++ + /* + * TX data handlers. + */ +@@ -212,6 +265,9 @@ + if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + return; + ++ if (rt2x00dev->ops->lib->tx_dma_done) ++ rt2x00dev->ops->lib->tx_dma_done(entry); ++ + /* + * Report the frame as DMA done + */ +@@ -227,10 +283,12 @@ + * Schedule the delayed work for reading the TX status + * from the device. + */ +- queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); ++ if (!test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags) || ++ !kfifo_is_empty(&rt2x00dev->txstatus_fifo)) ++ queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); + } + +-static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) ++static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data) + { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); +@@ -240,7 +298,7 @@ + + if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags) || + test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) +- return; ++ return true; + + /* + * USB devices cannot blindly pass the skb->len as the +@@ -261,6 +319,8 @@ + set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); + rt2x00lib_dmadone(entry); + } ++ ++ return false; + } + + /* +@@ -323,7 +383,7 @@ + queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work); + } + +-static void rt2x00usb_kick_rx_entry(struct queue_entry *entry) ++static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void* data) + { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); +@@ -332,7 +392,7 @@ + + if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || + test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) +- return; ++ return true; + + rt2x00lib_dmastart(entry); + +@@ -348,6 +408,8 @@ + set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); + rt2x00lib_dmadone(entry); + } ++ ++ return false; + } + + void rt2x00usb_kick_queue(struct data_queue *queue) +@@ -358,12 +420,18 @@ + case QID_AC_BE: + case QID_AC_BK: + if (!rt2x00queue_empty(queue)) +- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, ++ rt2x00queue_for_each_entry(queue, ++ Q_INDEX_DONE, ++ Q_INDEX, ++ NULL, + rt2x00usb_kick_tx_entry); + break; + case QID_RX: + if (!rt2x00queue_full(queue)) +- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, ++ rt2x00queue_for_each_entry(queue, ++ Q_INDEX_DONE, ++ Q_INDEX, ++ NULL, + rt2x00usb_kick_rx_entry); + break; + default: +@@ -372,14 +440,14 @@ + } + EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue); + +-static void rt2x00usb_flush_entry(struct queue_entry *entry) ++static bool rt2x00usb_flush_entry(struct queue_entry *entry, void* data) + { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; + struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; + + if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) +- return; ++ return true; + + usb_kill_urb(entry_priv->urb); + +@@ -387,17 +455,20 @@ + * Kill guardian urb (if required by driver). + */ + if ((entry->queue->qid == QID_BEACON) && +- (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))) ++ (test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))) + usb_kill_urb(bcn_priv->guardian_urb); ++ ++ return false; + } + +-void rt2x00usb_flush_queue(struct data_queue *queue) ++void rt2x00usb_flush_queue(struct data_queue *queue, bool drop) + { + struct work_struct *completion; + unsigned int i; + +- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, +- rt2x00usb_flush_entry); ++ if (drop) ++ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL, ++ rt2x00usb_flush_entry); + + /* + * Obtain the queue completion handler +@@ -416,7 +487,7 @@ + return; + } + +- for (i = 0; i < 20; i++) { ++ for (i = 0; i < 10; i++) { + /* + * Check if the driver is already done, otherwise we + * have to sleep a little while to give the driver/hw +@@ -456,15 +527,31 @@ + queue_work(queue->rt2x00dev->workqueue, &queue->rt2x00dev->txdone_work); + } + ++static int rt2x00usb_status_timeout(struct data_queue *queue) ++{ ++ struct queue_entry *entry; ++ ++ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); ++ return rt2x00queue_status_timeout(entry); ++} ++ ++static int rt2x00usb_dma_timeout(struct data_queue *queue) ++{ ++ struct queue_entry *entry; ++ ++ entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE); ++ return rt2x00queue_dma_timeout(entry); ++} ++ + void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) + { + struct data_queue *queue; + + tx_queue_for_each(rt2x00dev, queue) { + if (!rt2x00queue_empty(queue)) { +- if (rt2x00queue_dma_timeout(queue)) ++ if (rt2x00usb_dma_timeout(queue)) + rt2x00usb_watchdog_tx_dma(queue); +- if (rt2x00queue_status_timeout(queue)) ++ if (rt2x00usb_status_timeout(queue)) + rt2x00usb_watchdog_tx_status(queue); + } + } +@@ -489,7 +576,7 @@ + entry->flags = 0; + + if (entry->queue->qid == QID_RX) +- rt2x00usb_kick_rx_entry(entry); ++ rt2x00usb_kick_rx_entry(entry, NULL); + } + EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); + +@@ -583,7 +670,7 @@ + * then we are done. + */ + if (queue->qid != QID_BEACON || +- !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) ++ !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)) + return 0; + + for (i = 0; i < queue->limit; i++) { +@@ -618,7 +705,7 @@ + * then we are done. + */ + if (queue->qid != QID_BEACON || +- !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) ++ !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)) + return; + + for (i = 0; i < queue->limit; i++) { +@@ -707,10 +794,9 @@ + } + + int rt2x00usb_probe(struct usb_interface *usb_intf, +- const struct usb_device_id *id) ++ const struct rt2x00_ops *ops) + { + struct usb_device *usb_dev = interface_to_usbdev(usb_intf); +- struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_info; + struct ieee80211_hw *hw; + struct rt2x00_dev *rt2x00dev; + int retval; +@@ -735,6 +821,7 @@ + + INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone); + INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone); ++ init_timer(&rt2x00dev->txstatus_timer); + + retval = rt2x00usb_alloc_reg(rt2x00dev); + if (retval) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00usb.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00usb.h +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt2x00usb.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt2x00usb.h 2011-05-05 23:29:46.088449151 +0200 +@@ -35,12 +35,6 @@ + }) + + /* +- * This variable should be used with the +- * usb_driver structure initialization. +- */ +-#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) +- +-/* + * For USB vendor requests we need to pass a timeout + * time in ms, for this we use the REGISTER_TIMEOUT, + * however when loading firmware a higher value is +@@ -345,6 +339,23 @@ + const struct rt2x00_field32 field, + u32 *reg); + ++/** ++ * rt2x00usb_register_read_async - Asynchronously read 32bit register word ++ * @rt2x00dev: Device pointer, see &struct rt2x00_dev. ++ * @offset: Register offset ++ * @callback: Functon to call when read completes. ++ * ++ * Submit a control URB to read a 32bit register. This safe to ++ * be called from atomic context. The callback will be called ++ * when the URB completes. Otherwise the function is similar ++ * to rt2x00usb_register_read(). ++ * When the callback function returns false, the memory will be cleaned up, ++ * when it returns true, the urb will be fired again. ++ */ ++void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, ++ const unsigned int offset, ++ bool (*callback)(struct rt2x00_dev*, int, u32)); ++ + /* + * Radio handlers + */ +@@ -389,11 +400,13 @@ + /** + * rt2x00usb_flush_queue - Flush data queue + * @queue: Data queue to stop ++ * @drop: True to drop all pending frames. + * +- * This will walk through all entries of the queue and kill all +- * URB's which were send to the device. ++ * This will walk through all entries of the queue and will optionally ++ * kill all URB's which were send to the device, or at least wait until ++ * they have been returned from the device.. + */ +-void rt2x00usb_flush_queue(struct data_queue *queue); ++void rt2x00usb_flush_queue(struct data_queue *queue, bool drop); + + /** + * rt2x00usb_watchdog - Watchdog for USB communication +@@ -416,7 +429,7 @@ + * USB driver handlers. + */ + int rt2x00usb_probe(struct usb_interface *usb_intf, +- const struct usb_device_id *id); ++ const struct rt2x00_ops *ops); + void rt2x00usb_disconnect(struct usb_interface *usb_intf); + #ifdef CONFIG_PM + int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt61pci.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt61pci.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt61pci.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt61pci.c 2011-05-05 23:29:46.086449125 +0200 +@@ -683,7 +683,7 @@ + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529)); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, +- !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); ++ !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags)); + + /* + * Configure the RX antenna. +@@ -811,10 +811,10 @@ + + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { + sel = antenna_sel_a; +- lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); ++ lna = test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); + } else { + sel = antenna_sel_bg; +- lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); ++ lna = test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); + } + + for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) +@@ -834,7 +834,7 @@ + else if (rt2x00_rf(rt2x00dev, RF2527)) + rt61pci_config_antenna_2x(rt2x00dev, ant); + else if (rt2x00_rf(rt2x00dev, RF2529)) { +- if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) ++ if (test_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags)) + rt61pci_config_antenna_2x(rt2x00dev, ant); + else + rt61pci_config_antenna_2529(rt2x00dev, ant); +@@ -848,13 +848,13 @@ + short lna_gain = 0; + + if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) { +- if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) ++ if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } else { +- if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) ++ if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); +@@ -1050,14 +1050,14 @@ + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { + low_bound = 0x28; + up_bound = 0x48; +- if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { ++ if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) { + low_bound += 0x10; + up_bound += 0x10; + } + } else { + low_bound = 0x20; + up_bound = 0x40; +- if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { ++ if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) { + low_bound += 0x10; + up_bound += 0x10; + } +@@ -2260,8 +2260,8 @@ + rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); + } + +-static void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, +- struct rt2x00_field32 irq_field) ++static inline void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, ++ struct rt2x00_field32 irq_field) + { + u32 reg; + +@@ -2313,8 +2313,10 @@ + static void rt61pci_rxdone_tasklet(unsigned long data) + { + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; +- rt2x00pci_rxdone(rt2x00dev); +- rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); ++ if (rt2x00pci_rxdone(rt2x00dev)) ++ rt2x00pci_rxdone(rt2x00dev); ++ else ++ rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); + } + + static void rt61pci_autowake_tasklet(unsigned long data) +@@ -2535,7 +2537,7 @@ + * Determine number of antennas. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) +- __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags); + + /* + * Identify default antenna configuration. +@@ -2549,20 +2551,20 @@ + * Read the Frame type. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE)) +- __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags); + + /* + * Detect if this device has a hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) +- __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); + + /* + * Read frequency offset and RF programming sequence. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ)) +- __set_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags); + + rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); + +@@ -2572,9 +2574,9 @@ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) +- __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) +- __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); + + /* + * When working with a RF2529 chip without double antenna, +@@ -2582,7 +2584,7 @@ + * eeprom word. + */ + if (rt2x00_rf(rt2x00dev, RF2529) && +- !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) { ++ !test_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags)) { + rt2x00dev->default_ant.rx = + ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED); + rt2x00dev->default_ant.tx = +@@ -2797,7 +2799,7 @@ + spec->supported_bands = SUPPORT_BAND_2GHZ; + spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; + +- if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) { ++ if (!test_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags)) { + spec->num_channels = 14; + spec->channels = rf_vals_noseq; + } else { +@@ -2867,16 +2869,16 @@ + * This device has multiple filters for control frames, + * but has no a separate filter for PS Poll frames. + */ +- __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); + + /* + * This device requires firmware and DMA mapped skbs. + */ +- __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); +- __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); ++ __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); + if (!modparam_nohwcrypt) +- __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); +- __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); ++ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); + + /* + * Set the rssi offset. +@@ -2977,6 +2979,9 @@ + .get_tsf = rt61pci_get_tsf, + .rfkill_poll = rt2x00mac_rfkill_poll, + .flush = rt2x00mac_flush, ++ .set_antenna = rt2x00mac_set_antenna, ++ .get_antenna = rt2x00mac_get_antenna, ++ .get_ringparam = rt2x00mac_get_ringparam, + }; + + static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { +@@ -3001,6 +3006,7 @@ + .start_queue = rt61pci_start_queue, + .kick_queue = rt61pci_kick_queue, + .stop_queue = rt61pci_stop_queue, ++ .flush_queue = rt2x00pci_flush_queue, + .write_tx_desc = rt61pci_write_tx_desc, + .write_beacon = rt61pci_write_beacon, + .clear_beacon = rt61pci_clear_beacon, +@@ -3058,11 +3064,11 @@ + */ + static DEFINE_PCI_DEVICE_TABLE(rt61pci_device_table) = { + /* RT2561s */ +- { PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) }, ++ { PCI_DEVICE(0x1814, 0x0301) }, + /* RT2561 v2 */ +- { PCI_DEVICE(0x1814, 0x0302), PCI_DEVICE_DATA(&rt61pci_ops) }, ++ { PCI_DEVICE(0x1814, 0x0302) }, + /* RT2661 */ +- { PCI_DEVICE(0x1814, 0x0401), PCI_DEVICE_DATA(&rt61pci_ops) }, ++ { PCI_DEVICE(0x1814, 0x0401) }, + { 0, } + }; + +@@ -3077,10 +3083,16 @@ + MODULE_FIRMWARE(FIRMWARE_RT2661); + MODULE_LICENSE("GPL"); + ++static int rt61pci_probe(struct pci_dev *pci_dev, ++ const struct pci_device_id *id) ++{ ++ return rt2x00pci_probe(pci_dev, &rt61pci_ops); ++} ++ + static struct pci_driver rt61pci_driver = { + .name = KBUILD_MODNAME, + .id_table = rt61pci_device_table, +- .probe = rt2x00pci_probe, ++ .probe = rt61pci_probe, + .remove = __devexit_p(rt2x00pci_remove), + .suspend = rt2x00pci_suspend, + .resume = rt2x00pci_resume, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt73usb.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt73usb.c +--- linux-2.6.39-rc6/drivers/net/wireless/rt2x00/rt73usb.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rt2x00/rt73usb.c 2011-05-05 23:29:46.029448437 +0200 +@@ -595,7 +595,7 @@ + switch (ant->rx) { + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); +- temp = !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags) ++ temp = !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags) + && (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, temp); + break; +@@ -636,7 +636,7 @@ + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, +- !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); ++ !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags)); + + /* + * Configure the RX antenna. +@@ -709,10 +709,10 @@ + + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { + sel = antenna_sel_a; +- lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); ++ lna = test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); + } else { + sel = antenna_sel_bg; +- lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); ++ lna = test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); + } + + for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) +@@ -740,7 +740,7 @@ + short lna_gain = 0; + + if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) { +- if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) ++ if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); +@@ -930,7 +930,7 @@ + low_bound = 0x28; + up_bound = 0x48; + +- if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { ++ if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) { + low_bound += 0x10; + up_bound += 0x10; + } +@@ -946,7 +946,7 @@ + up_bound = 0x1c; + } + +- if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { ++ if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) { + low_bound += 0x14; + up_bound += 0x10; + } +@@ -1661,7 +1661,7 @@ + } + + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { +- if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { ++ if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) { + if (lna == 3 || lna == 2) + offset += 10; + } else { +@@ -1899,13 +1899,13 @@ + * Read the Frame type. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE)) +- __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags); + + /* + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) +- __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); + + /* + * Read frequency offset. +@@ -1919,8 +1919,8 @@ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA)) { +- __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); +- __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); ++ __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); + } + + /* +@@ -2200,16 +2200,16 @@ + * This device has multiple filters for control frames, + * but has no a separate filter for PS Poll frames. + */ +- __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); + + /* + * This device requires firmware. + */ +- __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); ++ __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); + if (!modparam_nohwcrypt) +- __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); +- __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); +- __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); ++ __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); ++ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); ++ __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); + + /* + * Set the rssi offset. +@@ -2311,6 +2311,9 @@ + .get_tsf = rt73usb_get_tsf, + .rfkill_poll = rt2x00mac_rfkill_poll, + .flush = rt2x00mac_flush, ++ .set_antenna = rt2x00mac_set_antenna, ++ .get_antenna = rt2x00mac_get_antenna, ++ .get_ringparam = rt2x00mac_get_ringparam, + }; + + static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { +@@ -2389,114 +2392,113 @@ + */ + static struct usb_device_id rt73usb_device_table[] = { + /* AboCom */ +- { USB_DEVICE(0x07b8, 0xb21b), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x07b8, 0xb21c), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x07b8, 0xb21e), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x07b8, 0xb21f), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x07b8, 0xb21b) }, ++ { USB_DEVICE(0x07b8, 0xb21c) }, ++ { USB_DEVICE(0x07b8, 0xb21d) }, ++ { USB_DEVICE(0x07b8, 0xb21e) }, ++ { USB_DEVICE(0x07b8, 0xb21f) }, + /* AL */ +- { USB_DEVICE(0x14b2, 0x3c10), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x14b2, 0x3c10) }, + /* Amigo */ +- { USB_DEVICE(0x148f, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0eb0, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x148f, 0x9021) }, ++ { USB_DEVICE(0x0eb0, 0x9021) }, + /* AMIT */ +- { USB_DEVICE(0x18c5, 0x0002), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x18c5, 0x0002) }, + /* Askey */ +- { USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x1690, 0x0722) }, + /* ASUS */ +- { USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x0b05, 0x1723) }, ++ { USB_DEVICE(0x0b05, 0x1724) }, + /* Belkin */ +- { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x050d, 0x905c), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x050d, 0x705a) }, ++ { USB_DEVICE(0x050d, 0x905b) }, ++ { USB_DEVICE(0x050d, 0x905c) }, + /* Billionton */ +- { USB_DEVICE(0x1631, 0xc019), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x1631, 0xc019) }, ++ { USB_DEVICE(0x08dd, 0x0120) }, + /* Buffalo */ +- { USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0411, 0x00d9), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0411, 0x0137), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x0411, 0x00d8) }, ++ { USB_DEVICE(0x0411, 0x00d9) }, ++ { USB_DEVICE(0x0411, 0x00f4) }, ++ { USB_DEVICE(0x0411, 0x0116) }, ++ { USB_DEVICE(0x0411, 0x0119) }, ++ { USB_DEVICE(0x0411, 0x0137) }, + /* CEIVA */ +- { USB_DEVICE(0x178d, 0x02be), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x178d, 0x02be) }, + /* CNet */ +- { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x1371, 0x9022) }, ++ { USB_DEVICE(0x1371, 0x9032) }, + /* Conceptronic */ +- { USB_DEVICE(0x14b2, 0x3c22), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x14b2, 0x3c22) }, + /* Corega */ +- { USB_DEVICE(0x07aa, 0x002e), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x07aa, 0x002e) }, + /* D-Link */ +- { USB_DEVICE(0x07d1, 0x3c03), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x07d1, 0x3c06), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x07d1, 0x3c07), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x07d1, 0x3c03) }, ++ { USB_DEVICE(0x07d1, 0x3c04) }, ++ { USB_DEVICE(0x07d1, 0x3c06) }, ++ { USB_DEVICE(0x07d1, 0x3c07) }, + /* Edimax */ +- { USB_DEVICE(0x7392, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x7392, 0x7618), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x7392, 0x7318) }, ++ { USB_DEVICE(0x7392, 0x7618) }, + /* EnGenius */ +- { USB_DEVICE(0x1740, 0x3701), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x1740, 0x3701) }, + /* Gemtek */ +- { USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x15a9, 0x0004) }, + /* Gigabyte */ +- { USB_DEVICE(0x1044, 0x8008), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x1044, 0x800a), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x1044, 0x8008) }, ++ { USB_DEVICE(0x1044, 0x800a) }, + /* Huawei-3Com */ +- { USB_DEVICE(0x1472, 0x0009), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x1472, 0x0009) }, + /* Hercules */ +- { USB_DEVICE(0x06f8, 0xe002), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x06f8, 0xe010), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x06f8, 0xe020), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x06f8, 0xe002) }, ++ { USB_DEVICE(0x06f8, 0xe010) }, ++ { USB_DEVICE(0x06f8, 0xe020) }, + /* Linksys */ +- { USB_DEVICE(0x13b1, 0x0020), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x13b1, 0x0028), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x13b1, 0x0020) }, ++ { USB_DEVICE(0x13b1, 0x0023) }, ++ { USB_DEVICE(0x13b1, 0x0028) }, + /* MSI */ +- { USB_DEVICE(0x0db0, 0x4600), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x0db0, 0x4600) }, ++ { USB_DEVICE(0x0db0, 0x6877) }, ++ { USB_DEVICE(0x0db0, 0x6874) }, ++ { USB_DEVICE(0x0db0, 0xa861) }, ++ { USB_DEVICE(0x0db0, 0xa874) }, + /* Ovislink */ +- { USB_DEVICE(0x1b75, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x1b75, 0x7318) }, + /* Ralink */ +- { USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0812, 0x3101), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x04bb, 0x093d) }, ++ { USB_DEVICE(0x148f, 0x2573) }, ++ { USB_DEVICE(0x148f, 0x2671) }, ++ { USB_DEVICE(0x0812, 0x3101) }, + /* Qcom */ +- { USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x18e8, 0x6238), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x18e8, 0x6196) }, ++ { USB_DEVICE(0x18e8, 0x6229) }, ++ { USB_DEVICE(0x18e8, 0x6238) }, + /* Samsung */ +- { USB_DEVICE(0x04e8, 0x4471), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x04e8, 0x4471) }, + /* Senao */ +- { USB_DEVICE(0x1740, 0x7100), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x1740, 0x7100) }, + /* Sitecom */ +- { USB_DEVICE(0x0df6, 0x0024), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0df6, 0x0027), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0df6, 0x002f), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0df6, 0x90ac), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x0df6, 0x0024) }, ++ { USB_DEVICE(0x0df6, 0x0027) }, ++ { USB_DEVICE(0x0df6, 0x002f) }, ++ { USB_DEVICE(0x0df6, 0x90ac) }, ++ { USB_DEVICE(0x0df6, 0x9712) }, + /* Surecom */ +- { USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x0769, 0x31f3) }, + /* Tilgin */ +- { USB_DEVICE(0x6933, 0x5001), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x6933, 0x5001) }, + /* Philips */ +- { USB_DEVICE(0x0471, 0x200a), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x0471, 0x200a) }, + /* Planex */ +- { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) }, +- { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x2019, 0xab01) }, ++ { USB_DEVICE(0x2019, 0xab50) }, + /* WideTell */ +- { USB_DEVICE(0x7167, 0x3840), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x7167, 0x3840) }, + /* Zcom */ +- { USB_DEVICE(0x0cde, 0x001c), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x0cde, 0x001c) }, + /* ZyXEL */ +- { USB_DEVICE(0x0586, 0x3415), USB_DEVICE_DATA(&rt73usb_ops) }, ++ { USB_DEVICE(0x0586, 0x3415) }, + { 0, } + }; + +@@ -2508,10 +2510,16 @@ + MODULE_FIRMWARE(FIRMWARE_RT2571); + MODULE_LICENSE("GPL"); + ++static int rt73usb_probe(struct usb_interface *usb_intf, ++ const struct usb_device_id *id) ++{ ++ return rt2x00usb_probe(usb_intf, &rt73usb_ops); ++} ++ + static struct usb_driver rt73usb_driver = { + .name = KBUILD_MODNAME, + .id_table = rt73usb_device_table, +- .probe = rt2x00usb_probe, ++ .probe = rt73usb_probe, + .disconnect = rt2x00usb_disconnect, + .suspend = rt2x00usb_suspend, + .resume = rt2x00usb_resume, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/base.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/base.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/base.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/base.c 2011-05-05 23:29:49.236487185 +0200 +@@ -50,8 +50,9 @@ + *3) functions called by core.c + *4) wq & timer callback functions + *5) frame process functions +- *6) sysfs functions +- *7) ... ++ *6) IOT functions ++ *7) sysfs functions ++ *8) ... + */ + + /********************************************************* +@@ -59,7 +60,7 @@ + * mac80211 init functions + * + *********************************************************/ +-static struct ieee80211_channel rtl_channeltable[] = { ++static struct ieee80211_channel rtl_channeltable_2g[] = { + {.center_freq = 2412, .hw_value = 1,}, + {.center_freq = 2417, .hw_value = 2,}, + {.center_freq = 2422, .hw_value = 3,}, +@@ -76,7 +77,34 @@ + {.center_freq = 2484, .hw_value = 14,}, + }; + +-static struct ieee80211_rate rtl_ratetable[] = { ++static struct ieee80211_channel rtl_channeltable_5g[] = { ++ {.center_freq = 5180, .hw_value = 36,}, ++ {.center_freq = 5200, .hw_value = 40,}, ++ {.center_freq = 5220, .hw_value = 44,}, ++ {.center_freq = 5240, .hw_value = 48,}, ++ {.center_freq = 5260, .hw_value = 52,}, ++ {.center_freq = 5280, .hw_value = 56,}, ++ {.center_freq = 5300, .hw_value = 60,}, ++ {.center_freq = 5320, .hw_value = 64,}, ++ {.center_freq = 5500, .hw_value = 100,}, ++ {.center_freq = 5520, .hw_value = 104,}, ++ {.center_freq = 5540, .hw_value = 108,}, ++ {.center_freq = 5560, .hw_value = 112,}, ++ {.center_freq = 5580, .hw_value = 116,}, ++ {.center_freq = 5600, .hw_value = 120,}, ++ {.center_freq = 5620, .hw_value = 124,}, ++ {.center_freq = 5640, .hw_value = 128,}, ++ {.center_freq = 5660, .hw_value = 132,}, ++ {.center_freq = 5680, .hw_value = 136,}, ++ {.center_freq = 5700, .hw_value = 140,}, ++ {.center_freq = 5745, .hw_value = 149,}, ++ {.center_freq = 5765, .hw_value = 153,}, ++ {.center_freq = 5785, .hw_value = 157,}, ++ {.center_freq = 5805, .hw_value = 161,}, ++ {.center_freq = 5825, .hw_value = 165,}, ++}; ++ ++static struct ieee80211_rate rtl_ratetable_2g[] = { + {.bitrate = 10, .hw_value = 0x00,}, + {.bitrate = 20, .hw_value = 0x01,}, + {.bitrate = 55, .hw_value = 0x02,}, +@@ -91,18 +119,57 @@ + {.bitrate = 540, .hw_value = 0x0b,}, + }; + ++static struct ieee80211_rate rtl_ratetable_5g[] = { ++ {.bitrate = 60, .hw_value = 0x04,}, ++ {.bitrate = 90, .hw_value = 0x05,}, ++ {.bitrate = 120, .hw_value = 0x06,}, ++ {.bitrate = 180, .hw_value = 0x07,}, ++ {.bitrate = 240, .hw_value = 0x08,}, ++ {.bitrate = 360, .hw_value = 0x09,}, ++ {.bitrate = 480, .hw_value = 0x0a,}, ++ {.bitrate = 540, .hw_value = 0x0b,}, ++}; ++ + static const struct ieee80211_supported_band rtl_band_2ghz = { + .band = IEEE80211_BAND_2GHZ, + +- .channels = rtl_channeltable, +- .n_channels = ARRAY_SIZE(rtl_channeltable), ++ .channels = rtl_channeltable_2g, ++ .n_channels = ARRAY_SIZE(rtl_channeltable_2g), + +- .bitrates = rtl_ratetable, +- .n_bitrates = ARRAY_SIZE(rtl_ratetable), ++ .bitrates = rtl_ratetable_2g, ++ .n_bitrates = ARRAY_SIZE(rtl_ratetable_2g), + + .ht_cap = {0}, + }; + ++static struct ieee80211_supported_band rtl_band_5ghz = { ++ .band = IEEE80211_BAND_5GHZ, ++ ++ .channels = rtl_channeltable_5g, ++ .n_channels = ARRAY_SIZE(rtl_channeltable_5g), ++ ++ .bitrates = rtl_ratetable_5g, ++ .n_bitrates = ARRAY_SIZE(rtl_ratetable_5g), ++ ++ .ht_cap = {0}, ++}; ++ ++static const u8 tid_to_ac[] = { ++ 2, /* IEEE80211_AC_BE */ ++ 3, /* IEEE80211_AC_BK */ ++ 3, /* IEEE80211_AC_BK */ ++ 2, /* IEEE80211_AC_BE */ ++ 1, /* IEEE80211_AC_VI */ ++ 1, /* IEEE80211_AC_VI */ ++ 0, /* IEEE80211_AC_VO */ ++ 0, /* IEEE80211_AC_VO */ ++}; ++ ++u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid) ++{ ++ return tid_to_ac[tid]; ++} ++ + static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, + struct ieee80211_sta_ht_cap *ht_cap) + { +@@ -115,6 +182,9 @@ + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU; + ++ if (rtlpriv->rtlhal.disable_amsdu_8k) ++ ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; ++ + /* + *Maximum length of AMPDU that the STA can receive. + *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) +@@ -159,37 +229,99 @@ + + static void _rtl_init_mac80211(struct ieee80211_hw *hw) + { ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct ieee80211_supported_band *sband; + +- /* <1> use mac->bands as mem for hw->wiphy->bands */ +- sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); + +- /* +- * <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] +- * to default value(1T1R) +- */ +- memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz, +- sizeof(struct ieee80211_supported_band)); ++ if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && rtlhal->bandset == ++ BAND_ON_BOTH) { ++ /* 1: 2.4 G bands */ ++ /* <1> use mac->bands as mem for hw->wiphy->bands */ ++ sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); ++ ++ /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] ++ * to default value(1T1R) */ ++ memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz, ++ sizeof(struct ieee80211_supported_band)); ++ ++ /* <3> init ht cap base on ant_num */ ++ _rtl_init_hw_ht_capab(hw, &sband->ht_cap); ++ ++ /* <4> set mac->sband to wiphy->sband */ ++ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; ++ ++ /* 2: 5 G bands */ ++ /* <1> use mac->bands as mem for hw->wiphy->bands */ ++ sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]); ++ ++ /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] ++ * to default value(1T1R) */ ++ memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), &rtl_band_5ghz, ++ sizeof(struct ieee80211_supported_band)); + +- /* <3> init ht cap base on ant_num */ +- _rtl_init_hw_ht_capab(hw, &sband->ht_cap); ++ /* <3> init ht cap base on ant_num */ ++ _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + +- /* <4> set mac->sband to wiphy->sband */ +- hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; ++ /* <4> set mac->sband to wiphy->sband */ ++ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; ++ } else { ++ if (rtlhal->current_bandtype == BAND_ON_2_4G) { ++ /* <1> use mac->bands as mem for hw->wiphy->bands */ ++ sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); ++ ++ /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] ++ * to default value(1T1R) */ ++ memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), ++ &rtl_band_2ghz, ++ sizeof(struct ieee80211_supported_band)); ++ ++ /* <3> init ht cap base on ant_num */ ++ _rtl_init_hw_ht_capab(hw, &sband->ht_cap); ++ ++ /* <4> set mac->sband to wiphy->sband */ ++ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; ++ } else if (rtlhal->current_bandtype == BAND_ON_5G) { ++ /* <1> use mac->bands as mem for hw->wiphy->bands */ ++ sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]); ++ ++ /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] ++ * to default value(1T1R) */ ++ memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), ++ &rtl_band_5ghz, ++ sizeof(struct ieee80211_supported_band)); + ++ /* <3> init ht cap base on ant_num */ ++ _rtl_init_hw_ht_capab(hw, &sband->ht_cap); ++ ++ /* <4> set mac->sband to wiphy->sband */ ++ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; ++ } else { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ++ ("Err BAND %d\n", ++ rtlhal->current_bandtype)); ++ } ++ } + /* <5> set hw caps */ + hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_RX_INCLUDES_FCS | +- IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_AMPDU_AGGREGATION | /*PS*/ +- /*IEEE80211_HW_SUPPORTS_PS | */ +- /*IEEE80211_HW_PS_NULLFUNC_STACK | */ +- /*IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ ++ IEEE80211_HW_BEACON_FILTER | ++ IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0; + ++ /* swlps or hwlps has been set in diff chip in init_sw_vars */ ++ if (rtlpriv->psc.swctrl_lps) ++ hw->flags |= IEEE80211_HW_SUPPORTS_PS | ++ IEEE80211_HW_PS_NULLFUNC_STACK | ++ /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ ++ 0; ++ + hw->wiphy->interface_modes = +- BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); ++ BIT(NL80211_IFTYPE_AP) | ++ BIT(NL80211_IFTYPE_STATION) | ++ BIT(NL80211_IFTYPE_ADHOC); + + hw->wiphy->rts_threshold = 2347; + +@@ -199,9 +331,10 @@ + /* TODO: Correct this value for our hw */ + /* TODO: define these hard code value */ + hw->channel_change_time = 100; +- hw->max_listen_interval = 5; ++ hw->max_listen_interval = 10; + hw->max_rate_tries = 4; + /* hw->max_rates = 1; */ ++ hw->sta_data_size = sizeof(struct rtl_sta_info); + + /* <6> mac address */ + if (is_valid_ether_addr(rtlefuse->dev_addr)) { +@@ -230,6 +363,10 @@ + (void *)rtl_watchdog_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, + (void *)rtl_ips_nic_off_wq_callback); ++ INIT_DELAYED_WORK(&rtlpriv->works.ps_work, ++ (void *)rtl_swlps_wq_callback); ++ INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq, ++ (void *)rtl_swlps_rfon_wq_callback); + + } + +@@ -241,6 +378,8 @@ + + cancel_delayed_work(&rtlpriv->works.watchdog_wq); + cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); ++ cancel_delayed_work(&rtlpriv->works.ps_work); ++ cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); + } + + void rtl_init_rfkill(struct ieee80211_hw *hw) +@@ -251,14 +390,16 @@ + bool blocked; + u8 valid = 0; + +- radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); ++ /*set init state to on */ ++ rtlpriv->rfkill.rfkill_state = 1; ++ wiphy_rfkill_set_hw_state(hw->wiphy, 0); + +- /*set init state to that of switch */ +- rtlpriv->rfkill.rfkill_state = radio_state; +- printk(KERN_INFO "rtlwifi: wireless switch is %s\n", +- rtlpriv->rfkill.rfkill_state ? "on" : "off"); ++ radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); + + if (valid) { ++ printk(KERN_INFO "rtlwifi: wireless switch is %s\n", ++ rtlpriv->rfkill.rfkill_state ? "on" : "off"); ++ + rtlpriv->rfkill.rfkill_state = radio_state; + + blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1; +@@ -308,6 +449,8 @@ + spin_lock_init(&rtlpriv->locks.rf_ps_lock); + spin_lock_init(&rtlpriv->locks.rf_lock); + spin_lock_init(&rtlpriv->locks.lps_lock); ++ spin_lock_init(&rtlpriv->locks.waitq_lock); ++ spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock); + + rtlmac->link_state = MAC80211_NOLINK; + +@@ -327,12 +470,6 @@ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf)); +- rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MGT_FILTER, +- (u8 *) (&mac->rx_mgt_filter)); +- rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CTRL_FILTER, +- (u8 *) (&mac->rx_ctrl_filter)); +- rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_DATA_FILTER, +- (u8 *) (&mac->rx_data_filter)); + } + + /********************************************************* +@@ -359,28 +496,40 @@ + } + + static void _rtl_query_shortgi(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, + struct rtl_tcb_desc *tcb_desc, + struct ieee80211_tx_info *info) + { + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u8 rate_flag = info->control.rates[0].flags; +- ++ u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0; + tcb_desc->use_shortgi = false; + +- if (!mac->ht_enable) ++ if (sta == NULL) ++ return; ++ ++ sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; ++ sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; ++ ++ if (!(sta->ht_cap.ht_supported)) + return; + +- if (!mac->sgi_40 && !mac->sgi_20) ++ if (!sgi_40 && !sgi_20) + return; + +- if ((mac->bw_40 == true) && mac->sgi_40) ++ if (mac->opmode == NL80211_IFTYPE_STATION) ++ bw_40 = mac->bw_40; ++ else if (mac->opmode == NL80211_IFTYPE_AP || ++ mac->opmode == NL80211_IFTYPE_ADHOC) ++ bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; ++ ++ if ((bw_40 == true) && sgi_40) + tcb_desc->use_shortgi = true; +- else if ((mac->bw_40 == false) && mac->sgi_20) ++ else if ((bw_40 == false) && sgi_20) + tcb_desc->use_shortgi = true; + + if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI)) + tcb_desc->use_shortgi = false; +- + } + + static void _rtl_query_protection_mode(struct ieee80211_hw *hw, +@@ -408,19 +557,25 @@ + tcb_desc->rts_enable = true; + tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M]; + } +- + } + + static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, + struct rtl_tcb_desc *tcb_desc) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_sta_info *sta_entry = NULL; ++ u8 ratr_index = 7; + ++ if (sta) { ++ sta_entry = (struct rtl_sta_info *) sta->drv_priv; ++ ratr_index = sta_entry->ratr_index; ++ } + if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) { +- if (mac->opmode == NL80211_IFTYPE_STATION) ++ if (mac->opmode == NL80211_IFTYPE_STATION) { + tcb_desc->ratr_index = 0; +- else if (mac->opmode == NL80211_IFTYPE_ADHOC) { ++ } else if (mac->opmode == NL80211_IFTYPE_ADHOC) { + if (tcb_desc->multicast || tcb_desc->broadcast) { + tcb_desc->hw_rate = + rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M]; +@@ -428,36 +583,61 @@ + } else { + /* TODO */ + } ++ tcb_desc->ratr_index = ratr_index; ++ } else if (mac->opmode == NL80211_IFTYPE_AP) { ++ tcb_desc->ratr_index = ratr_index; + } + } + + if (rtlpriv->dm.useramask) { + /* TODO we will differentiate adhoc and station futrue */ +- tcb_desc->mac_id = 0; ++ if (mac->opmode == NL80211_IFTYPE_STATION) { ++ tcb_desc->mac_id = 0; + +- if ((mac->mode == WIRELESS_MODE_N_24G) || +- (mac->mode == WIRELESS_MODE_N_5G)) { +- tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB; +- } else if (mac->mode & WIRELESS_MODE_G) { +- tcb_desc->ratr_index = RATR_INX_WIRELESS_GB; +- } else if (mac->mode & WIRELESS_MODE_B) { +- tcb_desc->ratr_index = RATR_INX_WIRELESS_B; ++ if (mac->mode == WIRELESS_MODE_N_24G) ++ tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB; ++ else if (mac->mode == WIRELESS_MODE_N_5G) ++ tcb_desc->ratr_index = RATR_INX_WIRELESS_NG; ++ else if (mac->mode & WIRELESS_MODE_G) ++ tcb_desc->ratr_index = RATR_INX_WIRELESS_GB; ++ else if (mac->mode & WIRELESS_MODE_B) ++ tcb_desc->ratr_index = RATR_INX_WIRELESS_B; ++ else if (mac->mode & WIRELESS_MODE_A) ++ tcb_desc->ratr_index = RATR_INX_WIRELESS_G; ++ } else if (mac->opmode == NL80211_IFTYPE_AP || ++ mac->opmode == NL80211_IFTYPE_ADHOC) { ++ if (NULL != sta) { ++ if (sta->aid > 0) ++ tcb_desc->mac_id = sta->aid + 1; ++ else ++ tcb_desc->mac_id = 1; ++ } else { ++ tcb_desc->mac_id = 0; ++ } + } + } + + } + + static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, + struct rtl_tcb_desc *tcb_desc) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + tcb_desc->packet_bw = false; +- +- if (!mac->bw_40 || !mac->ht_enable) ++ if (!sta) + return; +- ++ if (mac->opmode == NL80211_IFTYPE_AP || ++ mac->opmode == NL80211_IFTYPE_ADHOC) { ++ if (!(sta->ht_cap.ht_supported) || ++ !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) ++ return; ++ } else if (mac->opmode == NL80211_IFTYPE_STATION) { ++ if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) ++ return; ++ } + if (tcb_desc->multicast || tcb_desc->broadcast) + return; + +@@ -484,22 +664,21 @@ + + void rtl_get_tcb_desc(struct ieee80211_hw *hw, + struct ieee80211_tx_info *info, ++ struct ieee80211_sta *sta, + struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); ++ struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + struct ieee80211_rate *txrate; + __le16 fc = hdr->frame_control; + +- memset(tcb_desc, 0, sizeof(struct rtl_tcb_desc)); ++ txrate = ieee80211_get_tx_rate(hw, info); ++ tcb_desc->hw_rate = txrate->hw_value; + + if (ieee80211_is_data(fc)) { +- txrate = ieee80211_get_tx_rate(hw, info); +- tcb_desc->hw_rate = txrate->hw_value; +- + /* +- *we set data rate RTL_RC_CCK_RATE1M ++ *we set data rate INX 0 + *in rtl_rc.c if skb is special data or + *mgt which need low data rate. + */ +@@ -508,12 +687,11 @@ + *So tcb_desc->hw_rate is just used for + *special data and mgt frames + */ +- if (tcb_desc->hw_rate < rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]) { ++ if (info->control.rates[0].idx == 0 && ++ ieee80211_is_nullfunc(fc)) { + tcb_desc->use_driver_rate = true; +- tcb_desc->ratr_index = 7; ++ tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; + +- tcb_desc->hw_rate = +- rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; + tcb_desc->disable_ratefallback = 1; + } else { + /* +@@ -523,7 +701,7 @@ + *and N rate will all be controlled by FW + *when tcb_desc->use_driver_rate = false + */ +- if (rtlmac->ht_enable) { ++ if (sta && (sta->ht_cap.ht_supported)) { + tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw); + } else { + if (rtlmac->mode == WIRELESS_MODE_B) { +@@ -541,43 +719,25 @@ + else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr))) + tcb_desc->broadcast = 1; + +- _rtl_txrate_selectmode(hw, tcb_desc); +- _rtl_query_bandwidth_mode(hw, tcb_desc); ++ _rtl_txrate_selectmode(hw, sta, tcb_desc); ++ _rtl_query_bandwidth_mode(hw, sta, tcb_desc); + _rtl_qurey_shortpreamble_mode(hw, tcb_desc, info); +- _rtl_query_shortgi(hw, tcb_desc, info); ++ _rtl_query_shortgi(hw, sta, tcb_desc, info); + _rtl_query_protection_mode(hw, tcb_desc, info); + } else { + tcb_desc->use_driver_rate = true; +- tcb_desc->ratr_index = 7; ++ tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; + tcb_desc->disable_ratefallback = 1; + tcb_desc->mac_id = 0; +- +- tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; ++ tcb_desc->packet_bw = false; + } + } + EXPORT_SYMBOL(rtl_get_tcb_desc); + +-bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) +-{ +- struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +- struct rtl_priv *rtlpriv = rtl_priv(hw); +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); +- __le16 fc = hdr->frame_control; +- +- if (ieee80211_is_auth(fc)) { +- RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); +- rtl_ips_nic_on(hw); +- +- mac->link_state = MAC80211_LINKING; +- } +- +- return true; +-} +- + bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) + { + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); ++ struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + struct rtl_priv *rtlpriv = rtl_priv(hw); + __le16 fc = hdr->frame_control; + u8 *act = (u8 *) (((u8 *) skb->data + MAC80211_3ADDR_LEN)); +@@ -622,22 +782,20 @@ + u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +- __le16 fc = hdr->frame_control; ++ __le16 fc = rtl_get_fc(skb); + u16 ether_type; + u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb); + const struct iphdr *ip; + + if (!ieee80211_is_data(fc)) +- goto end; ++ return false; + +- if (ieee80211_is_nullfunc(fc)) +- return true; + + ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len + + SNAP_SIZE + PROTOC_TYPE_SIZE); + ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE); ++ /* ether_type = ntohs(ether_type); */ + + if (ETH_P_IP == ether_type) { + if (IPPROTO_UDP == ip->protocol) { +@@ -686,7 +844,6 @@ + return true; + } + +-end: + return false; + } + +@@ -695,61 +852,92 @@ + * functions called by core.c + * + *********************************************************/ +-int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, u16 tid, u16 *ssn) ++int rtl_tx_agg_start(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, u16 tid, u16 *ssn) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_sta_info *sta_entry = NULL; + +- RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, +- ("on ra = %pM tid = %d\n", ra, tid)); ++ if (sta == NULL) ++ return -EINVAL; + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + +- if (mac->tids[tid].agg.agg_state != RTL_AGG_OFF) { +- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +- ("Start AGG when state is not RTL_AGG_OFF !\n")); ++ sta_entry = (struct rtl_sta_info *)sta->drv_priv; ++ if (!sta_entry) + return -ENXIO; +- } +- +- tid_data = &mac->tids[tid]; +- *ssn = SEQ_TO_SN(tid_data->seq_number); ++ tid_data = &sta_entry->tids[tid]; + + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, +- ("HW queue is empty tid:%d\n", tid)); +- tid_data->agg.agg_state = RTL_AGG_ON; ++ ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid, ++ tid_data->seq_number)); ++ ++ *ssn = tid_data->seq_number; ++ tid_data->agg.agg_state = RTL_AGG_START; + +- ieee80211_start_tx_ba_cb_irqsafe(mac->vif, ra, tid); ++ ieee80211_start_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid); + + return 0; + } + +-int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 * ra, u16 tid) ++int rtl_tx_agg_stop(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, u16 tid) + { +- int ssn = -1; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_tid_data *tid_data; ++ struct rtl_sta_info *sta_entry = NULL; + +- if (!ra) { ++ if (sta == NULL) ++ return -EINVAL; ++ ++ if (!sta->addr) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n")); + return -EINVAL; + } + ++ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ++ ("on ra = %pM tid = %d\n", sta->addr, tid)); ++ + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + +- if (mac->tids[tid].agg.agg_state != RTL_AGG_ON) +- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +- ("Stopping AGG while state not ON or starting\n")); ++ sta_entry = (struct rtl_sta_info *)sta->drv_priv; ++ tid_data = &sta_entry->tids[tid]; ++ sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP; + +- tid_data = &mac->tids[tid]; +- ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; ++ ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid); + +- mac->tids[tid].agg.agg_state = RTL_AGG_OFF; ++ return 0; ++} + +- ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, ra, tid); ++int rtl_tx_agg_oper(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, u16 tid) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_tid_data *tid_data; ++ struct rtl_sta_info *sta_entry = NULL; ++ ++ if (sta == NULL) ++ return -EINVAL; ++ ++ if (!sta->addr) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n")); ++ return -EINVAL; ++ } ++ ++ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ++ ("on ra = %pM tid = %d\n", sta->addr, tid)); ++ ++ if (unlikely(tid >= MAX_TID_COUNT)) ++ return -EINVAL; ++ ++ sta_entry = (struct rtl_sta_info *)sta->drv_priv; ++ tid_data = &sta_entry->tids[tid]; ++ sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL; + + return 0; + } +@@ -768,18 +956,16 @@ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +- + bool busytraffic = false; + bool higher_busytraffic = false; + bool higher_busyrxtraffic = false; +- bool higher_busytxtraffic = false; +- +- u8 idx = 0; ++ u8 idx, tid; + u32 rx_cnt_inp4eriod = 0; + u32 tx_cnt_inp4eriod = 0; + u32 aver_rx_cnt_inperiod = 0; + u32 aver_tx_cnt_inperiod = 0; +- ++ u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0}; ++ u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0}; + bool enter_ps = false; + + if (is_hal_stop(rtlhal)) +@@ -793,9 +979,6 @@ + mac->cnt_after_linked = 0; + } + +- /* <2> DM */ +- rtlpriv->cfg->ops->dm_watchdog(hw); +- + /* + *<3> to check if traffic busy, if + * busytraffic we don't change channel +@@ -834,8 +1017,27 @@ + /* Extremely high Rx data. */ + if (aver_rx_cnt_inperiod > 5000) + higher_busyrxtraffic = true; ++ } ++ ++ /* check every tid's tx traffic */ ++ for (tid = 0; tid <= 7; tid++) { ++ for (idx = 0; idx <= 2; idx++) ++ rtlpriv->link_info.tidtx_in4period[tid][idx] = ++ rtlpriv->link_info.tidtx_in4period[tid] ++ [idx + 1]; ++ rtlpriv->link_info.tidtx_in4period[tid][3] = ++ rtlpriv->link_info.tidtx_inperiod[tid]; ++ ++ for (idx = 0; idx <= 3; idx++) ++ tidtx_inp4eriod[tid] += ++ rtlpriv->link_info.tidtx_in4period[tid][idx]; ++ aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4; ++ if (aver_tidtx_inperiod[tid] > 5000) ++ rtlpriv->link_info.higher_busytxtraffic[tid] = ++ true; + else +- higher_busytxtraffic = false; ++ rtlpriv->link_info.higher_busytxtraffic[tid] = ++ false; + } + + if (((rtlpriv->link_info.num_rx_inperiod + +@@ -854,11 +1056,15 @@ + + rtlpriv->link_info.num_rx_inperiod = 0; + rtlpriv->link_info.num_tx_inperiod = 0; ++ for (tid = 0; tid <= 7; tid++) ++ rtlpriv->link_info.tidtx_inperiod[tid] = 0; + + rtlpriv->link_info.busytraffic = busytraffic; + rtlpriv->link_info.higher_busytraffic = higher_busytraffic; + rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic; + ++ /* <3> DM */ ++ rtlpriv->cfg->ops->dm_watchdog(hw); + } + + void rtl_watch_dog_timer_callback(unsigned long data) +@@ -875,6 +1081,268 @@ + + /********************************************************* + * ++ * frame process functions ++ * ++ *********************************************************/ ++u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie) ++{ ++ struct ieee80211_mgmt *mgmt = (void *)data; ++ u8 *pos, *end; ++ ++ pos = (u8 *)mgmt->u.beacon.variable; ++ end = data + len; ++ while (pos < end) { ++ if (pos + 2 + pos[1] > end) ++ return NULL; ++ ++ if (pos[0] == ie) ++ return pos; ++ ++ pos += 2 + pos[1]; ++ } ++ return NULL; ++} ++ ++/* when we use 2 rx ants we send IEEE80211_SMPS_OFF */ ++/* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */ ++static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw, ++ enum ieee80211_smps_mode smps, u8 *da, u8 *bssid) ++{ ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ struct sk_buff *skb; ++ struct ieee80211_mgmt *action_frame; ++ ++ /* 27 = header + category + action + smps mode */ ++ skb = dev_alloc_skb(27 + hw->extra_tx_headroom); ++ if (!skb) ++ return NULL; ++ ++ skb_reserve(skb, hw->extra_tx_headroom); ++ action_frame = (void *)skb_put(skb, 27); ++ memset(action_frame, 0, 27); ++ memcpy(action_frame->da, da, ETH_ALEN); ++ memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN); ++ memcpy(action_frame->bssid, bssid, ETH_ALEN); ++ action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | ++ IEEE80211_STYPE_ACTION); ++ action_frame->u.action.category = WLAN_CATEGORY_HT; ++ action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS; ++ switch (smps) { ++ case IEEE80211_SMPS_AUTOMATIC:/* 0 */ ++ case IEEE80211_SMPS_NUM_MODES:/* 4 */ ++ WARN_ON(1); ++ case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/ ++ action_frame->u.action.u.ht_smps.smps_control = ++ WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */ ++ break; ++ case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/ ++ action_frame->u.action.u.ht_smps.smps_control = ++ WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */ ++ break; ++ case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/ ++ action_frame->u.action.u.ht_smps.smps_control = ++ WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */ ++ break; ++ } ++ ++ return skb; ++} ++ ++int rtl_send_smps_action(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, u8 *da, u8 *bssid, ++ enum ieee80211_smps_mode smps) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ struct sk_buff *skb = rtl_make_smps_action(hw, smps, da, bssid); ++ struct rtl_tcb_desc tcb_desc; ++ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); ++ ++ if (rtlpriv->mac80211.act_scanning) ++ goto err_free; ++ ++ if (!sta) ++ goto err_free; ++ ++ if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) ++ goto err_free; ++ ++ if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) ++ goto err_free; ++ ++ /* this is a type = mgmt * stype = action frame */ ++ if (skb) { ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ struct rtl_sta_info *sta_entry = ++ (struct rtl_sta_info *) sta->drv_priv; ++ sta_entry->mimo_ps = smps; ++ rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); ++ ++ info->control.rates[0].idx = 0; ++ info->control.sta = sta; ++ info->band = hw->conf.channel->band; ++ rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); ++ } ++err_free: ++ return 0; ++} ++ ++/********************************************************* ++ * ++ * IOT functions ++ * ++ *********************************************************/ ++static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw, ++ struct octet_string vendor_ie) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ bool matched = false; ++ static u8 athcap_1[] = { 0x00, 0x03, 0x7F }; ++ static u8 athcap_2[] = { 0x00, 0x13, 0x74 }; ++ static u8 broadcap_1[] = { 0x00, 0x10, 0x18 }; ++ static u8 broadcap_2[] = { 0x00, 0x0a, 0xf7 }; ++ static u8 broadcap_3[] = { 0x00, 0x05, 0xb5 }; ++ static u8 racap[] = { 0x00, 0x0c, 0x43 }; ++ static u8 ciscocap[] = { 0x00, 0x40, 0x96 }; ++ static u8 marvcap[] = { 0x00, 0x50, 0x43 }; ++ ++ if (memcmp(vendor_ie.octet, athcap_1, 3) == 0 || ++ memcmp(vendor_ie.octet, athcap_2, 3) == 0) { ++ rtlpriv->mac80211.vendor = PEER_ATH; ++ matched = true; ++ } else if (memcmp(vendor_ie.octet, broadcap_1, 3) == 0 || ++ memcmp(vendor_ie.octet, broadcap_2, 3) == 0 || ++ memcmp(vendor_ie.octet, broadcap_3, 3) == 0) { ++ rtlpriv->mac80211.vendor = PEER_BROAD; ++ matched = true; ++ } else if (memcmp(vendor_ie.octet, racap, 3) == 0) { ++ rtlpriv->mac80211.vendor = PEER_RAL; ++ matched = true; ++ } else if (memcmp(vendor_ie.octet, ciscocap, 3) == 0) { ++ rtlpriv->mac80211.vendor = PEER_CISCO; ++ matched = true; ++ } else if (memcmp(vendor_ie.octet, marvcap, 3) == 0) { ++ rtlpriv->mac80211.vendor = PEER_MARV; ++ matched = true; ++ } ++ ++ return matched; ++} ++ ++static bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data, ++ unsigned int len) ++{ ++ struct ieee80211_mgmt *mgmt = (void *)data; ++ struct octet_string vendor_ie; ++ u8 *pos, *end; ++ ++ pos = (u8 *)mgmt->u.beacon.variable; ++ end = data + len; ++ while (pos < end) { ++ if (pos[0] == 221) { ++ vendor_ie.length = pos[1]; ++ vendor_ie.octet = &pos[2]; ++ if (rtl_chk_vendor_ouisub(hw, vendor_ie)) ++ return true; ++ } ++ ++ if (pos + 2 + pos[1] > end) ++ return false; ++ ++ pos += 2 + pos[1]; ++ } ++ return false; ++} ++ ++void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct ieee80211_hdr *hdr = (void *)data; ++ u32 vendor = PEER_UNKNOWN; ++ ++ static u8 ap3_1[3] = { 0x00, 0x14, 0xbf }; ++ static u8 ap3_2[3] = { 0x00, 0x1a, 0x70 }; ++ static u8 ap3_3[3] = { 0x00, 0x1d, 0x7e }; ++ static u8 ap4_1[3] = { 0x00, 0x90, 0xcc }; ++ static u8 ap4_2[3] = { 0x00, 0x0e, 0x2e }; ++ static u8 ap4_3[3] = { 0x00, 0x18, 0x02 }; ++ static u8 ap4_4[3] = { 0x00, 0x17, 0x3f }; ++ static u8 ap4_5[3] = { 0x00, 0x1c, 0xdf }; ++ static u8 ap5_1[3] = { 0x00, 0x1c, 0xf0 }; ++ static u8 ap5_2[3] = { 0x00, 0x21, 0x91 }; ++ static u8 ap5_3[3] = { 0x00, 0x24, 0x01 }; ++ static u8 ap5_4[3] = { 0x00, 0x15, 0xe9 }; ++ static u8 ap5_5[3] = { 0x00, 0x17, 0x9A }; ++ static u8 ap5_6[3] = { 0x00, 0x18, 0xE7 }; ++ static u8 ap6_1[3] = { 0x00, 0x17, 0x94 }; ++ static u8 ap7_1[3] = { 0x00, 0x14, 0xa4 }; ++ ++ if (mac->opmode != NL80211_IFTYPE_STATION) ++ return; ++ ++ if (mac->link_state == MAC80211_NOLINK) { ++ mac->vendor = PEER_UNKNOWN; ++ return; ++ } ++ ++ if (mac->cnt_after_linked > 2) ++ return; ++ ++ /* check if this really is a beacon */ ++ if (!ieee80211_is_beacon(hdr->frame_control)) ++ return; ++ ++ /* min. beacon length + FCS_LEN */ ++ if (len <= 40 + FCS_LEN) ++ return; ++ ++ /* and only beacons from the associated BSSID, please */ ++ if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) ++ return; ++ ++ if (rtl_find_221_ie(hw, data, len)) ++ vendor = mac->vendor; ++ ++ if ((memcmp(mac->bssid, ap5_1, 3) == 0) || ++ (memcmp(mac->bssid, ap5_2, 3) == 0) || ++ (memcmp(mac->bssid, ap5_3, 3) == 0) || ++ (memcmp(mac->bssid, ap5_4, 3) == 0) || ++ (memcmp(mac->bssid, ap5_5, 3) == 0) || ++ (memcmp(mac->bssid, ap5_6, 3) == 0) || ++ vendor == PEER_ATH) { ++ vendor = PEER_ATH; ++ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ath find\n")); ++ } else if ((memcmp(mac->bssid, ap4_4, 3) == 0) || ++ (memcmp(mac->bssid, ap4_5, 3) == 0) || ++ (memcmp(mac->bssid, ap4_1, 3) == 0) || ++ (memcmp(mac->bssid, ap4_2, 3) == 0) || ++ (memcmp(mac->bssid, ap4_3, 3) == 0) || ++ vendor == PEER_RAL) { ++ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ral findn\n")); ++ vendor = PEER_RAL; ++ } else if (memcmp(mac->bssid, ap6_1, 3) == 0 || ++ vendor == PEER_CISCO) { ++ vendor = PEER_CISCO; ++ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>cisco find\n")); ++ } else if ((memcmp(mac->bssid, ap3_1, 3) == 0) || ++ (memcmp(mac->bssid, ap3_2, 3) == 0) || ++ (memcmp(mac->bssid, ap3_3, 3) == 0) || ++ vendor == PEER_BROAD) { ++ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>broad find\n")); ++ vendor = PEER_BROAD; ++ } else if (memcmp(mac->bssid, ap7_1, 3) == 0 || ++ vendor == PEER_MARV) { ++ vendor = PEER_MARV; ++ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>marv find\n")); ++ } ++ ++ mac->vendor = vendor; ++} ++ ++/********************************************************* ++ * + * sysfs functions + * + *********************************************************/ +@@ -940,12 +1408,13 @@ + if (rtl_rate_control_register()) + printk(KERN_ERR "rtlwifi: Unable to register rtl_rc," + "use default RC !!\n"); ++ + return 0; + } + + static void __exit rtl_core_module_exit(void) + { +- /*RC*/ ++ /*RC*/ + rtl_rate_control_unregister(); + } + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/base.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/base.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/base.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/base.h 2011-05-05 23:29:49.231487125 +0200 +@@ -24,13 +24,26 @@ + * Hsinchu 300, Taiwan. + * + * Larry Finger ++ * + *****************************************************************************/ + + #ifndef __RTL_BASE_H__ + #define __RTL_BASE_H__ + ++enum ap_peer { ++ PEER_UNKNOWN = 0, ++ PEER_RTL = 1, ++ PEER_RTL_92SE = 2, ++ PEER_BROAD = 3, ++ PEER_RAL = 4, ++ PEER_ATH = 5, ++ PEER_CISCO = 6, ++ PEER_MARV = 7, ++ PEER_AIRGO = 9, ++ PEER_MAX = 10, ++} ; ++ + #define RTL_DUMMY_OFFSET 0 +-#define RTL_RX_DESC_SIZE 24 + #define RTL_DUMMY_UNIT 8 + #define RTL_TX_DUMMY_SIZE (RTL_DUMMY_OFFSET * RTL_DUMMY_UNIT) + #define RTL_TX_DESC_SIZE 32 +@@ -53,6 +66,14 @@ + #define FRAME_OFFSET_SEQUENCE 22 + #define FRAME_OFFSET_ADDRESS4 24 + ++#define SET_80211_HDR_FRAME_CONTROL(_hdr, _val) \ ++ WRITEEF2BYTE(_hdr, _val) ++#define SET_80211_HDR_TYPE_AND_SUBTYPE(_hdr, _val) \ ++ WRITEEF1BYTE(_hdr, _val) ++#define SET_80211_HDR_PWR_MGNT(_hdr, _val) \ ++ SET_BITS_TO_LE_2BYTE(_hdr, 12, 1, _val) ++#define SET_80211_HDR_TO_DS(_hdr, _val) \ ++ SET_BITS_TO_LE_2BYTE(_hdr, 8, 1, _val) + + #define SET_80211_PS_POLL_AID(_hdr, _val) \ + (*(u16 *)((u8 *)(_hdr) + 2) = le16_to_cpu(_val)) +@@ -64,11 +85,27 @@ + #define SET_80211_HDR_DURATION(_hdr, _val) \ + (*(u16 *)((u8 *)(_hdr) + FRAME_OFFSET_DURATION) = le16_to_cpu(_val)) + #define SET_80211_HDR_ADDRESS1(_hdr, _val) \ +- memcpy((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8*)(_val), ETH_ALEN) ++ CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8 *)(_val)) + #define SET_80211_HDR_ADDRESS2(_hdr, _val) \ +- memcpy((u8 *)(_hdr) + FRAME_OFFSET_ADDRESS2, (u8 *)(_val), ETH_ALEN) ++ CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS2, (u8 *)(_val)) + #define SET_80211_HDR_ADDRESS3(_hdr, _val) \ +- memcpy((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val), ETH_ALEN) ++ CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val)) ++#define SET_80211_HDR_FRAGMENT_SEQUENCE(_hdr, _val) \ ++ WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_SEQUENCE, _val) ++ ++#define SET_BEACON_PROBE_RSP_TIME_STAMP_LOW(__phdr, __val) \ ++ WRITEEF4BYTE(((u8 *)(__phdr)) + 24, __val) ++#define SET_BEACON_PROBE_RSP_TIME_STAMP_HIGH(__phdr, __val) \ ++ WRITEEF4BYTE(((u8 *)(__phdr)) + 28, __val) ++#define SET_BEACON_PROBE_RSP_BEACON_INTERVAL(__phdr, __val) \ ++ WRITEEF2BYTE(((u8 *)(__phdr)) + 32, __val) ++#define GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) \ ++ READEF2BYTE(((u8 *)(__phdr)) + 34) ++#define SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ ++ WRITEEF2BYTE(((u8 *)(__phdr)) + 34, __val) ++#define MASK_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ ++ SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \ ++ (GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val)))) + + int rtl_init_core(struct ieee80211_hw *hw); + void rtl_deinit_core(struct ieee80211_hw *hw); +@@ -80,18 +117,27 @@ + void rtl_deinit_deferred_work(struct ieee80211_hw *hw); + + bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); +-bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); + u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); + + void rtl_watch_dog_timer_callback(unsigned long data); +-int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, ++int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + u16 tid, u16 *ssn); +-int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid); ++int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta, ++ u16 tid); ++int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta, ++ u16 tid); + void rtl_watchdog_wq_callback(void *data); + + void rtl_get_tcb_desc(struct ieee80211_hw *hw, + struct ieee80211_tx_info *info, ++ struct ieee80211_sta *sta, + struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc); + ++int rtl_send_smps_action(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, u8 *da, u8 *bssid, ++ enum ieee80211_smps_mode smps); ++u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie); ++void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); ++u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid); + extern struct attribute_group rtl_attribute_group; + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/cam.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/cam.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/cam.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/cam.c 2011-05-05 23:29:49.303487995 +0200 +@@ -23,6 +23,8 @@ + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * ++ * Larry Finger ++ * + *****************************************************************************/ + + #include "wifi.h" +@@ -49,7 +51,7 @@ + u32 target_content = 0; + u8 entry_i; + +- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("key_cont_128:\n %x:%x:%x:%x:%x:%x\n", + key_cont_128[0], key_cont_128[1], + key_cont_128[2], key_cont_128[3], +@@ -68,15 +70,13 @@ + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], + target_command); + +- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +- ("rtl_cam_program_entry(): " +- "WRITE %x: %x\n", ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ++ ("WRITE %x: %x\n", + rtlpriv->cfg->maps[WCAMI], target_content)); +- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("The Key ID is %d\n", entry_no)); +- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +- ("rtl_cam_program_entry(): " +- "WRITE %x: %x\n", ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ++ ("WRITE %x: %x\n", + rtlpriv->cfg->maps[RWCAM], target_command)); + + } else if (entry_i == 1) { +@@ -91,12 +91,10 @@ + rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], + target_command); + +- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +- ("rtl_cam_program_entry(): WRITE A4: %x\n", +- target_content)); +- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +- ("rtl_cam_program_entry(): WRITE A0: %x\n", +- target_command)); ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ++ ("WRITE A4: %x\n", target_content)); ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ++ ("WRITE A0: %x\n", target_command)); + + } else { + +@@ -113,16 +111,14 @@ + target_command); + udelay(100); + +- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +- ("rtl_cam_program_entry(): WRITE A4: %x\n", +- target_content)); +- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +- ("rtl_cam_program_entry(): WRITE A0: %x\n", +- target_command)); ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ++ ("WRITE A4: %x\n", target_content)); ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ++ ("WRITE A0: %x\n", target_command)); + } + } + +- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("after set key, usconfig:%x\n", us_config)); + } + +@@ -289,3 +285,71 @@ + + } + EXPORT_SYMBOL(rtl_cam_empty_entry); ++ ++u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4; ++ u8 entry_idx = 0; ++ u8 i, *addr; ++ ++ if (NULL == sta_addr) { ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, ++ ("sta_addr is NULL.\n")); ++ return TOTAL_CAM_ENTRY; ++ } ++ /* Does STA already exist? */ ++ for (i = 4; i < TOTAL_CAM_ENTRY; i++) { ++ addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; ++ if (memcmp(addr, sta_addr, ETH_ALEN) == 0) ++ return i; ++ } ++ /* Get a free CAM entry. */ ++ for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) { ++ if ((bitmap & BIT(0)) == 0) { ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, ++ ("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n", ++ rtlpriv->sec.hwsec_cam_bitmap, entry_idx)); ++ rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx; ++ memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx], ++ sta_addr, ETH_ALEN); ++ return entry_idx; ++ } ++ bitmap = bitmap >> 1; ++ } ++ return TOTAL_CAM_ENTRY; ++} ++EXPORT_SYMBOL(rtl_cam_get_free_entry); ++ ++void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u32 bitmap; ++ u8 i, *addr; ++ ++ if (NULL == sta_addr) { ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, ++ ("sta_addr is NULL.\n")); ++ } ++ ++ if ((sta_addr[0]|sta_addr[1]|sta_addr[2]|sta_addr[3]|\ ++ sta_addr[4]|sta_addr[5]) == 0) { ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, ++ ("sta_addr is 00:00:00:00:00:00.\n")); ++ return; ++ } ++ /* Does STA already exist? */ ++ for (i = 4; i < TOTAL_CAM_ENTRY; i++) { ++ addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; ++ bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i; ++ if (((bitmap & BIT(0)) == BIT(0)) && ++ (memcmp(addr, sta_addr, ETH_ALEN) == 0)) { ++ /* Remove from HW Security CAM */ ++ memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN); ++ rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i); ++ printk(KERN_INFO "&&&&&&&&&del entry %d\n", i); ++ } ++ } ++ return; ++} ++EXPORT_SYMBOL(rtl_cam_del_entry); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/cam.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/cam.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/cam.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/cam.h 2011-05-05 23:29:49.324488249 +0200 +@@ -23,12 +23,13 @@ + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * ++ * Larry Finger ++ * + *****************************************************************************/ + + #ifndef __RTL_CAM_H_ + #define __RTL_CAM_H_ + +-#define TOTAL_CAM_ENTRY 32 + #define CAM_CONTENT_COUNT 8 + + #define CFG_DEFAULT_KEY BIT(5) +@@ -49,5 +50,7 @@ + void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index); + void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index); + void rtl_cam_reset_sec_info(struct ieee80211_hw *hw); ++u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr); ++void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr); + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/core.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/core.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/core.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/core.c 2011-05-05 23:29:49.290487837 +0200 +@@ -24,6 +24,7 @@ + * Hsinchu 300, Taiwan. + * + * Larry Finger ++ * + *****************************************************************************/ + + #include "wifi.h" +@@ -35,7 +36,7 @@ + /*mutex for start & stop is must here. */ + static int rtl_op_start(struct ieee80211_hw *hw) + { +- int err = 0; ++ int err; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +@@ -45,10 +46,8 @@ + return 0; + mutex_lock(&rtlpriv->locks.conf_mutex); + err = rtlpriv->intf_ops->adapter_start(hw); +- if (err) +- goto out; +- rtl_watch_dog_timer_callback((unsigned long)hw); +-out: ++ if (!err) ++ rtl_watch_dog_timer_callback((unsigned long)hw); + mutex_unlock(&rtlpriv->locks.conf_mutex); + return err; + } +@@ -72,6 +71,7 @@ + + mac->link_state = MAC80211_NOLINK; + memset(mac->bssid, 0, 6); ++ mac->vendor = PEER_UNKNOWN; + + /*reset sec info */ + rtl_cam_reset_sec_info(hw); +@@ -87,6 +87,8 @@ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ struct rtl_tcb_desc tcb_desc; ++ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) + goto err_free; +@@ -94,8 +96,8 @@ + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + goto err_free; + +- +- rtlpriv->intf_ops->adapter_tx(hw, skb); ++ if (!rtlpriv->intf_ops->waitq_insert(hw, skb)) ++ rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); + + return; + +@@ -136,10 +138,26 @@ + + mac->link_state = MAC80211_LINKED; + rtlpriv->cfg->ops->set_bcn_reg(hw); ++ if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) ++ mac->basic_rates = 0xfff; ++ else ++ mac->basic_rates = 0xff0; ++ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, ++ (u8 *) (&mac->basic_rates)); ++ + break; + case NL80211_IFTYPE_AP: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + ("NL80211_IFTYPE_AP\n")); ++ ++ mac->link_state = MAC80211_LINKED; ++ rtlpriv->cfg->ops->set_bcn_reg(hw); ++ if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) ++ mac->basic_rates = 0xfff; ++ else ++ mac->basic_rates = 0xff0; ++ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, ++ (u8 *) (&mac->basic_rates)); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +@@ -186,13 +204,12 @@ + mac->vif = NULL; + mac->link_state = MAC80211_NOLINK; + memset(mac->bssid, 0, 6); ++ mac->vendor = PEER_UNKNOWN; + mac->opmode = NL80211_IFTYPE_UNSPECIFIED; + rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); +- + mutex_unlock(&rtlpriv->locks.conf_mutex); + } + +- + static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); +@@ -224,10 +241,25 @@ + + /*For LPS */ + if (changed & IEEE80211_CONF_CHANGE_PS) { +- if (conf->flags & IEEE80211_CONF_PS) +- rtl_lps_enter(hw); +- else +- rtl_lps_leave(hw); ++ cancel_delayed_work(&rtlpriv->works.ps_work); ++ cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); ++ if (conf->flags & IEEE80211_CONF_PS) { ++ rtlpriv->psc.sw_ps_enabled = true; ++ /* sleep here is must, or we may recv the beacon and ++ * cause mac80211 into wrong ps state, this will cause ++ * power save nullfunc send fail, and further cause ++ * pkt loss, So sleep must quickly but not immediatly ++ * because that will cause nullfunc send by mac80211 ++ * fail, and cause pkt loss, we have tested that 5mA ++ * is worked very well */ ++ if (!rtlpriv->psc.multi_buffered) ++ queue_delayed_work(rtlpriv->works.rtl_wq, ++ &rtlpriv->works.ps_work, ++ MSECS(5)); ++ } else { ++ rtl_swlps_rf_awake(hw); ++ rtlpriv->psc.sw_ps_enabled = false; ++ } + } + + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { +@@ -259,7 +291,7 @@ + case NL80211_CHAN_NO_HT: + /* SC */ + mac->cur_40_prime_sc = +- PRIME_CHNL_OFFSET_DONT_CARE; ++ PRIME_CHNL_OFFSET_DONT_CARE; + rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20; + mac->bw_40 = false; + break; +@@ -267,7 +299,7 @@ + /* SC */ + mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER; + rtlphy->current_chan_bw = +- HT_CHANNEL_WIDTH_20_40; ++ HT_CHANNEL_WIDTH_20_40; + mac->bw_40 = true; + + /*wide channel */ +@@ -278,7 +310,7 @@ + /* SC */ + mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER; + rtlphy->current_chan_bw = +- HT_CHANNEL_WIDTH_20_40; ++ HT_CHANNEL_WIDTH_20_40; + mac->bw_40 = true; + + /*wide channel */ +@@ -288,16 +320,29 @@ + default: + mac->bw_40 = false; + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +- ("switch case not processed\n")); ++ ("switch case not processed\n")); + break; + } + + if (wide_chan <= 0) + wide_chan = 1; ++ ++ /* In scanning, before we go offchannel we may send a ps=1 null ++ * to AP, and then we may send a ps = 0 null to AP quickly, but ++ * first null may have caused AP to put lots of packet to hw tx ++ * buffer. These packets must be tx'd before we go off channel ++ * so we must delay more time to let AP flush these packets ++ * before going offchannel, or dis-association or delete BA will ++ * happen by AP ++ */ ++ if (rtlpriv->mac80211.offchan_deley) { ++ rtlpriv->mac80211.offchan_deley = false; ++ mdelay(50); ++ } + rtlphy->current_channel = wide_chan; + +- rtlpriv->cfg->ops->set_channel_access(hw); + rtlpriv->cfg->ops->switch_channel(hw); ++ rtlpriv->cfg->ops->set_channel_access(hw); + rtlpriv->cfg->ops->set_bw_mode(hw, + hw->conf.channel_type); + } +@@ -345,27 +390,28 @@ + } + } + +- if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { +- /* +- *TODO: BIT(5) is probe response BIT(8) is beacon +- *TODO: Use define for BIT(5) and BIT(8) +- */ +- if (*new_flags & FIF_BCN_PRBRESP_PROMISC) +- mac->rx_mgt_filter |= (BIT(5) | BIT(8)); +- else +- mac->rx_mgt_filter &= ~(BIT(5) | BIT(8)); ++ /* if ssid not set to hw don't check bssid ++ * here just used for linked scanning, & linked ++ * and nolink check bssid is set in set network_type */ ++ if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) && ++ (mac->link_state >= MAC80211_LINKED)) { ++ if (mac->opmode != NL80211_IFTYPE_AP) { ++ if (*new_flags & FIF_BCN_PRBRESP_PROMISC) { ++ rtlpriv->cfg->ops->set_chk_bssid(hw, false); ++ } else { ++ rtlpriv->cfg->ops->set_chk_bssid(hw, true); ++ } ++ } + } + + if (changed_flags & FIF_CONTROL) { + if (*new_flags & FIF_CONTROL) { + mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF]; +- mac->rx_ctrl_filter |= RTL_SUPPORTED_CTRL_FILTER; + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + ("Enable receive control frame.\n")); + } else { + mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; +- mac->rx_ctrl_filter &= ~RTL_SUPPORTED_CTRL_FILTER; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + ("Disable receive control frame.\n")); + } +@@ -382,14 +428,54 @@ + ("Disable receive other BSS's frame.\n")); + } + } +- +- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf)); +- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MGT_FILTER, +- (u8 *) (&mac->rx_mgt_filter)); +- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CTRL_FILTER, +- (u8 *) (&mac->rx_ctrl_filter)); + } ++static int rtl_op_sta_add(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_sta_info *sta_entry; ++ ++ if (sta) { ++ sta_entry = (struct rtl_sta_info *) sta->drv_priv; ++ if (rtlhal->current_bandtype == BAND_ON_2_4G) { ++ sta_entry->wireless_mode = WIRELESS_MODE_G; ++ if (sta->supp_rates[0] <= 0xf) ++ sta_entry->wireless_mode = WIRELESS_MODE_B; ++ if (sta->ht_cap.ht_supported == true) ++ sta_entry->wireless_mode = WIRELESS_MODE_N_24G; ++ } else if (rtlhal->current_bandtype == BAND_ON_5G) { ++ sta_entry->wireless_mode = WIRELESS_MODE_A; ++ if (sta->ht_cap.ht_supported == true) ++ sta_entry->wireless_mode = WIRELESS_MODE_N_24G; ++ } + ++ /* I found some times mac80211 give wrong supp_rates for adhoc*/ ++ if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) ++ sta_entry->wireless_mode = WIRELESS_MODE_G; ++ ++ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ++ ("Add sta addr is "MAC_FMT"\n", MAC_ARG(sta->addr))); ++ rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); ++ } ++ return 0; ++} ++static int rtl_op_sta_remove(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_sta_info *sta_entry; ++ if (sta) { ++ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ++ ("Remove sta addr is "MAC_FMT"\n", MAC_ARG(sta->addr))); ++ sta_entry = (struct rtl_sta_info *) sta->drv_priv; ++ sta_entry->wireless_mode = 0; ++ sta_entry->ratr_index = 0; ++ } ++ return 0; ++} + static int _rtl_get_hal_qnum(u16 queue) + { + int qnum; +@@ -446,19 +532,18 @@ + struct ieee80211_bss_conf *bss_conf, u32 changed) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ struct ieee80211_sta *sta = NULL; + + mutex_lock(&rtlpriv->locks.conf_mutex); +- + if ((vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_MESH_POINT)) { +- + if ((changed & BSS_CHANGED_BEACON) || + (changed & BSS_CHANGED_BEACON_ENABLED && + bss_conf->enable_beacon)) { +- + if (mac->beacon_enabled == 0) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + ("BSS_CHANGED_BEACON_ENABLED\n")); +@@ -470,8 +555,13 @@ + rtlpriv->cfg->maps + [RTL_IBSS_INT_MASKS], + 0); ++ ++ if (rtlpriv->cfg->ops->linked_set_reg) ++ rtlpriv->cfg->ops->linked_set_reg(hw); + } +- } else { ++ } ++ if ((changed & BSS_CHANGED_BEACON_ENABLED && ++ !bss_conf->enable_beacon)) { + if (mac->beacon_enabled == 1) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + ("ADHOC DISABLE BEACON\n")); +@@ -482,7 +572,6 @@ + [RTL_IBSS_INT_MASKS]); + } + } +- + if (changed & BSS_CHANGED_BEACON_INT) { + RT_TRACE(rtlpriv, COMP_BEACON, DBG_TRACE, + ("BSS_CHANGED_BEACON_INT\n")); +@@ -494,11 +583,25 @@ + /*TODO: reference to enum ieee80211_bss_change */ + if (changed & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { ++ /* we should reset all sec info & cam ++ * before set cam after linked, we should not ++ * reset in disassoc, that will cause tkip->wep ++ * fail because some flag will be wrong */ ++ /* reset sec info */ ++ rtl_cam_reset_sec_info(hw); ++ /* reset cam to fix wep fail issue ++ * when change from wpa to wep */ ++ rtl_cam_reset_all_entry(hw); ++ + mac->link_state = MAC80211_LINKED; + mac->cnt_after_linked = 0; + mac->assoc_id = bss_conf->aid; + memcpy(mac->bssid, bss_conf->bssid, 6); + ++ if (rtlpriv->cfg->ops->linked_set_reg) ++ rtlpriv->cfg->ops->linked_set_reg(hw); ++ if (mac->opmode == NL80211_IFTYPE_STATION && sta) ++ rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + ("BSS_CHANGED_ASSOC\n")); + } else { +@@ -507,9 +610,7 @@ + + mac->link_state = MAC80211_NOLINK; + memset(mac->bssid, 0, 6); +- +- /* reset sec info */ +- rtl_cam_reset_sec_info(hw); ++ mac->vendor = PEER_UNKNOWN; + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + ("BSS_CHANGED_UN_ASSOC\n")); +@@ -546,14 +647,10 @@ + } + + if (changed & BSS_CHANGED_HT) { +- struct ieee80211_sta *sta = NULL; +- + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + ("BSS_CHANGED_HT\n")); +- + rcu_read_lock(); +- sta = ieee80211_find_sta(mac->vif, mac->bssid); +- ++ sta = get_sta(hw, vif, (u8 *)bss_conf->bssid); + if (sta) { + if (sta->ht_cap.ampdu_density > + mac->current_ampdu_density) +@@ -575,9 +672,7 @@ + } + + if (changed & BSS_CHANGED_BSSID) { +- struct ieee80211_sta *sta = NULL; + u32 basic_rates; +- u8 i; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID, + (u8 *) bss_conf->bssid); +@@ -585,96 +680,65 @@ + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + (MAC_FMT "\n", MAC_ARG(bss_conf->bssid))); + ++ mac->vendor = PEER_UNKNOWN; + memcpy(mac->bssid, bss_conf->bssid, 6); +- if (is_valid_ether_addr(bss_conf->bssid)) { +- switch (vif->type) { +- case NL80211_IFTYPE_UNSPECIFIED: +- break; +- case NL80211_IFTYPE_ADHOC: +- break; +- case NL80211_IFTYPE_STATION: +- break; +- case NL80211_IFTYPE_AP: +- break; +- default: +- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +- ("switch case not process\n")); +- break; +- } +- rtlpriv->cfg->ops->set_network_type(hw, vif->type); +- } else +- rtlpriv->cfg->ops->set_network_type(hw, +- NL80211_IFTYPE_UNSPECIFIED); +- +- memset(mac->mcs, 0, 16); +- mac->ht_enable = false; +- mac->sgi_40 = false; +- mac->sgi_20 = false; +- +- if (!bss_conf->use_short_slot) +- mac->mode = WIRELESS_MODE_B; +- else +- mac->mode = WIRELESS_MODE_G; ++ rtlpriv->cfg->ops->set_network_type(hw, vif->type); + + rcu_read_lock(); +- sta = ieee80211_find_sta(mac->vif, mac->bssid); ++ sta = get_sta(hw, vif, (u8 *)bss_conf->bssid); ++ if (!sta) { ++ rcu_read_unlock(); ++ goto out; ++ } + +- if (sta) { +- if (sta->ht_cap.ht_supported) { ++ if (rtlhal->current_bandtype == BAND_ON_5G) { ++ mac->mode = WIRELESS_MODE_A; ++ } else { ++ if (sta->supp_rates[0] <= 0xf) ++ mac->mode = WIRELESS_MODE_B; ++ else ++ mac->mode = WIRELESS_MODE_G; ++ } ++ ++ if (sta->ht_cap.ht_supported) { ++ if (rtlhal->current_bandtype == BAND_ON_2_4G) + mac->mode = WIRELESS_MODE_N_24G; +- mac->ht_enable = true; +- } ++ else ++ mac->mode = WIRELESS_MODE_N_5G; ++ } + +- if (mac->ht_enable) { +- u16 ht_cap = sta->ht_cap.cap; +- memcpy(mac->mcs, (u8 *) (&sta->ht_cap.mcs), 16); +- +- for (i = 0; i < 16; i++) +- RT_TRACE(rtlpriv, COMP_MAC80211, +- DBG_LOUD, ("%x ", +- mac->mcs[i])); +- RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, +- ("\n")); +- +- if (ht_cap & IEEE80211_HT_CAP_SGI_40) +- mac->sgi_40 = true; +- +- if (ht_cap & IEEE80211_HT_CAP_SGI_20) +- mac->sgi_20 = true; +- +- /* +- * for cisco 1252 bw20 it's wrong +- * if (ht_cap & +- * IEEE80211_HT_CAP_SUP_WIDTH_20_40) { +- * mac->bw_40 = true; +- * } +- */ +- } ++ /* just station need it, because ibss & ap mode will ++ * set in sta_add, and will be NULL here */ ++ if (mac->opmode == NL80211_IFTYPE_STATION) { ++ struct rtl_sta_info *sta_entry; ++ sta_entry = (struct rtl_sta_info *) sta->drv_priv; ++ sta_entry->wireless_mode = mac->mode; ++ } ++ ++ if (sta->ht_cap.ht_supported) { ++ mac->ht_enable = true; ++ ++ /* ++ * for cisco 1252 bw20 it's wrong ++ * if (ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { ++ * mac->bw_40 = true; ++ * } ++ * */ + } +- rcu_read_unlock(); + +- /*mac80211 just give us CCK rates any time +- *So we add G rate in basic rates when +- not in B mode*/ + if (changed & BSS_CHANGED_BASIC_RATES) { +- if (mac->mode == WIRELESS_MODE_B) +- basic_rates = bss_conf->basic_rates | 0x00f; ++ /* for 5G must << RATE_6M_INDEX=4, ++ * because 5G have no cck rate*/ ++ if (rtlhal->current_bandtype == BAND_ON_5G) ++ basic_rates = sta->supp_rates[1] << 4; + else +- basic_rates = bss_conf->basic_rates | 0xff0; +- +- if (!vif) +- goto out; ++ basic_rates = sta->supp_rates[0]; + + mac->basic_rates = basic_rates; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *) (&basic_rates)); +- +- if (rtlpriv->dm.useramask) +- rtlpriv->cfg->ops->update_rate_mask(hw, 0); +- else +- rtlpriv->cfg->ops->update_rate_table(hw); +- + } ++ rcu_read_unlock(); + } + + /* +@@ -760,16 +824,17 @@ + case IEEE80211_AMPDU_TX_START: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + ("IEEE80211_AMPDU_TX_START: TID:%d\n", tid)); +- return rtl_tx_agg_start(hw, sta->addr, tid, ssn); ++ return rtl_tx_agg_start(hw, sta, tid, ssn); + break; + case IEEE80211_AMPDU_TX_STOP: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + ("IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid)); +- return rtl_tx_agg_stop(hw, sta->addr, tid); ++ return rtl_tx_agg_stop(hw, sta, tid); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + ("IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid)); ++ rtl_tx_agg_oper(hw, sta, tid); + break; + case IEEE80211_AMPDU_RX_START: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, +@@ -799,8 +864,12 @@ + if (mac->link_state == MAC80211_LINKED) { + rtl_lps_leave(hw); + mac->link_state = MAC80211_LINKED_SCANNING; +- } else ++ } else { + rtl_ips_nic_on(hw); ++ } ++ ++ /* Dual mac */ ++ rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false; + + rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY); + rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP); +@@ -812,22 +881,19 @@ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("\n")); +- +- rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE); + mac->act_scanning = false; ++ /* Dual mac */ ++ rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false; ++ + if (mac->link_state == MAC80211_LINKED_SCANNING) { + mac->link_state = MAC80211_LINKED; +- +- /* fix fwlps issue */ +- rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); +- +- if (rtlpriv->dm.useramask) +- rtlpriv->cfg->ops->update_rate_mask(hw, 0); +- else +- rtlpriv->cfg->ops->update_rate_table(hw); +- ++ if (mac->opmode == NL80211_IFTYPE_STATION) { ++ /* fix fwlps issue */ ++ rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); ++ } + } + ++ rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE); + } + + static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +@@ -858,49 +924,73 @@ + rtl_ips_nic_on(hw); + mutex_lock(&rtlpriv->locks.conf_mutex); + /* <1> get encryption alg */ ++ + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + key_type = WEP40_ENCRYPTION; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP40\n")); +- rtlpriv->sec.use_defaultkey = true; + break; + case WLAN_CIPHER_SUITE_WEP104: + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("alg:WEP104\n")); + key_type = WEP104_ENCRYPTION; +- rtlpriv->sec.use_defaultkey = true; + break; + case WLAN_CIPHER_SUITE_TKIP: + key_type = TKIP_ENCRYPTION; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:TKIP\n")); +- if (mac->opmode == NL80211_IFTYPE_ADHOC) +- rtlpriv->sec.use_defaultkey = true; + break; + case WLAN_CIPHER_SUITE_CCMP: + key_type = AESCCMP_ENCRYPTION; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:CCMP\n")); +- if (mac->opmode == NL80211_IFTYPE_ADHOC) +- rtlpriv->sec.use_defaultkey = true; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("alg_err:%x!!!!:\n", key->cipher)); + goto out_unlock; + } ++ if (key_type == WEP40_ENCRYPTION || ++ key_type == WEP104_ENCRYPTION || ++ mac->opmode == NL80211_IFTYPE_ADHOC) ++ rtlpriv->sec.use_defaultkey = true; ++ + /* <2> get key_idx */ + key_idx = (u8) (key->keyidx); + if (key_idx > 3) + goto out_unlock; + /* <3> if pairwise key enable_hw_sec */ + group_key = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE); +- if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) || +- rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) { +- if (rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION && +- (key_type == WEP40_ENCRYPTION || +- key_type == WEP104_ENCRYPTION)) +- wep_only = true; +- rtlpriv->sec.pairwise_enc_algorithm = key_type; +- rtlpriv->cfg->ops->enable_hw_sec(hw); ++ ++ /* wep always be group key, but there are two conditions: ++ * 1) wep only: is just for wep enc, in this condition ++ * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION ++ * will be true & enable_hw_sec will be set when wep ++ * ke setting. ++ * 2) wep(group) + AES(pairwise): some AP like cisco ++ * may use it, in this condition enable_hw_sec will not ++ * be set when wep key setting */ ++ /* we must reset sec_info after lingked before set key, ++ * or some flag will be wrong*/ ++ if (mac->opmode == NL80211_IFTYPE_AP) { ++ if (!group_key || key_type == WEP40_ENCRYPTION || ++ key_type == WEP104_ENCRYPTION) { ++ if (group_key) ++ wep_only = true; ++ rtlpriv->cfg->ops->enable_hw_sec(hw); ++ } ++ } else { ++ if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) || ++ rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) { ++ if (rtlpriv->sec.pairwise_enc_algorithm == ++ NO_ENCRYPTION && ++ (key_type == WEP40_ENCRYPTION || ++ key_type == WEP104_ENCRYPTION)) ++ wep_only = true; ++ rtlpriv->sec.pairwise_enc_algorithm = key_type; ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ++ ("set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1" ++ " TKIP:2 AES:4 WEP104:5)\n", key_type)); ++ rtlpriv->cfg->ops->enable_hw_sec(hw); ++ } + } + /* <4> set key based on cmd */ + switch (cmd) { +@@ -932,6 +1022,7 @@ + if (!sta) { + RT_ASSERT(false, ("pairwise key withnot" + "mac_addr\n")); ++ + err = -EOPNOTSUPP; + goto out_unlock; + } +@@ -959,6 +1050,10 @@ + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("disable key delete one entry\n")); + /*set local buf about wep key. */ ++ if (mac->opmode == NL80211_IFTYPE_AP) { ++ if (sta) ++ rtl_cam_del_entry(hw, sta->addr); ++ } + memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen); + rtlpriv->sec.key_len[key_idx] = 0; + memcpy(mac_addr, zero_addr, ETH_ALEN); +@@ -1011,6 +1106,18 @@ + mutex_unlock(&rtlpriv->locks.conf_mutex); + } + ++/* this function is called by mac80211 to flush tx buffer ++ * before switch channle or power save, or tx buffer packet ++ * maybe send after offchannel or rf sleep, this may cause ++ * dis-association by AP */ ++static void rtl_op_flush(struct ieee80211_hw *hw, bool drop) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ if (rtlpriv->intf_ops->flush) ++ rtlpriv->intf_ops->flush(hw, drop); ++} ++ + const struct ieee80211_ops rtl_ops = { + .start = rtl_op_start, + .stop = rtl_op_stop, +@@ -1019,6 +1126,8 @@ + .remove_interface = rtl_op_remove_interface, + .config = rtl_op_config, + .configure_filter = rtl_op_configure_filter, ++ .sta_add = rtl_op_sta_add, ++ .sta_remove = rtl_op_sta_remove, + .set_key = rtl_op_set_key, + .conf_tx = rtl_op_conf_tx, + .bss_info_changed = rtl_op_bss_info_changed, +@@ -1030,4 +1139,5 @@ + .sw_scan_start = rtl_op_sw_scan_start, + .sw_scan_complete = rtl_op_sw_scan_complete, + .rfkill_poll = rtl_op_rfkill_poll, ++ .flush = rtl_op_flush, + }; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/core.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/core.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/core.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/core.h 2011-05-05 23:29:49.269487583 +0200 +@@ -24,6 +24,7 @@ + * Hsinchu 300, Taiwan. + * + * Larry Finger ++ * + *****************************************************************************/ + + #ifndef __RTL_CORE_H__ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/efuse.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/efuse.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/efuse.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/efuse.c 2011-05-05 23:29:49.301487971 +0200 +@@ -52,8 +52,6 @@ + {11, 0, 0, 28} + }; + +-static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, +- u8 *pbuf); + static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset, + u8 *value); + static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset, +@@ -79,7 +77,7 @@ + u8 *targetdata); + static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, + u16 efuse_addr, u8 word_en, u8 *data); +-static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, ++static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, + u8 pwrstate); + static u16 efuse_get_current_size(struct ieee80211_hw *hw); + static u8 efuse_calculate_word_cnts(u8 word_en); +@@ -115,8 +113,10 @@ + u8 bytetemp; + u8 temp; + u32 k = 0; ++ const u32 efuse_len = ++ rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + +- if (address < EFUSE_REAL_CONTENT_LEN) { ++ if (address < efuse_len) { + temp = address & 0xFF; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, + temp); +@@ -158,11 +158,13 @@ + u8 bytetemp; + u8 temp; + u32 k = 0; ++ const u32 efuse_len = ++ rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, + ("Addr=%x Data =%x\n", address, value)); + +- if (address < EFUSE_REAL_CONTENT_LEN) { ++ if (address < efuse_len) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value); + + temp = address & 0xFF; +@@ -198,7 +200,7 @@ + + } + +-static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) ++void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 value32; +@@ -233,24 +235,28 @@ + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +- u8 efuse_tbl[EFUSE_MAP_LEN]; ++ u8 efuse_tbl[HWSET_MAX_SIZE]; + u8 rtemp8[1]; + u16 efuse_addr = 0; + u8 offset, wren; + u16 i; + u16 j; ++ const u16 efuse_max_section = ++ rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP]; ++ const u32 efuse_len = ++ rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + u16 efuse_word[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT]; + u16 efuse_utilized = 0; + u8 efuse_usage; + +- if ((_offset + _size_byte) > EFUSE_MAP_LEN) { ++ if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) { + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, + ("read_efuse(): Invalid offset(%#x) with read " + "bytes(%#x)!!\n", _offset, _size_byte)); + return; + } + +- for (i = 0; i < EFUSE_MAX_SECTION; i++) ++ for (i = 0; i < efuse_max_section; i++) + for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) + efuse_word[i][j] = 0xFFFF; + +@@ -262,10 +268,10 @@ + efuse_addr++; + } + +- while ((*rtemp8 != 0xFF) && (efuse_addr < EFUSE_REAL_CONTENT_LEN)) { ++ while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) { + offset = ((*rtemp8 >> 4) & 0x0f); + +- if (offset < EFUSE_MAX_SECTION) { ++ if (offset < efuse_max_section) { + wren = (*rtemp8 & 0x0f); + RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, + ("offset-%d Worden=%x\n", offset, wren)); +@@ -281,7 +287,7 @@ + efuse_utilized++; + efuse_word[offset][i] = (*rtemp8 & 0xff); + +- if (efuse_addr >= EFUSE_REAL_CONTENT_LEN) ++ if (efuse_addr >= efuse_len) + break; + + RTPRINT(rtlpriv, FEEPROM, +@@ -294,7 +300,7 @@ + efuse_word[offset][i] |= + (((u16)*rtemp8 << 8) & 0xff00); + +- if (efuse_addr >= EFUSE_REAL_CONTENT_LEN) ++ if (efuse_addr >= efuse_len) + break; + } + +@@ -305,13 +311,13 @@ + RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, + ("Addr=%d\n", efuse_addr)); + read_efuse_byte(hw, efuse_addr, rtemp8); +- if (*rtemp8 != 0xFF && (efuse_addr < 512)) { ++ if (*rtemp8 != 0xFF && (efuse_addr < efuse_len)) { + efuse_utilized++; + efuse_addr++; + } + } + +- for (i = 0; i < EFUSE_MAX_SECTION; i++) { ++ for (i = 0; i < efuse_max_section; i++) { + for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { + efuse_tbl[(i * 8) + (j * 2)] = + (efuse_word[i][j] & 0xff); +@@ -324,7 +330,7 @@ + pbuf[i] = efuse_tbl[_offset + i]; + + rtlefuse->efuse_usedbytes = efuse_utilized; +- efuse_usage = (u8)((efuse_utilized * 100) / EFUSE_REAL_CONTENT_LEN); ++ efuse_usage = (u8) ((efuse_utilized * 100) / efuse_len); + rtlefuse->efuse_usedpercentage = efuse_usage; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES, + (u8 *)&efuse_utilized); +@@ -338,11 +344,11 @@ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 section_idx, i, Base; + u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used; +- bool bwordchanged, bresult = true; ++ bool wordchanged, result = true; + + for (section_idx = 0; section_idx < 16; section_idx++) { + Base = section_idx * 8; +- bwordchanged = false; ++ wordchanged = false; + + for (i = 0; i < 8; i = i + 2) { + if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i] != +@@ -351,11 +357,11 @@ + rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i + + 1])) { + words_need++; +- bwordchanged = true; ++ wordchanged = true; + } + } + +- if (bwordchanged == true) ++ if (wordchanged == true) + hdr_num++; + } + +@@ -364,14 +370,14 @@ + + if ((totalbytes + efuse_used) >= + (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) +- bresult = false; ++ result = false; + + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, + ("efuse_shadow_update_chk(): totalbytes(%#x), " + "hdr_num(%#x), words_need(%#x), efuse_used(%d)\n", + totalbytes, hdr_num, words_need, efuse_used)); + +- return bresult; ++ return result; + } + + void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, +@@ -394,7 +400,7 @@ + else if (type == 2) + efuse_shadow_write_2byte(hw, offset, (u16) value); + else if (type == 4) +- efuse_shadow_write_4byte(hw, offset, (u32) value); ++ efuse_shadow_write_4byte(hw, offset, value); + + } + +@@ -478,9 +484,10 @@ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + +- if (rtlefuse->autoload_failflag == true) { +- memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, 128); +- } else ++ if (rtlefuse->autoload_failflag == true) ++ memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, ++ rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); ++ else + efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); + + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], +@@ -572,7 +579,7 @@ + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmpidx = 0; +- int bresult; ++ int result; + + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, + (u8) (addr & 0xff)); +@@ -592,19 +599,18 @@ + + if (tmpidx < 100) { + *data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); +- bresult = true; ++ result = true; + } else { + *data = 0xff; +- bresult = false; ++ result = false; + } +- return bresult; ++ return result; + } + + static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmpidx = 0; +- bool bresult; + + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, + ("Addr = %x Data=%x\n", addr, data)); +@@ -626,17 +632,16 @@ + } + + if (tmpidx < 100) +- bresult = true; +- else +- bresult = false; ++ return true; + +- return bresult; ++ return false; + } + + static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse) + { ++ struct rtl_priv *rtlpriv = rtl_priv(hw); + efuse_power_switch(hw, false, true); +- read_efuse(hw, 0, 128, efuse); ++ read_efuse(hw, 0, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], efuse); + efuse_power_switch(hw, false, false); + } + +@@ -644,7 +649,7 @@ + u8 efuse_data, u8 offset, u8 *tmpdata, + u8 *readstate) + { +- bool bdataempty = true; ++ bool dataempty = true; + u8 hoffset; + u8 tmpidx; + u8 hworden; +@@ -660,13 +665,13 @@ + &efuse_data)) { + tmpdata[tmpidx] = efuse_data; + if (efuse_data != 0xff) +- bdataempty = true; ++ dataempty = true; + } + } + +- if (bdataempty == true) ++ if (dataempty == true) { + *readstate = PG_STATE_DATA; +- else { ++ } else { + *efuse_addr = *efuse_addr + (word_cnts * 2) + 1; + *readstate = PG_STATE_HEADER; + } +@@ -680,12 +685,9 @@ + static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) + { + u8 readstate = PG_STATE_HEADER; +- +- bool bcontinual = true; +- ++ bool continual = true; + u8 efuse_data, word_cnts = 0; + u16 efuse_addr = 0; +- u8 hworden = 0; + u8 tmpdata[8]; + + if (data == NULL) +@@ -696,7 +698,7 @@ + memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); + memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); + +- while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) { ++ while (continual && (efuse_addr < EFUSE_MAX_SIZE)) { + if (readstate & PG_STATE_HEADER) { + if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) + && (efuse_data != 0xFF)) +@@ -705,9 +707,9 @@ + offset, tmpdata, + &readstate); + else +- bcontinual = false; ++ continual = false; + } else if (readstate & PG_STATE_DATA) { +- efuse_word_enable_data_read(hworden, tmpdata, data); ++ efuse_word_enable_data_read(0, tmpdata, data); + efuse_addr = efuse_addr + (word_cnts * 2) + 1; + readstate = PG_STATE_HEADER; + } +@@ -725,13 +727,13 @@ + } + + static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, +- u8 efuse_data, u8 offset, int *bcontinual, ++ u8 efuse_data, u8 offset, int *continual, + u8 *write_state, struct pgpkt_struct *target_pkt, +- int *repeat_times, int *bresult, u8 word_en) ++ int *repeat_times, int *result, u8 word_en) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct pgpkt_struct tmp_pkt; +- int bdataempty = true; ++ bool dataempty = true; + u8 originaldata[8 * sizeof(u8)]; + u8 badworden = 0x0F; + u8 match_word_en, tmp_word_en; +@@ -751,10 +753,10 @@ + u16 address = *efuse_addr + 1 + tmpindex; + if (efuse_one_byte_read(hw, address, + &efuse_data) && (efuse_data != 0xFF)) +- bdataempty = false; ++ dataempty = false; + } + +- if (bdataempty == false) { ++ if (dataempty == false) { + *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; + *write_state = PG_STATE_HEADER; + } else { +@@ -799,24 +801,25 @@ + tmp_word_en &= (~BIT(1)); + + if ((target_pkt->word_en & BIT(2)) ^ +- (match_word_en & BIT(2))) ++ (match_word_en & BIT(2))) + tmp_word_en &= (~BIT(2)); + + if ((target_pkt->word_en & BIT(3)) ^ +- (match_word_en & BIT(3))) ++ (match_word_en & BIT(3))) + tmp_word_en &= (~BIT(3)); + + if ((tmp_word_en & 0x0F) != 0x0F) { + *efuse_addr = efuse_get_current_size(hw); + target_pkt->offset = offset; + target_pkt->word_en = tmp_word_en; +- } else +- *bcontinual = false; ++ } else { ++ *continual = false; ++ } + *write_state = PG_STATE_HEADER; + *repeat_times += 1; + if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { +- *bcontinual = false; +- *bresult = false; ++ *continual = false; ++ *result = false; + } + } else { + *efuse_addr += (2 * tmp_word_cnts) + 1; +@@ -830,9 +833,9 @@ + } + + static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, +- int *bcontinual, u8 *write_state, ++ int *continual, u8 *write_state, + struct pgpkt_struct target_pkt, +- int *repeat_times, int *bresult) ++ int *repeat_times, int *result) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct pgpkt_struct tmp_pkt; +@@ -846,14 +849,14 @@ + efuse_one_byte_write(hw, *efuse_addr, pg_header); + efuse_one_byte_read(hw, *efuse_addr, &tmp_header); + +- if (tmp_header == pg_header) ++ if (tmp_header == pg_header) { + *write_state = PG_STATE_DATA; +- else if (tmp_header == 0xFF) { ++ } else if (tmp_header == 0xFF) { + *write_state = PG_STATE_HEADER; + *repeat_times += 1; + if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { +- *bcontinual = false; +- *bresult = false; ++ *continual = false; ++ *result = false; + } + } else { + tmp_pkt.offset = (tmp_header >> 4) & 0x0F; +@@ -875,17 +878,19 @@ + reorg_worden, + originaldata); + *efuse_addr = efuse_get_current_size(hw); +- } else ++ } else { + *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + + 1; +- } else ++ } ++ } else { + *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; ++ } + + *write_state = PG_STATE_HEADER; + *repeat_times += 1; + if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { +- *bcontinual = false; +- *bresult = false; ++ *continual = false; ++ *result = false; + } + + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, +@@ -899,7 +904,7 @@ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct pgpkt_struct target_pkt; + u8 write_state = PG_STATE_HEADER; +- int bcontinual = true, bdataempty = true, bresult = true; ++ int continual = true, dataempty = true, result = true; + u16 efuse_addr = 0; + u8 efuse_data; + u8 target_word_cnts = 0; +@@ -923,11 +928,11 @@ + + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse Power ON\n")); + +- while (bcontinual && (efuse_addr < ++ while (continual && (efuse_addr < + (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) { + + if (write_state == PG_STATE_HEADER) { +- bdataempty = true; ++ dataempty = true; + badworden = 0x0F; + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + ("efuse PG_STATE_HEADER\n")); +@@ -936,32 +941,30 @@ + (efuse_data != 0xFF)) + efuse_write_data_case1(hw, &efuse_addr, + efuse_data, offset, +- &bcontinual, ++ &continual, + &write_state, &target_pkt, +- &repeat_times, &bresult, ++ &repeat_times, &result, + word_en); + else + efuse_write_data_case2(hw, &efuse_addr, +- &bcontinual, ++ &continual, + &write_state, + target_pkt, + &repeat_times, +- &bresult); ++ &result); + + } else if (write_state == PG_STATE_DATA) { + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + ("efuse PG_STATE_DATA\n")); +- badworden = 0x0f; + badworden = + efuse_word_enable_data_write(hw, efuse_addr + 1, + target_pkt.word_en, + target_pkt.data); + + if ((badworden & 0x0F) == 0x0F) { +- bcontinual = false; ++ continual = false; + } else { +- efuse_addr = +- efuse_addr + (2 * target_word_cnts) + 1; ++ efuse_addr += (2 * target_word_cnts) + 1; + + target_pkt.offset = offset; + target_pkt.word_en = badworden; +@@ -971,8 +974,8 @@ + write_state = PG_STATE_HEADER; + repeat_times++; + if (repeat_times > EFUSE_REPEAT_THRESHOLD_) { +- bcontinual = false; +- bresult = false; ++ continual = false; ++ result = false; + } + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + ("efuse PG_STATE_HEADER-3\n")); +@@ -1072,13 +1075,15 @@ + return badworden; + } + +-static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) ++static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tempval; + u16 tmpV16; + +- if (pwrstate == true) { ++ if (pwrstate && (rtlhal->hw_type != ++ HARDWARE_TYPE_RTL8192SE)) { + tmpV16 = rtl_read_word(rtlpriv, + rtlpriv->cfg->maps[SYS_ISO_CTRL]); + if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { +@@ -1106,20 +1111,29 @@ + } + } + +- if (pwrstate == true) { +- if (bwrite == true) { ++ if (pwrstate) { ++ if (write) { + tempval = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_TEST] + + 3); +- tempval &= 0x0F; +- tempval |= (VOLTAGE_V25 << 4); ++ ++ if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) { ++ tempval &= 0x0F; ++ tempval |= (VOLTAGE_V25 << 4); ++ } ++ + rtl_write_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_TEST] + 3, + (tempval | 0x80)); + } + ++ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { ++ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], ++ 0x03); ++ } ++ + } else { +- if (bwrite == true) { ++ if (write) { + tempval = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_TEST] + + 3); +@@ -1128,18 +1142,23 @@ + (tempval & 0x7F)); + } + ++ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { ++ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], ++ 0x02); ++ } ++ + } + + } + + static u16 efuse_get_current_size(struct ieee80211_hw *hw) + { +- int bcontinual = true; ++ int continual = true; + u16 efuse_addr = 0; + u8 hoffset, hworden; + u8 efuse_data, word_cnts; + +- while (bcontinual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) ++ while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) + && (efuse_addr < EFUSE_MAX_SIZE)) { + if (efuse_data != 0xFF) { + hoffset = (efuse_data >> 4) & 0x0F; +@@ -1147,7 +1166,7 @@ + word_cnts = efuse_calculate_word_cnts(hworden); + efuse_addr = efuse_addr + (word_cnts * 2) + 1; + } else { +- bcontinual = false; ++ continual = false; + } + } + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/efuse.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/efuse.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/efuse.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/efuse.h 2011-05-05 23:29:49.304488007 +0200 +@@ -30,9 +30,10 @@ + #ifndef __RTL_EFUSE_H_ + #define __RTL_EFUSE_H_ + ++#define EFUSE_IC_ID_OFFSET 506 ++ + #define EFUSE_REAL_CONTENT_LEN 512 + #define EFUSE_MAP_LEN 128 +-#define EFUSE_MAX_SECTION 16 + #define EFUSE_MAX_WORD_UNIT 4 + + #define EFUSE_INIT_MAP 0 +@@ -52,6 +53,7 @@ + #define _PRE_EXECUTE_READ_CMD_ + + #define EFUSE_REPEAT_THRESHOLD_ 3 ++#define EFUSE_ERROE_HANDLE 1 + + struct efuse_map { + u8 offset; +@@ -103,6 +105,7 @@ + u8 tx_power_g[14]; + }; + ++extern void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf); + extern void efuse_initialize(struct ieee80211_hw *hw); + extern u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address); + extern void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/Kconfig linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/Kconfig +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/Kconfig 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/Kconfig 2011-05-05 23:29:49.333488357 +0200 +@@ -10,6 +10,17 @@ + + If you choose to build it as a module, it will be called rtl8192ce + ++config RTL8192SE ++ tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter" ++ depends on MAC80211 && EXPERIMENTAL ++ select FW_LOADER ++ select RTLWIFI ++ ---help--- ++ This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe ++ wireless network adapters. ++ ++ If you choose to build it as a module, it will be called rtl8192se ++ + config RTL8192CU + tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter" + depends on MAC80211 && USB && EXPERIMENTAL +@@ -24,10 +35,10 @@ + + config RTLWIFI + tristate +- depends on RTL8192CE || RTL8192CU ++ depends on RTL8192CE || RTL8192CU || RTL8192SE + default m + + config RTL8192C_COMMON + tristate +- depends on RTL8192CE || RTL8192CU ++ depends on RTL8192CE || RTL8192CU || RTL8192SE + default m +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/Makefile linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/Makefile +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/Makefile 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/Makefile 2011-05-05 23:29:49.303487995 +0200 +@@ -22,5 +22,6 @@ + obj-$(CONFIG_RTL8192C_COMMON) += rtl8192c/ + obj-$(CONFIG_RTL8192CE) += rtl8192ce/ + obj-$(CONFIG_RTL8192CU) += rtl8192cu/ ++obj-$(CONFIG_RTL8192SE) += rtl8192se/ + + ccflags-y += -D__CHECK_ENDIAN__ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/pci.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/pci.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/pci.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/pci.c 2011-05-05 23:29:49.305488019 +0200 +@@ -32,6 +32,7 @@ + #include "pci.h" + #include "base.h" + #include "ps.h" ++#include "efuse.h" + + static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { + INTEL_VENDOR_ID, +@@ -40,6 +41,31 @@ + SIS_VENDOR_ID + }; + ++static const u8 ac_to_hwq[] = { ++ VO_QUEUE, ++ VI_QUEUE, ++ BE_QUEUE, ++ BK_QUEUE ++}; ++ ++static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw, ++ struct sk_buff *skb) ++{ ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ __le16 fc = rtl_get_fc(skb); ++ u8 queue_index = skb_get_queue_mapping(skb); ++ ++ if (unlikely(ieee80211_is_beacon(fc))) ++ return BEACON_QUEUE; ++ if (ieee80211_is_mgmt(fc)) ++ return MGNT_QUEUE; ++ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) ++ if (ieee80211_is_nullfunc(fc)) ++ return HIGH_QUEUE; ++ ++ return ac_to_hwq[queue_index]; ++} ++ + /* Update PCI dependent default settings*/ + static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) + { +@@ -48,6 +74,7 @@ + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; ++ u8 init_aspm; + + ppsc->reg_rfps_level = 0; + ppsc->support_aspm = 0; +@@ -125,7 +152,7 @@ + bool support_backdoor = true; + ppsc->support_aspm = support_aspm; + +- /*if(priv->oem_id == RT_CID_TOSHIBA && ++ /*if (priv->oem_id == RT_CID_TOSHIBA && + !priv->ndis_adapter.amd_l1_patch) + support_backdoor = false; */ + +@@ -145,6 +172,13 @@ + ("switch case not process\n")); + break; + } ++ ++ /* toshiba aspm issue, toshiba will set aspm selfly ++ * so we should not set aspm in driver */ ++ pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm); ++ if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE && ++ init_aspm == 0x43) ++ ppsc->support_aspm = false; + } + + static bool _rtl_pci_platform_switch_device_pci_aspm( +@@ -152,28 +186,28 @@ + u8 value) + { + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +- bool bresult = false; ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +- value |= 0x40; ++ if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) ++ value |= 0x40; + + pci_write_config_byte(rtlpci->pdev, 0x80, value); + +- return bresult; ++ return false; + } + + /*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/ + static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value) + { + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +- u8 buffer; +- bool bresult = false; +- +- buffer = value; ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + pci_write_config_byte(rtlpci->pdev, 0x81, value); +- bresult = true; + +- return bresult; ++ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) ++ udelay(100); ++ ++ return true; + } + + /*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/ +@@ -191,6 +225,10 @@ + u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter. + pcibridge_linkctrlreg; + u16 aspmlevel = 0; ++ u8 tmp_u1b = 0; ++ ++ if (!ppsc->support_aspm) ++ return; + + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, +@@ -204,11 +242,8 @@ + _rtl_pci_switch_clk_req(hw, 0x0); + } + +- if (1) { +- /*for promising device will in L0 state after an I/O. */ +- u8 tmp_u1b; +- pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); +- } ++ /*for promising device will in L0 state after an I/O. */ ++ pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); + + /*Set corresponding value. */ + aspmlevel |= BIT(0) | BIT(1); +@@ -224,7 +259,6 @@ + rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg); + + udelay(50); +- + } + + /* +@@ -249,6 +283,9 @@ + u8 u_pcibridge_aspmsetting; + u8 u_device_aspmsetting; + ++ if (!ppsc->support_aspm) ++ return; ++ + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + ("PCI(Bridge) UNKNOWN.\n")); +@@ -293,7 +330,7 @@ + RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ); + } +- udelay(200); ++ udelay(100); + } + + static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) +@@ -330,13 +367,13 @@ + u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; + u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; + u8 linkctrl_reg; +- u8 num4bBytes; ++ u8 num4bbytes; + +- num4bBytes = (capabilityoffset + 0x10) / 4; ++ num4bbytes = (capabilityoffset + 0x10) / 4; + + /*Read Link Control Register */ + rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, +- pcicfg_addrport + (num4bBytes << 2)); ++ pcicfg_addrport + (num4bbytes << 2)); + rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg); + + pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg; +@@ -369,7 +406,7 @@ + pci_write_config_byte(pdev, 0x70f, tmp); + } + +-static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw) ++static void rtl_pci_init_aspm(struct ieee80211_hw *hw) + { + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +@@ -383,52 +420,6 @@ + + } + +-static void rtl_pci_init_aspm(struct ieee80211_hw *hw) +-{ +- struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +- +- /*close ASPM for AMD defaultly */ +- rtlpci->const_amdpci_aspm = 0; +- +- /* +- * ASPM PS mode. +- * 0 - Disable ASPM, +- * 1 - Enable ASPM without Clock Req, +- * 2 - Enable ASPM with Clock Req, +- * 3 - Always Enable ASPM with Clock Req, +- * 4 - Always Enable ASPM without Clock Req. +- * set defult to RTL8192CE:3 RTL8192E:2 +- * */ +- rtlpci->const_pci_aspm = 3; +- +- /*Setting for PCI-E device */ +- rtlpci->const_devicepci_aspm_setting = 0x03; +- +- /*Setting for PCI-E bridge */ +- rtlpci->const_hostpci_aspm_setting = 0x02; +- +- /* +- * In Hw/Sw Radio Off situation. +- * 0 - Default, +- * 1 - From ASPM setting without low Mac Pwr, +- * 2 - From ASPM setting with low Mac Pwr, +- * 3 - Bus D3 +- * set default to RTL8192CE:0 RTL8192SE:2 +- */ +- rtlpci->const_hwsw_rfoff_d3 = 0; +- +- /* +- * This setting works for those device with +- * backdoor ASPM setting such as EPHY setting. +- * 0 - Not support ASPM, +- * 1 - Support ASPM, +- * 2 - According to chipset. +- */ +- rtlpci->const_support_pciaspm = 1; +- +- _rtl_pci_initialize_adapter_common(hw); +-} +- + static void _rtl_pci_io_handler_init(struct device *dev, + struct ieee80211_hw *hw) + { +@@ -450,6 +441,90 @@ + { + } + ++static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw, ++ struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc, u8 tid) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ u8 additionlen = FCS_LEN; ++ struct sk_buff *next_skb; ++ ++ /* here open is 4, wep/tkip is 8, aes is 12*/ ++ if (info->control.hw_key) ++ additionlen += info->control.hw_key->icv_len; ++ ++ /* The most skb num is 6 */ ++ tcb_desc->empkt_num = 0; ++ spin_lock_bh(&rtlpriv->locks.waitq_lock); ++ skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) { ++ struct ieee80211_tx_info *next_info; ++ ++ next_info = IEEE80211_SKB_CB(next_skb); ++ if (next_info->flags & IEEE80211_TX_CTL_AMPDU) { ++ tcb_desc->empkt_len[tcb_desc->empkt_num] = ++ next_skb->len + additionlen; ++ tcb_desc->empkt_num++; ++ } else { ++ break; ++ } ++ ++ if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid], ++ next_skb)) ++ break; ++ ++ if (tcb_desc->empkt_num >= 5) ++ break; ++ } ++ spin_unlock_bh(&rtlpriv->locks.waitq_lock); ++ ++ return true; ++} ++ ++/* just for early mode now */ ++static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ struct sk_buff *skb = NULL; ++ struct ieee80211_tx_info *info = NULL; ++ int tid; /* should be int */ ++ ++ if (!rtlpriv->rtlhal.earlymode_enable) ++ return; ++ ++ /* we juse use em for BE/BK/VI/VO */ ++ for (tid = 7; tid >= 0; tid--) { ++ u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)]; ++ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; ++ while (!mac->act_scanning && ++ rtlpriv->psc.rfpwr_state == ERFON) { ++ struct rtl_tcb_desc tcb_desc; ++ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); ++ ++ spin_lock_bh(&rtlpriv->locks.waitq_lock); ++ if (!skb_queue_empty(&mac->skb_waitq[tid]) && ++ (ring->entries - skb_queue_len(&ring->queue) > 5)) { ++ skb = skb_dequeue(&mac->skb_waitq[tid]); ++ } else { ++ spin_unlock_bh(&rtlpriv->locks.waitq_lock); ++ break; ++ } ++ spin_unlock_bh(&rtlpriv->locks.waitq_lock); ++ ++ /* Some macaddr can't do early mode. like ++ * multicast/broadcast/no_qos data */ ++ info = IEEE80211_SKB_CB(skb); ++ if (info->flags & IEEE80211_TX_CTL_AMPDU) ++ _rtl_update_earlymode_info(hw, skb, ++ &tcb_desc, tid); ++ ++ rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); ++ } ++ } ++} ++ ++ + static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); +@@ -461,6 +536,8 @@ + struct rtl_tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb; + struct ieee80211_tx_info *info; ++ __le16 fc; ++ u8 tid; + + u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true, + HW_DESC_OWN); +@@ -481,6 +558,10 @@ + HW_DESC_TXBUFF_ADDR), + skb->len, PCI_DMA_TODEVICE); + ++ /* remove early mode header */ ++ if (rtlpriv->rtlhal.earlymode_enable) ++ skb_pull(skb, EM_HDR_LEN); ++ + RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_TRACE, + ("new ring->idx:%d, " + "free: skb_queue_len:%d, free: seq:%x\n", +@@ -488,6 +569,30 @@ + skb_queue_len(&ring->queue), + *(u16 *) (skb->data + 22))); + ++ if (prio == TXCMD_QUEUE) { ++ dev_kfree_skb(skb); ++ goto tx_status_ok; ++ ++ } ++ ++ /* for sw LPS, just after NULL skb send out, we can ++ * sure AP kown we are sleeped, our we should not let ++ * rf to sleep*/ ++ fc = rtl_get_fc(skb); ++ if (ieee80211_is_nullfunc(fc)) { ++ if (ieee80211_has_pm(fc)) { ++ rtlpriv->mac80211.offchan_deley = true; ++ rtlpriv->psc.state_inap = 1; ++ } else { ++ rtlpriv->psc.state_inap = 0; ++ } ++ } ++ ++ /* update tid tx pkt num */ ++ tid = rtl_get_tid(skb); ++ if (tid <= 7) ++ rtlpriv->link_info.tidtx_inperiod[tid]++; ++ + info = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(info); + +@@ -510,7 +615,7 @@ + skb_get_queue_mapping + (skb)); + } +- ++tx_status_ok: + skb = NULL; + } + +@@ -582,23 +687,21 @@ + *skb_trim(skb, skb->len - 4); + */ + +- hdr = (struct ieee80211_hdr *)(skb->data); +- fc = hdr->frame_control; ++ hdr = rtl_get_hdr(skb); ++ fc = rtl_get_fc(skb); + +- if (!stats.crc) { ++ if (!stats.crc || !stats.hwerror) { + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, + sizeof(rx_status)); + +- if (is_broadcast_ether_addr(hdr->addr1)) ++ if (is_broadcast_ether_addr(hdr->addr1)) { + ;/*TODO*/ +- else { +- if (is_multicast_ether_addr(hdr->addr1)) +- ;/*TODO*/ +- else { +- unicast = true; +- rtlpriv->stats.rxbytesunicast += +- skb->len; +- } ++ } else if (is_multicast_ether_addr(hdr->addr1)) { ++ ;/*TODO*/ ++ } else { ++ unicast = true; ++ rtlpriv->stats.rxbytesunicast += ++ skb->len; + } + + rtl_is_special_data(hw, skb, false); +@@ -612,28 +715,38 @@ + num_rx_inperiod++; + } + +- if (unlikely(!rtl_action_proc(hw, skb, +- false))) { ++ /* for sw lps */ ++ rtl_swlps_beacon(hw, (void *)skb->data, ++ skb->len); ++ rtl_recognize_peer(hw, (void *)skb->data, ++ skb->len); ++ if ((rtlpriv->mac80211.opmode == ++ NL80211_IFTYPE_AP) && ++ (rtlpriv->rtlhal.current_bandtype == ++ BAND_ON_2_4G) && ++ (ieee80211_is_beacon(fc) || ++ ieee80211_is_probe_resp(fc))) { + dev_kfree_skb_any(skb); + } else { +- struct sk_buff *uskb = NULL; +- u8 *pdata; +- uskb = dev_alloc_skb(skb->len + 128); +- if (!uskb) { +- RT_TRACE(rtlpriv, +- (COMP_INTR | COMP_RECV), +- DBG_EMERG, +- ("can't alloc rx skb\n")); +- goto done; +- } +- memcpy(IEEE80211_SKB_RXCB(uskb), +- &rx_status, +- sizeof(rx_status)); +- pdata = (u8 *)skb_put(uskb, skb->len); +- memcpy(pdata, skb->data, skb->len); +- dev_kfree_skb_any(skb); ++ if (unlikely(!rtl_action_proc(hw, skb, ++ false))) { ++ dev_kfree_skb_any(skb); ++ } else { ++ struct sk_buff *uskb = NULL; ++ u8 *pdata; ++ uskb = dev_alloc_skb(skb->len ++ + 128); ++ memcpy(IEEE80211_SKB_RXCB(uskb), ++ &rx_status, ++ sizeof(rx_status)); ++ pdata = (u8 *)skb_put(uskb, ++ skb->len); ++ memcpy(pdata, skb->data, ++ skb->len); ++ dev_kfree_skb_any(skb); + +- ieee80211_rx_irqsafe(hw, uskb); ++ ieee80211_rx_irqsafe(hw, uskb); ++ } + } + } else { + dev_kfree_skb_any(skb); +@@ -648,7 +761,7 @@ + new_skb = dev_alloc_skb(rtlpci->rxbuffersize); + if (unlikely(!new_skb)) { + RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), +- DBG_EMERG, ++ DBG_DMESG, + ("can't alloc skb for rx\n")); + goto done; + } +@@ -666,7 +779,7 @@ + + } + done: +- bufferaddress = (u32)(*((dma_addr_t *) skb->cb)); ++ bufferaddress = (*((dma_addr_t *)skb->cb)); + tmp_one = 1; + rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, + HW_DESC_RXBUFF_ADDR, +@@ -695,6 +808,7 @@ + struct ieee80211_hw *hw = dev_id; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + unsigned long flags; + u32 inta = 0; + u32 intb = 0; +@@ -781,23 +895,36 @@ + _rtl_pci_tx_isr(hw, VO_QUEUE); + } + ++ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { ++ if (inta & rtlpriv->cfg->maps[RTL_IMR_COMDOK]) { ++ rtlpriv->link_info.num_tx_inperiod++; ++ ++ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ++ ("CMD TX OK interrupt!\n")); ++ _rtl_pci_tx_isr(hw, TXCMD_QUEUE); ++ } ++ } ++ + /*<2> Rx related */ + if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n")); +- tasklet_schedule(&rtlpriv->works.irq_tasklet); ++ _rtl_pci_rx_interrupt(hw); + } + + if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("rx descriptor unavailable!\n")); +- tasklet_schedule(&rtlpriv->works.irq_tasklet); ++ _rtl_pci_rx_interrupt(hw); + } + + if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx overflow !\n")); +- tasklet_schedule(&rtlpriv->works.irq_tasklet); ++ _rtl_pci_rx_interrupt(hw); + } + ++ if (rtlpriv->rtlhal.earlymode_enable) ++ tasklet_schedule(&rtlpriv->works.irq_tasklet); ++ + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + return IRQ_HANDLED; + +@@ -808,7 +935,7 @@ + + static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) + { +- _rtl_pci_rx_interrupt(hw); ++ _rtl_pci_tx_chk_waitq(hw); + } + + static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) +@@ -816,14 +943,15 @@ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +- struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; ++ struct rtl8192_tx_ring *ring = NULL; + struct ieee80211_hdr *hdr = NULL; + struct ieee80211_tx_info *info = NULL; + struct sk_buff *pskb = NULL; + struct rtl_tx_desc *pdesc = NULL; +- unsigned int queue_index; ++ struct rtl_tcb_desc tcb_desc; + u8 temp_one = 1; + ++ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + ring = &rtlpci->tx_ring[BEACON_QUEUE]; + pskb = __skb_dequeue(&ring->queue); + if (pskb) +@@ -833,14 +961,11 @@ + pskb = ieee80211_beacon_get(hw, mac->vif); + if (pskb == NULL) + return; +- hdr = (struct ieee80211_hdr *)(pskb->data); ++ hdr = rtl_get_hdr(pskb); + info = IEEE80211_SKB_CB(pskb); +- +- queue_index = BEACON_QUEUE; +- + pdesc = &ring->desc[0]; + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, +- info, pskb, queue_index); ++ info, pskb, BEACON_QUEUE, &tcb_desc); + + __skb_queue_tail(&ring->queue, pskb); + +@@ -882,7 +1007,6 @@ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +- struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + rtlpci->up_first_time = true; + rtlpci->being_init_adapter = false; +@@ -890,31 +1014,20 @@ + rtlhal->hw = hw; + rtlpci->pdev = pdev; + +- ppsc->inactiveps = false; +- ppsc->leisure_ps = true; +- ppsc->fwctrl_lps = true; +- ppsc->reg_fwctrl_lps = 3; +- ppsc->reg_max_lps_awakeintvl = 5; +- +- if (ppsc->reg_fwctrl_lps == 1) +- ppsc->fwctrl_psmode = FW_PS_MIN_MODE; +- else if (ppsc->reg_fwctrl_lps == 2) +- ppsc->fwctrl_psmode = FW_PS_MAX_MODE; +- else if (ppsc->reg_fwctrl_lps == 3) +- ppsc->fwctrl_psmode = FW_PS_DTIM_MODE; +- + /*Tx/Rx related var */ + _rtl_pci_init_trx_var(hw); + +- /*IBSS*/ mac->beacon_interval = 100; ++ /*IBSS*/ mac->beacon_interval = 100; + +- /*AMPDU*/ mac->min_space_cfg = 0; ++ /*AMPDU*/ ++ mac->min_space_cfg = 0; + mac->max_mss_density = 0; + /*set sane AMPDU defaults */ + mac->current_ampdu_density = 7; + mac->current_ampdu_factor = 3; + +- /*QOS*/ rtlpci->acm_method = eAcmWay2_SW; ++ /*QOS*/ ++ rtlpci->acm_method = eAcmWay2_SW; + + /*task */ + tasklet_init(&rtlpriv->works.irq_tasklet, +@@ -955,7 +1068,8 @@ + ("queue:%d, ring_addr:%p\n", prio, ring)); + + for (i = 0; i < entries; i++) { +- nextdescaddress = (u32) dma + ((i + 1) % entries) * ++ nextdescaddress = (u32) dma + ++ ((i + 1) % entries) * + sizeof(*ring); + + rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]), +@@ -1020,7 +1134,7 @@ + rtlpci->rxbuffersize, + PCI_DMA_FROMDEVICE); + +- bufferaddress = (u32)(*((dma_addr_t *)skb->cb)); ++ bufferaddress = (*((dma_addr_t *)skb->cb)); + rtlpriv->cfg->ops->set_desc((u8 *)entry, false, + HW_DESC_RXBUFF_ADDR, + (u8 *)&bufferaddress); +@@ -1203,72 +1317,73 @@ + return 0; + } + +-static unsigned int _rtl_mac_to_hwqueue(__le16 fc, +- unsigned int mac80211_queue_index) ++static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, ++ struct sk_buff *skb) + { +- unsigned int hw_queue_index; +- +- if (unlikely(ieee80211_is_beacon(fc))) { +- hw_queue_index = BEACON_QUEUE; +- goto out; +- } +- +- if (ieee80211_is_mgmt(fc)) { +- hw_queue_index = MGNT_QUEUE; +- goto out; +- } +- +- switch (mac80211_queue_index) { +- case 0: +- hw_queue_index = VO_QUEUE; +- break; +- case 1: +- hw_queue_index = VI_QUEUE; +- break; +- case 2: +- hw_queue_index = BE_QUEUE;; +- break; +- case 3: +- hw_queue_index = BK_QUEUE; +- break; +- default: +- hw_queue_index = BE_QUEUE; +- RT_ASSERT(false, ("QSLT_BE queue, skb_queue:%d\n", +- mac80211_queue_index)); +- break; +- } ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ struct ieee80211_sta *sta = info->control.sta; ++ struct rtl_sta_info *sta_entry = NULL; ++ u8 tid = rtl_get_tid(skb); ++ ++ if (!sta) ++ return false; ++ sta_entry = (struct rtl_sta_info *)sta->drv_priv; ++ ++ if (!rtlpriv->rtlhal.earlymode_enable) ++ return false; ++ if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL) ++ return false; ++ if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE) ++ return false; ++ if (tid > 7) ++ return false; ++ ++ /* maybe every tid should be checked */ ++ if (!rtlpriv->link_info.higher_busytxtraffic[tid]) ++ return false; ++ ++ spin_lock_bh(&rtlpriv->locks.waitq_lock); ++ skb_queue_tail(&rtlpriv->mac80211.skb_waitq[tid], skb); ++ spin_unlock_bh(&rtlpriv->locks.waitq_lock); + +-out: +- return hw_queue_index; ++ return true; + } + +-static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ++static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb, ++ struct rtl_tcb_desc *ptcb_desc) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); +- struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_sta_info *sta_entry = NULL; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ struct ieee80211_sta *sta = info->control.sta; + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + u8 idx; +- unsigned int queue_index, hw_queue; ++ u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb); + unsigned long flags; +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); +- __le16 fc = hdr->frame_control; ++ struct ieee80211_hdr *hdr = rtl_get_hdr(skb); ++ __le16 fc = rtl_get_fc(skb); + u8 *pda_addr = hdr->addr1; + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + /*ssn */ +- u8 *qc = NULL; + u8 tid = 0; + u16 seq_number = 0; + u8 own; + u8 temp_one = 1; + +- if (ieee80211_is_mgmt(fc)) +- rtl_tx_mgmt_proc(hw, skb); +- rtl_action_proc(hw, skb, true); ++ if (ieee80211_is_auth(fc)) { ++ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); ++ rtl_ips_nic_on(hw); ++ } ++ ++ if (rtlpriv->psc.sw_ps_enabled) { ++ if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && ++ !ieee80211_has_pm(fc)) ++ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); ++ } + +- queue_index = skb_get_queue_mapping(skb); +- hw_queue = _rtl_mac_to_hwqueue(fc, queue_index); ++ rtl_action_proc(hw, skb, true); + + if (is_multicast_ether_addr(pda_addr)) + rtlpriv->stats.txbytesmulticast += skb->len; +@@ -1278,7 +1393,6 @@ + rtlpriv->stats.txbytesunicast += skb->len; + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); +- + ring = &rtlpci->tx_ring[hw_queue]; + if (hw_queue != BEACON_QUEUE) + idx = (ring->idx + skb_queue_len(&ring->queue)) % +@@ -1301,43 +1415,30 @@ + return skb->len; + } + +- /* +- *if(ieee80211_is_nullfunc(fc)) { +- * spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); +- * return 1; +- *} +- */ +- + if (ieee80211_is_data_qos(fc)) { +- qc = ieee80211_get_qos_ctl(hdr); +- tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; ++ tid = rtl_get_tid(skb); ++ if (sta) { ++ sta_entry = (struct rtl_sta_info *)sta->drv_priv; ++ seq_number = (le16_to_cpu(hdr->seq_ctrl) & ++ IEEE80211_SCTL_SEQ) >> 4; ++ seq_number += 1; + +- seq_number = mac->tids[tid].seq_number; +- seq_number &= IEEE80211_SCTL_SEQ; +- /* +- *hdr->seq_ctrl = hdr->seq_ctrl & +- *cpu_to_le16(IEEE80211_SCTL_FRAG); +- *hdr->seq_ctrl |= cpu_to_le16(seq_number); +- */ +- +- seq_number += 1; ++ if (!ieee80211_has_morefrags(hdr->frame_control)) ++ sta_entry->tids[tid].seq_number = seq_number; ++ } + } + + if (ieee80211_is_data(fc)) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); + +- rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, +- info, skb, hw_queue); ++ rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, ++ info, skb, hw_queue, ptcb_desc); + + __skb_queue_tail(&ring->queue, skb); + +- rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, ++ rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true, + HW_DESC_OWN, (u8 *)&temp_one); + +- if (!ieee80211_has_morefrags(hdr->frame_control)) { +- if (qc) +- mac->tids[tid].seq_number = seq_number; +- } + + if ((ring->entries - skb_queue_len(&ring->queue)) < 2 && + hw_queue != BEACON_QUEUE) { +@@ -1359,6 +1460,35 @@ + return 0; + } + ++static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ u16 i = 0; ++ int queue_id; ++ struct rtl8192_tx_ring *ring; ++ ++ for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) { ++ u32 queue_len; ++ ring = &pcipriv->dev.tx_ring[queue_id]; ++ queue_len = skb_queue_len(&ring->queue); ++ if (queue_len == 0 || queue_id == BEACON_QUEUE || ++ queue_id == TXCMD_QUEUE) { ++ queue_id--; ++ continue; ++ } else { ++ msleep(20); ++ i++; ++ } ++ ++ /* we just wait 1s for all queues */ ++ if (rtlpriv->psc.rfpwr_state == ERFOFF || ++ is_hal_stop(rtlhal) || i >= 200) ++ return; ++ } ++} ++ + static void rtl_pci_deinit(struct ieee80211_hw *hw) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); +@@ -1477,11 +1607,13 @@ + struct pci_dev *bridge_pdev = pdev->bus->self; + u16 venderid; + u16 deviceid; ++ u8 revisionid; + u16 irqline; + u8 tmp; + + venderid = pdev->vendor; + deviceid = pdev->device; ++ pci_read_config_byte(pdev, 0x8, &revisionid); + pci_read_config_word(pdev, 0x3C, &irqline); + + if (deviceid == RTL_PCI_8192_DID || +@@ -1492,7 +1624,7 @@ + deviceid == RTL_PCI_8173_DID || + deviceid == RTL_PCI_8172_DID || + deviceid == RTL_PCI_8171_DID) { +- switch (pdev->revision) { ++ switch (revisionid) { + case RTL_PCI_REVISION_ID_8192PCIE: + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + ("8192 PCI-E is found - " +@@ -1521,6 +1653,12 @@ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + ("8192C PCI-E is found - " + "vid/did=%x/%x\n", venderid, deviceid)); ++ } else if (deviceid == RTL_PCI_8192DE_DID || ++ deviceid == RTL_PCI_8192DE_DID2) { ++ rtlhal->hw_type = HARDWARE_TYPE_RTL8192DE; ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ++ ("8192D PCI-E is found - " ++ "vid/did=%x/%x\n", venderid, deviceid)); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("Err: Unknown device -" +@@ -1529,6 +1667,25 @@ + rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE; + } + ++ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) { ++ if (revisionid == 0 || revisionid == 1) { ++ if (revisionid == 0) { ++ RT_TRACE(rtlpriv, COMP_INIT, ++ DBG_LOUD, ("Find 92DE MAC0.\n")); ++ rtlhal->interfaceindex = 0; ++ } else if (revisionid == 1) { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("Find 92DE MAC1.\n")); ++ rtlhal->interfaceindex = 1; ++ } ++ } else { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("Unknown device - " ++ "VendorID/DeviceID=%x/%x, Revision=%x\n", ++ venderid, deviceid, revisionid)); ++ rtlhal->interfaceindex = 0; ++ } ++ } + /*find bus info */ + pcipriv->ndis_adapter.busnumber = pdev->bus->number; + pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn); +@@ -1554,12 +1711,12 @@ + PCI_SLOT(bridge_pdev->devfn); + pcipriv->ndis_adapter.pcibridge_funcnum = + PCI_FUNC(bridge_pdev->devfn); +- pcipriv->ndis_adapter.pcibridge_pciehdr_offset = +- pci_pcie_cap(bridge_pdev); + pcipriv->ndis_adapter.pcicfg_addrport = + (pcipriv->ndis_adapter.pcibridge_busnum << 16) | + (pcipriv->ndis_adapter.pcibridge_devnum << 11) | + (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31); ++ pcipriv->ndis_adapter.pcibridge_pciehdr_offset = ++ pci_pcie_cap(bridge_pdev); + pcipriv->ndis_adapter.num4bytes = + (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4; + +@@ -1642,6 +1799,11 @@ + pcipriv = (void *)rtlpriv->priv; + pcipriv->dev.pdev = pdev; + ++ /* init cfg & intf_ops */ ++ rtlpriv->rtlhal.interface = INTF_PCI; ++ rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); ++ rtlpriv->intf_ops = &rtl_pci_ops; ++ + /* + *init dbgp flags before all + *other functions, because we will +@@ -1659,13 +1821,14 @@ + return err; + } + +- pmem_start = pci_resource_start(pdev, 2); +- pmem_len = pci_resource_len(pdev, 2); +- pmem_flags = pci_resource_flags(pdev, 2); ++ pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id); ++ pmem_len = pci_resource_len(pdev, rtlpriv->cfg->bar_id); ++ pmem_flags = pci_resource_flags(pdev, rtlpriv->cfg->bar_id); + + /*shared mem start */ + rtlpriv->io.pci_mem_start = +- (unsigned long)pci_iomap(pdev, 2, pmem_len); ++ (unsigned long)pci_iomap(pdev, ++ rtlpriv->cfg->bar_id, pmem_len); + if (rtlpriv->io.pci_mem_start == 0) { + RT_ASSERT(false, ("Can't map PCI mem\n")); + goto fail2; +@@ -1684,11 +1847,6 @@ + pci_write_config_byte(pdev, 0x04, 0x06); + pci_write_config_byte(pdev, 0x04, 0x07); + +- /* init cfg & intf_ops */ +- rtlpriv->rtlhal.interface = INTF_PCI; +- rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); +- rtlpriv->intf_ops = &rtl_pci_ops; +- + /* find adapter */ + _rtl_pci_find_adapter(pdev, hw); + +@@ -1806,7 +1964,6 @@ + + rtl_pci_deinit(hw); + rtl_deinit_core(hw); +- rtlpriv->cfg->ops->deinit_sw_leds(hw); + _rtl_pci_io_handler_release(hw); + rtlpriv->cfg->ops->deinit_sw_vars(hw); + +@@ -1821,6 +1978,9 @@ + } + + pci_disable_device(pdev); ++ ++ rtl_pci_disable_aspm(hw); ++ + pci_set_drvdata(pdev, NULL); + + ieee80211_free_hw(hw); +@@ -1844,10 +2004,15 @@ + ****************************************/ + int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state) + { ++ struct ieee80211_hw *hw = pci_get_drvdata(pdev); ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ rtlpriv->cfg->ops->hw_suspend(hw); ++ rtl_deinit_rfkill(hw); ++ + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); +- + return 0; + } + EXPORT_SYMBOL(rtl_pci_suspend); +@@ -1855,6 +2020,8 @@ + int rtl_pci_resume(struct pci_dev *pdev) + { + int ret; ++ struct ieee80211_hw *hw = pci_get_drvdata(pdev); ++ struct rtl_priv *rtlpriv = rtl_priv(hw); + + pci_set_power_state(pdev, PCI_D0); + ret = pci_enable_device(pdev); +@@ -1865,15 +2032,20 @@ + + pci_restore_state(pdev); + ++ rtlpriv->cfg->ops->hw_resume(hw); ++ rtl_init_rfkill(hw); + return 0; + } + EXPORT_SYMBOL(rtl_pci_resume); + + struct rtl_intf_ops rtl_pci_ops = { ++ .read_efuse_byte = read_efuse_byte, + .adapter_start = rtl_pci_start, + .adapter_stop = rtl_pci_stop, + .adapter_tx = rtl_pci_tx, ++ .flush = rtl_pci_flush, + .reset_trx_ring = rtl_pci_reset_trx_ring, ++ .waitq_insert = rtl_pci_tx_chk_waitq_insert, + + .disable_aspm = rtl_pci_disable_aspm, + .enable_aspm = rtl_pci_enable_aspm, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/pci.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/pci.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/pci.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/pci.h 2011-05-05 23:29:49.269487583 +0200 +@@ -102,8 +102,8 @@ + #define RTL_PCI_8191CE_DID 0x8177 /*8192ce */ + #define RTL_PCI_8188CE_DID 0x8176 /*8192ce */ + #define RTL_PCI_8192CU_DID 0x8191 /*8192ce */ +-#define RTL_PCI_8192DE_DID 0x092D /*8192ce */ +-#define RTL_PCI_8192DU_DID 0x092D /*8192ce */ ++#define RTL_PCI_8192DE_DID 0x8193 /*8192de */ ++#define RTL_PCI_8192DE_DID2 0x002B /*92DE*/ + + /*8192 support 16 pages of IO registers*/ + #define RTL_MEM_MAPPED_IO_RANGE_8190PCI 0x1000 +@@ -129,6 +129,11 @@ + PCI_BRIDGE_VENDOR_MAX, + }; + ++struct rtl_pci_capabilities_header { ++ u8 capability_id; ++ u8 next; ++}; ++ + struct rtl_rx_desc { + u32 dword[8]; + } __packed; +@@ -161,7 +166,9 @@ + + bool driver_is_goingto_unload; + bool up_first_time; ++ bool first_init; + bool being_init_adapter; ++ bool init_ready; + bool irq_enabled; + + /*Tx */ +@@ -192,11 +199,14 @@ + u8 const_devicepci_aspm_setting; + /*If it supports ASPM, Offset[560h] = 0x40, + otherwise Offset[560h] = 0x00. */ +- bool b_support_aspm; +- bool b_support_backdoor; ++ bool support_aspm; ++ bool support_backdoor; + + /*QOS & EDCA */ + enum acm_method acm_method; ++ ++ u16 shortretry_limit; ++ u16 longretry_limit; + }; + + struct mp_adapter { +@@ -227,6 +237,7 @@ + struct rtl_pci dev; + struct mp_adapter ndis_adapter; + struct rtl_led_ctl ledctl; ++ struct bt_coexist_info bt_coexist; + }; + + #define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv)) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/ps.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/ps.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/ps.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/ps.c 2011-05-05 23:29:49.310488079 +0200 +@@ -36,7 +36,6 @@ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +- bool init_status = true; + + /*<1> reset trx ring */ + if (rtlhal->interface == INTF_PCI) +@@ -49,7 +48,6 @@ + /*<2> Enable Adapter */ + rtlpriv->cfg->ops->hw_init(hw); + RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); +- /*init_status = false; */ + + /*<3> Enable Interrupt */ + rtlpriv->cfg->ops->enable_interrupt(hw); +@@ -57,13 +55,12 @@ + /* */ + rtl_watch_dog_timer_callback((unsigned long)hw); + +- return init_status; ++ return true; + } + EXPORT_SYMBOL(rtl_ps_enable_nic); + + bool rtl_ps_disable_nic(struct ieee80211_hw *hw) + { +- bool status = true; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /*<1> Stop all timer */ +@@ -75,7 +72,7 @@ + /*<3> Disable Adapter */ + rtlpriv->cfg->ops->hw_disable(hw); + +- return status; ++ return true; + } + EXPORT_SYMBOL(rtl_ps_disable_nic); + +@@ -193,12 +190,13 @@ + + ppsc->swrf_processing = true; + +- if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) { ++ if (ppsc->inactive_pwrstate == ERFOFF && ++ rtlhal->interface == INTF_PCI) { + if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && +- RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM) && ++ RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && + rtlhal->interface == INTF_PCI) { + rtlpriv->intf_ops->disable_aspm(hw); +- RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); ++ RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + } + +@@ -207,9 +205,10 @@ + + if (ppsc->inactive_pwrstate == ERFOFF && + rtlhal->interface == INTF_PCI) { +- if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { ++ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && ++ !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->enable_aspm(hw); +- RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); ++ RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + } + +@@ -233,6 +232,9 @@ + return; + } + ++ if (mac->link_state > MAC80211_NOLINK) ++ return; ++ + if (is_hal_stop(rtlhal)) + return; + +@@ -284,10 +286,14 @@ + void rtl_ips_nic_on(struct ieee80211_hw *hw) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + enum rf_pwrstate rtstate; + unsigned long flags; + ++ if (mac->opmode != NL80211_IFTYPE_STATION) ++ return; ++ + spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags); + + if (ppsc->inactiveps) { +@@ -370,8 +376,7 @@ + * mode and set RPWM to turn RF on. + */ + +- if ((ppsc->fwctrl_lps) && (ppsc->leisure_ps) && +- ppsc->report_linked) { ++ if ((ppsc->fwctrl_lps) && ppsc->report_linked) { + bool fw_current_inps; + if (ppsc->dot11_psmode == EACTIVE) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +@@ -425,7 +430,7 @@ + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned long flag; + +- if (!(ppsc->fwctrl_lps && ppsc->leisure_ps)) ++ if (!ppsc->fwctrl_lps) + return; + + if (rtlpriv->sec.being_setkey) +@@ -446,17 +451,16 @@ + + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + +- if (ppsc->leisure_ps) { +- /* Idle for a while if we connect to AP a while ago. */ +- if (mac->cnt_after_linked >= 2) { +- if (ppsc->dot11_psmode == EACTIVE) { +- RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ /* Idle for a while if we connect to AP a while ago. */ ++ if (mac->cnt_after_linked >= 2) { ++ if (ppsc->dot11_psmode == EACTIVE) { ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Enter 802.11 power save mode...\n")); + +- rtl_lps_set_psmode(hw, EAUTOPS); +- } ++ rtl_lps_set_psmode(hw, EAUTOPS); + } + } ++ + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + } + +@@ -470,17 +474,17 @@ + + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + +- if (ppsc->fwctrl_lps && ppsc->leisure_ps) { ++ if (ppsc->fwctrl_lps) { + if (ppsc->dot11_psmode != EACTIVE) { + + /*FIX ME */ + rtlpriv->cfg->ops->enable_interrupt(hw); + + if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && +- RT_IN_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM) && ++ RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && + rtlhal->interface == INTF_PCI) { + rtlpriv->intf_ops->disable_aspm(hw); +- RT_CLEAR_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM); ++ RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +@@ -491,3 +495,214 @@ + } + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + } ++ ++/* For sw LPS*/ ++void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct ieee80211_hdr *hdr = (void *) data; ++ struct ieee80211_tim_ie *tim_ie; ++ u8 *tim; ++ u8 tim_len; ++ bool u_buffed; ++ bool m_buffed; ++ ++ if (mac->opmode != NL80211_IFTYPE_STATION) ++ return; ++ ++ if (!rtlpriv->psc.swctrl_lps) ++ return; ++ ++ if (rtlpriv->mac80211.link_state != MAC80211_LINKED) ++ return; ++ ++ if (!rtlpriv->psc.sw_ps_enabled) ++ return; ++ ++ if (rtlpriv->psc.fwctrl_lps) ++ return; ++ ++ if (likely(!(hw->conf.flags & IEEE80211_CONF_PS))) ++ return; ++ ++ /* check if this really is a beacon */ ++ if (!ieee80211_is_beacon(hdr->frame_control)) ++ return; ++ ++ /* min. beacon length + FCS_LEN */ ++ if (len <= 40 + FCS_LEN) ++ return; ++ ++ /* and only beacons from the associated BSSID, please */ ++ if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) ++ return; ++ ++ rtlpriv->psc.last_beacon = jiffies; ++ ++ tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM); ++ if (!tim) ++ return; ++ ++ if (tim[1] < sizeof(*tim_ie)) ++ return; ++ ++ tim_len = tim[1]; ++ tim_ie = (struct ieee80211_tim_ie *) &tim[2]; ++ ++ if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period)) ++ rtlpriv->psc.dtim_counter = tim_ie->dtim_count; ++ ++ /* Check whenever the PHY can be turned off again. */ ++ ++ /* 1. What about buffered unicast traffic for our AID? */ ++ u_buffed = ieee80211_check_tim(tim_ie, tim_len, ++ rtlpriv->mac80211.assoc_id); ++ ++ /* 2. Maybe the AP wants to send multicast/broadcast data? */ ++ m_buffed = tim_ie->bitmap_ctrl & 0x01; ++ rtlpriv->psc.multi_buffered = m_buffed; ++ ++ /* unicast will process by mac80211 through ++ * set ~IEEE80211_CONF_PS, So we just check ++ * multicast frames here */ ++ if (!m_buffed) { ++ /* back to low-power land. and delay is ++ * prevent null power save frame tx fail */ ++ queue_delayed_work(rtlpriv->works.rtl_wq, ++ &rtlpriv->works.ps_work, MSECS(5)); ++ } else { ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ("u_bufferd: %x, " ++ "m_buffered: %x\n", u_buffed, m_buffed)); ++ } ++} ++ ++void rtl_swlps_rf_awake(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ unsigned long flag; ++ ++ if (!rtlpriv->psc.swctrl_lps) ++ return; ++ if (mac->link_state != MAC80211_LINKED) ++ return; ++ ++ if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && ++ RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { ++ rtlpriv->intf_ops->disable_aspm(hw); ++ RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); ++ } ++ ++ spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); ++ rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false); ++ spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); ++} ++ ++void rtl_swlps_rfon_wq_callback(void *data) ++{ ++ struct rtl_works *rtlworks = ++ container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq); ++ struct ieee80211_hw *hw = rtlworks->hw; ++ ++ rtl_swlps_rf_awake(hw); ++} ++ ++void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ unsigned long flag; ++ u8 sleep_intv; ++ ++ if (!rtlpriv->psc.sw_ps_enabled) ++ return; ++ ++ if ((rtlpriv->sec.being_setkey) || ++ (mac->opmode == NL80211_IFTYPE_ADHOC)) ++ return; ++ ++ /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ ++ if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5)) ++ return; ++ ++ if (rtlpriv->link_info.busytraffic) ++ return; ++ ++ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); ++ if (rtlpriv->psc.rfchange_inprogress) { ++ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); ++ return; ++ } ++ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); ++ ++ spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); ++ rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS, false); ++ spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); ++ ++ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && ++ !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { ++ rtlpriv->intf_ops->enable_aspm(hw); ++ RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); ++ } ++ ++ /* here is power save alg, when this beacon is DTIM ++ * we will set sleep time to dtim_period * n; ++ * when this beacon is not DTIM, we will set sleep ++ * time to sleep_intv = rtlpriv->psc.dtim_counter or ++ * MAX_SW_LPS_SLEEP_INTV(default set to 5) */ ++ ++ if (rtlpriv->psc.dtim_counter == 0) { ++ if (hw->conf.ps_dtim_period == 1) ++ sleep_intv = hw->conf.ps_dtim_period * 2; ++ else ++ sleep_intv = hw->conf.ps_dtim_period; ++ } else { ++ sleep_intv = rtlpriv->psc.dtim_counter; ++ } ++ ++ if (sleep_intv > MAX_SW_LPS_SLEEP_INTV) ++ sleep_intv = MAX_SW_LPS_SLEEP_INTV; ++ ++ /* this print should always be dtim_conter = 0 & ++ * sleep = dtim_period, that meaons, we should ++ * awake before every dtim */ ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ++ ("dtim_counter:%x will sleep :%d" ++ " beacon_intv\n", rtlpriv->psc.dtim_counter, sleep_intv)); ++ ++ /* we tested that 40ms is enough for sw & hw sw delay */ ++ queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq, ++ MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40)); ++} ++ ++ ++void rtl_swlps_wq_callback(void *data) ++{ ++ struct rtl_works *rtlworks = container_of_dwork_rtl(data, ++ struct rtl_works, ++ ps_work); ++ struct ieee80211_hw *hw = rtlworks->hw; ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ bool ps = false; ++ ++ ps = (hw->conf.flags & IEEE80211_CONF_PS); ++ ++ /* we can sleep after ps null send ok */ ++ if (rtlpriv->psc.state_inap) { ++ rtl_swlps_rf_sleep(hw); ++ ++ if (rtlpriv->psc.state && !ps) { ++ rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies - ++ rtlpriv->psc.last_action); ++ } ++ ++ if (ps) ++ rtlpriv->psc.last_slept = jiffies; ++ ++ rtlpriv->psc.last_action = jiffies; ++ rtlpriv->psc.state = ps; ++ } ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/ps.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/ps.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/ps.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/ps.h 2011-05-05 23:29:49.268487571 +0200 +@@ -30,6 +30,8 @@ + #ifndef __REALTEK_RTL_PCI_PS_H__ + #define __REALTEK_RTL_PCI_PS_H__ + ++#define MAX_SW_LPS_SLEEP_INTV 5 ++ + bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, + enum rf_pwrstate state_toset, u32 changesource, + bool protect_or_not); +@@ -40,4 +42,11 @@ + void rtl_ips_nic_off_wq_callback(void *data); + void rtl_lps_enter(struct ieee80211_hw *hw); + void rtl_lps_leave(struct ieee80211_hw *hw); ++ ++void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len); ++void rtl_swlps_wq_callback(void *data); ++void rtl_swlps_rfon_wq_callback(void *data); ++void rtl_swlps_rf_awake(struct ieee80211_hw *hw); ++void rtl_swlps_rf_sleep(struct ieee80211_hw *hw); ++ + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rc.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rc.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rc.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rc.c 2011-05-05 23:29:49.333488357 +0200 +@@ -38,17 +38,14 @@ + *CCK11M or OFDM_54M based on wireless mode. + */ + static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, ++ struct ieee80211_sta *sta, + struct sk_buff *skb, bool not_data) + { + struct rtl_mac *rtlmac = rtl_mac(rtlpriv); +- +- /* +- *mgt use 1M, although we have check it +- *before this function use rate_control_send_low, +- *we still check it here +- */ +- if (not_data) +- return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; ++ struct rtl_hal *rtlhal = rtl_hal(rtlpriv); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_sta_info *sta_entry = NULL; ++ u8 wireless_mode = 0; + + /* + *this rate is no use for true rate, firmware +@@ -57,35 +54,78 @@ + *2.in rtl_get_tcb_desc when we check rate is + * 1M we will not use FW rate but user rate. + */ +- if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true)) { +- return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; ++ if (rtlmac->opmode == NL80211_IFTYPE_AP || ++ rtlmac->opmode == NL80211_IFTYPE_ADHOC) { ++ if (sta) { ++ sta_entry = (struct rtl_sta_info *) sta->drv_priv; ++ wireless_mode = sta_entry->wireless_mode; ++ } else { ++ return 0; ++ } ++ } else { ++ wireless_mode = rtlmac->mode; ++ } ++ ++ if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true) || ++ not_data) { ++ return 0; + } else { +- if (rtlmac->mode == WIRELESS_MODE_B) +- return rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]; +- else +- return rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]; ++ if (rtlhal->current_bandtype == BAND_ON_2_4G) { ++ if (wireless_mode == WIRELESS_MODE_B) { ++ return B_MODE_MAX_RIX; ++ } else if (wireless_mode == WIRELESS_MODE_G) { ++ return G_MODE_MAX_RIX; ++ } else { ++ if (get_rf_type(rtlphy) != RF_2T2R) ++ return N_MODE_MCS7_RIX; ++ else ++ return N_MODE_MCS15_RIX; ++ } ++ } else { ++ if (wireless_mode == WIRELESS_MODE_A) { ++ return A_MODE_MAX_RIX; ++ } else { ++ if (get_rf_type(rtlphy) != RF_2T2R) ++ return N_MODE_MCS7_RIX; ++ else ++ return N_MODE_MCS15_RIX; ++ } ++ } + } + } + + static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, ++ struct ieee80211_sta *sta, + struct ieee80211_tx_rate *rate, + struct ieee80211_tx_rate_control *txrc, +- u8 tries, u8 rix, int rtsctsenable, ++ u8 tries, char rix, int rtsctsenable, + bool not_data) + { + struct rtl_mac *mac = rtl_mac(rtlpriv); ++ u8 sgi_20 = 0, sgi_40 = 0; + ++ if (sta) { ++ sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; ++ sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; ++ } + rate->count = tries; +- rate->idx = (rix > 0x2) ? rix : 0x2; ++ rate->idx = rix >= 0x00 ? rix : 0x00; + + if (!not_data) { + if (txrc->short_preamble) + rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; +- if (mac->bw_40) +- rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; +- if (mac->sgi_20 || mac->sgi_40) ++ if (mac->opmode == NL80211_IFTYPE_AP || ++ mac->opmode == NL80211_IFTYPE_ADHOC) { ++ if (sta && (sta->ht_cap.cap & ++ IEEE80211_HT_CAP_SUP_WIDTH_20_40)) ++ rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; ++ } else { ++ if (mac->bw_40) ++ rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; ++ } ++ if (sgi_20 || sgi_40) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; +- if (mac->ht_enable) ++ if (sta && sta->ht_cap.ht_supported) + rate->flags |= IEEE80211_TX_RC_MCS; + } + } +@@ -97,39 +137,39 @@ + struct sk_buff *skb = txrc->skb; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rates = tx_info->control.rates; +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; +- __le16 fc = hdr->frame_control; ++ __le16 fc = rtl_get_fc(skb); + u8 try_per_rate, i, rix; + bool not_data = !ieee80211_is_data(fc); + + if (rate_control_send_low(sta, priv_sta, txrc)) + return; + +- rix = _rtl_rc_get_highest_rix(rtlpriv, skb, not_data); +- ++ rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data); + try_per_rate = 1; +- _rtl_rc_rate_set_series(rtlpriv, &rates[0], txrc, ++ _rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc, + try_per_rate, rix, 1, not_data); + + if (!not_data) { + for (i = 1; i < 4; i++) +- _rtl_rc_rate_set_series(rtlpriv, &rates[i], ++ _rtl_rc_rate_set_series(rtlpriv, sta, &rates[i], + txrc, i, (rix - i), 1, + not_data); + } + } + +-static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, u16 tid) ++static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, ++ struct rtl_sta_info *sta_entry, u16 tid) + { + struct rtl_mac *mac = rtl_mac(rtlpriv); + + if (mac->act_scanning) + return false; + +- if (mac->cnt_after_linked < 3) ++ if (mac->opmode == NL80211_IFTYPE_STATION && ++ mac->cnt_after_linked < 3) + return false; + +- if (mac->tids[tid].agg.agg_state == RTL_AGG_OFF) ++ if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP) + return true; + + return false; +@@ -143,11 +183,9 @@ + { + struct rtl_priv *rtlpriv = ppriv; + struct rtl_mac *mac = rtl_mac(rtlpriv); +- struct ieee80211_hdr *hdr; +- __le16 fc; +- +- hdr = (struct ieee80211_hdr *)skb->data; +- fc = hdr->frame_control; ++ struct ieee80211_hdr *hdr = rtl_get_hdr(skb); ++ __le16 fc = rtl_get_fc(skb); ++ struct rtl_sta_info *sta_entry; + + if (!priv_sta || !ieee80211_is_data(fc)) + return; +@@ -159,17 +197,21 @@ + || is_broadcast_ether_addr(ieee80211_get_DA(hdr))) + return; + +- /* Check if aggregation has to be enabled for this tid */ +- if (conf_is_ht(&mac->hw->conf) && +- !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { +- if (ieee80211_is_data_qos(fc)) { +- u8 *qc, tid; +- +- qc = ieee80211_get_qos_ctl(hdr); +- tid = qc[0] & 0xf; +- +- if (_rtl_tx_aggr_check(rtlpriv, tid)) +- ieee80211_start_tx_ba_session(sta, tid, 5000); ++ if (sta) { ++ /* Check if aggregation has to be enabled for this tid */ ++ sta_entry = (struct rtl_sta_info *) sta->drv_priv; ++ if ((sta->ht_cap.ht_supported == true) && ++ !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { ++ if (ieee80211_is_data_qos(fc)) { ++ u8 tid = rtl_get_tid(skb); ++ if (_rtl_tx_aggr_check(rtlpriv, sta_entry, ++ tid)) { ++ sta_entry->tids[tid].agg.agg_state = ++ RTL_AGG_PROGRESS; ++ ieee80211_start_tx_ba_session(sta, ++ tid, 5000); ++ } ++ } + } + } + } +@@ -178,43 +220,6 @@ + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta) + { +- struct rtl_priv *rtlpriv = ppriv; +- struct rtl_mac *mac = rtl_mac(rtlpriv); +- u8 is_ht = conf_is_ht(&mac->hw->conf); +- +- if ((mac->opmode == NL80211_IFTYPE_STATION) || +- (mac->opmode == NL80211_IFTYPE_MESH_POINT) || +- (mac->opmode == NL80211_IFTYPE_ADHOC)) { +- +- switch (sband->band) { +- case IEEE80211_BAND_2GHZ: +- rtlpriv->rate_priv->cur_ratetab_idx = +- RATR_INX_WIRELESS_G; +- if (is_ht) +- rtlpriv->rate_priv->cur_ratetab_idx = +- RATR_INX_WIRELESS_NGB; +- break; +- case IEEE80211_BAND_5GHZ: +- rtlpriv->rate_priv->cur_ratetab_idx = +- RATR_INX_WIRELESS_A; +- if (is_ht) +- rtlpriv->rate_priv->cur_ratetab_idx = +- RATR_INX_WIRELESS_NGB; +- break; +- default: +- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +- ("Invalid band\n")); +- rtlpriv->rate_priv->cur_ratetab_idx = +- RATR_INX_WIRELESS_NGB; +- break; +- } +- +- RT_TRACE(rtlpriv, COMP_RATE, DBG_DMESG, +- ("Choosing rate table index: %d\n", +- rtlpriv->rate_priv->cur_ratetab_idx)); +- +- } +- + } + + static void rtl_rate_update(void *ppriv, +@@ -223,49 +228,6 @@ + u32 changed, + enum nl80211_channel_type oper_chan_type) + { +- struct rtl_priv *rtlpriv = ppriv; +- struct rtl_mac *mac = rtl_mac(rtlpriv); +- struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +- bool oper_cw40 = false, oper_sgi40; +- bool local_cw40 = mac->bw_40; +- bool local_sgi40 = mac->sgi_40; +- u8 is_ht = conf_is_ht(&mac->hw->conf); +- +- if (changed & IEEE80211_RC_HT_CHANGED) { +- if (mac->opmode != NL80211_IFTYPE_STATION) +- return; +- +- if (rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40MINUS || +- rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40PLUS) +- oper_cw40 = true; +- +- oper_sgi40 = mac->sgi_40; +- +- if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) { +- switch (sband->band) { +- case IEEE80211_BAND_2GHZ: +- rtlpriv->rate_priv->cur_ratetab_idx = +- RATR_INX_WIRELESS_G; +- if (is_ht) +- rtlpriv->rate_priv->cur_ratetab_idx = +- RATR_INX_WIRELESS_NGB; +- break; +- case IEEE80211_BAND_5GHZ: +- rtlpriv->rate_priv->cur_ratetab_idx = +- RATR_INX_WIRELESS_A; +- if (is_ht) +- rtlpriv->rate_priv->cur_ratetab_idx = +- RATR_INX_WIRELESS_NGB; +- break; +- default: +- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +- ("Invalid band\n")); +- rtlpriv->rate_priv->cur_ratetab_idx = +- RATR_INX_WIRELESS_NGB; +- break; +- } +- } +- } + } + + static void *rtl_rate_alloc(struct ieee80211_hw *hw, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rc.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rc.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rc.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rc.h 2011-05-05 23:29:49.230487113 +0200 +@@ -30,8 +30,15 @@ + #ifndef __RTL_RC_H__ + #define __RTL_RC_H__ + ++#define B_MODE_MAX_RIX 3 ++#define G_MODE_MAX_RIX 11 ++#define A_MODE_MAX_RIX 7 ++ ++/* in mac80211 mcs0-mcs15 is idx0-idx15*/ ++#define N_MODE_MCS7_RIX 7 ++#define N_MODE_MCS15_RIX 15 ++ + struct rtl_rate_priv { +- u8 cur_ratetab_idx; + u8 ht_cap; + }; + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/regd.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/regd.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/regd.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/regd.c 2011-05-05 23:29:49.236487185 +0200 +@@ -66,31 +66,83 @@ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_OFDM) + ++/* 5G chan 36 - chan 64*/ ++#define RTL819x_5GHZ_5150_5350 \ ++ REG_RULE(5150-10, 5350+10, 40, 0, 30, \ ++ NL80211_RRF_PASSIVE_SCAN | \ ++ NL80211_RRF_NO_IBSS) ++ ++/* 5G chan 100 - chan 165*/ ++#define RTL819x_5GHZ_5470_5850 \ ++ REG_RULE(5470-10, 5850+10, 40, 0, 30, \ ++ NL80211_RRF_PASSIVE_SCAN | \ ++ NL80211_RRF_NO_IBSS) ++ ++/* 5G chan 149 - chan 165*/ ++#define RTL819x_5GHZ_5725_5850 \ ++ REG_RULE(5725-10, 5850+10, 40, 0, 30, \ ++ NL80211_RRF_PASSIVE_SCAN | \ ++ NL80211_RRF_NO_IBSS) ++ ++#define RTL819x_5GHZ_ALL \ ++ (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850) ++ + static const struct ieee80211_regdomain rtl_regdom_11 = { + .n_reg_rules = 1, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, +- } ++ } ++}; ++ ++static const struct ieee80211_regdomain rtl_regdom_12_13 = { ++ .n_reg_rules = 2, ++ .alpha2 = "99", ++ .reg_rules = { ++ RTL819x_2GHZ_CH01_11, ++ RTL819x_2GHZ_CH12_13, ++ } + }; + +-static const struct ieee80211_regdomain rtl_regdom_global = { ++static const struct ieee80211_regdomain rtl_regdom_no_midband = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, +- RTL819x_2GHZ_CH12_13, +- RTL819x_2GHZ_CH14, +- } ++ RTL819x_5GHZ_5150_5350, ++ RTL819x_5GHZ_5725_5850, ++ } + }; + +-static const struct ieee80211_regdomain rtl_regdom_world = { +- .n_reg_rules = 2, ++static const struct ieee80211_regdomain rtl_regdom_60_64 = { ++ .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, +- RTL819x_2GHZ_CH12_13, +- } ++ RTL819x_2GHZ_CH12_13, ++ RTL819x_5GHZ_5725_5850, ++ } ++}; ++ ++static const struct ieee80211_regdomain rtl_regdom_14_60_64 = { ++ .n_reg_rules = 4, ++ .alpha2 = "99", ++ .reg_rules = { ++ RTL819x_2GHZ_CH01_11, ++ RTL819x_2GHZ_CH12_13, ++ RTL819x_2GHZ_CH14, ++ RTL819x_5GHZ_5725_5850, ++ } ++}; ++ ++static const struct ieee80211_regdomain rtl_regdom_14 = { ++ .n_reg_rules = 3, ++ .alpha2 = "99", ++ .reg_rules = { ++ RTL819x_2GHZ_CH01_11, ++ RTL819x_2GHZ_CH12_13, ++ RTL819x_2GHZ_CH14, ++ } + }; + + static bool _rtl_is_radar_freq(u16 center_freq) +@@ -162,6 +214,8 @@ + u32 bandwidth = 0; + int r; + ++ if (!wiphy->bands[IEEE80211_BAND_2GHZ]) ++ return; + sband = wiphy->bands[IEEE80211_BAND_2GHZ]; + + /* +@@ -292,25 +346,26 @@ + { + switch (reg->country_code) { + case COUNTRY_CODE_FCC: ++ return &rtl_regdom_no_midband; + case COUNTRY_CODE_IC: + return &rtl_regdom_11; + case COUNTRY_CODE_ETSI: ++ case COUNTRY_CODE_TELEC_NETGEAR: ++ return &rtl_regdom_60_64; + case COUNTRY_CODE_SPAIN: + case COUNTRY_CODE_FRANCE: + case COUNTRY_CODE_ISRAEL: +- case COUNTRY_CODE_TELEC_NETGEAR: +- return &rtl_regdom_world; ++ case COUNTRY_CODE_WORLD_WIDE_13: ++ return &rtl_regdom_12_13; + case COUNTRY_CODE_MKK: + case COUNTRY_CODE_MKK1: + case COUNTRY_CODE_TELEC: + case COUNTRY_CODE_MIC: +- return &rtl_regdom_global; ++ return &rtl_regdom_14_60_64; + case COUNTRY_CODE_GLOBAL_DOMAIN: +- return &rtl_regdom_global; +- case COUNTRY_CODE_WORLD_WIDE_13: +- return &rtl_regdom_world; ++ return &rtl_regdom_14; + default: +- return &rtl_regdom_world; ++ return &rtl_regdom_no_midband; + } + } + +@@ -323,9 +378,11 @@ + const struct ieee80211_regdomain *regd; + + wiphy->reg_notifier = reg_notifier; ++ + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY; + wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS; ++ + regd = _rtl_regdomain_select(reg); + wiphy_apply_custom_regulatory(wiphy, regd); + _rtl_reg_apply_radar_flags(wiphy); +@@ -355,8 +412,8 @@ + if (wiphy == NULL || &rtlpriv->regd == NULL) + return -EINVAL; + +- /* force the channel plan to world wide 13 */ +- rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13; ++ /* init country_code from efuse channel plan */ ++ rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan; + + RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE, + (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n", +@@ -373,8 +430,8 @@ + country = _rtl_regd_find_country(rtlpriv->regd.country_code); + + if (country) { +- rtlpriv->regd.alpha2[0] = country->isoName[0]; +- rtlpriv->regd.alpha2[1] = country->isoName[1]; ++ rtlpriv->regd.alpha2[0] = country->iso_name[0]; ++ rtlpriv->regd.alpha2[1] = country->iso_name[1]; + } else { + rtlpriv->regd.alpha2[0] = '0'; + rtlpriv->regd.alpha2[1] = '0'; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/regd.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/regd.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/regd.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/regd.h 2011-05-05 23:29:49.302487983 +0200 +@@ -32,7 +32,7 @@ + + struct country_code_to_enum_rd { + u16 countrycode; +- const char *isoName; ++ const char *iso_name; + }; + + enum country_code_type_t { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c 2011-05-05 23:29:49.321488212 +0200 +@@ -28,10 +28,26 @@ + *****************************************************************************/ + + #include "dm_common.h" ++#include "phy_common.h" ++#include "../pci.h" ++#include "../base.h" + + struct dig_t dm_digtable; + static struct ps_t dm_pstable; + ++#define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1) ++#define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1) ++#define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1) ++#define BT_RSSI_STATE_BG_EDCA_LOW BIT_OFFSET_LEN_MASK_32(3, 1) ++#define BT_RSSI_STATE_TXPOWER_LOW BIT_OFFSET_LEN_MASK_32(4, 1) ++ ++#define RTLPRIV (struct rtl_priv *) ++#define GET_UNDECORATED_AVERAGE_RSSI(_priv) \ ++ ((RTLPRIV(_priv))->mac80211.opmode == \ ++ NL80211_IFTYPE_ADHOC) ? \ ++ ((RTLPRIV(_priv))->dm.entry_min_undecoratedsmoothed_pwdb) : \ ++ ((RTLPRIV(_priv))->dm.undecorated_smoothed_pwdb) ++ + static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = { + 0x7f8001fe, + 0x788001e2, +@@ -304,7 +320,7 @@ + + static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) + { +- static u8 binitialized; /* initialized to false */ ++ static u8 initialized; /* initialized to false */ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +@@ -315,11 +331,11 @@ + + if ((multi_sta == false) || (dm_digtable.cursta_connectctate != + DIG_STA_DISCONNECT)) { +- binitialized = false; ++ initialized = false; + dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + return; +- } else if (binitialized == false) { +- binitialized = true; ++ } else if (initialized == false) { ++ initialized = true; + dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; + dm_digtable.cur_igvalue = 0x20; + rtl92c_dm_write_dig(hw); +@@ -461,10 +477,7 @@ + if (mac->act_scanning == true) + return; + +- if ((mac->link_state > MAC80211_NOLINK) && +- (mac->link_state < MAC80211_LINKED)) +- dm_digtable.cursta_connectctate = DIG_STA_BEFORE_CONNECT; +- else if (mac->link_state >= MAC80211_LINKED) ++ if (mac->link_state >= MAC80211_LINKED) + dm_digtable.cursta_connectctate = DIG_STA_CONNECT; + else + dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT; +@@ -562,23 +575,42 @@ + static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ + static u64 last_txok_cnt; + static u64 last_rxok_cnt; +- u64 cur_txok_cnt; +- u64 cur_rxok_cnt; ++ static u32 last_bt_edca_ul; ++ static u32 last_bt_edca_dl; ++ u64 cur_txok_cnt = 0; ++ u64 cur_rxok_cnt = 0; + u32 edca_be_ul = 0x5ea42b; + u32 edca_be_dl = 0x5ea42b; ++ bool bt_change_edca = false; + +- if (mac->opmode == NL80211_IFTYPE_ADHOC) +- goto dm_checkedcaturbo_exit; ++ if ((last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) || ++ (last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) { ++ rtlpriv->dm.current_turbo_edca = false; ++ last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul; ++ last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl; ++ } ++ ++ if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) { ++ edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul; ++ bt_change_edca = true; ++ } ++ ++ if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) { ++ edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl; ++ bt_change_edca = true; ++ } + + if (mac->link_state != MAC80211_LINKED) { + rtlpriv->dm.current_turbo_edca = false; + return; + } + +- if (!mac->ht_enable) { /*FIX MERGE */ ++ if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) { + if (!(edca_be_ul & 0xffff0000)) + edca_be_ul |= 0x005e0000; + +@@ -586,10 +618,12 @@ + edca_be_dl |= 0x005e0000; + } + +- if ((!rtlpriv->dm.is_any_nonbepkts) && +- (!rtlpriv->dm.disable_framebursting)) { ++ if ((bt_change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) && ++ (!rtlpriv->dm.disable_framebursting))) { ++ + cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; + cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; ++ + if (cur_rxok_cnt > 4 * cur_txok_cnt) { + if (!rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { +@@ -618,7 +652,6 @@ + } + } + +-dm_checkedcaturbo_exit: + rtlpriv->dm.is_any_nonbepkts = false; + last_txok_cnt = rtlpriv->stats.txbytesunicast; + last_rxok_cnt = rtlpriv->stats.rxbytesunicast; +@@ -633,14 +666,14 @@ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 thermalvalue, delta, delta_lck, delta_iqk; + long ele_a, ele_d, temp_cck, val_x, value32; +- long val_y, ele_c; +- u8 ofdm_index[2], cck_index, ofdm_index_old[2], cck_index_old; ++ long val_y, ele_c = 0; ++ u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0; + int i; + bool is2t = IS_92C_SERIAL(rtlhal->version); + u8 txpwr_level[2] = {0, 0}; + u8 ofdm_min_index = 6, rf; + +- rtlpriv->dm.txpower_trackingInit = true; ++ rtlpriv->dm.txpower_trackinginit = true; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("rtl92c_dm_txpower_tracking_callback_thermalmeter\n")); + +@@ -683,7 +716,6 @@ + for (i = 0; i < OFDM_TABLE_LENGTH; i++) { + if (ele_d == (ofdmswing_table[i] & + MASKOFDM_D)) { +- ofdm_index_old[1] = (u8) i; + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, + DBG_LOUD, +@@ -1062,7 +1094,7 @@ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.txpower_tracking = true; +- rtlpriv->dm.txpower_trackingInit = false; ++ rtlpriv->dm.txpower_trackinginit = false; + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("pMgntInfo->txpower_tracking = %d\n", +@@ -1132,6 +1164,7 @@ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rate_adaptive *p_ra = &(rtlpriv->ra); + u32 low_rssithresh_for_ra, high_rssithresh_for_ra; ++ struct ieee80211_sta *sta = NULL; + + if (is_hal_stop(rtlhal)) { + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, +@@ -1145,8 +1178,8 @@ + return; + } + +- if (mac->link_state == MAC80211_LINKED) { +- ++ if (mac->link_state == MAC80211_LINKED && ++ mac->opmode == NL80211_IFTYPE_STATION) { + switch (p_ra->pre_ratr_state) { + case DM_RATR_STA_HIGH: + high_rssithresh_for_ra = 50; +@@ -1185,10 +1218,13 @@ + ("PreState = %d, CurState = %d\n", + p_ra->pre_ratr_state, p_ra->ratr_state)); + +- rtlpriv->cfg->ops->update_rate_mask(hw, ++ rcu_read_lock(); ++ sta = ieee80211_find_sta(mac->vif, mac->bssid); ++ rtlpriv->cfg->ops->update_rate_tbl(hw, sta, + p_ra->ratr_state); + + p_ra->pre_ratr_state = p_ra->ratr_state; ++ rcu_read_unlock(); + } + } + } +@@ -1202,51 +1238,6 @@ + dm_pstable.rssi_val_min = 0; + } + +-static void rtl92c_dm_1r_cca(struct ieee80211_hw *hw) +-{ +- struct rtl_priv *rtlpriv = rtl_priv(hw); +- struct rtl_phy *rtlphy = &(rtlpriv->phy); +- +- if (dm_pstable.rssi_val_min != 0) { +- if (dm_pstable.pre_ccastate == CCA_2R) { +- if (dm_pstable.rssi_val_min >= 35) +- dm_pstable.cur_ccasate = CCA_1R; +- else +- dm_pstable.cur_ccasate = CCA_2R; +- } else { +- if (dm_pstable.rssi_val_min <= 30) +- dm_pstable.cur_ccasate = CCA_2R; +- else +- dm_pstable.cur_ccasate = CCA_1R; +- } +- } else { +- dm_pstable.cur_ccasate = CCA_MAX; +- } +- +- if (dm_pstable.pre_ccastate != dm_pstable.cur_ccasate) { +- if (dm_pstable.cur_ccasate == CCA_1R) { +- if (get_rf_type(rtlphy) == RF_2T2R) { +- rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, +- MASKBYTE0, 0x13); +- rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x20); +- } else { +- rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, +- MASKBYTE0, 0x23); +- rtl_set_bbreg(hw, 0xe70, 0x7fc00000, 0x10c); +- } +- } else { +- rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, +- 0x33); +- rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x63); +- } +- dm_pstable.pre_ccastate = dm_pstable.cur_ccasate; +- } +- +- RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, ("CCAStage = %s\n", +- (dm_pstable.cur_ccasate == +- 0) ? "1RCCA" : "2RCCA")); +-} +- + void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal) + { + static u8 initialize; +@@ -1352,7 +1343,9 @@ + } + + if (IS_92C_SERIAL(rtlhal->version)) +- rtl92c_dm_1r_cca(hw); ++ ;/* rtl92c_dm_1r_cca(hw); */ ++ else ++ rtl92c_dm_rf_saving(hw, false); + } + + void rtl92c_dm_init(struct ieee80211_hw *hw) +@@ -1369,6 +1362,84 @@ + } + EXPORT_SYMBOL(rtl92c_dm_init); + ++void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ long undecorated_smoothed_pwdb; ++ ++ if (!rtlpriv->dm.dynamic_txpower_enable) ++ return; ++ ++ if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { ++ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; ++ return; ++ } ++ ++ if ((mac->link_state < MAC80211_LINKED) && ++ (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, ++ ("Not connected to any\n")); ++ ++ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; ++ ++ rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; ++ return; ++ } ++ ++ if (mac->link_state >= MAC80211_LINKED) { ++ if (mac->opmode == NL80211_IFTYPE_ADHOC) { ++ undecorated_smoothed_pwdb = ++ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("AP Client PWDB = 0x%lx\n", ++ undecorated_smoothed_pwdb)); ++ } else { ++ undecorated_smoothed_pwdb = ++ rtlpriv->dm.undecorated_smoothed_pwdb; ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("STA Default Port PWDB = 0x%lx\n", ++ undecorated_smoothed_pwdb)); ++ } ++ } else { ++ undecorated_smoothed_pwdb = ++ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; ++ ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("AP Ext Port PWDB = 0x%lx\n", ++ undecorated_smoothed_pwdb)); ++ } ++ ++ if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { ++ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n")); ++ } else if ((undecorated_smoothed_pwdb < ++ (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && ++ (undecorated_smoothed_pwdb >= ++ TX_POWER_NEAR_FIELD_THRESH_LVL1)) { ++ ++ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n")); ++ } else if (undecorated_smoothed_pwdb < ++ (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { ++ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("TXHIGHPWRLEVEL_NORMAL\n")); ++ } ++ ++ if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) { ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("PHY_SetTxPowerLevel8192S() Channel = %d\n", ++ rtlphy->current_channel)); ++ rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); ++ } ++ ++ rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; ++} ++ + void rtl92c_dm_watchdog(struct ieee80211_hw *hw) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); +@@ -1388,11 +1459,321 @@ + rtl92c_dm_dig(hw); + rtl92c_dm_false_alarm_counter_statistics(hw); + rtl92c_dm_dynamic_bb_powersaving(hw); +- rtlpriv->cfg->ops->dm_dynamic_txpower(hw); ++ rtl92c_dm_dynamic_txpower(hw); + rtl92c_dm_check_txpower_tracking(hw); + rtl92c_dm_refresh_rate_adaptive_mask(hw); ++ rtl92c_dm_bt_coexist(hw); + rtl92c_dm_check_edca_turbo(hw); +- + } + } + EXPORT_SYMBOL(rtl92c_dm_watchdog); ++ ++u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); ++ long undecorated_smoothed_pwdb; ++ u8 curr_bt_rssi_state = 0x00; ++ ++ if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { ++ undecorated_smoothed_pwdb = ++ GET_UNDECORATED_AVERAGE_RSSI(rtlpriv); ++ } else { ++ if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0) ++ undecorated_smoothed_pwdb = 100; ++ else ++ undecorated_smoothed_pwdb = ++ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; ++ } ++ ++ /* Check RSSI to determine HighPower/NormalPower state for ++ * BT coexistence. */ ++ if (undecorated_smoothed_pwdb >= 67) ++ curr_bt_rssi_state &= (~BT_RSSI_STATE_NORMAL_POWER); ++ else if (undecorated_smoothed_pwdb < 62) ++ curr_bt_rssi_state |= BT_RSSI_STATE_NORMAL_POWER; ++ ++ /* Check RSSI to determine AMPDU setting for BT coexistence. */ ++ if (undecorated_smoothed_pwdb >= 40) ++ curr_bt_rssi_state &= (~BT_RSSI_STATE_AMDPU_OFF); ++ else if (undecorated_smoothed_pwdb <= 32) ++ curr_bt_rssi_state |= BT_RSSI_STATE_AMDPU_OFF; ++ ++ /* Marked RSSI state. It will be used to determine BT coexistence ++ * setting later. */ ++ if (undecorated_smoothed_pwdb < 35) ++ curr_bt_rssi_state |= BT_RSSI_STATE_SPECIAL_LOW; ++ else ++ curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW); ++ ++ /* Set Tx Power according to BT status. */ ++ if (undecorated_smoothed_pwdb >= 30) ++ curr_bt_rssi_state |= BT_RSSI_STATE_TXPOWER_LOW; ++ else if (undecorated_smoothed_pwdb < 25) ++ curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW); ++ ++ /* Check BT state related to BT_Idle in B/G mode. */ ++ if (undecorated_smoothed_pwdb < 15) ++ curr_bt_rssi_state |= BT_RSSI_STATE_BG_EDCA_LOW; ++ else ++ curr_bt_rssi_state &= (~BT_RSSI_STATE_BG_EDCA_LOW); ++ ++ if (curr_bt_rssi_state != rtlpcipriv->bt_coexist.bt_rssi_state) { ++ rtlpcipriv->bt_coexist.bt_rssi_state = curr_bt_rssi_state; ++ return true; ++ } else { ++ return false; ++ } ++} ++EXPORT_SYMBOL(rtl92c_bt_rssi_state_change); ++ ++static bool rtl92c_bt_state_change(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); ++ ++ u32 polling, ratio_tx, ratio_pri; ++ u32 bt_tx, bt_pri; ++ u8 bt_state; ++ u8 cur_service_type; ++ ++ if (rtlpriv->mac80211.link_state < MAC80211_LINKED) ++ return false; ++ ++ bt_state = rtl_read_byte(rtlpriv, 0x4fd); ++ bt_tx = rtl_read_dword(rtlpriv, 0x488); ++ bt_tx = bt_tx & 0x00ffffff; ++ bt_pri = rtl_read_dword(rtlpriv, 0x48c); ++ bt_pri = bt_pri & 0x00ffffff; ++ polling = rtl_read_dword(rtlpriv, 0x490); ++ ++ if (bt_tx == 0xffffffff && bt_pri == 0xffffffff && ++ polling == 0xffffffff && bt_state == 0xff) ++ return false; ++ ++ bt_state &= BIT_OFFSET_LEN_MASK_32(0, 1); ++ if (bt_state != rtlpcipriv->bt_coexist.bt_cur_state) { ++ rtlpcipriv->bt_coexist.bt_cur_state = bt_state; ++ ++ if (rtlpcipriv->bt_coexist.reg_bt_sco == 3) { ++ rtlpcipriv->bt_coexist.bt_service = BT_IDLE; ++ ++ bt_state = bt_state | ++ ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? ++ 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | ++ BIT_OFFSET_LEN_MASK_32(2, 1); ++ rtl_write_byte(rtlpriv, 0x4fd, bt_state); ++ } ++ return true; ++ } ++ ++ ratio_tx = bt_tx * 1000 / polling; ++ ratio_pri = bt_pri * 1000 / polling; ++ rtlpcipriv->bt_coexist.ratio_tx = ratio_tx; ++ rtlpcipriv->bt_coexist.ratio_pri = ratio_pri; ++ ++ if (bt_state && rtlpcipriv->bt_coexist.reg_bt_sco == 3) { ++ ++ if ((ratio_tx < 30) && (ratio_pri < 30)) ++ cur_service_type = BT_IDLE; ++ else if ((ratio_pri > 110) && (ratio_pri < 250)) ++ cur_service_type = BT_SCO; ++ else if ((ratio_tx >= 200) && (ratio_pri >= 200)) ++ cur_service_type = BT_BUSY; ++ else if ((ratio_tx >= 350) && (ratio_tx < 500)) ++ cur_service_type = BT_OTHERBUSY; ++ else if (ratio_tx >= 500) ++ cur_service_type = BT_PAN; ++ else ++ cur_service_type = BT_OTHER_ACTION; ++ ++ if (cur_service_type != rtlpcipriv->bt_coexist.bt_service) { ++ rtlpcipriv->bt_coexist.bt_service = cur_service_type; ++ bt_state = bt_state | ++ ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? ++ 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | ++ ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) ? ++ 0 : BIT_OFFSET_LEN_MASK_32(2, 1)); ++ ++ /* Add interrupt migration when bt is not ini ++ * idle state (no traffic). */ ++ if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { ++ rtl_write_word(rtlpriv, 0x504, 0x0ccc); ++ rtl_write_byte(rtlpriv, 0x506, 0x54); ++ rtl_write_byte(rtlpriv, 0x507, 0x54); ++ } else { ++ rtl_write_byte(rtlpriv, 0x506, 0x00); ++ rtl_write_byte(rtlpriv, 0x507, 0x00); ++ } ++ ++ rtl_write_byte(rtlpriv, 0x4fd, bt_state); ++ return true; ++ } ++ } ++ ++ return false; ++ ++} ++ ++static bool rtl92c_bt_wifi_connect_change(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ static bool media_connect; ++ ++ if (rtlpriv->mac80211.link_state < MAC80211_LINKED) { ++ media_connect = false; ++ } else { ++ if (!media_connect) { ++ media_connect = true; ++ return true; ++ } ++ media_connect = true; ++ } ++ ++ return false; ++} ++ ++static void rtl92c_bt_set_normal(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); ++ ++ ++ if (rtlpcipriv->bt_coexist.bt_service == BT_OTHERBUSY) { ++ rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72b; ++ rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72b; ++ } else if (rtlpcipriv->bt_coexist.bt_service == BT_BUSY) { ++ rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82f; ++ rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82f; ++ } else if (rtlpcipriv->bt_coexist.bt_service == BT_SCO) { ++ if (rtlpcipriv->bt_coexist.ratio_tx > 160) { ++ rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72f; ++ rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72f; ++ } else { ++ rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea32b; ++ rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea42b; ++ } ++ } else { ++ rtlpcipriv->bt_coexist.bt_edca_ul = 0; ++ rtlpcipriv->bt_coexist.bt_edca_dl = 0; ++ } ++ ++ if ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) && ++ (rtlpriv->mac80211.mode == WIRELESS_MODE_G || ++ (rtlpriv->mac80211.mode == (WIRELESS_MODE_G | WIRELESS_MODE_B))) && ++ (rtlpcipriv->bt_coexist.bt_rssi_state & ++ BT_RSSI_STATE_BG_EDCA_LOW)) { ++ rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82b; ++ rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82b; ++ } ++} ++ ++static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); ++ ++ ++ /* Only enable HW BT coexist when BT in "Busy" state. */ ++ if (rtlpriv->mac80211.vendor == PEER_CISCO && ++ rtlpcipriv->bt_coexist.bt_service == BT_OTHER_ACTION) { ++ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); ++ } else { ++ if ((rtlpcipriv->bt_coexist.bt_service == BT_BUSY) && ++ (rtlpcipriv->bt_coexist.bt_rssi_state & ++ BT_RSSI_STATE_NORMAL_POWER)) { ++ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); ++ } else if ((rtlpcipriv->bt_coexist.bt_service == ++ BT_OTHER_ACTION) && (rtlpriv->mac80211.mode < ++ WIRELESS_MODE_N_24G) && ++ (rtlpcipriv->bt_coexist.bt_rssi_state & ++ BT_RSSI_STATE_SPECIAL_LOW)) { ++ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); ++ } else if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) { ++ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); ++ } else { ++ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); ++ } ++ } ++ ++ if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) ++ rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x10100); ++ else ++ rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x0); ++ ++ if (rtlpcipriv->bt_coexist.bt_rssi_state & ++ BT_RSSI_STATE_NORMAL_POWER) { ++ rtl92c_bt_set_normal(hw); ++ } else { ++ rtlpcipriv->bt_coexist.bt_edca_ul = 0; ++ rtlpcipriv->bt_coexist.bt_edca_dl = 0; ++ } ++ ++ if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { ++ rtlpriv->cfg->ops->set_rfreg(hw, ++ RF90_PATH_A, ++ 0x1e, ++ 0xf0, 0xf); ++ } else { ++ rtlpriv->cfg->ops->set_rfreg(hw, ++ RF90_PATH_A, 0x1e, 0xf0, ++ rtlpcipriv->bt_coexist.bt_rfreg_origin_1e); ++ } ++ ++ if (!rtlpriv->dm.dynamic_txpower_enable) { ++ if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { ++ if (rtlpcipriv->bt_coexist.bt_rssi_state & ++ BT_RSSI_STATE_TXPOWER_LOW) { ++ rtlpriv->dm.dynamic_txhighpower_lvl = ++ TXHIGHPWRLEVEL_BT2; ++ } else { ++ rtlpriv->dm.dynamic_txhighpower_lvl = ++ TXHIGHPWRLEVEL_BT1; ++ } ++ } else { ++ rtlpriv->dm.dynamic_txhighpower_lvl = ++ TXHIGHPWRLEVEL_NORMAL; ++ } ++ rtl92c_phy_set_txpower_level(hw, ++ rtlpriv->phy.current_channel); ++ } ++} ++ ++static void rtl92c_check_bt_change(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); ++ ++ if (rtlpcipriv->bt_coexist.bt_cur_state) { ++ if (rtlpcipriv->bt_coexist.bt_ant_isolation) ++ rtl92c_bt_ant_isolation(hw); ++ } else { ++ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); ++ rtlpriv->cfg->ops->set_rfreg(hw, RF90_PATH_A, 0x1e, 0xf0, ++ rtlpcipriv->bt_coexist.bt_rfreg_origin_1e); ++ ++ rtlpcipriv->bt_coexist.bt_edca_ul = 0; ++ rtlpcipriv->bt_coexist.bt_edca_dl = 0; ++ } ++} ++ ++void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw) ++{ ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); ++ ++ bool wifi_connect_change; ++ bool bt_state_change; ++ bool rssi_state_change; ++ ++ if ((rtlpcipriv->bt_coexist.bt_coexistence) && ++ (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) { ++ ++ wifi_connect_change = rtl92c_bt_wifi_connect_change(hw); ++ bt_state_change = rtl92c_bt_state_change(hw); ++ rssi_state_change = rtl92c_bt_rssi_state_change(hw); ++ ++ if (wifi_connect_change || bt_state_change || rssi_state_change) ++ rtl92c_check_bt_change(hw); ++ } ++} ++EXPORT_SYMBOL(rtl92c_dm_bt_coexist); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h 2011-05-05 23:29:49.324488249 +0200 +@@ -200,5 +200,7 @@ + void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); + void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); + void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery); ++void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw); ++void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw); + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c 2011-05-05 23:29:49.323488237 +0200 +@@ -171,7 +171,6 @@ + static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); +- int err = -EIO; + u32 counter = 0; + u32 value32; + +@@ -184,7 +183,7 @@ + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("chksum report faill ! REG_MCUFWDL:0x%08x .\n", + value32)); +- goto exit; ++ return -EIO; + } + + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, +@@ -204,8 +203,7 @@ + ("Polling FW ready success!!" + " REG_MCUFWDL:0x%08x .\n", + value32)); +- err = 0; +- goto exit; ++ return 0; + } + + mdelay(FW_8192C_POLLING_DELAY); +@@ -214,9 +212,7 @@ + + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32)); +- +-exit: +- return err; ++ return -EIO; + } + + int rtl92c_download_fw(struct ieee80211_hw *hw) +@@ -226,32 +222,16 @@ + struct rtl92c_firmware_header *pfwheader; + u8 *pfwdata; + u32 fwsize; +- int err; + enum version_8192c version = rtlhal->version; +- const struct firmware *firmware; + +- printk(KERN_INFO "rtl8192cu: Loading firmware file %s\n", ++ printk(KERN_INFO "rtl8192c: Loading firmware file %s\n", + rtlpriv->cfg->fw_name); +- err = request_firmware(&firmware, rtlpriv->cfg->fw_name, +- rtlpriv->io.dev); +- if (err) { +- printk(KERN_ERR "rtl8192cu: Firmware loading failed\n"); +- return 1; +- } +- +- if (firmware->size > 0x4000) { +- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +- ("Firmware is too big!\n")); +- release_firmware(firmware); ++ if (!rtlhal->pfirmware) + return 1; +- } +- +- memcpy(rtlhal->pfirmware, firmware->data, firmware->size); +- fwsize = firmware->size; +- release_firmware(firmware); + + pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; + pfwdata = (u8 *) rtlhal->pfirmware; ++ fwsize = rtlhal->fwsize; + + if (IS_FW_HEADER_EXIST(pfwheader)) { + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, +@@ -267,8 +247,7 @@ + _rtl92c_write_fw(hw, version, pfwdata, fwsize); + _rtl92c_enable_fw_download(hw, false); + +- err = _rtl92c_fw_free_to_go(hw); +- if (err) { ++ if (_rtl92c_fw_free_to_go(hw)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Firmware is not ready to run!\n")); + } else { +@@ -300,10 +279,9 @@ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 boxnum; +- u16 box_reg, box_extreg; ++ u16 box_reg = 0, box_extreg = 0; + u8 u1b_tmp; + bool isfw_read = false; +- u8 buf_index = 0; + bool bwrite_sucess = false; + u8 wait_h2c_limmit = 100; + u8 wait_writeh2c_limmit = 100; +@@ -414,7 +392,7 @@ + case 1: + boxcontent[0] &= ~(BIT(7)); + memcpy((u8 *) (boxcontent) + 1, +- p_cmdbuffer + buf_index, 1); ++ p_cmdbuffer, 1); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, +@@ -424,7 +402,7 @@ + case 2: + boxcontent[0] &= ~(BIT(7)); + memcpy((u8 *) (boxcontent) + 1, +- p_cmdbuffer + buf_index, 2); ++ p_cmdbuffer, 2); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, +@@ -434,7 +412,7 @@ + case 3: + boxcontent[0] &= ~(BIT(7)); + memcpy((u8 *) (boxcontent) + 1, +- p_cmdbuffer + buf_index, 3); ++ p_cmdbuffer, 3); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, +@@ -444,9 +422,9 @@ + case 4: + boxcontent[0] |= (BIT(7)); + memcpy((u8 *) (boxextcontent), +- p_cmdbuffer + buf_index, 2); ++ p_cmdbuffer, 2); + memcpy((u8 *) (boxcontent) + 1, +- p_cmdbuffer + buf_index + 2, 2); ++ p_cmdbuffer + 2, 2); + + for (idx = 0; idx < 2; idx++) { + rtl_write_byte(rtlpriv, box_extreg + idx, +@@ -461,9 +439,9 @@ + case 5: + boxcontent[0] |= (BIT(7)); + memcpy((u8 *) (boxextcontent), +- p_cmdbuffer + buf_index, 2); ++ p_cmdbuffer, 2); + memcpy((u8 *) (boxcontent) + 1, +- p_cmdbuffer + buf_index + 2, 3); ++ p_cmdbuffer + 2, 3); + + for (idx = 0; idx < 2; idx++) { + rtl_write_byte(rtlpriv, box_extreg + idx, +@@ -561,6 +539,39 @@ + } + EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd); + ++static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, ++ struct sk_buff *skb) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ struct rtl8192_tx_ring *ring; ++ struct rtl_tx_desc *pdesc; ++ u8 own; ++ unsigned long flags; ++ struct sk_buff *pskb = NULL; ++ ++ ring = &rtlpci->tx_ring[BEACON_QUEUE]; ++ ++ pskb = __skb_dequeue(&ring->queue); ++ if (pskb) ++ kfree_skb(pskb); ++ ++ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); ++ ++ pdesc = &ring->desc[0]; ++ own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); ++ ++ rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); ++ ++ __skb_queue_tail(&ring->queue, skb); ++ ++ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); ++ ++ rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); ++ ++ return true; ++} ++ + #define BEACON_PG 0 /*->1*/ + #define PSPOLL_PG 2 + #define NULL_PG 3 +@@ -678,7 +689,7 @@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + +-void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) ++void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +@@ -687,12 +698,12 @@ + u32 totalpacketlen; + bool rtstatus; + u8 u1RsvdPageLoc[3] = {0}; +- bool b_dlok = false; ++ bool dlok = false; + + u8 *beacon; +- u8 *p_pspoll; ++ u8 *pspoll; + u8 *nullfunc; +- u8 *p_probersp; ++ u8 *probersp; + /*--------------------------------------------------------- + (1) beacon + ---------------------------------------------------------*/ +@@ -703,10 +714,10 @@ + /*------------------------------------------------------- + (2) ps-poll + --------------------------------------------------------*/ +- p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; +- SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); +- SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); +- SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); ++ pspoll = &reserved_page_packet[PSPOLL_PG * 128]; ++ SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000)); ++ SET_80211_PS_POLL_BSSID(pspoll, mac->bssid); ++ SET_80211_PS_POLL_TA(pspoll, mac->mac_addr); + + SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG); + +@@ -723,10 +734,10 @@ + /*--------------------------------------------------------- + (4) probe response + ----------------------------------------------------------*/ +- p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; +- SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); +- SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); +- SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); ++ probersp = &reserved_page_packet[PROBERSP_PG * 128]; ++ SET_80211_HDR_ADDRESS1(probersp, mac->bssid); ++ SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr); ++ SET_80211_HDR_ADDRESS3(probersp, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG); + +@@ -744,12 +755,12 @@ + memcpy((u8 *) skb_put(skb, totalpacketlen), + &reserved_page_packet, totalpacketlen); + +- rtstatus = rtlpriv->cfg->ops->cmd_send_packet(hw, skb); ++ rtstatus = _rtl92c_cmd_send_packet(hw, skb); + + if (rtstatus) +- b_dlok = true; ++ dlok = true; + +- if (b_dlok) { ++ if (dlok) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Set RSVD page location to Fw.\n")); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h 2011-05-05 23:29:49.323488237 +0200 +@@ -27,8 +27,8 @@ + * + *****************************************************************************/ + +-#ifndef __RTL92C__FW__H__ +-#define __RTL92C__FW__H__ ++#ifndef __RTL92C__FW__COMMON__H__ ++#define __RTL92C__FW__COMMON__H__ + + #define FW_8192C_SIZE 0x3000 + #define FW_8192C_START_ADDRESS 0x1000 +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c 2011-05-05 23:29:49.322488225 +0200 +@@ -78,27 +78,29 @@ + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," + " data(%#x)\n", regaddr, bitmask, + data)); ++ + } + EXPORT_SYMBOL(rtl92c_phy_set_bb_reg); + + u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, +- enum radio_path rfpath, u32 offset) ++ enum radio_path rfpath, u32 offset) + { + RT_ASSERT(false, ("deprecated!\n")); + return 0; ++ + } + EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_read); + + void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, +- enum radio_path rfpath, u32 offset, +- u32 data) ++ enum radio_path rfpath, u32 offset, ++ u32 data) + { + RT_ASSERT(false, ("deprecated!\n")); + } + EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_write); + + u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, +- enum radio_path rfpath, u32 offset) ++ enum radio_path rfpath, u32 offset) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); +@@ -149,8 +151,8 @@ + EXPORT_SYMBOL(_rtl92c_phy_rf_serial_read); + + void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, +- enum radio_path rfpath, u32 offset, +- u32 data) ++ enum radio_path rfpath, u32 offset, ++ u32 data) + { + u32 data_and_addr; + u32 newoffset; +@@ -197,6 +199,7 @@ + rtl_set_bbreg(hw, 0xe80, 0x0c000000, 0x2); + rtl_set_bbreg(hw, 0xe88, 0x0c000000, 0x2); + } ++ + bool rtl92c_phy_rf_config(struct ieee80211_hw *hw) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); +@@ -241,13 +244,14 @@ + rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + 0x200)); ++ + return true; + } + EXPORT_SYMBOL(_rtl92c_phy_bb8192c_config_parafile); + + void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, +- u32 regaddr, u32 bitmask, +- u32 data) ++ u32 regaddr, u32 bitmask, ++ u32 data) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); +@@ -317,61 +321,48 @@ + } + if (regaddr == RTXAGC_B_RATE54_24) { + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9] = data; +- + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n", + rtlphy->pwrgroup_cnt, + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9])); + } +- + if (regaddr == RTXAGC_B_CCK1_55_MCS32) { + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14] = data; +- + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n", + rtlphy->pwrgroup_cnt, + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14])); + } +- + if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) { + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15] = data; +- + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n", + rtlphy->pwrgroup_cnt, + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15])); + } +- + if (regaddr == RTXAGC_B_MCS03_MCS00) { + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10] = data; +- + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n", + rtlphy->pwrgroup_cnt, + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10])); + } +- + if (regaddr == RTXAGC_B_MCS07_MCS04) { + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11] = data; +- + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n", + rtlphy->pwrgroup_cnt, + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11])); + } +- + if (regaddr == RTXAGC_B_MCS11_MCS08) { + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12] = data; +- + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n", + rtlphy->pwrgroup_cnt, + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12])); + } +- + if (regaddr == RTXAGC_B_MCS15_MCS12) { + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][13] = data; +- + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n", + rtlphy->pwrgroup_cnt, +@@ -583,6 +574,7 @@ + + rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; + rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; ++ + } + + void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) +@@ -611,7 +603,6 @@ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 idx; + u8 rf_path; +- + u8 ccktxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw, + WIRELESS_MODE_B, + power_indbm); +@@ -639,11 +630,6 @@ + } + EXPORT_SYMBOL(rtl92c_phy_update_txpower_dbm); + +-void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval) +-{ +-} +-EXPORT_SYMBOL(rtl92c_phy_set_beacon_hw_reg); +- + u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, + enum wireless_mode wirelessmode, + long power_indbm) +@@ -741,9 +727,9 @@ + if (rtlphy->set_bwmode_inprogress) + return; + rtlphy->set_bwmode_inprogress = true; +- if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) +- rtlpriv->cfg->ops->phy_set_bw_mode_callback(hw); +- else { ++ if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { ++ rtlphy->set_bwmode_inprogress = false; ++ } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("FALSE driver sleep or unload\n")); + rtlphy->set_bwmode_inprogress = false; +@@ -773,8 +759,9 @@ + mdelay(delay); + else + continue; +- } else ++ } else { + rtlphy->sw_chnl_inprogress = false; ++ } + break; + } while (true); + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); +@@ -811,9 +798,32 @@ + } + EXPORT_SYMBOL(rtl92c_phy_sw_chnl); + +-static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, +- u8 channel, u8 *stage, u8 *step, +- u32 *delay) ++static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, ++ u32 cmdtableidx, u32 cmdtablesz, ++ enum swchnlcmd_id cmdid, ++ u32 para1, u32 para2, u32 msdelay) ++{ ++ struct swchnlcmd *pcmd; ++ ++ if (cmdtable == NULL) { ++ RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); ++ return false; ++ } ++ ++ if (cmdtableidx >= cmdtablesz) ++ return false; ++ ++ pcmd = cmdtable + cmdtableidx; ++ pcmd->cmdid = cmdid; ++ pcmd->para1 = para1; ++ pcmd->para2 = para2; ++ pcmd->msdelay = msdelay; ++ return true; ++} ++ ++bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, ++ u8 channel, u8 *stage, u8 *step, ++ u32 *delay) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); +@@ -917,29 +927,6 @@ + return false; + } + +-static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, +- u32 cmdtableidx, u32 cmdtablesz, +- enum swchnlcmd_id cmdid, +- u32 para1, u32 para2, u32 msdelay) +-{ +- struct swchnlcmd *pcmd; +- +- if (cmdtable == NULL) { +- RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); +- return false; +- } +- +- if (cmdtableidx >= cmdtablesz) +- return false; +- +- pcmd = cmdtable + cmdtableidx; +- pcmd->cmdid = cmdid; +- pcmd->para1 = para1; +- pcmd->para2 = para2; +- pcmd->msdelay = msdelay; +- return true; +-} +- + bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath) + { + return true; +@@ -1002,13 +989,13 @@ + reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD); + reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD); + reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD); ++ + if (!(reg_eac & BIT(31)) && + (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) && + (((reg_ebc & 0x03FF0000) >> 16) != 0x42)) + result |= 0x01; + else + return result; +- + if (!(reg_eac & BIT(30)) && + (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) && + (((reg_ecc & 0x03FF0000) >> 16) != 0x36)) +@@ -1023,9 +1010,9 @@ + u32 oldval_0, x, tx0_a, reg; + long y, tx0_c; + +- if (final_candidate == 0xFF) ++ if (final_candidate == 0xFF) { + return; +- else if (iqk_ok) { ++ } else if (iqk_ok) { + oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, + MASKDWORD) >> 22) & 0x3FF; + x = result[final_candidate][0]; +@@ -1063,9 +1050,9 @@ + u32 oldval_1, x, tx1_a, reg; + long y, tx1_c; + +- if (final_candidate == 0xFF) ++ if (final_candidate == 0xFF) { + return; +- else if (iqk_ok) { ++ } else if (iqk_ok) { + oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, + MASKDWORD) >> 22) & 0x3FF; + x = result[final_candidate][4]; +@@ -1282,6 +1269,7 @@ + RFPGA0_XA_HSSIPARAMETER1, + BIT(8)); + } ++ + if (!rtlphy->rfpi_enable) + _rtl92c_phy_pi_mode_switch(hw, true); + if (t == 0) { +@@ -1317,9 +1305,10 @@ + 0x3FF0000) >> 16; + break; + } else if (i == (retrycount - 1) && patha_ok == 0x01) ++ + result[t][0] = (rtl_get_bbreg(hw, 0xe94, + MASKDWORD) & 0x3FF0000) >> +- 16; ++ 16; + result[t][1] = + (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; + +@@ -1375,8 +1364,7 @@ + static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, + char delta, bool is2t) + { +- /* This routine is deliberately dummied out for later fixes */ +-#if 0 ++#if 0 /* This routine is deliberately dummied out for later fixes */ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +@@ -1434,7 +1422,7 @@ + 0x04db25a4, 0x0b1b25a4 + }; + +- u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c }; ++ const u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c }; + + u32 apk_normal_offset[PATH_NUM] = { 0xb28, 0xb98 }; + +@@ -1463,13 +1451,15 @@ + 0x00050006 + }; + +- const u32 apk_result[PATH_NUM][APK_BB_REG_NUM]; ++ u32 apk_result[PATH_NUM][APK_BB_REG_NUM]; + + long bb_offset, delta_v, delta_offset; + + if (!is2t) + pathbound = 1; + ++ return; ++ + for (index = 0; index < PATH_NUM; index++) { + apk_offset[index] = apk_normal_offset[index]; + apk_value[index] = apk_normal_value[index]; +@@ -1730,8 +1720,7 @@ + 0x08)); + + } +- +- rtlphy->apk_done = true; ++ rtlphy->b_apk_done = true; + #endif + } + +@@ -1758,6 +1747,7 @@ + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1); + + } ++ + } + + #undef IQK_ADDA_REG_NUM +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h 2011-05-05 23:29:49.324488249 +0200 +@@ -27,8 +27,8 @@ + * + *****************************************************************************/ + +-#ifndef __RTL92C_PHY_H__ +-#define __RTL92C_PHY_H__ ++#ifndef __RTL92C_PHY_COMMON_H__ ++#define __RTL92C_PHY_COMMON_H__ + + #define MAX_PRECMD_CNT 16 + #define MAX_RFDEPENDCMD_CNT 16 +@@ -39,6 +39,7 @@ + #define RT_CANNOT_IO(hw) false + #define HIGHPOWER_RADIOA_ARRAYLEN 22 + ++#define IQK_ADDA_REG_NUM 16 + #define MAX_TOLERANCE 5 + #define IQK_DELAY_TIME 1 + +@@ -56,6 +57,7 @@ + #define IQK_ADDA_REG_NUM 16 + #define IQK_MAC_REG_NUM 4 + ++#define IQK_DELAY_TIME 1 + #define RF90_PATH_MAX 2 + + #define CT_OFFSET_MAC_ADDR 0X16 +@@ -77,6 +79,7 @@ + + #define RTL92C_MAX_PATH_NUM 2 + #define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255 ++ + enum swchnlcmd_id { + CMDID_END, + CMDID_SET_TXPOWEROWER_LEVEL, +@@ -184,45 +187,41 @@ + u32 mcs_original_offset[4][16]; + }; + +-extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, ++u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask); +-extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, ++void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, u32 data); +-extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, ++u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask); +-extern void rtl92c_phy_set_rf_reg(struct ieee80211_hw *hw, +- enum radio_path rfpath, u32 regaddr, +- u32 bitmask, u32 data); +-extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); +-extern bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); +-extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); +-extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, ++bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); ++bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); ++bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); ++bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +-extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +-extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, ++void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); ++void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, + long *powerlevel); +-extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +-extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, ++void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); ++bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, + long power_indbm); +-extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, ++void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, + u8 operation); +-extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +-extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, ++void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); +-extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); +-extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); +-extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +-extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, ++void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); ++u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); ++void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); ++void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, + u16 beaconinterval); + void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); + void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); + void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); + bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +-extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, ++bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, + u32 rfpath); +-extern bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, ++bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); + void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw); + void rtl92c_phy_set_io(struct ieee80211_hw *hw); +@@ -235,12 +234,25 @@ + enum wireless_mode wirelessmode, + long power_indbm); + void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); +-static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, +- u32 cmdtableidx, u32 cmdtablesz, +- enum swchnlcmd_id cmdid, u32 para1, +- u32 para2, u32 msdelay); +-static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, +- u8 channel, u8 *stage, u8 *step, +- u32 *delay); ++void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw); ++bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, ++ u8 channel, u8 *stage, u8 *step, ++ u32 *delay); ++u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw); ++u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, ++ enum radio_path rfpath, u32 offset); ++void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, ++ enum radio_path rfpath, u32 offset, ++ u32 data); ++u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, ++ enum radio_path rfpath, u32 offset); ++void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, ++ enum radio_path rfpath, u32 offset, ++ u32 data); ++bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw); ++void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, ++ u32 regaddr, u32 bitmask, ++ u32 data); ++bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/def.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/def.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/def.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/def.h 2011-05-05 23:29:49.330488321 +0200 +@@ -121,19 +121,6 @@ + #define CHIP_92C 0x01 + #define CHIP_88C 0x00 + +-/* Add vendor information into chip version definition. +- * Add UMC B-Cut and RTL8723 chip info definition. +- * +- * BIT 7 Reserved +- * BIT 6 UMC BCut +- * BIT 5 Manufacturer(TSMC/UMC) +- * BIT 4 TEST/NORMAL +- * BIT 3 8723 Version +- * BIT 2 8723? +- * BIT 1 1T2R? +- * BIT 0 88C/92C +-*/ +- + enum version_8192c { + VERSION_A_CHIP_92C = 0x01, + VERSION_A_CHIP_88C = 0x00, +@@ -280,20 +267,6 @@ + u8 *p_cmdbuffer; + }; + +-static inline u8 _rtl92c_get_chnl_group(u8 chnl) +-{ +- u8 group = 0; +- +- if (chnl < 3) +- group = 0; +- else if (chnl < 9) +- group = 1; +- else +- group = 2; +- +- return group; +-} +- + /* NOTE: reference to rtl8192c_rates struct */ + static inline int _rtl92c_rate_mapping(struct ieee80211_hw *hw, bool isHT, + u8 desc_rate, bool first_ampdu) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c 2011-05-05 23:29:49.332488345 +0200 +@@ -29,10 +29,12 @@ + + #include "../wifi.h" + #include "../base.h" ++#include "../pci.h" + #include "reg.h" + #include "def.h" + #include "phy.h" + #include "dm.h" ++#include "../rtl8192c/fw_common.h" + + void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw) + { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h 2011-05-05 23:29:49.325488261 +0200 +@@ -192,6 +192,7 @@ + void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw); + void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); + void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); ++void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw); + void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw); + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c 2011-05-05 23:29:49.331488333 +0200 +@@ -30,12 +30,14 @@ + #include "../wifi.h" + #include "../efuse.h" + #include "../base.h" ++#include "../regd.h" + #include "../cam.h" + #include "../ps.h" + #include "../pci.h" + #include "reg.h" + #include "def.h" + #include "phy.h" ++#include "../rtl8192c/fw_common.h" + #include "dm.h" + #include "led.h" + #include "hw.h" +@@ -137,15 +139,6 @@ + + break; + } +- case HW_VAR_MGT_FILTER: +- *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP0); +- break; +- case HW_VAR_CTRL_FILTER: +- *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP1); +- break; +- case HW_VAR_DATA_FILTER: +- *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP2); +- break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); +@@ -156,6 +149,7 @@ + void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +@@ -178,7 +172,7 @@ + rate_cfg |= 0x01; + rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff); + rtl_write_byte(rtlpriv, REG_RRSR + 1, +- (rate_cfg >> 8)&0xff); ++ (rate_cfg >> 8) & 0xff); + while (rate_cfg > 0x1) { + rate_cfg = (rate_cfg >> 1); + rate_index++; +@@ -276,13 +270,19 @@ + break; + } + case HW_VAR_AMPDU_FACTOR:{ +- u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 }; ++ u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9}; ++ u8 regtoset_bt[4] = {0x31, 0x74, 0x42, 0x97}; + + u8 factor_toset; + u8 *p_regtoset = NULL; + u8 index = 0; + +- p_regtoset = regtoset_normal; ++ if ((rtlpcipriv->bt_coexist.bt_coexistence) && ++ (rtlpcipriv->bt_coexist.bt_coexist_type == ++ BT_CSR_BC4)) ++ p_regtoset = regtoset_bt; ++ else ++ p_regtoset = regtoset_normal; + + factor_toset = *((u8 *) val); + if (factor_toset <= 3) { +@@ -317,45 +317,7 @@ + } + case HW_VAR_AC_PARAM:{ + u8 e_aci = *((u8 *) val); +- u32 u4b_ac_param; +- u16 cw_min = le16_to_cpu(mac->ac[e_aci].cw_min); +- u16 cw_max = le16_to_cpu(mac->ac[e_aci].cw_max); +- u16 tx_op = le16_to_cpu(mac->ac[e_aci].tx_op); +- +- u4b_ac_param = (u32) mac->ac[e_aci].aifs; +- u4b_ac_param |= ((u32)cw_min +- & 0xF) << AC_PARAM_ECW_MIN_OFFSET; +- u4b_ac_param |= ((u32)cw_max & +- 0xF) << AC_PARAM_ECW_MAX_OFFSET; +- u4b_ac_param |= (u32)tx_op << AC_PARAM_TXOP_OFFSET; +- +- RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, +- ("queue:%x, ac_param:%x\n", e_aci, +- u4b_ac_param)); +- +- switch (e_aci) { +- case AC1_BK: +- rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, +- u4b_ac_param); +- break; +- case AC0_BE: +- rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, +- u4b_ac_param); +- break; +- case AC2_VI: +- rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, +- u4b_ac_param); +- break; +- case AC3_VO: +- rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, +- u4b_ac_param); +- break; +- default: +- RT_ASSERT(false, +- ("SetHwReg8185(): invalid aci: %d !\n", +- e_aci)); +- break; +- } ++ rtl92c_dm_init_edca_turbo(hw); + + if (rtlpci->acm_method != eAcmWay2_SW) + rtlpriv->cfg->ops->set_hw_reg(hw, +@@ -526,9 +488,6 @@ + case HW_VAR_CORRECT_TSF:{ + u8 btype_ibss = ((u8 *) (val))[0]; + +- /*btype_ibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? +- 1 : 0;*/ +- + if (btype_ibss == true) + _rtl92ce_stop_tx_beacon(hw); + +@@ -537,7 +496,7 @@ + rtl_write_dword(rtlpriv, REG_TSFTR, + (u32) (mac->tsf & 0xffffffff)); + rtl_write_dword(rtlpriv, REG_TSFTR + 4, +- (u32) ((mac->tsf >> 32)&0xffffffff)); ++ (u32) ((mac->tsf >> 32) & 0xffffffff)); + + _rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0); + +@@ -547,15 +506,6 @@ + break; + + } +- case HW_VAR_MGT_FILTER: +- rtl_write_word(rtlpriv, REG_RXFLTMAP0, *(u16 *) val); +- break; +- case HW_VAR_CTRL_FILTER: +- rtl_write_word(rtlpriv, REG_RXFLTMAP1, *(u16 *) val); +- break; +- case HW_VAR_DATA_FILTER: +- rtl_write_word(rtlpriv, REG_RXFLTMAP2, *(u16 *) val); +- break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case " + "not process\n")); +@@ -679,12 +629,12 @@ + rtl92ce_sw_led_on(hw, pLed0); + else + rtl92ce_sw_led_off(hw, pLed0); +- + } + + static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +@@ -693,9 +643,22 @@ + u16 retry; + + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); ++ if (rtlpcipriv->bt_coexist.bt_coexistence) { ++ u32 value32; ++ value32 = rtl_read_dword(rtlpriv, REG_APS_FSMCO); ++ value32 |= (SOP_ABG | SOP_AMB | XOP_BTCK); ++ rtl_write_dword(rtlpriv, REG_APS_FSMCO, value32); ++ } + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0F); + ++ if (rtlpcipriv->bt_coexist.bt_coexistence) { ++ u32 u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL); ++ ++ u4b_tmp &= (~0x00024800); ++ rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp); ++ } ++ + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) | BIT(0); + udelay(2); + +@@ -726,6 +689,11 @@ + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x82); + udelay(2); + ++ if (rtlpcipriv->bt_coexist.bt_coexistence) { ++ bytetmp = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+2) & 0xfd; ++ rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+2, bytetmp); ++ } ++ + rtl_write_word(rtlpriv, REG_CR, 0x2ff); + + if (_rtl92ce_llt_table_init(hw) == false) +@@ -793,6 +761,7 @@ + { + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 reg_bw_opmode; + u32 reg_ratr, reg_prsr; + +@@ -824,7 +793,11 @@ + rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000); + rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504); + +- rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); ++ if ((rtlpcipriv->bt_coexist.bt_coexistence) && ++ (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) ++ rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x97427431); ++ else ++ rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); + + rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2); + +@@ -840,11 +813,20 @@ + rtl_write_byte(rtlpriv, REG_PIFS, 0x1C); + rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); + +- rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); +- +- rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); ++ if ((rtlpcipriv->bt_coexist.bt_coexistence) && ++ (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) { ++ rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); ++ rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0402); ++ } else { ++ rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); ++ rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); ++ } + +- rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666); ++ if ((rtlpcipriv->bt_coexist.bt_coexistence) && ++ (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) ++ rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666); ++ else ++ rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666); + + rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); + +@@ -948,8 +930,8 @@ + } + + rtlhal->last_hmeboxnum = 0; +- rtl92ce_phy_mac_config(hw); +- rtl92ce_phy_bb_config(hw); ++ rtl92c_phy_mac_config(hw); ++ rtl92c_phy_bb_config(hw); + rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; + rtl92c_phy_rf_config(hw); + rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, +@@ -962,15 +944,20 @@ + _rtl92ce_hw_configure(hw); + rtl_cam_reset_all_entry(hw); + rtl92ce_enable_hw_security_config(hw); ++ + ppsc->rfpwr_state = ERFON; ++ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); + _rtl92ce_enable_aspm_back_door(hw); + rtlpriv->intf_ops->enable_aspm(hw); ++ ++ rtl8192ce_bt_hw_init(hw); ++ + if (ppsc->rfpwr_state == ERFON) { + rtl92c_phy_set_rfpath_switch(hw, 1); +- if (iqk_initialized) ++ if (iqk_initialized) { + rtl92c_phy_iq_calibrate(hw, true); +- else { ++ } else { + rtl92c_phy_iq_calibrate(hw, false); + iqk_initialized = true; + } +@@ -1128,75 +1115,62 @@ + return 0; + } + +-static void _rtl92ce_set_check_bssid(struct ieee80211_hw *hw, +- enum nl80211_iftype type) ++void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); +- u8 filterout_non_associated_bssid = false; + +- switch (type) { +- case NL80211_IFTYPE_ADHOC: +- case NL80211_IFTYPE_STATION: +- filterout_non_associated_bssid = true; +- break; +- case NL80211_IFTYPE_UNSPECIFIED: +- case NL80211_IFTYPE_AP: +- default: +- break; +- } ++ if (rtlpriv->psc.rfpwr_state != ERFON) ++ return; + +- if (filterout_non_associated_bssid == true) { ++ if (check_bssid == true) { + reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, + (u8 *) (®_rcr)); + _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4)); +- } else if (filterout_non_associated_bssid == false) { ++ } else if (check_bssid == false) { + reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); + _rtl92ce_set_bcn_ctrl_reg(hw, BIT(4), 0); + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_RCR, (u8 *) (®_rcr)); + } ++ + } + + int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) + { ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ + if (_rtl92ce_set_media_status(hw, type)) + return -EOPNOTSUPP; +- _rtl92ce_set_check_bssid(hw, type); ++ ++ if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { ++ if (type != NL80211_IFTYPE_AP) ++ rtl92ce_set_check_bssid(hw, true); ++ } else { ++ rtl92ce_set_check_bssid(hw, false); ++ } ++ + return 0; + } + ++/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */ + void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); +- struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +- u32 u4b_ac_param; +- u16 cw_min = le16_to_cpu(mac->ac[aci].cw_min); +- u16 cw_max = le16_to_cpu(mac->ac[aci].cw_max); +- u16 tx_op = le16_to_cpu(mac->ac[aci].tx_op); +- + rtl92c_dm_init_edca_turbo(hw); +- u4b_ac_param = (u32) mac->ac[aci].aifs; +- u4b_ac_param |= (u32) ((cw_min & 0xF) << AC_PARAM_ECW_MIN_OFFSET); +- u4b_ac_param |= (u32) ((cw_max & 0xF) << AC_PARAM_ECW_MAX_OFFSET); +- u4b_ac_param |= (u32) (tx_op << AC_PARAM_TXOP_OFFSET); +- RT_TRACE(rtlpriv, COMP_QOS, DBG_DMESG, +- ("queue:%x, ac_param:%x aifs:%x cwmin:%x cwmax:%x txop:%x\n", +- aci, u4b_ac_param, mac->ac[aci].aifs, cw_min, +- cw_max, tx_op)); + switch (aci) { + case AC1_BK: +- rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, u4b_ac_param); ++ rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f); + break; + case AC0_BE: +- rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); ++ /* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); */ + break; + case AC2_VI: +- rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, u4b_ac_param); ++ rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322); + break; + case AC3_VO: +- rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, u4b_ac_param); ++ rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222); + break; + default: + RT_ASSERT(false, ("invalid aci: %d !\n", aci)); +@@ -1227,8 +1201,10 @@ + static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 u1b_tmp; ++ u32 u4b_tmp; + + rtlpriv->intf_ops->enable_aspm(hw); + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); +@@ -1243,13 +1219,27 @@ + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00000000); + u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL); +- rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 | +- (u1b_tmp << 8)); ++ if ((rtlpcipriv->bt_coexist.bt_coexistence) && ++ ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) || ++ (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8))) { ++ rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00F30000 | ++ (u1b_tmp << 8)); ++ } else { ++ rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 | ++ (u1b_tmp << 8)); ++ } + rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790); + rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80); + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23); +- rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e); ++ if (rtlpcipriv->bt_coexist.bt_coexistence) { ++ u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL); ++ u4b_tmp |= 0x03824800; ++ rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp); ++ } else { ++ rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e); ++ } ++ + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e); + rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, 0x10); + } +@@ -1327,6 +1317,7 @@ + + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr)); ++ + if (add_msr) + rtlpci->irq_mask[0] |= add_msr; + if (rm_msr) +@@ -1582,7 +1573,7 @@ + ("RTL819X Not boot from eeprom, check it !!")); + } + +- RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, ("MAP\n"), ++ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"), + hwinfo, HWSET_MAX_SIZE); + + eeprom_id = *((u16 *)&hwinfo[0]); +@@ -1610,6 +1601,10 @@ + rtlefuse->autoload_failflag, + hwinfo); + ++ rtl8192ce_read_bt_coexist_info_from_hwpg(hw, ++ rtlefuse->autoload_failflag, ++ hwinfo); ++ + rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; + rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; + rtlefuse->txpwr_fromeprom = true; +@@ -1618,6 +1613,9 @@ + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid)); + ++ /* set channel paln to world wide 13 */ ++ rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; ++ + if (rtlhal->oem_id == RT_CID_DEFAULT) { + switch (rtlefuse->eeprom_oemid) { + case EEPROM_CID_DEFAULT: +@@ -1701,30 +1699,36 @@ + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n")); + } +- + _rtl92ce_hal_customized_behavior(hw); + } + +-void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) ++static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +- +- u32 ratr_value = (u32) mac->basic_rates; +- u8 *mcsrate = mac->mcs; ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ u32 ratr_value; + u8 ratr_index = 0; + u8 nmode = mac->ht_enable; +- u8 mimo_ps = 1; ++ u8 mimo_ps = IEEE80211_SMPS_OFF; + u16 shortgi_rate; + u32 tmp_ratr_value; + u8 curtxbw_40mhz = mac->bw_40; +- u8 curshortgi_40mhz = mac->sgi_40; +- u8 curshortgi_20mhz = mac->sgi_20; ++ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? ++ 1 : 0; ++ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? ++ 1 : 0; + enum wireless_mode wirelessmode = mac->mode; + +- ratr_value |= ((*(u16 *) (mcsrate))) << 12; +- ++ if (rtlhal->current_bandtype == BAND_ON_5G) ++ ratr_value = sta->supp_rates[1] << 4; ++ else ++ ratr_value = sta->supp_rates[0]; ++ ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | ++ sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + if (ratr_value & 0x0000000c) +@@ -1738,7 +1742,7 @@ + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + nmode = 1; +- if (mimo_ps == 0) { ++ if (mimo_ps == IEEE80211_SMPS_STATIC) { + ratr_value &= 0x0007F005; + } else { + u32 ratr_mask; +@@ -1761,10 +1765,19 @@ + break; + } + +- ratr_value &= 0x0FFFFFFF; ++ if ((rtlpcipriv->bt_coexist.bt_coexistence) && ++ (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) && ++ (rtlpcipriv->bt_coexist.bt_cur_state) && ++ (rtlpcipriv->bt_coexist.bt_ant_isolation) && ++ ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) || ++ (rtlpcipriv->bt_coexist.bt_service == BT_BUSY))) ++ ratr_value &= 0x0fffcfc0; ++ else ++ ratr_value &= 0x0FFFFFFF; + +- if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) || (!curtxbw_40mhz && +- curshortgi_20mhz))) { ++ if (nmode && ((curtxbw_40mhz && ++ curshortgi_40mhz) || (!curtxbw_40mhz && ++ curshortgi_20mhz))) { + + ratr_value |= 0x10000000; + tmp_ratr_value = (ratr_value >> 12); +@@ -1784,24 +1797,42 @@ + ("%x\n", rtl_read_dword(rtlpriv, REG_ARFR0))); + } + +-void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) ++static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, u8 rssi_level) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +- u32 ratr_bitmap = (u32) mac->basic_rates; +- u8 *p_mcsrate = mac->mcs; ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_sta_info *sta_entry = NULL; ++ u32 ratr_bitmap; + u8 ratr_index; +- u8 curtxbw_40mhz = mac->bw_40; +- u8 curshortgi_40mhz = mac->sgi_40; +- u8 curshortgi_20mhz = mac->sgi_20; +- enum wireless_mode wirelessmode = mac->mode; ++ u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ++ ? 1 : 0; ++ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? ++ 1 : 0; ++ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? ++ 1 : 0; ++ enum wireless_mode wirelessmode = 0; + bool shortgi = false; + u8 rate_mask[5]; + u8 macid = 0; +- u8 mimops = 1; ++ u8 mimo_ps = IEEE80211_SMPS_OFF; ++ ++ sta_entry = (struct rtl_sta_info *) sta->drv_priv; ++ wirelessmode = sta_entry->wireless_mode; ++ if (mac->opmode == NL80211_IFTYPE_STATION) ++ curtxbw_40mhz = mac->bw_40; ++ else if (mac->opmode == NL80211_IFTYPE_AP || ++ mac->opmode == NL80211_IFTYPE_ADHOC) ++ macid = sta->aid + 1; + +- ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12); ++ if (rtlhal->current_bandtype == BAND_ON_5G) ++ ratr_bitmap = sta->supp_rates[1] << 4; ++ else ++ ratr_bitmap = sta->supp_rates[0]; ++ ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | ++ sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + ratr_index = RATR_INX_WIRELESS_B; +@@ -1828,7 +1859,7 @@ + case WIRELESS_MODE_N_5G: + ratr_index = RATR_INX_WIRELESS_NGB; + +- if (mimops == 0) { ++ if (mimo_ps == IEEE80211_SMPS_STATIC) { + if (rssi_level == 1) + ratr_bitmap &= 0x00070000; + else if (rssi_level == 2) +@@ -1892,8 +1923,8 @@ + } + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + ("ratr_bitmap :%x\n", ratr_bitmap)); +- *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) | +- (ratr_index << 28); ++ *(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) | ++ (ratr_index << 28)); + rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80; + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, ("Rate_index:%x, " + "ratr_val:%x, %x:%x:%x:%x:%x\n", +@@ -1902,6 +1933,20 @@ + rate_mask[2], rate_mask[3], + rate_mask[4])); + rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask); ++ ++ if (macid != 0) ++ sta_entry->ratr_index = ratr_index; ++} ++ ++void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, u8 rssi_level) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ if (rtlpriv->dm.useramask) ++ rtl92ce_update_hal_rate_mask(hw, sta, rssi_level); ++ else ++ rtl92ce_update_hal_rate_table(hw, sta); + } + + void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw) +@@ -1919,7 +1964,7 @@ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); + } + +-bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) ++bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +@@ -1929,7 +1974,7 @@ + bool actuallyset = false; + unsigned long flag; + +- if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter)) ++ if (rtlpci->being_init_adapter) + return false; + + if (ppsc->swrf_processing) +@@ -1946,12 +1991,6 @@ + + cur_rfstate = ppsc->rfpwr_state; + +- if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && +- RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) { +- rtlpriv->intf_ops->disable_aspm(hw); +- RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); +- } +- + rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv, + REG_MAC_PINMUX_CFG)&~(BIT(3))); + +@@ -1976,38 +2015,13 @@ + } + + if (actuallyset) { +- if (e_rfpowerstate_toset == ERFON) { +- if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && +- RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) { +- rtlpriv->intf_ops->disable_aspm(hw); +- RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); +- } +- } +- + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); +- +- if (e_rfpowerstate_toset == ERFOFF) { +- if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { +- rtlpriv->intf_ops->enable_aspm(hw); +- RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); +- } +- } +- +- } else if (e_rfpowerstate_toset == ERFOFF || cur_rfstate == ERFOFF) { ++ } else { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + +- if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { +- rtlpriv->intf_ops->enable_aspm(hw); +- RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); +- } +- +- spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); +- ppsc->rfchange_inprogress = false; +- spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); +- } else { + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); +@@ -2086,15 +2100,31 @@ + macaddr = cam_const_broad; + entry_id = key_index; + } else { ++ if (mac->opmode == NL80211_IFTYPE_AP) { ++ entry_id = rtl_cam_get_free_entry(hw, ++ p_macaddr); ++ if (entry_id >= TOTAL_CAM_ENTRY) { ++ RT_TRACE(rtlpriv, COMP_SEC, ++ DBG_EMERG, ++ ("Can not find free hw" ++ " security cam entry\n")); ++ return; ++ } ++ } else { ++ entry_id = CAM_PAIRWISE_KEY_POSITION; ++ } ++ + key_index = PAIRWISE_KEYIDX; +- entry_id = CAM_PAIRWISE_KEY_POSITION; + is_pairwise = true; + } + } + + if (rtlpriv->sec.key_len[key_index] == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +- ("delete one entry\n")); ++ ("delete one entry, entry_id is %d\n", ++ entry_id)); ++ if (mac->opmode == NL80211_IFTYPE_AP) ++ rtl_cam_del_entry(hw, p_macaddr); + rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, +@@ -2146,3 +2176,132 @@ + } + } + } ++ ++static void rtl8192ce_bt_var_init(struct ieee80211_hw *hw) ++{ ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); ++ ++ rtlpcipriv->bt_coexist.bt_coexistence = ++ rtlpcipriv->bt_coexist.eeprom_bt_coexist; ++ rtlpcipriv->bt_coexist.bt_ant_num = ++ rtlpcipriv->bt_coexist.eeprom_bt_ant_num; ++ rtlpcipriv->bt_coexist.bt_coexist_type = ++ rtlpcipriv->bt_coexist.eeprom_bt_type; ++ ++ if (rtlpcipriv->bt_coexist.reg_bt_iso == 2) ++ rtlpcipriv->bt_coexist.bt_ant_isolation = ++ rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation; ++ else ++ rtlpcipriv->bt_coexist.bt_ant_isolation = ++ rtlpcipriv->bt_coexist.reg_bt_iso; ++ ++ rtlpcipriv->bt_coexist.bt_radio_shared_type = ++ rtlpcipriv->bt_coexist.eeprom_bt_radio_shared; ++ ++ if (rtlpcipriv->bt_coexist.bt_coexistence) { ++ ++ if (rtlpcipriv->bt_coexist.reg_bt_sco == 1) ++ rtlpcipriv->bt_coexist.bt_service = BT_OTHER_ACTION; ++ else if (rtlpcipriv->bt_coexist.reg_bt_sco == 2) ++ rtlpcipriv->bt_coexist.bt_service = BT_SCO; ++ else if (rtlpcipriv->bt_coexist.reg_bt_sco == 4) ++ rtlpcipriv->bt_coexist.bt_service = BT_BUSY; ++ else if (rtlpcipriv->bt_coexist.reg_bt_sco == 5) ++ rtlpcipriv->bt_coexist.bt_service = BT_OTHERBUSY; ++ else ++ rtlpcipriv->bt_coexist.bt_service = BT_IDLE; ++ ++ rtlpcipriv->bt_coexist.bt_edca_ul = 0; ++ rtlpcipriv->bt_coexist.bt_edca_dl = 0; ++ rtlpcipriv->bt_coexist.bt_rssi_state = 0xff; ++ } ++} ++ ++void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, ++ bool auto_load_fail, u8 *hwinfo) ++{ ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); ++ u8 value; ++ ++ if (!auto_load_fail) { ++ rtlpcipriv->bt_coexist.eeprom_bt_coexist = ++ ((hwinfo[RF_OPTION1] & 0xe0) >> 5); ++ value = hwinfo[RF_OPTION4]; ++ rtlpcipriv->bt_coexist.eeprom_bt_type = ((value & 0xe) >> 1); ++ rtlpcipriv->bt_coexist.eeprom_bt_ant_num = (value & 0x1); ++ rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = ++ ((value & 0x10) >> 4); ++ rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = ++ ((value & 0x20) >> 5); ++ } else { ++ rtlpcipriv->bt_coexist.eeprom_bt_coexist = 0; ++ rtlpcipriv->bt_coexist.eeprom_bt_type = BT_2WIRE; ++ rtlpcipriv->bt_coexist.eeprom_bt_ant_num = ANT_X2; ++ rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = 0; ++ rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = BT_RADIO_SHARED; ++ } ++ ++ rtl8192ce_bt_var_init(hw); ++} ++ ++void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw) ++{ ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); ++ ++ /* 0:Low, 1:High, 2:From Efuse. */ ++ rtlpcipriv->bt_coexist.reg_bt_iso = 2; ++ /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */ ++ rtlpcipriv->bt_coexist.reg_bt_sco = 3; ++ /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ ++ rtlpcipriv->bt_coexist.reg_bt_sco = 0; ++} ++ ++ ++void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); ++ ++ u8 u1_tmp; ++ ++ if (rtlpcipriv->bt_coexist.bt_coexistence && ++ ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) || ++ rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8)) { ++ ++ if (rtlpcipriv->bt_coexist.bt_ant_isolation) ++ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); ++ ++ u1_tmp = rtl_read_byte(rtlpriv, 0x4fd) & ++ BIT_OFFSET_LEN_MASK_32(0, 1); ++ u1_tmp = u1_tmp | ++ ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? ++ 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | ++ ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) ? ++ 0 : BIT_OFFSET_LEN_MASK_32(2, 1)); ++ rtl_write_byte(rtlpriv, 0x4fd, u1_tmp); ++ ++ rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+4, 0xaaaa9aaa); ++ rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+8, 0xffbd0040); ++ rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+0xc, 0x40000010); ++ ++ /* Config to 1T1R. */ ++ if (rtlphy->rf_type == RF_1T1R) { ++ u1_tmp = rtl_read_byte(rtlpriv, ROFDM0_TRXPATHENABLE); ++ u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1)); ++ rtl_write_byte(rtlpriv, ROFDM0_TRXPATHENABLE, u1_tmp); ++ ++ u1_tmp = rtl_read_byte(rtlpriv, ROFDM1_TRXPATHENABLE); ++ u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1)); ++ rtl_write_byte(rtlpriv, ROFDM1_TRXPATHENABLE, u1_tmp); ++ } ++ } ++} ++ ++void rtl92ce_suspend(struct ieee80211_hw *hw) ++{ ++} ++ ++void rtl92ce_resume(struct ieee80211_hw *hw) ++{ ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h 2011-05-05 23:29:49.329488309 +0200 +@@ -30,7 +30,18 @@ + #ifndef __RTL92CE_HW_H__ + #define __RTL92CE_HW_H__ + +-#define H2C_RA_MASK 6 ++static inline u8 _rtl92c_get_chnl_group(u8 chnl) ++{ ++ u8 group; ++ ++ if (chnl < 3) ++ group = 0; ++ else if (chnl < 9) ++ group = 1; ++ else ++ group = 2; ++ return group; ++} + + void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); + void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw); +@@ -41,28 +52,27 @@ + void rtl92ce_enable_interrupt(struct ieee80211_hw *hw); + void rtl92ce_disable_interrupt(struct ieee80211_hw *hw); + int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); ++void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); + void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci); + void rtl92ce_set_beacon_related_registers(struct ieee80211_hw *hw); + void rtl92ce_set_beacon_interval(struct ieee80211_hw *hw); + void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr); + void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +-void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw); +-void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level); ++void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, u8 rssi_level); + void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw); + bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); + void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw); + void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, + u8 *p_macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all); +-bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); +-void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); +-void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +-void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); +-int rtl92c_download_fw(struct ieee80211_hw *hw); +-void rtl92c_firmware_selfreset(struct ieee80211_hw *hw); +-void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, +- u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); +-bool rtl92ce_phy_mac_config(struct ieee80211_hw *hw); ++ ++void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, ++ bool autoload_fail, u8 *hwinfo); ++void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw); ++void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw); ++void rtl92ce_suspend(struct ieee80211_hw *hw); ++void rtl92ce_resume(struct ieee80211_hw *hw); + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/led.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/led.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/led.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/led.c 2011-05-05 23:29:49.329488309 +0200 +@@ -32,6 +32,14 @@ + #include "reg.h" + #include "led.h" + ++static void _rtl92ce_init_led(struct ieee80211_hw *hw, ++ struct rtl_led *pled, enum rtl_led_pin ledpin) ++{ ++ pled->hw = hw; ++ pled->ledpin = ledpin; ++ pled->ledon = false; ++} ++ + void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) + { + u8 ledcfg; +@@ -97,13 +105,12 @@ + + void rtl92ce_init_sw_leds(struct ieee80211_hw *hw) + { ++ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); ++ _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); ++ _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); + } + +-void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw) +-{ +-} +- +-void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, ++static void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction) + { + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +@@ -138,7 +145,7 @@ + ledaction == LED_CTL_POWER_ON)) { + return; + } +- RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n", ++ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d.\n", + ledaction)); + _rtl92ce_sw_led_control(hw, ledaction); + } +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/led.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/led.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/led.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/led.h 2011-05-05 23:29:49.328488297 +0200 +@@ -31,11 +31,8 @@ + #define __RTL92CE_LED_H__ + + void rtl92ce_init_sw_leds(struct ieee80211_hw *hw); +-void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw); + void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); + void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); + void rtl92ce_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); +-void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, +- enum led_ctl_mode ledaction); + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c 2011-05-05 23:29:49.326488273 +0200 +@@ -38,7 +38,9 @@ + #include "dm.h" + #include "table.h" + +-u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw, ++static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); ++ ++u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, u32 bitmask) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); +@@ -73,9 +75,47 @@ + return readback_value; + } + ++bool rtl92c_phy_mac_config(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ bool is92c = IS_92C_SERIAL(rtlhal->version); ++ bool rtstatus = _rtl92c_phy_config_mac_with_headerfile(hw); ++ ++ if (is92c) ++ rtl_write_byte(rtlpriv, 0x14, 0x71); ++ return rtstatus; ++} ++ ++bool rtl92c_phy_bb_config(struct ieee80211_hw *hw) ++{ ++ bool rtstatus = true; ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u16 regval; ++ u32 regvaldw; ++ u8 reg_hwparafile = 1; ++ ++ _rtl92c_phy_init_bb_rf_register_definition(hw); ++ regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); ++ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, ++ regval | BIT(13) | BIT(0) | BIT(1)); ++ rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83); ++ rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); ++ rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); ++ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, ++ FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE | ++ FEN_BB_GLB_RSTn | FEN_BBRSTB); ++ rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); ++ regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0); ++ rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23)); ++ if (reg_hwparafile == 1) ++ rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); ++ return rtstatus; ++} ++ + void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, +- enum radio_path rfpath, +- u32 regaddr, u32 bitmask, u32 data) ++ enum radio_path rfpath, ++ u32 regaddr, u32 bitmask, u32 data) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); +@@ -121,45 +161,7 @@ + bitmask, data, rfpath)); + } + +-bool rtl92ce_phy_mac_config(struct ieee80211_hw *hw) +-{ +- struct rtl_priv *rtlpriv = rtl_priv(hw); +- struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +- bool is92c = IS_92C_SERIAL(rtlhal->version); +- bool rtstatus = _rtl92ce_phy_config_mac_with_headerfile(hw); +- +- if (is92c) +- rtl_write_byte(rtlpriv, 0x14, 0x71); +- return rtstatus; +-} +- +-bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw) +-{ +- bool rtstatus = true; +- struct rtl_priv *rtlpriv = rtl_priv(hw); +- u16 regval; +- u32 regvaldw; +- u8 reg_hwparafile = 1; +- +- _rtl92c_phy_init_bb_rf_register_definition(hw); +- regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); +- rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, +- regval | BIT(13) | BIT(0) | BIT(1)); +- rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83); +- rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); +- rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); +- rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, +- FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE | +- FEN_BB_GLB_RSTn | FEN_BBRSTB); +- rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); +- regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0); +- rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23)); +- if (reg_hwparafile == 1) +- rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); +- return rtstatus; +-} +- +-bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) ++static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; +@@ -177,7 +179,7 @@ + } + + bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, +- u8 configtype) ++ u8 configtype) + { + int i; + u32 *phy_regarray_table; +@@ -236,7 +238,7 @@ + } + + bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, +- u8 configtype) ++ u8 configtype) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i; +@@ -274,7 +276,7 @@ + return true; + } + +-bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, ++bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath) + { + +@@ -364,74 +366,6 @@ + return true; + } + +-void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw) +-{ +- struct rtl_priv *rtlpriv = rtl_priv(hw); +- struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +- struct rtl_phy *rtlphy = &(rtlpriv->phy); +- struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +- u8 reg_bw_opmode; +- u8 reg_prsr_rsc; +- +- RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, +- ("Switch to %s bandwidth\n", +- rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? +- "20MHz" : "40MHz")) +- +- if (is_hal_stop(rtlhal)) +- return; +- +- reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE); +- reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2); +- +- switch (rtlphy->current_chan_bw) { +- case HT_CHANNEL_WIDTH_20: +- reg_bw_opmode |= BW_OPMODE_20MHZ; +- rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); +- break; +- +- case HT_CHANNEL_WIDTH_20_40: +- reg_bw_opmode &= ~BW_OPMODE_20MHZ; +- rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); +- +- reg_prsr_rsc = +- (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5); +- rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc); +- break; +- +- default: +- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +- ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); +- break; +- } +- +- switch (rtlphy->current_chan_bw) { +- case HT_CHANNEL_WIDTH_20: +- rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0); +- rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0); +- rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); +- break; +- case HT_CHANNEL_WIDTH_20_40: +- rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); +- rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); +- rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND, +- (mac->cur_40_prime_sc >> 1)); +- rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); +- rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0); +- rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)), +- (mac->cur_40_prime_sc == +- HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1); +- break; +- default: +- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +- ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); +- break; +- } +- rtl92c_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); +- rtlphy->set_bwmode_inprogress = false; +- RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); +-} +- + void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) + { + u8 tmpreg; +@@ -477,6 +411,36 @@ + } + } + ++static void _rtl92ce_phy_set_rf_sleep(struct ieee80211_hw *hw) ++{ ++ u32 u4b_tmp; ++ u8 delay = 5; ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); ++ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); ++ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); ++ u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); ++ while (u4b_tmp != 0 && delay > 0) { ++ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); ++ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); ++ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); ++ u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); ++ delay--; ++ } ++ if (delay == 0) { ++ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00); ++ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); ++ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); ++ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, ++ ("Switch RF timeout !!!.\n")); ++ return; ++ } ++ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); ++ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); ++} ++ + static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) + { +@@ -523,33 +487,6 @@ + break; + } + case ERFOFF:{ +- for (queue_id = 0, i = 0; +- queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { +- ring = &pcipriv->dev.tx_ring[queue_id]; +- if (skb_queue_len(&ring->queue) == 0 || +- queue_id == BEACON_QUEUE) { +- queue_id++; +- continue; +- } else { +- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +- ("eRf Off/Sleep: %d times " +- "TcbBusyQueue[%d] " +- "=%d before doze!\n", (i + 1), +- queue_id, +- skb_queue_len(&ring->queue))); +- udelay(10); +- i++; +- } +- if (i >= MAX_DOZE_WAITING_TIMES_9x) { +- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +- ("\nERFOFF: %d times " +- "TcbBusyQueue[%d] = %d !\n", +- MAX_DOZE_WAITING_TIMES_9x, +- queue_id, +- skb_queue_len(&ring->queue))); +- break; +- } +- } + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("IPS Set eRf nic disable\n")); +@@ -581,6 +518,7 @@ + "TcbBusyQueue[%d] =%d before " + "doze!\n", (i + 1), queue_id, + skb_queue_len(&ring->queue))); ++ + udelay(10); + i++; + } +@@ -599,7 +537,7 @@ + jiffies_to_msecs(jiffies - + ppsc->last_awake_jiffies))); + ppsc->last_sleep_jiffies = jiffies; +- _rtl92c_phy_set_rf_sleep(hw); ++ _rtl92ce_phy_set_rf_sleep(hw); + break; + } + default: +@@ -614,10 +552,11 @@ + return bresult; + } + +-bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, ++bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) + { + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ + bool bresult = false; + + if (rfpwr_state == ppsc->rfpwr_state) +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h 2011-05-05 23:29:49.327488285 +0200 +@@ -39,6 +39,7 @@ + #define RT_CANNOT_IO(hw) false + #define HIGHPOWER_RADIOA_ARRAYLEN 22 + ++#define IQK_ADDA_REG_NUM 16 + #define MAX_TOLERANCE 5 + #define IQK_DELAY_TIME 1 + +@@ -56,6 +57,8 @@ + #define IQK_ADDA_REG_NUM 16 + #define IQK_MAC_REG_NUM 4 + ++#define IQK_DELAY_TIME 1 ++ + #define RF90_PATH_MAX 2 + + #define CT_OFFSET_MAC_ADDR 0X16 +@@ -76,7 +79,7 @@ + #define CT_OFFSET_CUSTOMER_ID 0x7F + + #define RTL92C_MAX_PATH_NUM 2 +-#define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255 ++ + enum swchnlcmd_id { + CMDID_END, + CMDID_SET_TXPOWEROWER_LEVEL, +@@ -184,43 +187,44 @@ + u32 mcs_original_offset[4][16]; + }; + +-extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, ++bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); ++u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask); +-extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, ++void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, u32 data); +-extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, ++u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask); + extern void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, +- enum radio_path rfpath, u32 regaddr, +- u32 bitmask, u32 data); +-extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); ++ enum radio_path rfpath, u32 regaddr, ++ u32 bitmask, u32 data); ++bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); + bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw); +-extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); +-extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, ++bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); ++bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +-extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +-extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, ++void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); ++void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, + long *powerlevel); +-extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +-extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, ++void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); ++bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, + long power_indbm); +-extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, ++void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, + u8 operation); +-extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +-extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, ++void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); +-extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); +-extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); +-extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +-extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, ++void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); ++u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); ++void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); ++void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, + u16 beaconinterval); + void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); + void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); ++void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); + void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); + bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +-extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, ++bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, + u32 rfpath); + bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); + bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, +@@ -237,9 +241,6 @@ + void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +-void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, +- u32 regaddr, u32 bitmask, +- u32 data); + void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +@@ -250,5 +251,11 @@ + void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); + bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw); + void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw); ++bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, ++ enum rf_pwrstate rfpwr_state); ++bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, ++ u8 configtype); ++bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, ++ u8 configtype); + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h 2011-05-05 23:29:49.332488345 +0200 +@@ -72,6 +72,7 @@ + #define REG_GPIO_IO_SEL_2 0x0062 + /* RTL8723 WIFI/BT/GPS Multi-Function control source. */ + #define REG_MULTI_FUNC_CTRL 0x0068 ++ + #define REG_MCUFWDL 0x0080 + + #define REG_HMEBOX_EXT_0 0x0088 +@@ -542,7 +543,7 @@ + #define IMR_OCPINT BIT(1) + #define IMR_WLANOFF BIT(0) + +-#define HWSET_MAX_SIZE 128 ++#define EFUSE_REAL_CONTENT_LEN 512 + + #define EEPROM_DEFAULT_TSSI 0x0 + #define EEPROM_DEFAULT_TXPOWERDIFF 0x0 +@@ -656,6 +657,7 @@ + #define STOPBE BIT(1) + #define STOPBK BIT(0) + ++#define RCR_APPFCS BIT(31) + #define RCR_APP_FCS BIT(31) + #define RCR_APP_MIC BIT(30) + #define RCR_APP_ICV BIT(29) +@@ -688,6 +690,7 @@ + + #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 +@@ -775,7 +778,6 @@ + + #define BOOT_FROM_EEPROM BIT(4) + #define EEPROM_EN BIT(5) +-#define EEPROMSEL BOOT_FROM_EEPROM + + #define AFE_BGEN BIT(0) + #define AFE_MBEN BIT(1) +@@ -901,28 +903,7 @@ + #define BD_PKG_SEL BIT(25) + #define BD_HCI_SEL BIT(26) + #define TYPE_ID BIT(27) +- +-/* 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)) ++#define RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28)) + + #define CHIP_VER_RTL_MASK 0xF000 + #define CHIP_VER_RTL_SHIFT 12 +@@ -1077,6 +1058,7 @@ + #define _RARF_RC8(x) (((x) & 0x1F) << 24) + + #define AC_PARAM_TXOP_OFFSET 16 ++#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 +@@ -1221,33 +1203,11 @@ + #define EPROM_CMD_CONFIG 0x3 + #define EPROM_CMD_LOAD 1 + +-#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE ++#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE + +-#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2) +- +-/* REG_MULTI_FUNC_CTRL(For RTL8723 Only) */ +-/* Enable GPIO[9] as WiFi HW PDn source */ + #define WL_HWPDN_EN BIT(0) +-/* WiFi HW PDn polarity control */ +-#define WL_HWPDN_SL BIT(1) +-/* WiFi function enable */ +-#define WL_FUNC_EN BIT(2) +-/* Enable GPIO[9] as WiFi RF HW PDn source */ +-#define WL_HWROF_EN BIT(3) +-/* Enable GPIO[11] as BT HW PDn source */ +-#define BT_HWPDN_EN BIT(16) +-/* BT HW PDn polarity control */ +-#define BT_HWPDN_SL BIT(17) +-/* BT function enable */ +-#define BT_FUNC_EN BIT(18) +-/* Enable GPIO[11] as BT/GPS RF HW PDn source */ +-#define BT_HWROF_EN BIT(19) +-/* Enable GPIO[10] as GPS HW PDn source */ +-#define GPS_HWPDN_EN BIT(20) +-/* GPS HW PDn polarity control */ +-#define GPS_HWPDN_SL BIT(21) +-/* GPS function enable */ +-#define GPS_FUNC_EN BIT(22) ++ ++#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2) + + #define RPMAC_RESET 0x100 + #define RPMAC_TXSTART 0x104 +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c 2011-05-05 23:29:49.328488297 +0200 +@@ -34,9 +34,9 @@ + #include "rf.h" + #include "dm.h" + +-static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw); ++static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw); + +-void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) ++void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); +@@ -62,7 +62,7 @@ + } + + void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, +- u8 *ppowerlevel) ++ u8 *ppowerlevel) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); +@@ -128,8 +128,7 @@ + + tmpval = tx_agc[RF90_PATH_A] >> 8; + +- if (mac->mode == WIRELESS_MODE_B) +- tmpval = tmpval & 0xff00ffff; ++ tmpval = tmpval & 0xff00ffff; + + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); + +@@ -202,7 +201,7 @@ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +- u8 i, chnlgroup, pwr_diff_limit[4]; ++ u8 i, chnlgroup = 0, pwr_diff_limit[4]; + u32 writeVal, customer_limit, rf; + + for (rf = 0; rf < 2; rf++) { +@@ -440,16 +439,17 @@ + else + rtlphy->num_total_rfpath = 2; + +- return _rtl92c_phy_rf6052_config_parafile(hw); ++ return _rtl92ce_phy_rf6052_config_parafile(hw); ++ + } + +-static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) ++static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); +- u32 u4_regvalue; ++ u32 u4_regvalue = 0; + u8 rfpath; +- bool rtstatus; ++ bool rtstatus = true; + struct bb_reg_def *pphyreg; + + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { +@@ -484,12 +484,12 @@ + + switch (rfpath) { + case RF90_PATH_A: +- rtstatus = rtl92ce_phy_config_rf_with_headerfile(hw, +- (enum radio_path) rfpath); ++ rtstatus = rtl92c_phy_config_rf_with_headerfile(hw, ++ (enum radio_path)rfpath); + break; + case RF90_PATH_B: +- rtstatus = rtl92ce_phy_config_rf_with_headerfile(hw, +- (enum radio_path) rfpath); ++ rtstatus = rtl92c_phy_config_rf_with_headerfile(hw, ++ (enum radio_path)rfpath); + break; + case RF90_PATH_C: + break; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h 2011-05-05 23:29:49.329488309 +0200 +@@ -34,14 +34,11 @@ + #define RF6052_MAX_REG 0x3F + #define RF6052_MAX_PATH 2 + +-extern void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, +- u8 bandwidth); +-extern void rtl92c_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, +- u8 *ppowerlevel); +-extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, +- u8 *ppowerlevel, u8 channel); +-bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw); +-bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, +- enum radio_path rfpath); +- ++extern void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, ++ u8 bandwidth); ++extern void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, ++ u8 *ppowerlevel); ++extern void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, ++ u8 *ppowerlevel, u8 channel); ++extern bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw); + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c 2011-05-05 23:29:49.332488345 +0200 +@@ -42,10 +42,58 @@ + #include "trx.h" + #include "led.h" + ++static void rtl92c_init_aspm_vars(struct ieee80211_hw *hw) ++{ ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ ++ /*close ASPM for AMD defaultly */ ++ rtlpci->const_amdpci_aspm = 0; ++ ++ /* ++ * ASPM PS mode. ++ * 0 - Disable ASPM, ++ * 1 - Enable ASPM without Clock Req, ++ * 2 - Enable ASPM with Clock Req, ++ * 3 - Alwyas Enable ASPM with Clock Req, ++ * 4 - Always Enable ASPM without Clock Req. ++ * set defult to RTL8192CE:3 RTL8192E:2 ++ * */ ++ rtlpci->const_pci_aspm = 3; ++ ++ /*Setting for PCI-E device */ ++ rtlpci->const_devicepci_aspm_setting = 0x03; ++ ++ /*Setting for PCI-E bridge */ ++ rtlpci->const_hostpci_aspm_setting = 0x02; ++ ++ /* ++ * In Hw/Sw Radio Off situation. ++ * 0 - Default, ++ * 1 - From ASPM setting without low Mac Pwr, ++ * 2 - From ASPM setting with low Mac Pwr, ++ * 3 - Bus D3 ++ * set default to RTL8192CE:0 RTL8192SE:2 ++ */ ++ rtlpci->const_hwsw_rfoff_d3 = 0; ++ ++ /* ++ * This setting works for those device with ++ * backdoor ASPM setting such as EPHY setting. ++ * 0 - Not support ASPM, ++ * 1 - Support ASPM, ++ * 2 - According to chipset. ++ */ ++ rtlpci->const_support_pciaspm = 1; ++} ++ + int rtl92c_init_sw_vars(struct ieee80211_hw *hw) + { ++ int err; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ const struct firmware *firmware; ++ ++ rtl8192ce_bt_reg_init(hw); + + rtlpriv->dm.dm_initialgain_enable = 1; + rtlpriv->dm.dm_flag = 0; +@@ -53,7 +101,12 @@ + rtlpriv->dm.thermalvalue = 0; + rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13); + +- rtlpci->receive_config = (RCR_APP_FCS | ++ /* compatible 5G band 88ce just 2.4G band & smsp */ ++ rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; ++ rtlpriv->rtlhal.bandset = BAND_ON_2_4G; ++ rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; ++ ++ rtlpci->receive_config = (RCR_APPFCS | + RCR_AMF | + RCR_ADF | + RCR_APP_MIC | +@@ -76,13 +129,49 @@ + + rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD | 0); + +- rtlpriv->rtlhal.pfirmware = (u8 *) vmalloc(0x4000); ++ /* for LPS & IPS */ ++ rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; ++ rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; ++ rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; ++ rtlpriv->psc.reg_fwctrl_lps = 3; ++ rtlpriv->psc.reg_max_lps_awakeintvl = 5; ++ /* for ASPM, you can close aspm through ++ * set const_support_pciaspm = 0 */ ++ rtl92c_init_aspm_vars(hw); ++ ++ if (rtlpriv->psc.reg_fwctrl_lps == 1) ++ rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; ++ else if (rtlpriv->psc.reg_fwctrl_lps == 2) ++ rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; ++ else if (rtlpriv->psc.reg_fwctrl_lps == 3) ++ rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; ++ ++ /* for firmware buf */ ++ rtlpriv->rtlhal.pfirmware = vzalloc(0x4000); + if (!rtlpriv->rtlhal.pfirmware) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Can't alloc buffer for fw.\n")); + return 1; + } + ++ /* request fw */ ++ err = request_firmware(&firmware, rtlpriv->cfg->fw_name, ++ rtlpriv->io.dev); ++ if (err) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Failed to request firmware!\n")); ++ return 1; ++ } ++ if (firmware->size > 0x4000) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Firmware is too big!\n")); ++ release_firmware(firmware); ++ return 1; ++ } ++ memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); ++ rtlpriv->rtlhal.fwsize = firmware->size; ++ release_firmware(firmware); ++ + return 0; + } + +@@ -103,17 +192,19 @@ + .interrupt_recognized = rtl92ce_interrupt_recognized, + .hw_init = rtl92ce_hw_init, + .hw_disable = rtl92ce_card_disable, ++ .hw_suspend = rtl92ce_suspend, ++ .hw_resume = rtl92ce_resume, + .enable_interrupt = rtl92ce_enable_interrupt, + .disable_interrupt = rtl92ce_disable_interrupt, + .set_network_type = rtl92ce_set_network_type, ++ .set_chk_bssid = rtl92ce_set_check_bssid, + .set_qos = rtl92ce_set_qos, + .set_bcn_reg = rtl92ce_set_beacon_related_registers, + .set_bcn_intv = rtl92ce_set_beacon_interval, + .update_interrupt_mask = rtl92ce_update_interrupt_mask, + .get_hw_reg = rtl92ce_get_hw_reg, + .set_hw_reg = rtl92ce_set_hw_reg, +- .update_rate_table = rtl92ce_update_hal_rate_table, +- .update_rate_mask = rtl92ce_update_hal_rate_mask, ++ .update_rate_tbl = rtl92ce_update_hal_rate_tbl, + .fill_tx_desc = rtl92ce_tx_fill_desc, + .fill_tx_cmddesc = rtl92ce_tx_fill_cmddesc, + .query_rx_desc = rtl92ce_rx_query_desc, +@@ -123,7 +214,7 @@ + .switch_channel = rtl92c_phy_sw_chnl, + .dm_watchdog = rtl92c_dm_watchdog, + .scan_operation_backup = rtl92c_phy_scan_operation_backup, +- .set_rf_power_state = rtl92ce_phy_set_rf_power_state, ++ .set_rf_power_state = rtl92c_phy_set_rf_power_state, + .led_control = rtl92ce_led_control, + .set_desc = rtl92ce_set_desc, + .get_desc = rtl92ce_get_desc, +@@ -131,27 +222,29 @@ + .enable_hw_sec = rtl92ce_enable_hw_security_config, + .set_key = rtl92ce_set_key, + .init_sw_leds = rtl92ce_init_sw_leds, +- .deinit_sw_leds = rtl92ce_deinit_sw_leds, + .get_bbreg = rtl92c_phy_query_bb_reg, + .set_bbreg = rtl92c_phy_set_bb_reg, +- .get_rfreg = rtl92ce_phy_query_rf_reg, + .set_rfreg = rtl92ce_phy_set_rf_reg, +- .cmd_send_packet = _rtl92c_cmd_send_packet, ++ .get_rfreg = rtl92c_phy_query_rf_reg, + .phy_rf6052_config = rtl92ce_phy_rf6052_config, + .phy_rf6052_set_cck_txpower = rtl92ce_phy_rf6052_set_cck_txpower, + .phy_rf6052_set_ofdm_txpower = rtl92ce_phy_rf6052_set_ofdm_txpower, + .config_bb_with_headerfile = _rtl92ce_phy_config_bb_with_headerfile, + .config_bb_with_pgheaderfile = _rtl92ce_phy_config_bb_with_pgheaderfile, + .phy_lc_calibrate = _rtl92ce_phy_lc_calibrate, +- .phy_set_bw_mode_callback = rtl92ce_phy_set_bw_mode_callback, + .dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower, + }; + + static struct rtl_mod_params rtl92ce_mod_params = { +- .sw_crypto = 0, ++ .sw_crypto = false, ++ .inactiveps = true, ++ .swctrl_lps = false, ++ .fwctrl_lps = true, + }; + + static struct rtl_hal_cfg rtl92ce_hal_cfg = { ++ .bar_id = 2, ++ .write_readback = true, + .name = "rtl92c_pci", + .fw_name = "rtlwifi/rtl8192cfw.bin", + .ops = &rtl8192ce_hal_ops, +@@ -175,6 +268,8 @@ + .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN, + .maps[EFUSE_ANA8M] = EFUSE_ANA8M, + .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE, ++ .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, ++ .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, + + .maps[RWCAM] = REG_CAMCMD, + .maps[WCAMI] = REG_CAMWRITE, +@@ -239,7 +334,7 @@ + .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, + }; + +-static struct pci_device_id rtl92ce_pci_ids[] __devinitdata = { ++DEFINE_PCI_DEVICE_TABLE(rtl92ce_pci_ids) = { + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8191, rtl92ce_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8178, rtl92ce_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8177, rtl92ce_hal_cfg)}, +@@ -257,7 +352,13 @@ + MODULE_FIRMWARE("rtlwifi/rtl8192cfw.bin"); + + module_param_named(swenc, rtl92ce_mod_params.sw_crypto, bool, 0444); ++module_param_named(ips, rtl92ce_mod_params.inactiveps, bool, 0444); ++module_param_named(swlps, rtl92ce_mod_params.swctrl_lps, bool, 0444); ++module_param_named(fwlps, rtl92ce_mod_params.fwctrl_lps, bool, 0444); + MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); ++MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); ++MODULE_PARM_DESC(fwlps, "using linked fw control power save " ++ "(default 1 is open)\n"); + + static struct pci_driver rtl92ce_driver = { + .name = KBUILD_MODNAME, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h 2011-05-05 23:29:49.325488261 +0200 +@@ -33,19 +33,9 @@ + int rtl92c_init_sw_vars(struct ieee80211_hw *hw); + void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw); + void rtl92c_init_var_map(struct ieee80211_hw *hw); +-bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, +- struct sk_buff *skb); +-void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, +- u8 *ppowerlevel); +-void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, +- u8 *ppowerlevel, u8 channel); + bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, +- u8 configtype); ++ u8 configtype); + bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, +- u8 configtype); +-void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); +-u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw, +- enum radio_path rfpath, u32 regaddr, u32 bitmask); +-void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw); ++ u8 configtype); + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c 2011-05-05 23:29:49.327488285 +0200 +@@ -36,42 +36,16 @@ + #include "trx.h" + #include "led.h" + +-static enum rtl_desc_qsel _rtl92ce_map_hwqueue_to_fwqueue(__le16 fc, +- unsigned int +- skb_queue) ++static u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) + { +- enum rtl_desc_qsel qsel; ++ __le16 fc = rtl_get_fc(skb); + +- if (unlikely(ieee80211_is_beacon(fc))) { +- qsel = QSLT_BEACON; +- return qsel; +- } +- +- if (ieee80211_is_mgmt(fc)) { +- qsel = QSLT_MGNT; +- return qsel; +- } ++ if (unlikely(ieee80211_is_beacon(fc))) ++ return QSLT_BEACON; ++ if (ieee80211_is_mgmt(fc)) ++ return QSLT_MGNT; + +- switch (skb_queue) { +- case VO_QUEUE: +- qsel = QSLT_VO; +- break; +- case VI_QUEUE: +- qsel = QSLT_VI; +- break; +- case BE_QUEUE: +- qsel = QSLT_BE; +- break; +- case BK_QUEUE: +- qsel = QSLT_BK; +- break; +- default: +- qsel = QSLT_BE; +- RT_ASSERT(false, ("BE queue, skb_queue:%d," +- " set qsel = 0x%X\n", skb_queue, QSLT_BE)); +- break; +- } +- return qsel; ++ return skb->priority; + } + + static int _rtl92ce_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu) +@@ -255,6 +229,7 @@ + u8 evm, pwdb_all, rf_rx_num = 0; + u8 i, max_spatial_stream; + u32 rssi, total_rssi = 0; ++ bool in_powersavemode = false; + bool is_cck_rate; + + is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); +@@ -270,9 +245,13 @@ + u8 report, cck_highpwr; + cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; + +- cck_highpwr = (u8) rtl_get_bbreg(hw, +- RFPGA0_XA_HSSIPARAMETER2, +- BIT(9)); ++ if (!in_powersavemode) ++ cck_highpwr = (u8) rtl_get_bbreg(hw, ++ RFPGA0_XA_HSSIPARAMETER2, ++ BIT(9)); ++ else ++ cck_highpwr = false; ++ + if (!cck_highpwr) { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = cck_buf->cck_agc_rpt & 0xc0; +@@ -398,6 +377,7 @@ + + if (rtlpriv->stats.ui_rssi.total_num++ >= + PHY_RSSI_SLID_WIN_MAX) { ++ + rtlpriv->stats.ui_rssi.total_num = + PHY_RSSI_SLID_WIN_MAX; + last_rssi = +@@ -424,10 +404,6 @@ + if (!pstats->is_cck && pstats->packet_toself) { + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { +- +- if (!rtl8192_phy_check_is_legal_rfpath(hw, rfpath)) +- continue; +- + if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + pstats->rx_mimo_signalstrength[rfpath]; +@@ -723,7 +699,7 @@ + void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, struct sk_buff *skb, +- unsigned int queue_index) ++ u8 hw_queue, struct rtl_tcb_desc *tcb_desc) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +@@ -732,16 +708,9 @@ + bool defaultadapter = true; + struct ieee80211_sta *sta; + u8 *pdesc = (u8 *) pdesc_tx; +- struct rtl_tcb_desc tcb_desc; +- u8 *qc = ieee80211_get_qos_ctl(hdr); +- u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + u16 seq_number; + __le16 fc = hdr->frame_control; +- u8 rate_flag = info->control.rates[0].flags; +- +- enum rtl_desc_qsel fw_qsel = +- _rtl92ce_map_hwqueue_to_fwqueue(fc, queue_index); +- ++ u8 fw_qsel = _rtl92ce_map_hwqueue_to_fwqueue(skb, hw_queue); + bool firstseg = ((hdr->seq_ctrl & + cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); + +@@ -751,56 +720,68 @@ + dma_addr_t mapping = pci_map_single(rtlpci->pdev, + skb->data, skb->len, + PCI_DMA_TODEVICE); ++ u8 bw_40 = 0; ++ ++ rcu_read_lock(); ++ sta = get_sta(hw, mac->vif, mac->bssid); ++ if (mac->opmode == NL80211_IFTYPE_STATION) { ++ bw_40 = mac->bw_40; ++ } else if (mac->opmode == NL80211_IFTYPE_AP || ++ mac->opmode == NL80211_IFTYPE_ADHOC) { ++ if (sta) ++ bw_40 = sta->ht_cap.cap & ++ IEEE80211_HT_CAP_SUP_WIDTH_20_40; ++ } + + seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + +- rtl_get_tcb_desc(hw, info, skb, &tcb_desc); ++ rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); + + CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92c)); + ++ if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { ++ firstseg = true; ++ lastseg = true; ++ } + if (firstseg) { + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + +- SET_TX_DESC_TX_RATE(pdesc, tcb_desc.hw_rate); ++ SET_TX_DESC_TX_RATE(pdesc, tcb_desc->hw_rate); + +- if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble) ++ if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble) + SET_TX_DESC_DATA_SHORTGI(pdesc, 1); + +- if (mac->tids[tid].agg.agg_state == RTL_AGG_ON && +- info->flags & IEEE80211_TX_CTL_AMPDU) { ++ if (info->flags & IEEE80211_TX_CTL_AMPDU) { + SET_TX_DESC_AGG_BREAK(pdesc, 1); + SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14); + } + SET_TX_DESC_SEQ(pdesc, seq_number); + +- SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc.rts_enable && +- !tcb_desc. ++ SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc->rts_enable && ++ !tcb_desc-> + cts_enable) ? 1 : 0)); + SET_TX_DESC_HW_RTS_ENABLE(pdesc, +- ((tcb_desc.rts_enable +- || tcb_desc.cts_enable) ? 1 : 0)); +- SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc.cts_enable) ? 1 : 0)); +- SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc.rts_stbc) ? 1 : 0)); ++ ((tcb_desc->rts_enable ++ || tcb_desc->cts_enable) ? 1 : 0)); ++ SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc->cts_enable) ? 1 : 0)); ++ SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc->rts_stbc) ? 1 : 0)); + +- SET_TX_DESC_RTS_RATE(pdesc, tcb_desc.rts_rate); ++ SET_TX_DESC_RTS_RATE(pdesc, tcb_desc->rts_rate); + SET_TX_DESC_RTS_BW(pdesc, 0); +- SET_TX_DESC_RTS_SC(pdesc, tcb_desc.rts_sc); ++ SET_TX_DESC_RTS_SC(pdesc, tcb_desc->rts_sc); + SET_TX_DESC_RTS_SHORT(pdesc, +- ((tcb_desc.rts_rate <= DESC92C_RATE54M) ? +- (tcb_desc.rts_use_shortpreamble ? 1 : 0) +- : (tcb_desc.rts_use_shortgi ? 1 : 0))); ++ ((tcb_desc->rts_rate <= DESC92C_RATE54M) ? ++ (tcb_desc->rts_use_shortpreamble ? 1 : 0) ++ : (tcb_desc->rts_use_shortgi ? 1 : 0))); + +- if (mac->bw_40) { +- if (tcb_desc.packet_bw) { ++ if (bw_40) { ++ if (tcb_desc->packet_bw) { + SET_TX_DESC_DATA_BW(pdesc, 1); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3); + } else { + SET_TX_DESC_DATA_BW(pdesc, 0); +- +- if (rate_flag & IEEE80211_TX_RC_DUP_DATA) { +- SET_TX_DESC_TX_SUB_CARRIER(pdesc, +- mac->cur_40_prime_sc); +- } ++ SET_TX_DESC_TX_SUB_CARRIER(pdesc, ++ mac->cur_40_prime_sc); + } + } else { + SET_TX_DESC_DATA_BW(pdesc, 0); +@@ -810,13 +791,10 @@ + SET_TX_DESC_LINIP(pdesc, 0); + SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); + +- rcu_read_lock(); +- sta = ieee80211_find_sta(mac->vif, mac->bssid); + if (sta) { + u8 ampdu_density = sta->ht_cap.ampdu_density; + SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density); + } +- rcu_read_unlock(); + + if (info->control.hw_key) { + struct ieee80211_key_conf *keyconf = +@@ -844,7 +822,7 @@ + SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); + SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF); + SET_TX_DESC_DISABLE_FB(pdesc, 0); +- SET_TX_DESC_USE_RATE(pdesc, tcb_desc.use_driver_rate ? 1 : 0); ++ SET_TX_DESC_USE_RATE(pdesc, tcb_desc->use_driver_rate ? 1 : 0); + + if (ieee80211_is_data_qos(fc)) { + if (mac->rdg_en) { +@@ -855,24 +833,24 @@ + } + } + } ++ rcu_read_unlock(); + + SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); + SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); + + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); + +- SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); ++ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + + if (rtlpriv->dm.useramask) { +- SET_TX_DESC_RATE_ID(pdesc, tcb_desc.ratr_index); +- SET_TX_DESC_MACID(pdesc, tcb_desc.mac_id); ++ SET_TX_DESC_RATE_ID(pdesc, tcb_desc->ratr_index); ++ SET_TX_DESC_MACID(pdesc, tcb_desc->mac_id); + } else { +- SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc.ratr_index); +- SET_TX_DESC_MACID(pdesc, tcb_desc.ratr_index); ++ SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc->ratr_index); ++ SET_TX_DESC_MACID(pdesc, tcb_desc->ratr_index); + } + +- if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps && +- ppsc->fwctrl_lps) { ++ if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) { + SET_TX_DESC_HWSEQ_EN(pdesc, 1); + SET_TX_DESC_PKT_ID(pdesc, 8); + +@@ -923,7 +901,7 @@ + + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len)); + +- SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); ++ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + + SET_TX_DESC_RATE_ID(pdesc, 7); + SET_TX_DESC_MACID(pdesc, 0); +@@ -1021,7 +999,7 @@ + return ret; + } + +-void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue) ++void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (hw_queue == BEACON_QUEUE) { +@@ -1032,35 +1010,3 @@ + } + } + +-bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, +- struct sk_buff *skb) +-{ +- struct rtl_priv *rtlpriv = rtl_priv(hw); +- struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +- struct rtl8192_tx_ring *ring; +- struct rtl_tx_desc *pdesc; +- u8 own; +- unsigned long flags; +- struct sk_buff *pskb = NULL; +- +- ring = &rtlpci->tx_ring[BEACON_QUEUE]; +- +- spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); +- +- pskb = __skb_dequeue(&ring->queue); +- if (pskb) +- kfree_skb(pskb); +- +- pdesc = &ring->desc[0]; +- own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); +- +- rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); +- +- __skb_queue_tail(&ring->queue, skb); +- +- spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); +- +- rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); +- +- return true; +-} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h 2011-05-05 23:29:49.330488321 +0200 +@@ -532,9 +532,9 @@ + #define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ + do { \ + if (_size > TX_DESC_NEXT_DESC_OFFSET) \ +- memset((void *)__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ ++ memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ + else \ +- memset((void *)__pdesc, 0, _size); \ ++ memset(__pdesc, 0, _size); \ + } while (0); + + #define RX_HAL_IS_CCK_RATE(_pdesc)\ +@@ -724,17 +724,16 @@ + void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, + u8 *pdesc, struct ieee80211_tx_info *info, +- struct sk_buff *skb, unsigned int qsel); ++ struct sk_buff *skb, u8 hw_queue, ++ struct rtl_tcb_desc *ptcb_desc); + bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, + struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, + u8 *pdesc, struct sk_buff *skb); + void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); + u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name); +-void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue); ++void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); + void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, + bool b_firstseg, bool b_lastseg, + struct sk_buff *skb); +-bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb); +- + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c 2011-05-05 23:29:49.267487559 +0200 +@@ -39,6 +39,7 @@ + #include "mac.h" + #include "dm.h" + #include "hw.h" ++#include "../rtl8192ce/hw.h" + #include "trx.h" + #include "led.h" + #include "table.h" +@@ -605,10 +606,10 @@ + if (!IS_NORMAL_CHIP(rtlhal->version)) + return; + tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); +- rtlefuse->epromtype = (tmp_u1b & EEPROMSEL) ? ++ rtlefuse->epromtype = (tmp_u1b & BOOT_FROM_EEPROM) ? + EEPROM_93C46 : EEPROM_BOOT_EFUSE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from %s\n", +- (tmp_u1b & EEPROMSEL) ? "EERROM" : "EFUSE")); ++ (tmp_u1b & BOOT_FROM_EEPROM) ? "EERROM" : "EFUSE")); + rtlefuse->autoload_failflag = (tmp_u1b & EEPROM_EN) ? false : true; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload %s\n", + (tmp_u1b & EEPROM_EN) ? "OK!!" : "ERR!!")); +@@ -921,7 +922,7 @@ + u8 out_ep_num, + u8 queue_sel) + { +- u8 hq_sele; ++ u8 hq_sele = 0; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (out_ep_num) { +@@ -977,7 +978,7 @@ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +- mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APP_FCS | ++ mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APPFCS | + RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | + RCR_APP_MIC | RCR_APP_PHYSTS | RCR_ACRC32); + rtl_write_dword(rtlpriv, REG_RCR, mac->rx_conf); +@@ -2182,7 +2183,9 @@ + } + } + +-void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw) ++void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, ++ u8 rssi_level) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h 2011-05-05 23:29:49.263487511 +0200 +@@ -98,13 +98,14 @@ + u32 add_msr, u32 rm_msr); + void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); + void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +-void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw); ++void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, ++ u8 rssi_level); + void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level); + + void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw); + bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid); + void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +-u8 _rtl92c_get_chnl_group(u8 chnl); + int rtl92c_download_fw(struct ieee80211_hw *hw); + void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); + void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c 2011-05-05 23:29:49.246487305 +0200 +@@ -38,7 +38,7 @@ + #include "table.h" + + u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, +- enum radio_path rfpath, u32 regaddr, u32 bitmask) ++ enum radio_path rfpath, u32 regaddr, u32 bitmask) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 original_value, readback_value, bitshift; +@@ -64,8 +64,8 @@ + } + + void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw, +- enum radio_path rfpath, +- u32 regaddr, u32 bitmask, u32 data) ++ enum radio_path rfpath, ++ u32 regaddr, u32 bitmask, u32 data) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); +@@ -163,7 +163,7 @@ + } + + bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, +- u8 configtype) ++ u8 configtype) + { + int i; + u32 *phy_regarray_table; +@@ -223,7 +223,7 @@ + } + + bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, +- u8 configtype) ++ u8 configtype) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); +@@ -459,7 +459,7 @@ + } + } + +-bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, ++static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); +@@ -595,7 +595,7 @@ + } + + bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, +- enum rf_pwrstate rfpwr_state) ++ enum rf_pwrstate rfpwr_state) + { + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool bresult = false; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h 2011-05-05 23:29:49.247487318 +0200 +@@ -34,3 +34,17 @@ + void rtl92c_phy_set_io(struct ieee80211_hw *hw); + bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); + bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw); ++u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, ++ enum radio_path rfpath, u32 regaddr, u32 bitmask); ++void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw, ++ enum radio_path rfpath, ++ u32 regaddr, u32 bitmask, u32 data); ++bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw); ++bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, ++ u8 configtype); ++void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); ++bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, ++ u8 configtype); ++void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw); ++bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, ++ enum rf_pwrstate rfpwr_state); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c 2011-05-05 23:29:49.248487331 +0200 +@@ -62,7 +62,7 @@ + } + + void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, +- u8 *ppowerlevel) ++ u8 *ppowerlevel) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); +@@ -389,7 +389,7 @@ + } + + void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, +- u8 *ppowerlevel, u8 channel) ++ u8 *ppowerlevel, u8 channel) + { + u32 writeVal[2], powerBase0[2], powerBase1[2]; + u8 index = 0; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h 2011-05-05 23:29:49.265487535 +0200 +@@ -43,5 +43,9 @@ + bool rtl92cu_phy_rf6052_config(struct ieee80211_hw *hw); + bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath); ++void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, ++ u8 *ppowerlevel); ++void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, ++ u8 *ppowerlevel, u8 channel); + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c 2011-05-05 23:29:49.268487571 +0200 +@@ -94,7 +94,7 @@ + .update_interrupt_mask = rtl92cu_update_interrupt_mask, + .get_hw_reg = rtl92cu_get_hw_reg, + .set_hw_reg = rtl92cu_set_hw_reg, +- .update_rate_table = rtl92cu_update_hal_rate_table, ++ .update_rate_tbl = rtl92cu_update_hal_rate_table, + .update_rate_mask = rtl92cu_update_hal_rate_mask, + .fill_tx_desc = rtl92cu_tx_fill_desc, + .fill_fake_txdesc = rtl92cu_fill_fake_txdesc, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c 2011-05-05 23:29:49.248487331 +0200 +@@ -498,14 +498,14 @@ + void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, struct sk_buff *skb, +- unsigned int queue_index) ++ u8 queue_index, ++ struct rtl_tcb_desc *tcb_desc) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool defaultadapter = true; +- struct ieee80211_sta *sta; +- struct rtl_tcb_desc tcb_desc; ++ struct ieee80211_sta *sta = info->control.sta = info->control.sta; + u8 *qc = ieee80211_get_qos_ctl(hdr); + u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + u16 seq_number; +@@ -517,15 +517,15 @@ + u8 *txdesc; + + seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; +- rtl_get_tcb_desc(hw, info, skb, &tcb_desc); ++ rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); + txdesc = (u8 *)skb_push(skb, RTL_TX_HEADER_SIZE); + memset(txdesc, 0, RTL_TX_HEADER_SIZE); + SET_TX_DESC_PKT_SIZE(txdesc, pktlen); + SET_TX_DESC_LINIP(txdesc, 0); + SET_TX_DESC_PKT_OFFSET(txdesc, RTL_DUMMY_OFFSET); + SET_TX_DESC_OFFSET(txdesc, RTL_TX_HEADER_SIZE); +- SET_TX_DESC_TX_RATE(txdesc, tcb_desc.hw_rate); +- if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble) ++ SET_TX_DESC_TX_RATE(txdesc, tcb_desc->hw_rate); ++ if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble) + SET_TX_DESC_DATA_SHORTGI(txdesc, 1); + if (mac->tids[tid].agg.agg_state == RTL_AGG_ON && + info->flags & IEEE80211_TX_CTL_AMPDU) { +@@ -535,21 +535,21 @@ + SET_TX_DESC_AGG_BREAK(txdesc, 1); + } + SET_TX_DESC_SEQ(txdesc, seq_number); +- SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc.rts_enable && +- !tcb_desc.cts_enable) ? 1 : 0)); +- SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc.rts_enable || +- tcb_desc.cts_enable) ? 1 : 0)); +- SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc.cts_enable) ? 1 : 0)); +- SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc.rts_stbc) ? 1 : 0)); +- SET_TX_DESC_RTS_RATE(txdesc, tcb_desc.rts_rate); ++ SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable && ++ !tcb_desc->cts_enable) ? 1 : 0)); ++ SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable || ++ tcb_desc->cts_enable) ? 1 : 0)); ++ SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc->cts_enable) ? 1 : 0)); ++ SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc->rts_stbc) ? 1 : 0)); ++ SET_TX_DESC_RTS_RATE(txdesc, tcb_desc->rts_rate); + SET_TX_DESC_RTS_BW(txdesc, 0); +- SET_TX_DESC_RTS_SC(txdesc, tcb_desc.rts_sc); ++ SET_TX_DESC_RTS_SC(txdesc, tcb_desc->rts_sc); + SET_TX_DESC_RTS_SHORT(txdesc, +- ((tcb_desc.rts_rate <= DESC92C_RATE54M) ? +- (tcb_desc.rts_use_shortpreamble ? 1 : 0) +- : (tcb_desc.rts_use_shortgi ? 1 : 0))); ++ ((tcb_desc->rts_rate <= DESC92C_RATE54M) ? ++ (tcb_desc->rts_use_shortpreamble ? 1 : 0) ++ : (tcb_desc->rts_use_shortgi ? 1 : 0))); + if (mac->bw_40) { +- if (tcb_desc.packet_bw) { ++ if (tcb_desc->packet_bw) { + SET_TX_DESC_DATA_BW(txdesc, 1); + SET_TX_DESC_DATA_SC(txdesc, 3); + } else { +@@ -590,7 +590,7 @@ + SET_TX_DESC_DATA_RATE_FB_LIMIT(txdesc, 0x1F); + SET_TX_DESC_RTS_RATE_FB_LIMIT(txdesc, 0xF); + SET_TX_DESC_DISABLE_FB(txdesc, 0); +- SET_TX_DESC_USE_RATE(txdesc, tcb_desc.use_driver_rate ? 1 : 0); ++ SET_TX_DESC_USE_RATE(txdesc, tcb_desc->use_driver_rate ? 1 : 0); + if (ieee80211_is_data_qos(fc)) { + if (mac->rdg_en) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, +@@ -600,11 +600,11 @@ + } + } + if (rtlpriv->dm.useramask) { +- SET_TX_DESC_RATE_ID(txdesc, tcb_desc.ratr_index); +- SET_TX_DESC_MACID(txdesc, tcb_desc.mac_id); ++ SET_TX_DESC_RATE_ID(txdesc, tcb_desc->ratr_index); ++ SET_TX_DESC_MACID(txdesc, tcb_desc->mac_id); + } else { +- SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc.ratr_index); +- SET_TX_DESC_MACID(txdesc, tcb_desc.ratr_index); ++ SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc->ratr_index); ++ SET_TX_DESC_MACID(txdesc, tcb_desc->ratr_index); + } + if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps && + ppsc->fwctrl_lps) { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h 2011-05-05 23:29:49.266487547 +0200 +@@ -37,6 +37,8 @@ + #define RTL92C_SIZE_MAX_RX_BUFFER 15360 /* 8192 */ + #define RX_DRV_INFO_SIZE_UNIT 8 + ++#define RTL_AGG_ON 1 ++ + enum usb_rx_agg_mode { + USB_RX_AGG_DISABLE, + USB_RX_AGG_DMA, +@@ -419,7 +421,8 @@ + void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, struct sk_buff *skb, +- unsigned int queue_index); ++ u8 queue_index, ++ struct rtl_tcb_desc *tcb_desc); + void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc, + u32 buffer_len, bool bIsPsPoll); + void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/def.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/def.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/def.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/def.h 2011-05-05 23:29:49.281487729 +0200 +@@ -0,0 +1,598 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++#ifndef __REALTEK_92S_DEF_H__ ++#define __REALTEK_92S_DEF_H__ ++ ++#define RX_MPDU_QUEUE 0 ++#define RX_CMD_QUEUE 1 ++#define RX_MAX_QUEUE 2 ++ ++#define DESC92S_RATE1M 0x00 ++#define DESC92S_RATE2M 0x01 ++#define DESC92S_RATE5_5M 0x02 ++#define DESC92S_RATE11M 0x03 ++#define DESC92S_RATE6M 0x04 ++#define DESC92S_RATE9M 0x05 ++#define DESC92S_RATE12M 0x06 ++#define DESC92S_RATE18M 0x07 ++#define DESC92S_RATE24M 0x08 ++#define DESC92S_RATE36M 0x09 ++#define DESC92S_RATE48M 0x0a ++#define DESC92S_RATE54M 0x0b ++#define DESC92S_RATEMCS0 0x0c ++#define DESC92S_RATEMCS1 0x0d ++#define DESC92S_RATEMCS2 0x0e ++#define DESC92S_RATEMCS3 0x0f ++#define DESC92S_RATEMCS4 0x10 ++#define DESC92S_RATEMCS5 0x11 ++#define DESC92S_RATEMCS6 0x12 ++#define DESC92S_RATEMCS7 0x13 ++#define DESC92S_RATEMCS8 0x14 ++#define DESC92S_RATEMCS9 0x15 ++#define DESC92S_RATEMCS10 0x16 ++#define DESC92S_RATEMCS11 0x17 ++#define DESC92S_RATEMCS12 0x18 ++#define DESC92S_RATEMCS13 0x19 ++#define DESC92S_RATEMCS14 0x1a ++#define DESC92S_RATEMCS15 0x1b ++#define DESC92S_RATEMCS15_SG 0x1c ++#define DESC92S_RATEMCS32 0x20 ++ ++#define SHORT_SLOT_TIME 9 ++#define NON_SHORT_SLOT_TIME 20 ++ ++/* Rx smooth factor */ ++#define RX_SMOOTH_FACTOR 20 ++ ++/* Queue Select Value in TxDesc */ ++#define QSLT_BK 0x2 ++#define QSLT_BE 0x0 ++#define QSLT_VI 0x5 ++#define QSLT_VO 0x6 ++#define QSLT_BEACON 0x10 ++#define QSLT_HIGH 0x11 ++#define QSLT_MGNT 0x12 ++#define QSLT_CMD 0x13 ++ ++#define PHY_RSSI_SLID_WIN_MAX 100 ++#define PHY_LINKQUALITY_SLID_WIN_MAX 20 ++#define PHY_BEACON_RSSI_SLID_WIN_MAX 10 ++ ++/* Tx Desc */ ++#define TX_DESC_SIZE_RTL8192S (16 * 4) ++#define TX_CMDDESC_SIZE_RTL8192S (16 * 4) ++ ++/* Define a macro that takes a le32 word, converts it to host ordering, ++ * right shifts by a specified count, creates a mask of the specified ++ * bit count, and extracts that number of bits. ++ */ ++ ++#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \ ++ ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \ ++ BIT_LEN_MASK_32(__mask)) ++ ++/* Define a macro that clears a bit field in an le32 word and ++ * sets the specified value into that bit field. The resulting ++ * value remains in le32 ordering; however, it is properly converted ++ * to host ordering for the clear and set operations before conversion ++ * back to le32. ++ */ ++ ++#define SET_BITS_OFFSET_LE(__pdesc, __shift, __len, __val) \ ++ (*(__le32 *)(__pdesc) = \ ++ (cpu_to_le32((le32_to_cpu(*((__le32 *)(__pdesc))) & \ ++ (~(BIT_OFFSET_LEN_MASK_32((__shift), __len)))) | \ ++ (((u32)(__val) & BIT_LEN_MASK_32(__len)) << (__shift))))); ++ ++/* macros to read/write various fields in RX or TX descriptors */ ++ ++/* Dword 0 */ ++#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 0, 16, __val) ++#define SET_TX_DESC_OFFSET(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 16, 8, __val) ++#define SET_TX_DESC_TYPE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val) ++#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) ++#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) ++#define SET_TX_DESC_LINIP(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) ++#define SET_TX_DESC_AMSDU(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) ++#define SET_TX_DESC_GREEN_FIELD(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) ++#define SET_TX_DESC_OWN(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) ++ ++#define GET_TX_DESC_OWN(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 31, 1) ++ ++/* Dword 1 */ ++#define SET_TX_DESC_MACID(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) ++#define SET_TX_DESC_MORE_DATA(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 5, 1, __val) ++#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 6, 1, __val) ++#define SET_TX_DESC_PIFS(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 7, 1, __val) ++#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 8, 5, __val) ++#define SET_TX_DESC_ACK_POLICY(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 13, 2, __val) ++#define SET_TX_DESC_NO_ACM(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val) ++#define SET_TX_DESC_NON_QOS(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 16, 1, __val) ++#define SET_TX_DESC_KEY_ID(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 17, 2, __val) ++#define SET_TX_DESC_OUI(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 19, 1, __val) ++#define SET_TX_DESC_PKT_TYPE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 20, 1, __val) ++#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 21, 1, __val) ++#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 22, 2, __val) ++#define SET_TX_DESC_WDS(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val) ++#define SET_TX_DESC_HTC(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val) ++#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 26, 5, __val) ++#define SET_TX_DESC_HWPC(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val) ++ ++/* Dword 2 */ ++#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 8, 0, 6, __val) ++#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 8, 6, 1, __val) ++#define SET_TX_DESC_TSFL(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 8, 7, 5, __val) ++#define SET_TX_DESC_RTS_RETRY_COUNT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 8, 12, 6, __val) ++#define SET_TX_DESC_DATA_RETRY_COUNT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 8, 18, 6, __val) ++#define SET_TX_DESC_RSVD_MACID(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(((__pdesc) + 8), 24, 5, __val) ++#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 8, 29, 1, __val) ++#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val) ++#define SET_TX_DESC_OWN_MAC(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 8, 31, 1, __val) ++ ++/* Dword 3 */ ++#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 0, 8, __val) ++#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 8, 8, __val) ++#define SET_TX_DESC_SEQ(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 16, 12, __val) ++#define SET_TX_DESC_FRAG(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 28, 4, __val) ++ ++/* Dword 4 */ ++#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 0, 6, __val) ++#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 6, 1, __val) ++#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 7, 4, __val) ++#define SET_TX_DESC_CTS_ENABLE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 11, 1, __val) ++#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 12, 1, __val) ++#define SET_TX_DESC_RA_BRSR_ID(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 13, 3, __val) ++#define SET_TX_DESC_TXHT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 16, 1, __val) ++#define SET_TX_DESC_TX_SHORT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 17, 1, __val) ++#define SET_TX_DESC_TX_BANDWIDTH(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 18, 1, __val) ++#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 19, 2, __val) ++#define SET_TX_DESC_TX_STBC(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 21, 2, __val) ++#define SET_TX_DESC_TX_REVERSE_DIRECTION(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 23, 1, __val) ++#define SET_TX_DESC_RTS_HT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 24, 1, __val) ++#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 25, 1, __val) ++#define SET_TX_DESC_RTS_BANDWIDTH(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 26, 1, __val) ++#define SET_TX_DESC_RTS_SUB_CARRIER(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 27, 2, __val) ++#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 29, 2, __val) ++#define SET_TX_DESC_USER_RATE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 31, 1, __val) ++ ++/* Dword 5 */ ++#define SET_TX_DESC_PACKET_ID(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 20, 0, 9, __val) ++#define SET_TX_DESC_TX_RATE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 20, 9, 6, __val) ++#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 20, 15, 1, __val) ++#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 20, 16, 5, __val) ++#define SET_TX_DESC_TX_AGC(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 20, 21, 11, __val) ++ ++/* Dword 6 */ ++#define SET_TX_DESC_IP_CHECK_SUM(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 24, 0, 16, __val) ++#define SET_TX_DESC_TCP_CHECK_SUM(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 24, 16, 16, __val) ++ ++/* Dword 7 */ ++#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 28, 0, 16, __val) ++#define SET_TX_DESC_IP_HEADER_OFFSET(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 28, 16, 8, __val) ++#define SET_TX_DESC_TCP_ENABLE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 28, 31, 1, __val) ++ ++/* Dword 8 */ ++#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 32, 0, 32, __val) ++#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 32, 0, 32) ++ ++/* Dword 9 */ ++#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 36, 0, 32, __val) ++ ++/* Because the PCI Tx descriptors are chaied at the ++ * initialization and all the NextDescAddresses in ++ * these descriptors cannot not be cleared (,or ++ * driver/HW cannot find the next descriptor), the ++ * offset 36 (NextDescAddresses) is reserved when ++ * the desc is cleared. */ ++#define TX_DESC_NEXT_DESC_OFFSET 36 ++#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ ++do { \ ++ if (_size > TX_DESC_NEXT_DESC_OFFSET) \ ++ memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ ++ else \ ++ memset(__pdesc, 0, _size); \ ++} while (0); ++ ++/* Rx Desc */ ++#define RX_STATUS_DESC_SIZE 24 ++#define RX_DRV_INFO_SIZE_UNIT 8 ++ ++/* DWORD 0 */ ++#define SET_RX_STATUS_DESC_PKT_LEN(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 0, 14, __val) ++#define SET_RX_STATUS_DESC_CRC32(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 14, 1, __val) ++#define SET_RX_STATUS_DESC_ICV(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 15, 1, __val) ++#define SET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 16, 4, __val) ++#define SET_RX_STATUS_DESC_SECURITY(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 20, 3, __val) ++#define SET_RX_STATUS_DESC_QOS(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 23, 1, __val) ++#define SET_RX_STATUS_DESC_SHIFT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val) ++#define SET_RX_STATUS_DESC_PHY_STATUS(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) ++#define SET_RX_STATUS_DESC_SWDEC(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) ++#define SET_RX_STATUS_DESC_LAST_SEG(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) ++#define SET_RX_STATUS_DESC_FIRST_SEG(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) ++#define SET_RX_STATUS_DESC_EOR(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) ++#define SET_RX_STATUS_DESC_OWN(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) ++ ++#define GET_RX_STATUS_DESC_PKT_LEN(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 0, 14) ++#define GET_RX_STATUS_DESC_CRC32(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 14, 1) ++#define GET_RX_STATUS_DESC_ICV(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 15, 1) ++#define GET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 16, 4) ++#define GET_RX_STATUS_DESC_SECURITY(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 20, 3) ++#define GET_RX_STATUS_DESC_QOS(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 23, 1) ++#define GET_RX_STATUS_DESC_SHIFT(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 24, 2) ++#define GET_RX_STATUS_DESC_PHY_STATUS(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 26, 1) ++#define GET_RX_STATUS_DESC_SWDEC(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 27, 1) ++#define GET_RX_STATUS_DESC_LAST_SEG(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 28, 1) ++#define GET_RX_STATUS_DESC_FIRST_SEG(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 29, 1) ++#define GET_RX_STATUS_DESC_EOR(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 30, 1) ++#define GET_RX_STATUS_DESC_OWN(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc, 31, 1) ++ ++/* DWORD 1 */ ++#define SET_RX_STATUS_DESC_MACID(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) ++#define SET_RX_STATUS_DESC_TID(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 5, 4, __val) ++#define SET_RX_STATUS_DESC_PAGGR(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 14, 1, __val) ++#define SET_RX_STATUS_DESC_FAGGR(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val) ++#define SET_RX_STATUS_DESC_A1_FIT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 16, 4, __val) ++#define SET_RX_STATUS_DESC_A2_FIT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 20, 4, __val) ++#define SET_RX_STATUS_DESC_PAM(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val) ++#define SET_RX_STATUS_DESC_PWR(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val) ++#define SET_RX_STATUS_DESC_MOREDATA(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 26, 1, __val) ++#define SET_RX_STATUS_DESC_MOREFRAG(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val) ++#define SET_RX_STATUS_DESC_TYPE(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 28, 2, __val) ++#define SET_RX_STATUS_DESC_MC(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 30, 1, __val) ++#define SET_RX_STATUS_DESC_BC(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 4, 31, 1, __val) ++ ++#define GET_RX_STATUS_DEC_MACID(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 0, 5) ++#define GET_RX_STATUS_DESC_TID(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 5, 4) ++#define GET_RX_STATUS_DESC_PAGGR(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 14, 1) ++#define GET_RX_STATUS_DESC_FAGGR(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 15, 1) ++#define GET_RX_STATUS_DESC_A1_FIT(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 16, 4) ++#define GET_RX_STATUS_DESC_A2_FIT(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 20, 4) ++#define GET_RX_STATUS_DESC_PAM(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 24, 1) ++#define GET_RX_STATUS_DESC_PWR(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 25, 1) ++#define GET_RX_STATUS_DESC_MORE_DATA(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 26, 1) ++#define GET_RX_STATUS_DESC_MORE_FRAG(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 27, 1) ++#define GET_RX_STATUS_DESC_TYPE(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 28, 2) ++#define GET_RX_STATUS_DESC_MC(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 30, 1) ++#define GET_RX_STATUS_DESC_BC(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 4, 31, 1) ++ ++/* DWORD 2 */ ++#define SET_RX_STATUS_DESC_SEQ(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 8, 0, 12, __val) ++#define SET_RX_STATUS_DESC_FRAG(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 8, 12, 4, __val) ++#define SET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 8, 16, 8, __val) ++#define SET_RX_STATUS_DESC_NEXT_IND(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val) ++ ++#define GET_RX_STATUS_DESC_SEQ(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 8, 0, 12) ++#define GET_RX_STATUS_DESC_FRAG(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 8, 12, 4) ++#define GET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 8, 16, 8) ++#define GET_RX_STATUS_DESC_NEXT_IND(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 8, 30, 1) ++ ++/* DWORD 3 */ ++#define SET_RX_STATUS_DESC_RX_MCS(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 0, 6, __val) ++#define SET_RX_STATUS_DESC_RX_HT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 6, 1, __val) ++#define SET_RX_STATUS_DESC_AMSDU(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 7, 1, __val) ++#define SET_RX_STATUS_DESC_SPLCP(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 8, 1, __val) ++#define SET_RX_STATUS_DESC_BW(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 9, 1, __val) ++#define SET_RX_STATUS_DESC_HTC(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 10, 1, __val) ++#define SET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 11, 1, __val) ++#define SET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 12, 1, __val) ++#define SET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 13, 1, __val) ++#define SET_RX_STATUS_DESC_HWPC_ERR(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 14, 1, __val) ++#define SET_RX_STATUS_DESC_HWPC_IND(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 15, 1, __val) ++#define SET_RX_STATUS_DESC_IV0(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 12, 16, 16, __val) ++ ++#define GET_RX_STATUS_DESC_RX_MCS(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 12, 0, 6) ++#define GET_RX_STATUS_DESC_RX_HT(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 12, 6, 1) ++#define GET_RX_STATUS_DESC_AMSDU(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 12, 7, 1) ++#define GET_RX_STATUS_DESC_SPLCP(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 12, 8, 1) ++#define GET_RX_STATUS_DESC_BW(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 12, 9, 1) ++#define GET_RX_STATUS_DESC_HTC(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 12, 10, 1) ++#define GET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 12, 11, 1) ++#define GET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 12, 12, 1) ++#define GET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 12, 13, 1) ++#define GET_RX_STATUS_DESC_HWPC_ERR(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 12, 14, 1) ++#define GET_RX_STATUS_DESC_HWPC_IND(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 12, 15, 1) ++#define GET_RX_STATUS_DESC_IV0(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 12, 16, 16) ++ ++/* DWORD 4 */ ++#define SET_RX_STATUS_DESC_IV1(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 16, 0, 32, __val) ++#define GET_RX_STATUS_DESC_IV1(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 16, 0, 32) ++ ++/* DWORD 5 */ ++#define SET_RX_STATUS_DESC_TSFL(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 20, 0, 32, __val) ++#define GET_RX_STATUS_DESC_TSFL(__pdesc) \ ++ SHIFT_AND_MASK_LE(__pdesc + 20, 0, 32) ++ ++/* DWORD 6 */ ++#define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \ ++ SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val) ++ ++#define RX_HAL_IS_CCK_RATE(_pdesc)\ ++ (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE1M || \ ++ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE2M || \ ++ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE5_5M ||\ ++ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE11M) ++ ++enum rf_optype { ++ RF_OP_BY_SW_3WIRE = 0, ++ RF_OP_BY_FW, ++ RF_OP_MAX ++}; ++ ++enum ic_inferiority { ++ IC_INFERIORITY_A = 0, ++ IC_INFERIORITY_B = 1, ++}; ++ ++enum fwcmd_iotype { ++ /* For DIG DM */ ++ FW_CMD_DIG_ENABLE = 0, ++ FW_CMD_DIG_DISABLE = 1, ++ FW_CMD_DIG_HALT = 2, ++ FW_CMD_DIG_RESUME = 3, ++ /* For High Power DM */ ++ FW_CMD_HIGH_PWR_ENABLE = 4, ++ FW_CMD_HIGH_PWR_DISABLE = 5, ++ /* For Rate adaptive DM */ ++ FW_CMD_RA_RESET = 6, ++ FW_CMD_RA_ACTIVE = 7, ++ FW_CMD_RA_REFRESH_N = 8, ++ FW_CMD_RA_REFRESH_BG = 9, ++ FW_CMD_RA_INIT = 10, ++ /* For FW supported IQK */ ++ FW_CMD_IQK_INIT = 11, ++ /* Tx power tracking switch, ++ * MP driver only */ ++ FW_CMD_TXPWR_TRACK_ENABLE = 12, ++ /* Tx power tracking switch, ++ * MP driver only */ ++ FW_CMD_TXPWR_TRACK_DISABLE = 13, ++ /* Tx power tracking with thermal ++ * indication, for Normal driver */ ++ FW_CMD_TXPWR_TRACK_THERMAL = 14, ++ FW_CMD_PAUSE_DM_BY_SCAN = 15, ++ FW_CMD_RESUME_DM_BY_SCAN = 16, ++ FW_CMD_RA_REFRESH_N_COMB = 17, ++ FW_CMD_RA_REFRESH_BG_COMB = 18, ++ FW_CMD_ANTENNA_SW_ENABLE = 19, ++ FW_CMD_ANTENNA_SW_DISABLE = 20, ++ /* Tx Status report for CCX from FW */ ++ FW_CMD_TX_FEEDBACK_CCX_ENABLE = 21, ++ /* Indifate firmware that driver ++ * enters LPS, For PS-Poll issue */ ++ FW_CMD_LPS_ENTER = 22, ++ /* Indicate firmware that driver ++ * leave LPS*/ ++ FW_CMD_LPS_LEAVE = 23, ++ /* Set DIG mode to signal strength */ ++ FW_CMD_DIG_MODE_SS = 24, ++ /* Set DIG mode to false alarm. */ ++ FW_CMD_DIG_MODE_FA = 25, ++ FW_CMD_ADD_A2_ENTRY = 26, ++ FW_CMD_CTRL_DM_BY_DRIVER = 27, ++ FW_CMD_CTRL_DM_BY_DRIVER_NEW = 28, ++ FW_CMD_PAPE_CONTROL = 29, ++ FW_CMD_IQK_ENABLE = 30, ++}; ++ ++/* ++ * Driver info contain PHY status ++ * and other variabel size info ++ * PHY Status content as below ++ */ ++struct rx_fwinfo { ++ /* DWORD 0 */ ++ u8 gain_trsw[4]; ++ /* DWORD 1 */ ++ u8 pwdb_all; ++ u8 cfosho[4]; ++ /* DWORD 2 */ ++ u8 cfotail[4]; ++ /* DWORD 3 */ ++ s8 rxevm[2]; ++ s8 rxsnr[4]; ++ /* DWORD 4 */ ++ u8 pdsnr[2]; ++ /* DWORD 5 */ ++ u8 csi_current[2]; ++ u8 csi_target[2]; ++ /* DWORD 6 */ ++ u8 sigevm; ++ u8 max_ex_pwr; ++ u8 ex_intf_flag:1; ++ u8 sgi_en:1; ++ u8 rxsc:2; ++ u8 reserve:4; ++}; ++ ++struct phy_sts_cck_8192s_t { ++ u8 adc_pwdb_x[4]; ++ u8 sq_rpt; ++ u8 cck_agc_rpt; ++}; ++ ++#endif ++ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/dm.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/dm.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/dm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/dm.c 2011-05-05 23:29:49.284487765 +0200 +@@ -0,0 +1,733 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#include "../wifi.h" ++#include "../base.h" ++#include "reg.h" ++#include "def.h" ++#include "phy.h" ++#include "dm.h" ++#include "fw.h" ++ ++struct dig_t digtable; ++static const u32 edca_setting_dl[PEER_MAX] = { ++ 0xa44f, /* 0 UNKNOWN */ ++ 0x5ea44f, /* 1 REALTEK_90 */ ++ 0x5ea44f, /* 2 REALTEK_92SE */ ++ 0xa630, /* 3 BROAD */ ++ 0xa44f, /* 4 RAL */ ++ 0xa630, /* 5 ATH */ ++ 0xa630, /* 6 CISCO */ ++ 0xa42b, /* 7 MARV */ ++}; ++ ++static const u32 edca_setting_dl_gmode[PEER_MAX] = { ++ 0x4322, /* 0 UNKNOWN */ ++ 0xa44f, /* 1 REALTEK_90 */ ++ 0x5ea44f, /* 2 REALTEK_92SE */ ++ 0xa42b, /* 3 BROAD */ ++ 0x5e4322, /* 4 RAL */ ++ 0x4322, /* 5 ATH */ ++ 0xa430, /* 6 CISCO */ ++ 0x5ea44f, /* 7 MARV */ ++}; ++ ++static const u32 edca_setting_ul[PEER_MAX] = { ++ 0x5e4322, /* 0 UNKNOWN */ ++ 0xa44f, /* 1 REALTEK_90 */ ++ 0x5ea44f, /* 2 REALTEK_92SE */ ++ 0x5ea322, /* 3 BROAD */ ++ 0x5ea422, /* 4 RAL */ ++ 0x5ea322, /* 5 ATH */ ++ 0x3ea44f, /* 6 CISCO */ ++ 0x5ea44f, /* 7 MARV */ ++}; ++ ++static void _rtl92s_dm_check_edca_turbo(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ ++ static u64 last_txok_cnt; ++ static u64 last_rxok_cnt; ++ u64 cur_txok_cnt = 0; ++ u64 cur_rxok_cnt = 0; ++ ++ u32 edca_be_ul = edca_setting_ul[mac->vendor]; ++ u32 edca_be_dl = edca_setting_dl[mac->vendor]; ++ u32 edca_gmode = edca_setting_dl_gmode[mac->vendor]; ++ ++ if (mac->link_state != MAC80211_LINKED) { ++ rtlpriv->dm.current_turbo_edca = false; ++ goto dm_checkedcaturbo_exit; ++ } ++ ++ if ((!rtlpriv->dm.is_any_nonbepkts) && ++ (!rtlpriv->dm.disable_framebursting)) { ++ cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; ++ cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; ++ ++ if (rtlpriv->phy.rf_type == RF_1T2R) { ++ if (cur_txok_cnt > 4 * cur_rxok_cnt) { ++ /* Uplink TP is present. */ ++ if (rtlpriv->dm.is_cur_rdlstate || ++ !rtlpriv->dm.current_turbo_edca) { ++ rtl_write_dword(rtlpriv, EDCAPARA_BE, ++ edca_be_ul); ++ rtlpriv->dm.is_cur_rdlstate = false; ++ } ++ } else {/* Balance TP is present. */ ++ if (!rtlpriv->dm.is_cur_rdlstate || ++ !rtlpriv->dm.current_turbo_edca) { ++ if (mac->mode == WIRELESS_MODE_G || ++ mac->mode == WIRELESS_MODE_B) ++ rtl_write_dword(rtlpriv, ++ EDCAPARA_BE, ++ edca_gmode); ++ else ++ rtl_write_dword(rtlpriv, ++ EDCAPARA_BE, ++ edca_be_dl); ++ rtlpriv->dm.is_cur_rdlstate = true; ++ } ++ } ++ rtlpriv->dm.current_turbo_edca = true; ++ } else { ++ if (cur_rxok_cnt > 4 * cur_txok_cnt) { ++ if (!rtlpriv->dm.is_cur_rdlstate || ++ !rtlpriv->dm.current_turbo_edca) { ++ if (mac->mode == WIRELESS_MODE_G || ++ mac->mode == WIRELESS_MODE_B) ++ rtl_write_dword(rtlpriv, ++ EDCAPARA_BE, ++ edca_gmode); ++ else ++ rtl_write_dword(rtlpriv, ++ EDCAPARA_BE, ++ edca_be_dl); ++ rtlpriv->dm.is_cur_rdlstate = true; ++ } ++ } else { ++ if (rtlpriv->dm.is_cur_rdlstate || ++ !rtlpriv->dm.current_turbo_edca) { ++ rtl_write_dword(rtlpriv, EDCAPARA_BE, ++ edca_be_ul); ++ rtlpriv->dm.is_cur_rdlstate = false; ++ } ++ } ++ rtlpriv->dm.current_turbo_edca = true; ++ } ++ } else { ++ if (rtlpriv->dm.current_turbo_edca) { ++ u8 tmp = AC0_BE; ++ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, ++ (u8 *)(&tmp)); ++ rtlpriv->dm.current_turbo_edca = false; ++ } ++ } ++ ++dm_checkedcaturbo_exit: ++ rtlpriv->dm.is_any_nonbepkts = false; ++ last_txok_cnt = rtlpriv->stats.txbytesunicast; ++ last_rxok_cnt = rtlpriv->stats.rxbytesunicast; ++} ++ ++static void _rtl92s_dm_txpowertracking_callback_thermalmeter( ++ struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ u8 thermalvalue = 0; ++ ++ rtlpriv->dm.txpower_trackinginit = true; ++ ++ thermalvalue = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0x1f); ++ ++ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, ++ ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x " ++ "eeprom_thermalmeter 0x%x\n", thermalvalue, ++ rtlpriv->dm.thermalvalue, rtlefuse->eeprom_thermalmeter)); ++ ++ if (thermalvalue) { ++ rtlpriv->dm.thermalvalue = thermalvalue; ++ rtl92s_phy_set_fw_cmd(hw, FW_CMD_TXPWR_TRACK_THERMAL); ++ } ++ ++ rtlpriv->dm.txpowercount = 0; ++} ++ ++static void _rtl92s_dm_check_txpowertracking_thermalmeter( ++ struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ static u8 tm_trigger; ++ u8 tx_power_checkcnt = 5; ++ ++ /* 2T2R TP issue */ ++ if (rtlphy->rf_type == RF_2T2R) ++ return; ++ ++ if (!rtlpriv->dm.txpower_tracking) ++ return; ++ ++ if (rtlpriv->dm.txpowercount <= tx_power_checkcnt) { ++ rtlpriv->dm.txpowercount++; ++ return; ++ } ++ ++ if (!tm_trigger) { ++ rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, ++ RFREG_OFFSET_MASK, 0x60); ++ tm_trigger = 1; ++ } else { ++ _rtl92s_dm_txpowertracking_callback_thermalmeter(hw); ++ tm_trigger = 0; ++ } ++} ++ ++static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rate_adaptive *ra = &(rtlpriv->ra); ++ ++ u32 low_rssi_thresh = 0; ++ u32 middle_rssi_thresh = 0; ++ u32 high_rssi_thresh = 0; ++ u8 rssi_level; ++ struct ieee80211_sta *sta = NULL; ++ ++ if (is_hal_stop(rtlhal)) ++ return; ++ ++ if (!rtlpriv->dm.useramask) ++ return; ++ ++ if (!rtlpriv->dm.inform_fw_driverctrldm) { ++ rtl92s_phy_set_fw_cmd(hw, FW_CMD_CTRL_DM_BY_DRIVER); ++ rtlpriv->dm.inform_fw_driverctrldm = true; ++ } ++ ++ rcu_read_lock(); ++ if (mac->opmode == NL80211_IFTYPE_STATION) ++ sta = get_sta(hw, mac->vif, mac->bssid); ++ if ((mac->link_state == MAC80211_LINKED) && ++ (mac->opmode == NL80211_IFTYPE_STATION)) { ++ switch (ra->pre_ratr_state) { ++ case DM_RATR_STA_HIGH: ++ high_rssi_thresh = 40; ++ middle_rssi_thresh = 30; ++ low_rssi_thresh = 20; ++ break; ++ case DM_RATR_STA_MIDDLE: ++ high_rssi_thresh = 44; ++ middle_rssi_thresh = 30; ++ low_rssi_thresh = 20; ++ break; ++ case DM_RATR_STA_LOW: ++ high_rssi_thresh = 44; ++ middle_rssi_thresh = 34; ++ low_rssi_thresh = 20; ++ break; ++ case DM_RATR_STA_ULTRALOW: ++ high_rssi_thresh = 44; ++ middle_rssi_thresh = 34; ++ low_rssi_thresh = 24; ++ break; ++ default: ++ high_rssi_thresh = 44; ++ middle_rssi_thresh = 34; ++ low_rssi_thresh = 24; ++ break; ++ } ++ ++ if (rtlpriv->dm.undecorated_smoothed_pwdb > ++ (long)high_rssi_thresh) { ++ ra->ratr_state = DM_RATR_STA_HIGH; ++ rssi_level = 1; ++ } else if (rtlpriv->dm.undecorated_smoothed_pwdb > ++ (long)middle_rssi_thresh) { ++ ra->ratr_state = DM_RATR_STA_LOW; ++ rssi_level = 3; ++ } else if (rtlpriv->dm.undecorated_smoothed_pwdb > ++ (long)low_rssi_thresh) { ++ ra->ratr_state = DM_RATR_STA_LOW; ++ rssi_level = 5; ++ } else { ++ ra->ratr_state = DM_RATR_STA_ULTRALOW; ++ rssi_level = 6; ++ } ++ ++ if (ra->pre_ratr_state != ra->ratr_state) { ++ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, ("RSSI = %ld " ++ "RSSI_LEVEL = %d PreState = %d, CurState = %d\n", ++ rtlpriv->dm.undecorated_smoothed_pwdb, ++ ra->ratr_state, ++ ra->pre_ratr_state, ra->ratr_state)); ++ ++ rtlpriv->cfg->ops->update_rate_tbl(hw, sta, ++ ra->ratr_state); ++ ra->pre_ratr_state = ra->ratr_state; ++ } ++ } ++ rcu_read_unlock(); ++} ++ ++static void _rtl92s_dm_switch_baseband_mrc(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ bool current_mrc; ++ bool enable_mrc = true; ++ long tmpentry_maxpwdb = 0; ++ u8 rssi_a = 0; ++ u8 rssi_b = 0; ++ ++ if (is_hal_stop(rtlhal)) ++ return; ++ ++ if ((rtlphy->rf_type == RF_1T1R) || (rtlphy->rf_type == RF_2T2R)) ++ return; ++ ++ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MRC, (u8 *)(¤t_mrc)); ++ ++ if (mac->link_state >= MAC80211_LINKED) { ++ if (rtlpriv->dm.undecorated_smoothed_pwdb > tmpentry_maxpwdb) { ++ rssi_a = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_A]; ++ rssi_b = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_B]; ++ } ++ } ++ ++ /* MRC settings would NOT affect TP on Wireless B mode. */ ++ if (mac->mode != WIRELESS_MODE_B) { ++ if ((rssi_a == 0) && (rssi_b == 0)) { ++ enable_mrc = true; ++ } else if (rssi_b > 30) { ++ /* Turn on B-Path */ ++ enable_mrc = true; ++ } else if (rssi_b < 5) { ++ /* Turn off B-path */ ++ enable_mrc = false; ++ /* Take care of RSSI differentiation. */ ++ } else if (rssi_a > 15 && (rssi_a >= rssi_b)) { ++ if ((rssi_a - rssi_b) > 15) ++ /* Turn off B-path */ ++ enable_mrc = false; ++ else if ((rssi_a - rssi_b) < 10) ++ /* Turn on B-Path */ ++ enable_mrc = true; ++ else ++ enable_mrc = current_mrc; ++ } else { ++ /* Turn on B-Path */ ++ enable_mrc = true; ++ } ++ } ++ ++ /* Update MRC settings if needed. */ ++ if (enable_mrc != current_mrc) ++ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC, ++ (u8 *)&enable_mrc); ++ ++} ++ ++void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ rtlpriv->dm.current_turbo_edca = false; ++ rtlpriv->dm.is_any_nonbepkts = false; ++ rtlpriv->dm.is_cur_rdlstate = false; ++} ++ ++static void _rtl92s_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rate_adaptive *ra = &(rtlpriv->ra); ++ ++ ra->ratr_state = DM_RATR_STA_MAX; ++ ra->pre_ratr_state = DM_RATR_STA_MAX; ++ ++ if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) ++ rtlpriv->dm.useramask = true; ++ else ++ rtlpriv->dm.useramask = false; ++ ++ rtlpriv->dm.useramask = false; ++ rtlpriv->dm.inform_fw_driverctrldm = false; ++} ++ ++static void _rtl92s_dm_init_txpowertracking_thermalmeter( ++ struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ rtlpriv->dm.txpower_tracking = true; ++ rtlpriv->dm.txpowercount = 0; ++ rtlpriv->dm.txpower_trackinginit = false; ++} ++ ++static void _rtl92s_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); ++ u32 ret_value; ++ ++ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD); ++ falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16); ++ ++ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD); ++ falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff); ++ falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); ++ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD); ++ falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff); ++ ++ falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail + ++ falsealm_cnt->cnt_rate_illegal + falsealm_cnt->cnt_crc8_fail + ++ falsealm_cnt->cnt_mcs_fail; ++ ++ /* read CCK false alarm */ ++ ret_value = rtl_get_bbreg(hw, 0xc64, MASKDWORD); ++ falsealm_cnt->cnt_cck_fail = (ret_value & 0xffff); ++ falsealm_cnt->cnt_all = falsealm_cnt->cnt_ofdm_fail + ++ falsealm_cnt->cnt_cck_fail; ++} ++ ++static void rtl92s_backoff_enable_flag(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); ++ ++ if (falsealm_cnt->cnt_all > digtable.fa_highthresh) { ++ if ((digtable.backoff_val - 6) < ++ digtable.backoffval_range_min) ++ digtable.backoff_val = digtable.backoffval_range_min; ++ else ++ digtable.backoff_val -= 6; ++ } else if (falsealm_cnt->cnt_all < digtable.fa_lowthresh) { ++ if ((digtable.backoff_val + 6) > ++ digtable.backoffval_range_max) ++ digtable.backoff_val = ++ digtable.backoffval_range_max; ++ else ++ digtable.backoff_val += 6; ++ } ++} ++ ++static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); ++ static u8 initialized, force_write; ++ u8 initial_gain = 0; ++ ++ if ((digtable.pre_sta_connectstate == digtable.cur_sta_connectstate) || ++ (digtable.cur_sta_connectstate == DIG_STA_BEFORE_CONNECT)) { ++ if (digtable.cur_sta_connectstate == DIG_STA_BEFORE_CONNECT) { ++ if (rtlpriv->psc.rfpwr_state != ERFON) ++ return; ++ ++ if (digtable.backoff_enable_flag == true) ++ rtl92s_backoff_enable_flag(hw); ++ else ++ digtable.backoff_val = DM_DIG_BACKOFF; ++ ++ if ((digtable.rssi_val + 10 - digtable.backoff_val) > ++ digtable.rx_gain_range_max) ++ digtable.cur_igvalue = ++ digtable.rx_gain_range_max; ++ else if ((digtable.rssi_val + 10 - digtable.backoff_val) ++ < digtable.rx_gain_range_min) ++ digtable.cur_igvalue = ++ digtable.rx_gain_range_min; ++ else ++ digtable.cur_igvalue = digtable.rssi_val + 10 - ++ digtable.backoff_val; ++ ++ if (falsealm_cnt->cnt_all > 10000) ++ digtable.cur_igvalue = ++ (digtable.cur_igvalue > 0x33) ? ++ digtable.cur_igvalue : 0x33; ++ ++ if (falsealm_cnt->cnt_all > 16000) ++ digtable.cur_igvalue = ++ digtable.rx_gain_range_max; ++ /* connected -> connected or disconnected -> disconnected */ ++ } else { ++ /* Firmware control DIG, do nothing in driver dm */ ++ return; ++ } ++ /* disconnected -> connected or connected -> ++ * disconnected or beforeconnect->(dis)connected */ ++ } else { ++ /* Enable FW DIG */ ++ digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; ++ rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_ENABLE); ++ ++ digtable.backoff_val = DM_DIG_BACKOFF; ++ digtable.cur_igvalue = rtlpriv->phy.default_initialgain[0]; ++ digtable.pre_igvalue = 0; ++ return; ++ } ++ ++ /* Forced writing to prevent from fw-dig overwriting. */ ++ if (digtable.pre_igvalue != rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, ++ MASKBYTE0)) ++ force_write = 1; ++ ++ if ((digtable.pre_igvalue != digtable.cur_igvalue) || ++ !initialized || force_write) { ++ /* Disable FW DIG */ ++ rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_DISABLE); ++ ++ initial_gain = (u8)digtable.cur_igvalue; ++ ++ /* Set initial gain. */ ++ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, initial_gain); ++ rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, initial_gain); ++ digtable.pre_igvalue = digtable.cur_igvalue; ++ initialized = 1; ++ force_write = 0; ++ } ++} ++ ++static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ if (rtlpriv->mac80211.act_scanning) ++ return; ++ ++ /* Decide the current status and if modify initial gain or not */ ++ if (rtlpriv->mac80211.link_state >= MAC80211_LINKED || ++ rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) ++ digtable.cur_sta_connectstate = DIG_STA_CONNECT; ++ else ++ digtable.cur_sta_connectstate = DIG_STA_DISCONNECT; ++ ++ digtable.rssi_val = rtlpriv->dm.undecorated_smoothed_pwdb; ++ ++ /* Change dig mode to rssi */ ++ if (digtable.cur_sta_connectstate != DIG_STA_DISCONNECT) { ++ if (digtable.dig_twoport_algorithm == ++ DIG_TWO_PORT_ALGO_FALSE_ALARM) { ++ digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; ++ rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_MODE_SS); ++ } ++ } ++ ++ _rtl92s_dm_false_alarm_counter_statistics(hw); ++ _rtl92s_dm_initial_gain_sta_beforeconnect(hw); ++ ++ digtable.pre_sta_connectstate = digtable.cur_sta_connectstate; ++} ++ ++static void _rtl92s_dm_ctrl_initgain_byrssi(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ ++ /* 2T2R TP issue */ ++ if (rtlphy->rf_type == RF_2T2R) ++ return; ++ ++ if (!rtlpriv->dm.dm_initialgain_enable) ++ return; ++ ++ if (digtable.dig_enable_flag == false) ++ return; ++ ++ _rtl92s_dm_ctrl_initgain_bytwoport(hw); ++} ++ ++static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ long undecorated_smoothed_pwdb; ++ long txpwr_threshold_lv1, txpwr_threshold_lv2; ++ ++ /* 2T2R TP issue */ ++ if (rtlphy->rf_type == RF_2T2R) ++ return; ++ ++ if (!rtlpriv->dm.dynamic_txpower_enable || ++ rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { ++ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; ++ return; ++ } ++ ++ if ((mac->link_state < MAC80211_LINKED) && ++ (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, ++ ("Not connected to any\n")); ++ ++ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; ++ ++ rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL; ++ return; ++ } ++ ++ if (mac->link_state >= MAC80211_LINKED) { ++ if (mac->opmode == NL80211_IFTYPE_ADHOC) { ++ undecorated_smoothed_pwdb = ++ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("AP Client PWDB = 0x%lx\n", ++ undecorated_smoothed_pwdb)); ++ } else { ++ undecorated_smoothed_pwdb = ++ rtlpriv->dm.undecorated_smoothed_pwdb; ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("STA Default Port PWDB = 0x%lx\n", ++ undecorated_smoothed_pwdb)); ++ } ++ } else { ++ undecorated_smoothed_pwdb = ++ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; ++ ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("AP Ext Port PWDB = 0x%lx\n", ++ undecorated_smoothed_pwdb)); ++ } ++ ++ txpwr_threshold_lv2 = TX_POWER_NEAR_FIELD_THRESH_LVL2; ++ txpwr_threshold_lv1 = TX_POWER_NEAR_FIELD_THRESH_LVL1; ++ ++ if (rtl_get_bbreg(hw, 0xc90, MASKBYTE0) == 1) ++ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; ++ else if (undecorated_smoothed_pwdb >= txpwr_threshold_lv2) ++ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL2; ++ else if ((undecorated_smoothed_pwdb < (txpwr_threshold_lv2 - 3)) && ++ (undecorated_smoothed_pwdb >= txpwr_threshold_lv1)) ++ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL1; ++ else if (undecorated_smoothed_pwdb < (txpwr_threshold_lv1 - 3)) ++ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; ++ ++ if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) ++ rtl92s_phy_set_txpower(hw, rtlphy->current_channel); ++ ++ rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; ++} ++ ++static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ /* Disable DIG scheme now.*/ ++ digtable.dig_enable_flag = true; ++ digtable.backoff_enable_flag = true; ++ ++ if ((rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) && ++ (hal_get_firmwareversion(rtlpriv) >= 0x3c)) ++ digtable.dig_algorithm = DIG_ALGO_BY_TOW_PORT; ++ else ++ digtable.dig_algorithm = ++ DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM; ++ ++ digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; ++ digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; ++ /* off=by real rssi value, on=by digtable.rssi_val for new dig */ ++ digtable.dig_dbgmode = DM_DBG_OFF; ++ digtable.dig_slgorithm_switch = 0; ++ ++ /* 2007/10/04 MH Define init gain threshol. */ ++ digtable.dig_state = DM_STA_DIG_MAX; ++ digtable.dig_highpwrstate = DM_STA_DIG_MAX; ++ ++ digtable.cur_sta_connectstate = DIG_STA_DISCONNECT; ++ digtable.pre_sta_connectstate = DIG_STA_DISCONNECT; ++ digtable.cur_ap_connectstate = DIG_AP_DISCONNECT; ++ digtable.pre_ap_connectstate = DIG_AP_DISCONNECT; ++ ++ digtable.rssi_lowthresh = DM_DIG_THRESH_LOW; ++ digtable.rssi_highthresh = DM_DIG_THRESH_HIGH; ++ ++ digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW; ++ digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH; ++ ++ digtable.rssi_highpower_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW; ++ digtable.rssi_highpower_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH; ++ ++ /* for dig debug rssi value */ ++ digtable.rssi_val = 50; ++ digtable.backoff_val = DM_DIG_BACKOFF; ++ digtable.rx_gain_range_max = DM_DIG_MAX; ++ ++ digtable.rx_gain_range_min = DM_DIG_MIN; ++ ++ digtable.backoffval_range_max = DM_DIG_BACKOFF_MAX; ++ digtable.backoffval_range_min = DM_DIG_BACKOFF_MIN; ++} ++ ++static void _rtl92s_dm_init_dynamic_txpower(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ if ((hal_get_firmwareversion(rtlpriv) >= 60) && ++ (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)) ++ rtlpriv->dm.dynamic_txpower_enable = true; ++ else ++ rtlpriv->dm.dynamic_txpower_enable = false; ++ ++ rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL; ++ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; ++} ++ ++void rtl92s_dm_init(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; ++ rtlpriv->dm.undecorated_smoothed_pwdb = -1; ++ ++ _rtl92s_dm_init_dynamic_txpower(hw); ++ rtl92s_dm_init_edca_turbo(hw); ++ _rtl92s_dm_init_rate_adaptive_mask(hw); ++ _rtl92s_dm_init_txpowertracking_thermalmeter(hw); ++ _rtl92s_dm_init_dig(hw); ++ ++ rtl_write_dword(rtlpriv, WFM5, FW_CCA_CHK_ENABLE); ++} ++ ++void rtl92s_dm_watchdog(struct ieee80211_hw *hw) ++{ ++ _rtl92s_dm_check_edca_turbo(hw); ++ _rtl92s_dm_check_txpowertracking_thermalmeter(hw); ++ _rtl92s_dm_ctrl_initgain_byrssi(hw); ++ _rtl92s_dm_dynamic_txpower(hw); ++ _rtl92s_dm_refresh_rateadaptive_mask(hw); ++ _rtl92s_dm_switch_baseband_mrc(hw); ++} ++ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/dm.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/dm.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/dm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/dm.h 2011-05-05 23:29:49.269487583 +0200 +@@ -0,0 +1,164 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++#ifndef __RTL_92S_DM_H__ ++#define __RTL_92S_DM_H__ ++ ++struct dig_t { ++ u8 dig_enable_flag; ++ u8 dig_algorithm; ++ u8 dig_twoport_algorithm; ++ u8 dig_ext_port_stage; ++ u8 dig_dbgmode; ++ u8 dig_slgorithm_switch; ++ ++ long rssi_lowthresh; ++ long rssi_highthresh; ++ ++ u32 fa_lowthresh; ++ u32 fa_highthresh; ++ ++ long rssi_highpower_lowthresh; ++ long rssi_highpower_highthresh; ++ ++ u8 dig_state; ++ u8 dig_highpwrstate; ++ u8 cur_sta_connectstate; ++ u8 pre_sta_connectstate; ++ u8 cur_ap_connectstate; ++ u8 pre_ap_connectstate; ++ ++ u8 cur_pd_thstate; ++ u8 pre_pd_thstate; ++ u8 cur_cs_ratiostate; ++ u8 pre_cs_ratiostate; ++ ++ u32 pre_igvalue; ++ u32 cur_igvalue; ++ ++ u8 backoff_enable_flag; ++ char backoff_val; ++ char backoffval_range_max; ++ char backoffval_range_min; ++ u8 rx_gain_range_max; ++ u8 rx_gain_range_min; ++ ++ long rssi_val; ++}; ++ ++enum dm_dig_alg { ++ DIG_ALGO_BY_FALSE_ALARM = 0, ++ DIG_ALGO_BY_RSSI = 1, ++ DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM = 2, ++ DIG_ALGO_BY_TOW_PORT = 3, ++ DIG_ALGO_MAX ++}; ++ ++enum dm_dig_two_port_alg { ++ DIG_TWO_PORT_ALGO_RSSI = 0, ++ DIG_TWO_PORT_ALGO_FALSE_ALARM = 1, ++}; ++ ++enum dm_dig_dbg { ++ DM_DBG_OFF = 0, ++ DM_DBG_ON = 1, ++ DM_DBG_MAX ++}; ++ ++enum dm_dig_sta { ++ DM_STA_DIG_OFF = 0, ++ DM_STA_DIG_ON, ++ DM_STA_DIG_MAX ++}; ++ ++enum dm_dig_connect { ++ DIG_STA_DISCONNECT = 0, ++ DIG_STA_CONNECT = 1, ++ DIG_STA_BEFORE_CONNECT = 2, ++ DIG_AP_DISCONNECT = 3, ++ DIG_AP_CONNECT = 4, ++ DIG_AP_ADD_STATION = 5, ++ DIG_CONNECT_MAX ++}; ++ ++enum dm_dig_ext_port_alg { ++ DIG_EXT_PORT_STAGE_0 = 0, ++ DIG_EXT_PORT_STAGE_1 = 1, ++ DIG_EXT_PORT_STAGE_2 = 2, ++ DIG_EXT_PORT_STAGE_3 = 3, ++ DIG_EXT_PORT_STAGE_MAX = 4, ++}; ++ ++enum dm_ratr_sta { ++ DM_RATR_STA_HIGH = 0, ++ DM_RATR_STA_MIDDLEHIGH = 1, ++ DM_RATR_STA_MIDDLE = 2, ++ DM_RATR_STA_MIDDLELOW = 3, ++ DM_RATR_STA_LOW = 4, ++ DM_RATR_STA_ULTRALOW = 5, ++ DM_RATR_STA_MAX ++}; ++ ++#define DM_TYPE_BYFW 0 ++#define DM_TYPE_BYDRIVER 1 ++ ++#define TX_HIGH_PWR_LEVEL_NORMAL 0 ++#define TX_HIGH_PWR_LEVEL_LEVEL1 1 ++#define TX_HIGH_PWR_LEVEL_LEVEL2 2 ++ ++#define HAL_DM_DIG_DISABLE BIT(0) /* Disable Dig */ ++#define HAL_DM_HIPWR_DISABLE BIT(1) /* Disable High Power */ ++ ++#define TX_HIGHPWR_LEVEL_NORMAL 0 ++#define TX_HIGHPWR_LEVEL_NORMAL1 1 ++#define TX_HIGHPWR_LEVEL_NORMAL2 2 ++ ++#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 ++#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 ++ ++#define DM_DIG_THRESH_HIGH 40 ++#define DM_DIG_THRESH_LOW 35 ++#define DM_FALSEALARM_THRESH_LOW 40 ++#define DM_FALSEALARM_THRESH_HIGH 1000 ++#define DM_DIG_HIGH_PWR_THRESH_HIGH 75 ++#define DM_DIG_HIGH_PWR_THRESH_LOW 70 ++#define DM_DIG_BACKOFF 12 ++#define DM_DIG_MAX 0x3e ++#define DM_DIG_MIN 0x1c ++#define DM_DIG_MIN_Netcore 0x12 ++#define DM_DIG_BACKOFF_MAX 12 ++#define DM_DIG_BACKOFF_MIN -4 ++ ++extern struct dig_t digtable; ++ ++void rtl92s_dm_watchdog(struct ieee80211_hw *hw); ++void rtl92s_dm_init(struct ieee80211_hw *hw); ++void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw); ++ ++#endif ++ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/fw.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/fw.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/fw.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/fw.c 2011-05-05 23:29:49.270487595 +0200 +@@ -0,0 +1,654 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#include "../wifi.h" ++#include "../pci.h" ++#include "../base.h" ++#include "reg.h" ++#include "def.h" ++#include "fw.h" ++ ++static void _rtl92s_fw_set_rqpn(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ rtl_write_dword(rtlpriv, RQPN, 0xffffffff); ++ rtl_write_dword(rtlpriv, RQPN + 4, 0xffffffff); ++ rtl_write_byte(rtlpriv, RQPN + 8, 0xff); ++ rtl_write_byte(rtlpriv, RQPN + 0xB, 0x80); ++} ++ ++static bool _rtl92s_firmware_enable_cpu(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u32 ichecktime = 200; ++ u16 tmpu2b; ++ u8 tmpu1b, cpustatus = 0; ++ ++ _rtl92s_fw_set_rqpn(hw); ++ ++ /* Enable CPU. */ ++ tmpu1b = rtl_read_byte(rtlpriv, SYS_CLKR); ++ /* AFE source */ ++ rtl_write_byte(rtlpriv, SYS_CLKR, (tmpu1b | SYS_CPU_CLKSEL)); ++ ++ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); ++ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | FEN_CPUEN)); ++ ++ /* Polling IMEM Ready after CPU has refilled. */ ++ do { ++ cpustatus = rtl_read_byte(rtlpriv, TCR); ++ if (cpustatus & IMEM_RDY) { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("IMEM Ready after CPU has refilled.\n")); ++ break; ++ } ++ ++ udelay(100); ++ } while (ichecktime--); ++ ++ if (!(cpustatus & IMEM_RDY)) ++ return false; ++ ++ return true; ++} ++ ++static enum fw_status _rtl92s_firmware_get_nextstatus( ++ enum fw_status fw_currentstatus) ++{ ++ enum fw_status next_fwstatus = 0; ++ ++ switch (fw_currentstatus) { ++ case FW_STATUS_INIT: ++ next_fwstatus = FW_STATUS_LOAD_IMEM; ++ break; ++ case FW_STATUS_LOAD_IMEM: ++ next_fwstatus = FW_STATUS_LOAD_EMEM; ++ break; ++ case FW_STATUS_LOAD_EMEM: ++ next_fwstatus = FW_STATUS_LOAD_DMEM; ++ break; ++ case FW_STATUS_LOAD_DMEM: ++ next_fwstatus = FW_STATUS_READY; ++ break; ++ default: ++ break; ++ } ++ ++ return next_fwstatus; ++} ++ ++static u8 _rtl92s_firmware_header_map_rftype(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ ++ switch (rtlphy->rf_type) { ++ case RF_1T1R: ++ return 0x11; ++ break; ++ case RF_1T2R: ++ return 0x12; ++ break; ++ case RF_2T2R: ++ return 0x22; ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ++ ("Unknown RF type(%x)\n", ++ rtlphy->rf_type)); ++ break; ++ } ++ return 0x22; ++} ++ ++static void _rtl92s_firmwareheader_priveupdate(struct ieee80211_hw *hw, ++ struct fw_priv *pfw_priv) ++{ ++ /* Update RF types for RATR settings. */ ++ pfw_priv->rf_config = _rtl92s_firmware_header_map_rftype(hw); ++} ++ ++ ++ ++static bool _rtl92s_cmd_send_packet(struct ieee80211_hw *hw, ++ struct sk_buff *skb, u8 last) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ struct rtl8192_tx_ring *ring; ++ struct rtl_tx_desc *pdesc; ++ unsigned long flags; ++ u8 idx = 0; ++ ++ ring = &rtlpci->tx_ring[TXCMD_QUEUE]; ++ ++ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); ++ ++ idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; ++ pdesc = &ring->desc[idx]; ++ rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb); ++ __skb_queue_tail(&ring->queue, skb); ++ ++ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); ++ ++ return true; ++} ++ ++static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw, ++ u8 *code_virtual_address, u32 buffer_len) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct sk_buff *skb; ++ struct rtl_tcb_desc *tcb_desc; ++ unsigned char *seg_ptr; ++ u16 frag_threshold = MAX_FIRMWARE_CODE_SIZE; ++ u16 frag_length, frag_offset = 0; ++ u16 extra_descoffset = 0; ++ u8 last_inipkt = 0; ++ ++ _rtl92s_fw_set_rqpn(hw); ++ ++ if (buffer_len >= MAX_FIRMWARE_CODE_SIZE) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Size over FIRMWARE_CODE_SIZE!\n")); ++ ++ return false; ++ } ++ ++ extra_descoffset = 0; ++ ++ do { ++ if ((buffer_len - frag_offset) > frag_threshold) { ++ frag_length = frag_threshold + extra_descoffset; ++ } else { ++ frag_length = (u16)(buffer_len - frag_offset + ++ extra_descoffset); ++ last_inipkt = 1; ++ } ++ ++ /* Allocate skb buffer to contain firmware */ ++ /* info and tx descriptor info. */ ++ skb = dev_alloc_skb(frag_length); ++ skb_reserve(skb, extra_descoffset); ++ seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length - ++ extra_descoffset)); ++ memcpy(seg_ptr, code_virtual_address + frag_offset, ++ (u32)(frag_length - extra_descoffset)); ++ ++ tcb_desc = (struct rtl_tcb_desc *)(skb->cb); ++ tcb_desc->queue_index = TXCMD_QUEUE; ++ tcb_desc->cmd_or_init = DESC_PACKET_TYPE_INIT; ++ tcb_desc->last_inipkt = last_inipkt; ++ ++ _rtl92s_cmd_send_packet(hw, skb, last_inipkt); ++ ++ frag_offset += (frag_length - extra_descoffset); ++ ++ } while (frag_offset < buffer_len); ++ ++ rtl_write_byte(rtlpriv, TP_POLL, TPPOLL_CQ); ++ ++ return true ; ++} ++ ++static bool _rtl92s_firmware_checkready(struct ieee80211_hw *hw, ++ u8 loadfw_status) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rt_firmware *firmware = (struct rt_firmware *)rtlhal->pfirmware; ++ u32 tmpu4b; ++ u8 cpustatus = 0; ++ short pollingcnt = 1000; ++ bool rtstatus = true; ++ ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("LoadStaus(%d)\n", ++ loadfw_status)); ++ ++ firmware->fwstatus = (enum fw_status)loadfw_status; ++ ++ switch (loadfw_status) { ++ case FW_STATUS_LOAD_IMEM: ++ /* Polling IMEM code done. */ ++ do { ++ cpustatus = rtl_read_byte(rtlpriv, TCR); ++ if (cpustatus & IMEM_CODE_DONE) ++ break; ++ udelay(5); ++ } while (pollingcnt--); ++ ++ if (!(cpustatus & IMEM_CHK_RPT) || (pollingcnt <= 0)) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("FW_STATUS_LOAD_IMEM" ++ " FAIL CPU, Status=%x\r\n", cpustatus)); ++ goto status_check_fail; ++ } ++ break; ++ ++ case FW_STATUS_LOAD_EMEM: ++ /* Check Put Code OK and Turn On CPU */ ++ /* Polling EMEM code done. */ ++ do { ++ cpustatus = rtl_read_byte(rtlpriv, TCR); ++ if (cpustatus & EMEM_CODE_DONE) ++ break; ++ udelay(5); ++ } while (pollingcnt--); ++ ++ if (!(cpustatus & EMEM_CHK_RPT) || (pollingcnt <= 0)) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("FW_STATUS_LOAD_EMEM" ++ " FAIL CPU, Status=%x\r\n", cpustatus)); ++ goto status_check_fail; ++ } ++ ++ /* Turn On CPU */ ++ rtstatus = _rtl92s_firmware_enable_cpu(hw); ++ if (rtstatus != true) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Enable CPU fail!\n")); ++ goto status_check_fail; ++ } ++ break; ++ ++ case FW_STATUS_LOAD_DMEM: ++ /* Polling DMEM code done */ ++ do { ++ cpustatus = rtl_read_byte(rtlpriv, TCR); ++ if (cpustatus & DMEM_CODE_DONE) ++ break; ++ udelay(5); ++ } while (pollingcnt--); ++ ++ if (!(cpustatus & DMEM_CODE_DONE) || (pollingcnt <= 0)) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Polling DMEM code done" ++ " fail ! cpustatus(%#x)\n", cpustatus)); ++ goto status_check_fail; ++ } ++ ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("DMEM code download success," ++ " cpustatus(%#x)\n", cpustatus)); ++ ++ /* Prevent Delay too much and being scheduled out */ ++ /* Polling Load Firmware ready */ ++ pollingcnt = 2000; ++ do { ++ cpustatus = rtl_read_byte(rtlpriv, TCR); ++ if (cpustatus & FWRDY) ++ break; ++ udelay(40); ++ } while (pollingcnt--); ++ ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("Polling Load Firmware ready," ++ " cpustatus(%x)\n", cpustatus)); ++ ++ if (((cpustatus & LOAD_FW_READY) != LOAD_FW_READY) || ++ (pollingcnt <= 0)) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Polling Load Firmware" ++ " ready fail ! cpustatus(%x)\n", cpustatus)); ++ goto status_check_fail; ++ } ++ ++ /* If right here, we can set TCR/RCR to desired value */ ++ /* and config MAC lookback mode to normal mode */ ++ tmpu4b = rtl_read_dword(rtlpriv, TCR); ++ rtl_write_dword(rtlpriv, TCR, (tmpu4b & (~TCR_ICV))); ++ ++ tmpu4b = rtl_read_dword(rtlpriv, RCR); ++ rtl_write_dword(rtlpriv, RCR, (tmpu4b | RCR_APPFCS | ++ RCR_APP_ICV | RCR_APP_MIC)); ++ ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("Current RCR settings(%#x)\n", tmpu4b)); ++ ++ /* Set to normal mode. */ ++ rtl_write_byte(rtlpriv, LBKMD_SEL, LBK_NORMAL); ++ break; ++ ++ default: ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ++ ("Unknown status check!\n")); ++ rtstatus = false; ++ break; ++ } ++ ++status_check_fail: ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("loadfw_status(%d), " ++ "rtstatus(%x)\n", loadfw_status, rtstatus)); ++ return rtstatus; ++} ++ ++int rtl92s_download_fw(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rt_firmware *firmware = NULL; ++ struct fw_hdr *pfwheader; ++ struct fw_priv *pfw_priv = NULL; ++ u8 *puc_mappedfile = NULL; ++ u32 ul_filelength = 0; ++ u32 file_length = 0; ++ u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE; ++ u8 fwstatus = FW_STATUS_INIT; ++ bool rtstatus = true; ++ ++ if (!rtlhal->pfirmware) ++ return 1; ++ ++ firmware = (struct rt_firmware *)rtlhal->pfirmware; ++ firmware->fwstatus = FW_STATUS_INIT; ++ ++ puc_mappedfile = firmware->sz_fw_tmpbuffer; ++ file_length = firmware->sz_fw_tmpbufferlen; ++ ++ /* 1. Retrieve FW header. */ ++ firmware->pfwheader = (struct fw_hdr *) puc_mappedfile; ++ pfwheader = firmware->pfwheader; ++ firmware->firmwareversion = byte(pfwheader->version, 0); ++ firmware->pfwheader->fwpriv.hci_sel = 1;/* pcie */ ++ ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("signature:%x, version:" ++ "%x, size:%x," ++ "imemsize:%x, sram size:%x\n", pfwheader->signature, ++ pfwheader->version, pfwheader->dmem_size, ++ pfwheader->img_imem_size, pfwheader->img_sram_size)); ++ ++ /* 2. Retrieve IMEM image. */ ++ if ((pfwheader->img_imem_size == 0) || (pfwheader->img_imem_size > ++ sizeof(firmware->fw_imem))) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("memory for data image is less than IMEM required\n")); ++ goto fail; ++ } else { ++ puc_mappedfile += fwhdr_size; ++ ++ memcpy(firmware->fw_imem, puc_mappedfile, ++ pfwheader->img_imem_size); ++ firmware->fw_imem_len = pfwheader->img_imem_size; ++ } ++ ++ /* 3. Retriecve EMEM image. */ ++ if (pfwheader->img_sram_size > sizeof(firmware->fw_emem)) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("memory for data image is less than EMEM required\n")); ++ goto fail; ++ } else { ++ puc_mappedfile += firmware->fw_imem_len; ++ ++ memcpy(firmware->fw_emem, puc_mappedfile, ++ pfwheader->img_sram_size); ++ firmware->fw_emem_len = pfwheader->img_sram_size; ++ } ++ ++ /* 4. download fw now */ ++ fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus); ++ while (fwstatus != FW_STATUS_READY) { ++ /* Image buffer redirection. */ ++ switch (fwstatus) { ++ case FW_STATUS_LOAD_IMEM: ++ puc_mappedfile = firmware->fw_imem; ++ ul_filelength = firmware->fw_imem_len; ++ break; ++ case FW_STATUS_LOAD_EMEM: ++ puc_mappedfile = firmware->fw_emem; ++ ul_filelength = firmware->fw_emem_len; ++ break; ++ case FW_STATUS_LOAD_DMEM: ++ /* Partial update the content of header private. */ ++ pfwheader = firmware->pfwheader; ++ pfw_priv = &pfwheader->fwpriv; ++ _rtl92s_firmwareheader_priveupdate(hw, pfw_priv); ++ puc_mappedfile = (u8 *)(firmware->pfwheader) + ++ RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; ++ ul_filelength = fwhdr_size - ++ RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Unexpected Download step!!\n")); ++ goto fail; ++ break; ++ } ++ ++ /* <2> Download image file */ ++ rtstatus = _rtl92s_firmware_downloadcode(hw, puc_mappedfile, ++ ul_filelength); ++ ++ if (rtstatus != true) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("fail!\n")); ++ goto fail; ++ } ++ ++ /* <3> Check whether load FW process is ready */ ++ rtstatus = _rtl92s_firmware_checkready(hw, fwstatus); ++ if (rtstatus != true) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("fail!\n")); ++ goto fail; ++ } ++ ++ fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus); ++ } ++ ++ return rtstatus; ++fail: ++ return 0; ++} ++ ++static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen, ++ u32 cmd_num, u32 *pelement_id, u32 *pcmd_len, ++ u8 **pcmb_buffer, u8 *cmd_start_seq) ++{ ++ u32 totallen = 0, len = 0, tx_desclen = 0; ++ u32 pre_continueoffset = 0; ++ u8 *ph2c_buffer; ++ u8 i = 0; ++ ++ do { ++ /* 8 - Byte aligment */ ++ len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8); ++ ++ /* Buffer length is not enough */ ++ if (h2cbufferlen < totallen + len + tx_desclen) ++ break; ++ ++ /* Clear content */ ++ ph2c_buffer = (u8 *)skb_put(skb, (u32)len); ++ memset((ph2c_buffer + totallen + tx_desclen), 0, len); ++ ++ /* CMD len */ ++ SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), ++ 0, 16, pcmd_len[i]); ++ ++ /* CMD ID */ ++ SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), ++ 16, 8, pelement_id[i]); ++ ++ /* CMD Sequence */ ++ *cmd_start_seq = *cmd_start_seq % 0x80; ++ SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), ++ 24, 7, *cmd_start_seq); ++ ++*cmd_start_seq; ++ ++ /* Copy memory */ ++ memcpy((ph2c_buffer + totallen + tx_desclen + ++ H2C_TX_CMD_HDR_LEN), pcmb_buffer[i], pcmd_len[i]); ++ ++ /* CMD continue */ ++ /* set the continue in prevoius cmd. */ ++ if (i < cmd_num - 1) ++ SET_BITS_TO_LE_4BYTE((ph2c_buffer + pre_continueoffset), ++ 31, 1, 1); ++ ++ pre_continueoffset = totallen; ++ ++ totallen += len; ++ } while (++i < cmd_num); ++ ++ return totallen; ++} ++ ++static u32 _rtl92s_get_h2c_cmdlen(u32 h2cbufferlen, u32 cmd_num, u32 *pcmd_len) ++{ ++ u32 totallen = 0, len = 0, tx_desclen = 0; ++ u8 i = 0; ++ ++ do { ++ /* 8 - Byte aligment */ ++ len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8); ++ ++ /* Buffer length is not enough */ ++ if (h2cbufferlen < totallen + len + tx_desclen) ++ break; ++ ++ totallen += len; ++ } while (++i < cmd_num); ++ ++ return totallen + tx_desclen; ++} ++ ++static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd, ++ u8 *pcmd_buffer) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_tcb_desc *cb_desc; ++ struct sk_buff *skb; ++ u32 element_id = 0; ++ u32 cmd_len = 0; ++ u32 len; ++ ++ switch (h2c_cmd) { ++ case FW_H2C_SETPWRMODE: ++ element_id = H2C_SETPWRMODE_CMD ; ++ cmd_len = sizeof(struct h2c_set_pwrmode_parm); ++ break; ++ case FW_H2C_JOINBSSRPT: ++ element_id = H2C_JOINBSSRPT_CMD; ++ cmd_len = sizeof(struct h2c_joinbss_rpt_parm); ++ break; ++ case FW_H2C_WOWLAN_UPDATE_GTK: ++ element_id = H2C_WOWLAN_UPDATE_GTK_CMD; ++ cmd_len = sizeof(struct h2c_wpa_two_way_parm); ++ break; ++ case FW_H2C_WOWLAN_UPDATE_IV: ++ element_id = H2C_WOWLAN_UPDATE_IV_CMD; ++ cmd_len = sizeof(unsigned long long); ++ break; ++ case FW_H2C_WOWLAN_OFFLOAD: ++ element_id = H2C_WOWLAN_FW_OFFLOAD; ++ cmd_len = sizeof(u8); ++ break; ++ default: ++ break; ++ } ++ ++ len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len); ++ skb = dev_alloc_skb(len); ++ cb_desc = (struct rtl_tcb_desc *)(skb->cb); ++ cb_desc->queue_index = TXCMD_QUEUE; ++ cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL; ++ cb_desc->last_inipkt = false; ++ ++ _rtl92s_fill_h2c_cmd(skb, MAX_TRANSMIT_BUFFER_SIZE, 1, &element_id, ++ &cmd_len, &pcmd_buffer, &rtlhal->h2c_txcmd_seq); ++ _rtl92s_cmd_send_packet(hw, skb, false); ++ rtlpriv->cfg->ops->tx_polling(hw, TXCMD_QUEUE); ++ ++ return true; ++} ++ ++void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 Mode) ++{ ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ struct h2c_set_pwrmode_parm pwrmode; ++ u16 max_wakeup_period = 0; ++ ++ pwrmode.mode = Mode; ++ pwrmode.flag_low_traffic_en = 0; ++ pwrmode.flag_lpnav_en = 0; ++ pwrmode.flag_rf_low_snr_en = 0; ++ pwrmode.flag_dps_en = 0; ++ pwrmode.bcn_rx_en = 0; ++ pwrmode.bcn_to = 0; ++ SET_BITS_TO_LE_2BYTE((u8 *)(&pwrmode) + 8, 0, 16, ++ mac->vif->bss_conf.beacon_int); ++ pwrmode.app_itv = 0; ++ pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl; ++ pwrmode.smart_ps = 1; ++ pwrmode.bcn_pass_period = 10; ++ ++ /* Set beacon pass count */ ++ if (pwrmode.mode == FW_PS_MIN_MODE) ++ max_wakeup_period = mac->vif->bss_conf.beacon_int; ++ else if (pwrmode.mode == FW_PS_MAX_MODE) ++ max_wakeup_period = mac->vif->bss_conf.beacon_int * ++ mac->vif->bss_conf.dtim_period; ++ ++ if (max_wakeup_period >= 500) ++ pwrmode.bcn_pass_cnt = 1; ++ else if ((max_wakeup_period >= 300) && (max_wakeup_period < 500)) ++ pwrmode.bcn_pass_cnt = 2; ++ else if ((max_wakeup_period >= 200) && (max_wakeup_period < 300)) ++ pwrmode.bcn_pass_cnt = 3; ++ else if ((max_wakeup_period >= 20) && (max_wakeup_period < 200)) ++ pwrmode.bcn_pass_cnt = 5; ++ else ++ pwrmode.bcn_pass_cnt = 1; ++ ++ _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_SETPWRMODE, (u8 *)&pwrmode); ++ ++} ++ ++void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, ++ u8 mstatus, u8 ps_qosinfo) ++{ ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct h2c_joinbss_rpt_parm joinbss_rpt; ++ ++ joinbss_rpt.opmode = mstatus; ++ joinbss_rpt.ps_qos_info = ps_qosinfo; ++ joinbss_rpt.bssid[0] = mac->bssid[0]; ++ joinbss_rpt.bssid[1] = mac->bssid[1]; ++ joinbss_rpt.bssid[2] = mac->bssid[2]; ++ joinbss_rpt.bssid[3] = mac->bssid[3]; ++ joinbss_rpt.bssid[4] = mac->bssid[4]; ++ joinbss_rpt.bssid[5] = mac->bssid[5]; ++ SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 8, 0, 16, ++ mac->vif->bss_conf.beacon_int); ++ SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 10, 0, 16, mac->assoc_id); ++ ++ _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt); ++} ++ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/fw.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/fw.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/fw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/fw.h 2011-05-05 23:29:49.276487669 +0200 +@@ -0,0 +1,375 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++#ifndef __REALTEK_FIRMWARE92S_H__ ++#define __REALTEK_FIRMWARE92S_H__ ++ ++#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 ++#define RTL8190_CPU_START_OFFSET 0x80 ++/* Firmware Local buffer size. 64k */ ++#define MAX_FIRMWARE_CODE_SIZE 0xFF00 ++ ++#define RT_8192S_FIRMWARE_HDR_SIZE 80 ++#define RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE 32 ++ ++/* support till 64 bit bus width OS */ ++#define MAX_DEV_ADDR_SIZE 8 ++#define MAX_FIRMWARE_INFORMATION_SIZE 32 ++#define MAX_802_11_HEADER_LENGTH (40 + \ ++ MAX_FIRMWARE_INFORMATION_SIZE) ++#define ENCRYPTION_MAX_OVERHEAD 128 ++#define MAX_FRAGMENT_COUNT 8 ++#define MAX_TRANSMIT_BUFFER_SIZE (1600 + \ ++ (MAX_802_11_HEADER_LENGTH + \ ++ ENCRYPTION_MAX_OVERHEAD) *\ ++ MAX_FRAGMENT_COUNT) ++ ++#define H2C_TX_CMD_HDR_LEN 8 ++ ++/* The following DM control code are for Reg0x364, */ ++#define FW_DIG_ENABLE_CTL BIT(0) ++#define FW_HIGH_PWR_ENABLE_CTL BIT(1) ++#define FW_SS_CTL BIT(2) ++#define FW_RA_INIT_CTL BIT(3) ++#define FW_RA_BG_CTL BIT(4) ++#define FW_RA_N_CTL BIT(5) ++#define FW_PWR_TRK_CTL BIT(6) ++#define FW_IQK_CTL BIT(7) ++#define FW_FA_CTL BIT(8) ++#define FW_DRIVER_CTRL_DM_CTL BIT(9) ++#define FW_PAPE_CTL_BY_SW_HW BIT(10) ++#define FW_DISABLE_ALL_DM 0 ++#define FW_PWR_TRK_PARAM_CLR 0x0000ffff ++#define FW_RA_PARAM_CLR 0xffff0000 ++ ++enum desc_packet_type { ++ DESC_PACKET_TYPE_INIT = 0, ++ DESC_PACKET_TYPE_NORMAL = 1, ++}; ++ ++/* 8-bytes alignment required */ ++struct fw_priv { ++ /* --- long word 0 ---- */ ++ /* 0x12: CE product, 0x92: IT product */ ++ u8 signature_0; ++ /* 0x87: CE product, 0x81: IT product */ ++ u8 signature_1; ++ /* 0x81: PCI-AP, 01:PCIe, 02: 92S-U, ++ * 0x82: USB-AP, 0x12: 72S-U, 03:SDIO */ ++ u8 hci_sel; ++ /* the same value as reigster value */ ++ u8 chip_version; ++ /* customer ID low byte */ ++ u8 customer_id_0; ++ /* customer ID high byte */ ++ u8 customer_id_1; ++ /* 0x11: 1T1R, 0x12: 1T2R, ++ * 0x92: 1T2R turbo, 0x22: 2T2R */ ++ u8 rf_config; ++ /* 4: 4EP, 6: 6EP, 11: 11EP */ ++ u8 usb_ep_num; ++ ++ /* --- long word 1 ---- */ ++ /* regulatory class bit map 0 */ ++ u8 regulatory_class_0; ++ /* regulatory class bit map 1 */ ++ u8 regulatory_class_1; ++ /* regulatory class bit map 2 */ ++ u8 regulatory_class_2; ++ /* regulatory class bit map 3 */ ++ u8 regulatory_class_3; ++ /* 0:SWSI, 1:HWSI, 2:HWPI */ ++ u8 rfintfs; ++ u8 def_nettype; ++ u8 rsvd010; ++ u8 rsvd011; ++ ++ /* --- long word 2 ---- */ ++ /* 0x00: normal, 0x03: MACLBK, 0x01: PHYLBK */ ++ u8 lbk_mode; ++ /* 1: for MP use, 0: for normal ++ * driver (to be discussed) */ ++ u8 mp_mode; ++ u8 rsvd020; ++ u8 rsvd021; ++ u8 rsvd022; ++ u8 rsvd023; ++ u8 rsvd024; ++ u8 rsvd025; ++ ++ /* --- long word 3 ---- */ ++ /* QoS enable */ ++ u8 qos_en; ++ /* 40MHz BW enable */ ++ /* 4181 convert AMSDU to AMPDU, 0: disable */ ++ u8 bw_40mhz_en; ++ u8 amsdu2ampdu_en; ++ /* 11n AMPDU enable */ ++ u8 ampdu_en; ++ /* FW offloads, 0: driver handles */ ++ u8 rate_control_offload; ++ /* FW offloads, 0: driver handles */ ++ u8 aggregation_offload; ++ u8 rsvd030; ++ u8 rsvd031; ++ ++ /* --- long word 4 ---- */ ++ /* 1. FW offloads, 0: driver handles */ ++ u8 beacon_offload; ++ /* 2. FW offloads, 0: driver handles */ ++ u8 mlme_offload; ++ /* 3. FW offloads, 0: driver handles */ ++ u8 hwpc_offload; ++ /* 4. FW offloads, 0: driver handles */ ++ u8 tcp_checksum_offload; ++ /* 5. FW offloads, 0: driver handles */ ++ u8 tcp_offload; ++ /* 6. FW offloads, 0: driver handles */ ++ u8 ps_control_offload; ++ /* 7. FW offloads, 0: driver handles */ ++ u8 wwlan_offload; ++ u8 rsvd040; ++ ++ /* --- long word 5 ---- */ ++ /* tcp tx packet length low byte */ ++ u8 tcp_tx_frame_len_L; ++ /* tcp tx packet length high byte */ ++ u8 tcp_tx_frame_len_H; ++ /* tcp rx packet length low byte */ ++ u8 tcp_rx_frame_len_L; ++ /* tcp rx packet length high byte */ ++ u8 tcp_rx_frame_len_H; ++ u8 rsvd050; ++ u8 rsvd051; ++ u8 rsvd052; ++ u8 rsvd053; ++}; ++ ++/* 8-byte alinment required */ ++struct fw_hdr { ++ ++ /* --- LONG WORD 0 ---- */ ++ u16 signature; ++ /* 0x8000 ~ 0x8FFF for FPGA version, ++ * 0x0000 ~ 0x7FFF for ASIC version, */ ++ u16 version; ++ /* define the size of boot loader */ ++ u32 dmem_size; ++ ++ ++ /* --- LONG WORD 1 ---- */ ++ /* define the size of FW in IMEM */ ++ u32 img_imem_size; ++ /* define the size of FW in SRAM */ ++ u32 img_sram_size; ++ ++ /* --- LONG WORD 2 ---- */ ++ /* define the size of DMEM variable */ ++ u32 fw_priv_size; ++ u32 rsvd0; ++ ++ /* --- LONG WORD 3 ---- */ ++ u32 rsvd1; ++ u32 rsvd2; ++ ++ struct fw_priv fwpriv; ++ ++} ; ++ ++enum fw_status { ++ FW_STATUS_INIT = 0, ++ FW_STATUS_LOAD_IMEM = 1, ++ FW_STATUS_LOAD_EMEM = 2, ++ FW_STATUS_LOAD_DMEM = 3, ++ FW_STATUS_READY = 4, ++}; ++ ++struct rt_firmware { ++ struct fw_hdr *pfwheader; ++ enum fw_status fwstatus; ++ u16 firmwareversion; ++ u8 fw_imem[RTL8190_MAX_FIRMWARE_CODE_SIZE]; ++ u8 fw_emem[RTL8190_MAX_FIRMWARE_CODE_SIZE]; ++ u32 fw_imem_len; ++ u32 fw_emem_len; ++ u8 sz_fw_tmpbuffer[164000]; ++ u32 sz_fw_tmpbufferlen; ++ u16 cmdpacket_fragthresold; ++}; ++ ++struct h2c_set_pwrmode_parm { ++ u8 mode; ++ u8 flag_low_traffic_en; ++ u8 flag_lpnav_en; ++ u8 flag_rf_low_snr_en; ++ /* 1: dps, 0: 32k */ ++ u8 flag_dps_en; ++ u8 bcn_rx_en; ++ u8 bcn_pass_cnt; ++ /* beacon TO (ms). ¡§=0¡¨ no limit. */ ++ u8 bcn_to; ++ u16 bcn_itv; ++ /* only for VOIP mode. */ ++ u8 app_itv; ++ u8 awake_bcn_itvl; ++ u8 smart_ps; ++ /* unit: 100 ms */ ++ u8 bcn_pass_period; ++}; ++ ++struct h2c_joinbss_rpt_parm { ++ u8 opmode; ++ u8 ps_qos_info; ++ u8 bssid[6]; ++ u16 bcnitv; ++ u16 aid; ++} ; ++ ++struct h2c_wpa_ptk { ++ /* EAPOL-Key Key Confirmation Key (KCK) */ ++ u8 kck[16]; ++ /* EAPOL-Key Key Encryption Key (KEK) */ ++ u8 kek[16]; ++ /* Temporal Key 1 (TK1) */ ++ u8 tk1[16]; ++ union { ++ /* Temporal Key 2 (TK2) */ ++ u8 tk2[16]; ++ struct { ++ u8 tx_mic_key[8]; ++ u8 rx_mic_key[8]; ++ } athu; ++ } u; ++}; ++ ++struct h2c_wpa_two_way_parm { ++ /* algorithm TKIP or AES */ ++ u8 pairwise_en_alg; ++ u8 group_en_alg; ++ struct h2c_wpa_ptk wpa_ptk_value; ++} ; ++ ++enum h2c_cmd { ++ FW_H2C_SETPWRMODE = 0, ++ FW_H2C_JOINBSSRPT = 1, ++ FW_H2C_WOWLAN_UPDATE_GTK = 2, ++ FW_H2C_WOWLAN_UPDATE_IV = 3, ++ FW_H2C_WOWLAN_OFFLOAD = 4, ++}; ++ ++enum fw_h2c_cmd { ++ H2C_READ_MACREG_CMD, /*0*/ ++ H2C_WRITE_MACREG_CMD, ++ H2C_READBB_CMD, ++ H2C_WRITEBB_CMD, ++ H2C_READRF_CMD, ++ H2C_WRITERF_CMD, /*5*/ ++ H2C_READ_EEPROM_CMD, ++ H2C_WRITE_EEPROM_CMD, ++ H2C_READ_EFUSE_CMD, ++ H2C_WRITE_EFUSE_CMD, ++ H2C_READ_CAM_CMD, /*10*/ ++ H2C_WRITE_CAM_CMD, ++ H2C_SETBCNITV_CMD, ++ H2C_SETMBIDCFG_CMD, ++ H2C_JOINBSS_CMD, ++ H2C_DISCONNECT_CMD, /*15*/ ++ H2C_CREATEBSS_CMD, ++ H2C_SETOPMode_CMD, ++ H2C_SITESURVEY_CMD, ++ H2C_SETAUTH_CMD, ++ H2C_SETKEY_CMD, /*20*/ ++ H2C_SETSTAKEY_CMD, ++ H2C_SETASSOCSTA_CMD, ++ H2C_DELASSOCSTA_CMD, ++ H2C_SETSTAPWRSTATE_CMD, ++ H2C_SETBASICRATE_CMD, /*25*/ ++ H2C_GETBASICRATE_CMD, ++ H2C_SETDATARATE_CMD, ++ H2C_GETDATARATE_CMD, ++ H2C_SETPHYINFO_CMD, ++ H2C_GETPHYINFO_CMD, /*30*/ ++ H2C_SETPHY_CMD, ++ H2C_GETPHY_CMD, ++ H2C_READRSSI_CMD, ++ H2C_READGAIN_CMD, ++ H2C_SETATIM_CMD, /*35*/ ++ H2C_SETPWRMODE_CMD, ++ H2C_JOINBSSRPT_CMD, ++ H2C_SETRATABLE_CMD, ++ H2C_GETRATABLE_CMD, ++ H2C_GETCCXREPORT_CMD, /*40*/ ++ H2C_GETDTMREPORT_CMD, ++ H2C_GETTXRATESTATICS_CMD, ++ H2C_SETUSBSUSPEND_CMD, ++ H2C_SETH2CLBK_CMD, ++ H2C_TMP1, /*45*/ ++ H2C_WOWLAN_UPDATE_GTK_CMD, ++ H2C_WOWLAN_FW_OFFLOAD, ++ H2C_TMP2, ++ H2C_TMP3, ++ H2C_WOWLAN_UPDATE_IV_CMD, /*50*/ ++ H2C_TMP4, ++ MAX_H2CCMD /*52*/ ++}; ++ ++/* The following macros are used for FW ++ * CMD map and parameter updated. */ ++#define FW_CMD_IO_CLR(rtlpriv, _Bit) \ ++ do { \ ++ udelay(1000); \ ++ rtlpriv->rtlhal.fwcmd_iomap &= (~_Bit); \ ++ } while (0); ++ ++#define FW_CMD_IO_UPDATE(rtlpriv, _val) \ ++ rtlpriv->rtlhal.fwcmd_iomap = _val; ++ ++#define FW_CMD_IO_SET(rtlpriv, _val) \ ++ do { \ ++ rtl_write_word(rtlpriv, LBUS_MON_ADDR, (u16)_val); \ ++ FW_CMD_IO_UPDATE(rtlpriv, _val); \ ++ } while (0); ++ ++#define FW_CMD_PARA_SET(rtlpriv, _val) \ ++ do { \ ++ rtl_write_dword(rtlpriv, LBUS_ADDR_MASK, _val); \ ++ rtlpriv->rtlhal.fwcmd_ioparam = _val; \ ++ } while (0); ++ ++#define FW_CMD_IO_QUERY(rtlpriv) \ ++ (u16)(rtlpriv->rtlhal.fwcmd_iomap) ++#define FW_CMD_IO_PARA_QUERY(rtlpriv) \ ++ ((u32)(rtlpriv->rtlhal.fwcmd_ioparam)) ++ ++int rtl92s_download_fw(struct ieee80211_hw *hw); ++void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); ++void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, ++ u8 mstatus, u8 ps_qosinfo); ++ ++#endif ++ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/hw.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/hw.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/hw.c 2011-05-05 23:29:49.283487753 +0200 +@@ -0,0 +1,2512 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#include "../wifi.h" ++#include "../efuse.h" ++#include "../base.h" ++#include "../regd.h" ++#include "../cam.h" ++#include "../ps.h" ++#include "../pci.h" ++#include "reg.h" ++#include "def.h" ++#include "phy.h" ++#include "dm.h" ++#include "fw.h" ++#include "led.h" ++#include "hw.h" ++ ++void rtl92se_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ ++ switch (variable) { ++ case HW_VAR_RCR: { ++ *((u32 *) (val)) = rtlpci->receive_config; ++ break; ++ } ++ case HW_VAR_RF_STATE: { ++ *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state; ++ break; ++ } ++ case HW_VAR_FW_PSMODE_STATUS: { ++ *((bool *) (val)) = ppsc->fw_current_inpsmode; ++ break; ++ } ++ case HW_VAR_CORRECT_TSF: { ++ u64 tsf; ++ u32 *ptsf_low = (u32 *)&tsf; ++ u32 *ptsf_high = ((u32 *)&tsf) + 1; ++ ++ *ptsf_high = rtl_read_dword(rtlpriv, (TSFR + 4)); ++ *ptsf_low = rtl_read_dword(rtlpriv, TSFR); ++ ++ *((u64 *) (val)) = tsf; ++ ++ break; ++ } ++ case HW_VAR_MRC: { ++ *((bool *)(val)) = rtlpriv->dm.current_mrc_switch; ++ break; ++ } ++ default: { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("switch case not process\n")); ++ break; ++ } ++ } ++} ++ ++void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ ++ switch (variable) { ++ case HW_VAR_ETHER_ADDR:{ ++ rtl_write_dword(rtlpriv, IDR0, ((u32 *)(val))[0]); ++ rtl_write_word(rtlpriv, IDR4, ((u16 *)(val + 4))[0]); ++ break; ++ } ++ case HW_VAR_BASIC_RATE:{ ++ u16 rate_cfg = ((u16 *) val)[0]; ++ u8 rate_index = 0; ++ ++ if (rtlhal->version == VERSION_8192S_ACUT) ++ rate_cfg = rate_cfg & 0x150; ++ else ++ rate_cfg = rate_cfg & 0x15f; ++ ++ rate_cfg |= 0x01; ++ ++ rtl_write_byte(rtlpriv, RRSR, rate_cfg & 0xff); ++ rtl_write_byte(rtlpriv, RRSR + 1, ++ (rate_cfg >> 8) & 0xff); ++ ++ while (rate_cfg > 0x1) { ++ rate_cfg = (rate_cfg >> 1); ++ rate_index++; ++ } ++ rtl_write_byte(rtlpriv, INIRTSMCS_SEL, rate_index); ++ ++ break; ++ } ++ case HW_VAR_BSSID:{ ++ rtl_write_dword(rtlpriv, BSSIDR, ((u32 *)(val))[0]); ++ rtl_write_word(rtlpriv, BSSIDR + 4, ++ ((u16 *)(val + 4))[0]); ++ break; ++ } ++ case HW_VAR_SIFS:{ ++ rtl_write_byte(rtlpriv, SIFS_OFDM, val[0]); ++ rtl_write_byte(rtlpriv, SIFS_OFDM + 1, val[1]); ++ break; ++ } ++ case HW_VAR_SLOT_TIME:{ ++ u8 e_aci; ++ ++ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, ++ ("HW_VAR_SLOT_TIME %x\n", val[0])); ++ ++ rtl_write_byte(rtlpriv, SLOT_TIME, val[0]); ++ ++ for (e_aci = 0; e_aci < AC_MAX; e_aci++) { ++ rtlpriv->cfg->ops->set_hw_reg(hw, ++ HW_VAR_AC_PARAM, ++ (u8 *)(&e_aci)); ++ } ++ break; ++ } ++ case HW_VAR_ACK_PREAMBLE:{ ++ u8 reg_tmp; ++ u8 short_preamble = (bool) (*(u8 *) val); ++ reg_tmp = (mac->cur_40_prime_sc) << 5; ++ if (short_preamble) ++ reg_tmp |= 0x80; ++ ++ rtl_write_byte(rtlpriv, RRSR + 2, reg_tmp); ++ break; ++ } ++ case HW_VAR_AMPDU_MIN_SPACE:{ ++ u8 min_spacing_to_set; ++ u8 sec_min_space; ++ ++ min_spacing_to_set = *((u8 *)val); ++ if (min_spacing_to_set <= 7) { ++ if (rtlpriv->sec.pairwise_enc_algorithm == ++ NO_ENCRYPTION) ++ sec_min_space = 0; ++ else ++ sec_min_space = 1; ++ ++ if (min_spacing_to_set < sec_min_space) ++ min_spacing_to_set = sec_min_space; ++ if (min_spacing_to_set > 5) ++ min_spacing_to_set = 5; ++ ++ mac->min_space_cfg = ++ ((mac->min_space_cfg & 0xf8) | ++ min_spacing_to_set); ++ ++ *val = min_spacing_to_set; ++ ++ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, ++ ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", ++ mac->min_space_cfg)); ++ ++ rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, ++ mac->min_space_cfg); ++ } ++ break; ++ } ++ case HW_VAR_SHORTGI_DENSITY:{ ++ u8 density_to_set; ++ ++ density_to_set = *((u8 *) val); ++ mac->min_space_cfg = rtlpriv->rtlhal.minspace_cfg; ++ mac->min_space_cfg |= (density_to_set << 3); ++ ++ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, ++ ("Set HW_VAR_SHORTGI_DENSITY: %#x\n", ++ mac->min_space_cfg)); ++ ++ rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, ++ mac->min_space_cfg); ++ ++ break; ++ } ++ case HW_VAR_AMPDU_FACTOR:{ ++ u8 factor_toset; ++ u8 regtoset; ++ u8 factorlevel[18] = { ++ 2, 4, 4, 7, 7, 13, 13, ++ 13, 2, 7, 7, 13, 13, ++ 15, 15, 15, 15, 0}; ++ u8 index = 0; ++ ++ factor_toset = *((u8 *) val); ++ if (factor_toset <= 3) { ++ factor_toset = (1 << (factor_toset + 2)); ++ if (factor_toset > 0xf) ++ factor_toset = 0xf; ++ ++ for (index = 0; index < 17; index++) { ++ if (factorlevel[index] > factor_toset) ++ factorlevel[index] = ++ factor_toset; ++ } ++ ++ for (index = 0; index < 8; index++) { ++ regtoset = ((factorlevel[index * 2]) | ++ (factorlevel[index * ++ 2 + 1] << 4)); ++ rtl_write_byte(rtlpriv, ++ AGGLEN_LMT_L + index, ++ regtoset); ++ } ++ ++ regtoset = ((factorlevel[16]) | ++ (factorlevel[17] << 4)); ++ rtl_write_byte(rtlpriv, AGGLEN_LMT_H, regtoset); ++ ++ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, ++ ("Set HW_VAR_AMPDU_FACTOR: %#x\n", ++ factor_toset)); ++ } ++ break; ++ } ++ case HW_VAR_AC_PARAM:{ ++ u8 e_aci = *((u8 *) val); ++ rtl92s_dm_init_edca_turbo(hw); ++ ++ if (rtlpci->acm_method != eAcmWay2_SW) ++ rtlpriv->cfg->ops->set_hw_reg(hw, ++ HW_VAR_ACM_CTRL, ++ (u8 *)(&e_aci)); ++ break; ++ } ++ case HW_VAR_ACM_CTRL:{ ++ u8 e_aci = *((u8 *) val); ++ union aci_aifsn *p_aci_aifsn = (union aci_aifsn *)(&( ++ mac->ac[0].aifs)); ++ u8 acm = p_aci_aifsn->f.acm; ++ u8 acm_ctrl = rtl_read_byte(rtlpriv, AcmHwCtrl); ++ ++ acm_ctrl = acm_ctrl | ((rtlpci->acm_method == 2) ? ++ 0x0 : 0x1); ++ ++ if (acm) { ++ switch (e_aci) { ++ case AC0_BE: ++ acm_ctrl |= AcmHw_BeqEn; ++ break; ++ case AC2_VI: ++ acm_ctrl |= AcmHw_ViqEn; ++ break; ++ case AC3_VO: ++ acm_ctrl |= AcmHw_VoqEn; ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ++ ("HW_VAR_ACM_CTRL acm set " ++ "failed: eACI is %d\n", acm)); ++ break; ++ } ++ } else { ++ switch (e_aci) { ++ case AC0_BE: ++ acm_ctrl &= (~AcmHw_BeqEn); ++ break; ++ case AC2_VI: ++ acm_ctrl &= (~AcmHw_ViqEn); ++ break; ++ case AC3_VO: ++ acm_ctrl &= (~AcmHw_BeqEn); ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("switch case not process\n")); ++ break; ++ } ++ } ++ ++ RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE, ++ ("HW_VAR_ACM_CTRL Write 0x%X\n", acm_ctrl)); ++ rtl_write_byte(rtlpriv, AcmHwCtrl, acm_ctrl); ++ break; ++ } ++ case HW_VAR_RCR:{ ++ rtl_write_dword(rtlpriv, RCR, ((u32 *) (val))[0]); ++ rtlpci->receive_config = ((u32 *) (val))[0]; ++ break; ++ } ++ case HW_VAR_RETRY_LIMIT:{ ++ u8 retry_limit = ((u8 *) (val))[0]; ++ ++ rtl_write_word(rtlpriv, RETRY_LIMIT, ++ retry_limit << RETRY_LIMIT_SHORT_SHIFT | ++ retry_limit << RETRY_LIMIT_LONG_SHIFT); ++ break; ++ } ++ case HW_VAR_DUAL_TSF_RST: { ++ break; ++ } ++ case HW_VAR_EFUSE_BYTES: { ++ rtlefuse->efuse_usedbytes = *((u16 *) val); ++ break; ++ } ++ case HW_VAR_EFUSE_USAGE: { ++ rtlefuse->efuse_usedpercentage = *((u8 *) val); ++ break; ++ } ++ case HW_VAR_IO_CMD: { ++ break; ++ } ++ case HW_VAR_WPA_CONFIG: { ++ rtl_write_byte(rtlpriv, REG_SECR, *((u8 *) val)); ++ break; ++ } ++ case HW_VAR_SET_RPWM:{ ++ break; ++ } ++ case HW_VAR_H2C_FW_PWRMODE:{ ++ break; ++ } ++ case HW_VAR_FW_PSMODE_STATUS: { ++ ppsc->fw_current_inpsmode = *((bool *) val); ++ break; ++ } ++ case HW_VAR_H2C_FW_JOINBSSRPT:{ ++ break; ++ } ++ case HW_VAR_AID:{ ++ break; ++ } ++ case HW_VAR_CORRECT_TSF:{ ++ break; ++ } ++ case HW_VAR_MRC: { ++ bool bmrc_toset = *((bool *)val); ++ u8 u1bdata = 0; ++ ++ if (bmrc_toset) { ++ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, ++ MASKBYTE0, 0x33); ++ u1bdata = (u8)rtl_get_bbreg(hw, ++ ROFDM1_TRXPATHENABLE, ++ MASKBYTE0); ++ rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, ++ MASKBYTE0, ++ ((u1bdata & 0xf0) | 0x03)); ++ u1bdata = (u8)rtl_get_bbreg(hw, ++ ROFDM0_TRXPATHENABLE, ++ MASKBYTE1); ++ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, ++ MASKBYTE1, ++ (u1bdata | 0x04)); ++ ++ /* Update current settings. */ ++ rtlpriv->dm.current_mrc_switch = bmrc_toset; ++ } else { ++ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, ++ MASKBYTE0, 0x13); ++ u1bdata = (u8)rtl_get_bbreg(hw, ++ ROFDM1_TRXPATHENABLE, ++ MASKBYTE0); ++ rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, ++ MASKBYTE0, ++ ((u1bdata & 0xf0) | 0x01)); ++ u1bdata = (u8)rtl_get_bbreg(hw, ++ ROFDM0_TRXPATHENABLE, ++ MASKBYTE1); ++ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, ++ MASKBYTE1, (u1bdata & 0xfb)); ++ ++ /* Update current settings. */ ++ rtlpriv->dm.current_mrc_switch = bmrc_toset; ++ } ++ ++ break; ++ } ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("switch case not process\n")); ++ break; ++ } ++ ++} ++ ++void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u8 sec_reg_value = 0x0; ++ ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("PairwiseEncAlgorithm = %d " ++ "GroupEncAlgorithm = %d\n", ++ rtlpriv->sec.pairwise_enc_algorithm, ++ rtlpriv->sec.group_enc_algorithm)); ++ ++ if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ++ ("not open hw encryption\n")); ++ return; ++ } ++ ++ sec_reg_value = SCR_TXENCENABLE | SCR_RXENCENABLE; ++ ++ if (rtlpriv->sec.use_defaultkey) { ++ sec_reg_value |= SCR_TXUSEDK; ++ sec_reg_value |= SCR_RXUSEDK; ++ } ++ ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("The SECR-value %x\n", ++ sec_reg_value)); ++ ++ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); ++ ++} ++ ++static u8 _rtl92ce_halset_sysclk(struct ieee80211_hw *hw, u8 data) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u8 waitcount = 100; ++ bool bresult = false; ++ u8 tmpvalue; ++ ++ rtl_write_byte(rtlpriv, SYS_CLKR + 1, data); ++ ++ /* Wait the MAC synchronized. */ ++ udelay(400); ++ ++ /* Check if it is set ready. */ ++ tmpvalue = rtl_read_byte(rtlpriv, SYS_CLKR + 1); ++ bresult = ((tmpvalue & BIT(7)) == (data & BIT(7))); ++ ++ if ((data & (BIT(6) | BIT(7))) == false) { ++ waitcount = 100; ++ tmpvalue = 0; ++ ++ while (1) { ++ waitcount--; ++ ++ tmpvalue = rtl_read_byte(rtlpriv, SYS_CLKR + 1); ++ if ((tmpvalue & BIT(6))) ++ break; ++ ++ printk(KERN_ERR "wait for BIT(6) return value %x\n", ++ tmpvalue); ++ if (waitcount == 0) ++ break; ++ ++ udelay(10); ++ } ++ ++ if (waitcount == 0) ++ bresult = false; ++ else ++ bresult = true; ++ } ++ ++ return bresult; ++} ++ ++void rtl8192se_gpiobit3_cfg_inputmode(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u8 u1tmp; ++ ++ /* The following config GPIO function */ ++ rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO)); ++ u1tmp = rtl_read_byte(rtlpriv, GPIO_IO_SEL); ++ ++ /* config GPIO3 to input */ ++ u1tmp &= HAL_8192S_HW_GPIO_OFF_MASK; ++ rtl_write_byte(rtlpriv, GPIO_IO_SEL, u1tmp); ++ ++} ++ ++static u8 _rtl92se_rf_onoff_detect(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u8 u1tmp; ++ u8 retval = ERFON; ++ ++ /* The following config GPIO function */ ++ rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO)); ++ u1tmp = rtl_read_byte(rtlpriv, GPIO_IO_SEL); ++ ++ /* config GPIO3 to input */ ++ u1tmp &= HAL_8192S_HW_GPIO_OFF_MASK; ++ rtl_write_byte(rtlpriv, GPIO_IO_SEL, u1tmp); ++ ++ /* On some of the platform, driver cannot read correct ++ * value without delay between Write_GPIO_SEL and Read_GPIO_IN */ ++ mdelay(10); ++ ++ /* check GPIO3 */ ++ u1tmp = rtl_read_byte(rtlpriv, GPIO_IN); ++ retval = (u1tmp & HAL_8192S_HW_GPIO_OFF_BIT) ? ERFON : ERFOFF; ++ ++ return retval; ++} ++ ++static void _rtl92se_macconfig_before_fwdownload(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ ++ u8 i; ++ u8 tmpu1b; ++ u16 tmpu2b; ++ u8 pollingcnt = 20; ++ ++ if (rtlpci->first_init) { ++ /* Reset PCIE Digital */ ++ tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); ++ tmpu1b &= 0xFE; ++ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b); ++ udelay(1); ++ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b | BIT(0)); ++ } ++ ++ /* Switch to SW IO control */ ++ tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); ++ if (tmpu1b & BIT(7)) { ++ tmpu1b &= ~(BIT(6) | BIT(7)); ++ ++ /* Set failed, return to prevent hang. */ ++ if (!_rtl92ce_halset_sysclk(hw, tmpu1b)) ++ return; ++ } ++ ++ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x0); ++ udelay(50); ++ rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); ++ udelay(50); ++ ++ /* Clear FW RPWM for FW control LPS.*/ ++ rtl_write_byte(rtlpriv, RPWM, 0x0); ++ ++ /* Reset MAC-IO and CPU and Core Digital BIT(10)/11/15 */ ++ tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); ++ tmpu1b &= 0x73; ++ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b); ++ /* wait for BIT 10/11/15 to pull high automatically!! */ ++ mdelay(1); ++ ++ rtl_write_byte(rtlpriv, CMDR, 0); ++ rtl_write_byte(rtlpriv, TCR, 0); ++ ++ /* Data sheet not define 0x562!!! Copy from WMAC!!!!! */ ++ tmpu1b = rtl_read_byte(rtlpriv, 0x562); ++ tmpu1b |= 0x08; ++ rtl_write_byte(rtlpriv, 0x562, tmpu1b); ++ tmpu1b &= ~(BIT(3)); ++ rtl_write_byte(rtlpriv, 0x562, tmpu1b); ++ ++ /* Enable AFE clock source */ ++ tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL); ++ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, (tmpu1b | 0x01)); ++ /* Delay 1.5ms */ ++ mdelay(2); ++ tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL + 1); ++ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, (tmpu1b & 0xfb)); ++ ++ /* Enable AFE Macro Block's Bandgap */ ++ tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); ++ rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | BIT(0))); ++ mdelay(1); ++ ++ /* Enable AFE Mbias */ ++ tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); ++ rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | 0x02)); ++ mdelay(1); ++ ++ /* Enable LDOA15 block */ ++ tmpu1b = rtl_read_byte(rtlpriv, LDOA15_CTRL); ++ rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0))); ++ ++ /* Set Digital Vdd to Retention isolation Path. */ ++ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_ISO_CTRL); ++ rtl_write_word(rtlpriv, REG_SYS_ISO_CTRL, (tmpu2b | BIT(11))); ++ ++ /* For warm reboot NIC disappera bug. */ ++ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); ++ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(13))); ++ ++ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x68); ++ ++ /* Enable AFE PLL Macro Block */ ++ /* We need to delay 100u before enabling PLL. */ ++ udelay(200); ++ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL); ++ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4))); ++ ++ /* for divider reset */ ++ udelay(100); ++ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | ++ BIT(4) | BIT(6))); ++ udelay(10); ++ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4))); ++ udelay(10); ++ ++ /* Enable MAC 80MHZ clock */ ++ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL + 1); ++ rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, (tmpu1b | BIT(0))); ++ mdelay(1); ++ ++ /* Release isolation AFE PLL & MD */ ++ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, 0xA6); ++ ++ /* Enable MAC clock */ ++ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); ++ rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11))); ++ ++ /* Enable Core digital and enable IOREG R/W */ ++ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); ++ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11))); ++ ++ tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); ++ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b & ~(BIT(7))); ++ ++ /* enable REG_EN */ ++ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15))); ++ ++ /* Switch the control path. */ ++ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); ++ rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b & (~BIT(2)))); ++ ++ tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); ++ tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6))); ++ if (!_rtl92ce_halset_sysclk(hw, tmpu1b)) ++ return; /* Set failed, return to prevent hang. */ ++ ++ rtl_write_word(rtlpriv, CMDR, 0x07FC); ++ ++ /* MH We must enable the section of code to prevent load IMEM fail. */ ++ /* Load MAC register from WMAc temporarily We simulate macreg. */ ++ /* txt HW will provide MAC txt later */ ++ rtl_write_byte(rtlpriv, 0x6, 0x30); ++ rtl_write_byte(rtlpriv, 0x49, 0xf0); ++ ++ rtl_write_byte(rtlpriv, 0x4b, 0x81); ++ ++ rtl_write_byte(rtlpriv, 0xb5, 0x21); ++ ++ rtl_write_byte(rtlpriv, 0xdc, 0xff); ++ rtl_write_byte(rtlpriv, 0xdd, 0xff); ++ rtl_write_byte(rtlpriv, 0xde, 0xff); ++ rtl_write_byte(rtlpriv, 0xdf, 0xff); ++ ++ rtl_write_byte(rtlpriv, 0x11a, 0x00); ++ rtl_write_byte(rtlpriv, 0x11b, 0x00); ++ ++ for (i = 0; i < 32; i++) ++ rtl_write_byte(rtlpriv, INIMCS_SEL + i, 0x1b); ++ ++ rtl_write_byte(rtlpriv, 0x236, 0xff); ++ ++ rtl_write_byte(rtlpriv, 0x503, 0x22); ++ ++ if (ppsc->support_aspm && !ppsc->support_backdoor) ++ rtl_write_byte(rtlpriv, 0x560, 0x40); ++ else ++ rtl_write_byte(rtlpriv, 0x560, 0x00); ++ ++ rtl_write_byte(rtlpriv, DBG_PORT, 0x91); ++ ++ /* Set RX Desc Address */ ++ rtl_write_dword(rtlpriv, RDQDA, rtlpci->rx_ring[RX_MPDU_QUEUE].dma); ++ rtl_write_dword(rtlpriv, RCDA, rtlpci->rx_ring[RX_CMD_QUEUE].dma); ++ ++ /* Set TX Desc Address */ ++ rtl_write_dword(rtlpriv, TBKDA, rtlpci->tx_ring[BK_QUEUE].dma); ++ rtl_write_dword(rtlpriv, TBEDA, rtlpci->tx_ring[BE_QUEUE].dma); ++ rtl_write_dword(rtlpriv, TVIDA, rtlpci->tx_ring[VI_QUEUE].dma); ++ rtl_write_dword(rtlpriv, TVODA, rtlpci->tx_ring[VO_QUEUE].dma); ++ rtl_write_dword(rtlpriv, TBDA, rtlpci->tx_ring[BEACON_QUEUE].dma); ++ rtl_write_dword(rtlpriv, TCDA, rtlpci->tx_ring[TXCMD_QUEUE].dma); ++ rtl_write_dword(rtlpriv, TMDA, rtlpci->tx_ring[MGNT_QUEUE].dma); ++ rtl_write_dword(rtlpriv, THPDA, rtlpci->tx_ring[HIGH_QUEUE].dma); ++ rtl_write_dword(rtlpriv, HDA, rtlpci->tx_ring[HCCA_QUEUE].dma); ++ ++ rtl_write_word(rtlpriv, CMDR, 0x37FC); ++ ++ /* To make sure that TxDMA can ready to download FW. */ ++ /* We should reset TxDMA if IMEM RPT was not ready. */ ++ do { ++ tmpu1b = rtl_read_byte(rtlpriv, TCR); ++ if ((tmpu1b & TXDMA_INIT_VALUE) == TXDMA_INIT_VALUE) ++ break; ++ ++ udelay(5); ++ } while (pollingcnt--); ++ ++ if (pollingcnt <= 0) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Polling TXDMA_INIT_VALUE " ++ "timeout!! Current TCR(%#x)\n", tmpu1b)); ++ tmpu1b = rtl_read_byte(rtlpriv, CMDR); ++ rtl_write_byte(rtlpriv, CMDR, tmpu1b & (~TXDMA_EN)); ++ udelay(2); ++ /* Reset TxDMA */ ++ rtl_write_byte(rtlpriv, CMDR, tmpu1b | TXDMA_EN); ++ } ++ ++ /* After MACIO reset,we must refresh LED state. */ ++ if ((ppsc->rfoff_reason == RF_CHANGE_BY_IPS) || ++ (ppsc->rfoff_reason == 0)) { ++ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); ++ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); ++ enum rf_pwrstate rfpwr_state_toset; ++ rfpwr_state_toset = _rtl92se_rf_onoff_detect(hw); ++ ++ if (rfpwr_state_toset == ERFON) ++ rtl92se_sw_led_on(hw, pLed0); ++ } ++} ++ ++static void _rtl92se_macconfig_after_fwdownload(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ u8 i; ++ u16 tmpu2b; ++ ++ /* 1. System Configure Register (Offset: 0x0000 - 0x003F) */ ++ ++ /* 2. Command Control Register (Offset: 0x0040 - 0x004F) */ ++ /* Turn on 0x40 Command register */ ++ rtl_write_word(rtlpriv, CMDR, (BBRSTN | BB_GLB_RSTN | ++ SCHEDULE_EN | MACRXEN | MACTXEN | DDMA_EN | FW2HW_EN | ++ RXDMA_EN | TXDMA_EN | HCI_RXDMA_EN | HCI_TXDMA_EN)); ++ ++ /* Set TCR TX DMA pre 2 FULL enable bit */ ++ rtl_write_dword(rtlpriv, TCR, rtl_read_dword(rtlpriv, TCR) | ++ TXDMAPRE2FULL); ++ ++ /* Set RCR */ ++ rtl_write_dword(rtlpriv, RCR, rtlpci->receive_config); ++ ++ /* 3. MACID Setting Register (Offset: 0x0050 - 0x007F) */ ++ ++ /* 4. Timing Control Register (Offset: 0x0080 - 0x009F) */ ++ /* Set CCK/OFDM SIFS */ ++ /* CCK SIFS shall always be 10us. */ ++ rtl_write_word(rtlpriv, SIFS_CCK, 0x0a0a); ++ rtl_write_word(rtlpriv, SIFS_OFDM, 0x1010); ++ ++ /* Set AckTimeout */ ++ rtl_write_byte(rtlpriv, ACK_TIMEOUT, 0x40); ++ ++ /* Beacon related */ ++ rtl_write_word(rtlpriv, BCN_INTERVAL, 100); ++ rtl_write_word(rtlpriv, ATIMWND, 2); ++ ++ /* 5. FIFO Control Register (Offset: 0x00A0 - 0x015F) */ ++ /* 5.1 Initialize Number of Reserved Pages in Firmware Queue */ ++ /* Firmware allocate now, associate with FW internal setting.!!! */ ++ ++ /* 5.2 Setting TX/RX page size 0/1/2/3/4=64/128/256/512/1024 */ ++ /* 5.3 Set driver info, we only accept PHY status now. */ ++ /* 5.4 Set RXDMA arbitration to control RXDMA/MAC/FW R/W for RXFIFO */ ++ rtl_write_byte(rtlpriv, RXDMA, rtl_read_byte(rtlpriv, RXDMA) | BIT(6)); ++ ++ /* 6. Adaptive Control Register (Offset: 0x0160 - 0x01CF) */ ++ /* Set RRSR to all legacy rate and HT rate ++ * CCK rate is supported by default. ++ * CCK rate will be filtered out only when associated ++ * AP does not support it. ++ * Only enable ACK rate to OFDM 24M ++ * Disable RRSR for CCK rate in A-Cut */ ++ ++ if (rtlhal->version == VERSION_8192S_ACUT) ++ rtl_write_byte(rtlpriv, RRSR, 0xf0); ++ else if (rtlhal->version == VERSION_8192S_BCUT) ++ rtl_write_byte(rtlpriv, RRSR, 0xff); ++ rtl_write_byte(rtlpriv, RRSR + 1, 0x01); ++ rtl_write_byte(rtlpriv, RRSR + 2, 0x00); ++ ++ /* A-Cut IC do not support CCK rate. We forbid ARFR to */ ++ /* fallback to CCK rate */ ++ for (i = 0; i < 8; i++) { ++ /*Disable RRSR for CCK rate in A-Cut */ ++ if (rtlhal->version == VERSION_8192S_ACUT) ++ rtl_write_dword(rtlpriv, ARFR0 + i * 4, 0x1f0ff0f0); ++ } ++ ++ /* Different rate use different AMPDU size */ ++ /* MCS32/ MCS15_SG use max AMPDU size 15*2=30K */ ++ rtl_write_byte(rtlpriv, AGGLEN_LMT_H, 0x0f); ++ /* MCS0/1/2/3 use max AMPDU size 4*2=8K */ ++ rtl_write_word(rtlpriv, AGGLEN_LMT_L, 0x7442); ++ /* MCS4/5 use max AMPDU size 8*2=16K 6/7 use 10*2=20K */ ++ rtl_write_word(rtlpriv, AGGLEN_LMT_L + 2, 0xddd7); ++ /* MCS8/9 use max AMPDU size 8*2=16K 10/11 use 10*2=20K */ ++ rtl_write_word(rtlpriv, AGGLEN_LMT_L + 4, 0xd772); ++ /* MCS12/13/14/15 use max AMPDU size 15*2=30K */ ++ rtl_write_word(rtlpriv, AGGLEN_LMT_L + 6, 0xfffd); ++ ++ /* Set Data / Response auto rate fallack retry count */ ++ rtl_write_dword(rtlpriv, DARFRC, 0x04010000); ++ rtl_write_dword(rtlpriv, DARFRC + 4, 0x09070605); ++ rtl_write_dword(rtlpriv, RARFRC, 0x04010000); ++ rtl_write_dword(rtlpriv, RARFRC + 4, 0x09070605); ++ ++ /* 7. EDCA Setting Register (Offset: 0x01D0 - 0x01FF) */ ++ /* Set all rate to support SG */ ++ rtl_write_word(rtlpriv, SG_RATE, 0xFFFF); ++ ++ /* 8. WMAC, BA, and CCX related Register (Offset: 0x0200 - 0x023F) */ ++ /* Set NAV protection length */ ++ rtl_write_word(rtlpriv, NAV_PROT_LEN, 0x0080); ++ /* CF-END Threshold */ ++ rtl_write_byte(rtlpriv, CFEND_TH, 0xFF); ++ /* Set AMPDU minimum space */ ++ rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, 0x07); ++ /* Set TXOP stall control for several queue/HI/BCN/MGT/ */ ++ rtl_write_byte(rtlpriv, TXOP_STALL_CTRL, 0x00); ++ ++ /* 9. Security Control Register (Offset: 0x0240 - 0x025F) */ ++ /* 10. Power Save Control Register (Offset: 0x0260 - 0x02DF) */ ++ /* 11. General Purpose Register (Offset: 0x02E0 - 0x02FF) */ ++ /* 12. Host Interrupt Status Register (Offset: 0x0300 - 0x030F) */ ++ /* 13. Test Mode and Debug Control Register (Offset: 0x0310 - 0x034F) */ ++ ++ /* 14. Set driver info, we only accept PHY status now. */ ++ rtl_write_byte(rtlpriv, RXDRVINFO_SZ, 4); ++ ++ /* 15. For EEPROM R/W Workaround */ ++ /* 16. For EFUSE to share REG_SYS_FUNC_EN with EEPROM!!! */ ++ tmpu2b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN); ++ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, tmpu2b | BIT(13)); ++ tmpu2b = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL); ++ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, tmpu2b & (~BIT(8))); ++ ++ /* 17. For EFUSE */ ++ /* We may R/W EFUSE in EEPROM mode */ ++ if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { ++ u8 tempval; ++ ++ tempval = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL + 1); ++ tempval &= 0xFE; ++ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, tempval); ++ ++ /* Change Program timing */ ++ rtl_write_byte(rtlpriv, REG_EFUSE_CTRL + 3, 0x72); ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("EFUSE CONFIG OK\n")); ++ } ++ ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("OK\n")); ++ ++} ++ ++static void _rtl92se_hw_configure(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ ++ u8 reg_bw_opmode = 0; ++ u32 reg_ratr = 0, reg_rrsr = 0; ++ u8 regtmp = 0; ++ ++ reg_bw_opmode = BW_OPMODE_20MHZ; ++ reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | ++ RATE_ALL_OFDM_2SS; ++ reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ ++ regtmp = rtl_read_byte(rtlpriv, INIRTSMCS_SEL); ++ reg_rrsr = ((reg_rrsr & 0x000fffff) << 8) | regtmp; ++ rtl_write_dword(rtlpriv, INIRTSMCS_SEL, reg_rrsr); ++ rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode); ++ ++ /* Set Retry Limit here */ ++ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, ++ (u8 *)(&rtlpci->shortretry_limit)); ++ ++ rtl_write_byte(rtlpriv, MLT, 0x8f); ++ ++ /* For Min Spacing configuration. */ ++ switch (rtlphy->rf_type) { ++ case RF_1T2R: ++ case RF_1T1R: ++ rtlhal->minspace_cfg = (MAX_MSS_DENSITY_1T << 3); ++ break; ++ case RF_2T2R: ++ case RF_2T2R_GREEN: ++ rtlhal->minspace_cfg = (MAX_MSS_DENSITY_2T << 3); ++ break; ++ } ++ rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, rtlhal->minspace_cfg); ++} ++ ++int rtl92se_hw_init(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ u8 tmp_byte = 0; ++ ++ bool rtstatus = true; ++ u8 tmp_u1b; ++ int err = false; ++ u8 i; ++ int wdcapra_add[] = { ++ EDCAPARA_BE, EDCAPARA_BK, ++ EDCAPARA_VI, EDCAPARA_VO}; ++ u8 secr_value = 0x0; ++ ++ rtlpci->being_init_adapter = true; ++ ++ rtlpriv->intf_ops->disable_aspm(hw); ++ ++ /* 1. MAC Initialize */ ++ /* Before FW download, we have to set some MAC register */ ++ _rtl92se_macconfig_before_fwdownload(hw); ++ ++ rtlhal->version = (enum version_8192s)((rtl_read_dword(rtlpriv, ++ PMC_FSM) >> 16) & 0xF); ++ ++ rtl8192se_gpiobit3_cfg_inputmode(hw); ++ ++ /* 2. download firmware */ ++ rtstatus = rtl92s_download_fw(hw); ++ if (!rtstatus) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ++ ("Failed to download FW. " ++ "Init HW without FW now.., Please copy FW into" ++ "/lib/firmware/rtlwifi\n")); ++ rtlhal->fw_ready = false; ++ } else { ++ rtlhal->fw_ready = true; ++ } ++ ++ /* After FW download, we have to reset MAC register */ ++ _rtl92se_macconfig_after_fwdownload(hw); ++ ++ /*Retrieve default FW Cmd IO map. */ ++ rtlhal->fwcmd_iomap = rtl_read_word(rtlpriv, LBUS_MON_ADDR); ++ rtlhal->fwcmd_ioparam = rtl_read_dword(rtlpriv, LBUS_ADDR_MASK); ++ ++ /* 3. Initialize MAC/PHY Config by MACPHY_reg.txt */ ++ if (rtl92s_phy_mac_config(hw) != true) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("MAC Config failed\n")); ++ return rtstatus; ++ } ++ ++ /* Make sure BB/RF write OK. We should prevent enter IPS. radio off. */ ++ /* We must set flag avoid BB/RF config period later!! */ ++ rtl_write_dword(rtlpriv, CMDR, 0x37FC); ++ ++ /* 4. Initialize BB After MAC Config PHY_reg.txt, AGC_Tab.txt */ ++ if (rtl92s_phy_bb_config(hw) != true) { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ("BB Config failed\n")); ++ return rtstatus; ++ } ++ ++ /* 5. Initiailze RF RAIO_A.txt RF RAIO_B.txt */ ++ /* Before initalizing RF. We can not use FW to do RF-R/W. */ ++ ++ rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; ++ ++ /* RF Power Save */ ++#if 0 ++ /* H/W or S/W RF OFF before sleep. */ ++ if (rtlpriv->psc.rfoff_reason > RF_CHANGE_BY_PS) { ++ u32 rfoffreason = rtlpriv->psc.rfoff_reason; ++ ++ rtlpriv->psc.rfoff_reason = RF_CHANGE_BY_INIT; ++ rtlpriv->psc.rfpwr_state = ERFON; ++ rtl_ps_set_rf_state(hw, ERFOFF, rfoffreason, true); ++ } else { ++ /* gpio radio on/off is out of adapter start */ ++ if (rtlpriv->psc.hwradiooff == false) { ++ rtlpriv->psc.rfpwr_state = ERFON; ++ rtlpriv->psc.rfoff_reason = 0; ++ } ++ } ++#endif ++ ++ /* Before RF-R/W we must execute the IO from Scott's suggestion. */ ++ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, 0xDB); ++ if (rtlhal->version == VERSION_8192S_ACUT) ++ rtl_write_byte(rtlpriv, SPS1_CTRL + 3, 0x07); ++ else ++ rtl_write_byte(rtlpriv, RF_CTRL, 0x07); ++ ++ if (rtl92s_phy_rf_config(hw) != true) { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("RF Config failed\n")); ++ return rtstatus; ++ } ++ ++ /* After read predefined TXT, we must set BB/MAC/RF ++ * register as our requirement */ ++ ++ rtlphy->rfreg_chnlval[0] = rtl92s_phy_query_rf_reg(hw, ++ (enum radio_path)0, ++ RF_CHNLBW, ++ RFREG_OFFSET_MASK); ++ rtlphy->rfreg_chnlval[1] = rtl92s_phy_query_rf_reg(hw, ++ (enum radio_path)1, ++ RF_CHNLBW, ++ RFREG_OFFSET_MASK); ++ ++ /*---- Set CCK and OFDM Block "ON"----*/ ++ rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); ++ rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); ++ ++ /*3 Set Hardware(Do nothing now) */ ++ _rtl92se_hw_configure(hw); ++ ++ /* Read EEPROM TX power index and PHY_REG_PG.txt to capture correct */ ++ /* TX power index for different rate set. */ ++ /* Get original hw reg values */ ++ rtl92s_phy_get_hw_reg_originalvalue(hw); ++ /* Write correct tx power index */ ++ rtl92s_phy_set_txpower(hw, rtlphy->current_channel); ++ ++ /* We must set MAC address after firmware download. */ ++ for (i = 0; i < 6; i++) ++ rtl_write_byte(rtlpriv, MACIDR0 + i, rtlefuse->dev_addr[i]); ++ ++ /* EEPROM R/W workaround */ ++ tmp_u1b = rtl_read_byte(rtlpriv, MAC_PINMUX_CFG); ++ rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, tmp_u1b & (~BIT(3))); ++ ++ rtl_write_byte(rtlpriv, 0x4d, 0x0); ++ ++ if (hal_get_firmwareversion(rtlpriv) >= 0x49) { ++ tmp_byte = rtl_read_byte(rtlpriv, FW_RSVD_PG_CRTL) & (~BIT(4)); ++ tmp_byte = tmp_byte | BIT(5); ++ rtl_write_byte(rtlpriv, FW_RSVD_PG_CRTL, tmp_byte); ++ rtl_write_dword(rtlpriv, TXDESC_MSK, 0xFFFFCFFF); ++ } ++ ++ /* We enable high power and RA related mechanism after NIC ++ * initialized. */ ++ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_INIT); ++ ++ /* Add to prevent ASPM bug. */ ++ /* Always enable hst and NIC clock request. */ ++ rtl92s_phy_switch_ephy_parameter(hw); ++ ++ /* Security related ++ * 1. Clear all H/W keys. ++ * 2. Enable H/W encryption/decryption. */ ++ rtl_cam_reset_all_entry(hw); ++ secr_value |= SCR_TXENCENABLE; ++ secr_value |= SCR_RXENCENABLE; ++ secr_value |= SCR_NOSKMC; ++ rtl_write_byte(rtlpriv, REG_SECR, secr_value); ++ ++ for (i = 0; i < 4; i++) ++ rtl_write_dword(rtlpriv, wdcapra_add[i], 0x5e4322); ++ ++ if (rtlphy->rf_type == RF_1T2R) { ++ bool mrc2set = true; ++ /* Turn on B-Path */ ++ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC, (u8 *)&mrc2set); ++ } ++ ++ rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON); ++ rtl92s_dm_init(hw); ++ rtlpci->being_init_adapter = false; ++ ++ return err; ++} ++ ++void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr) ++{ ++} ++ ++void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ u32 reg_rcr = rtlpci->receive_config; ++ ++ if (rtlpriv->psc.rfpwr_state != ERFON) ++ return; ++ ++ if (check_bssid == true) { ++ reg_rcr |= (RCR_CBSSID); ++ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); ++ } else if (check_bssid == false) { ++ reg_rcr &= (~RCR_CBSSID); ++ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); ++ } ++ ++} ++ ++static int _rtl92se_set_media_status(struct ieee80211_hw *hw, ++ enum nl80211_iftype type) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u8 bt_msr = rtl_read_byte(rtlpriv, MSR); ++ enum led_ctl_mode ledaction = LED_CTL_NO_LINK; ++ u32 temp; ++ bt_msr &= ~MSR_LINK_MASK; ++ ++ switch (type) { ++ case NL80211_IFTYPE_UNSPECIFIED: ++ bt_msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT); ++ ledaction = LED_CTL_LINK; ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ++ ("Set Network type to NO LINK!\n")); ++ break; ++ case NL80211_IFTYPE_ADHOC: ++ bt_msr |= (MSR_LINK_ADHOC << MSR_LINK_SHIFT); ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ++ ("Set Network type to Ad Hoc!\n")); ++ break; ++ case NL80211_IFTYPE_STATION: ++ bt_msr |= (MSR_LINK_MANAGED << MSR_LINK_SHIFT); ++ ledaction = LED_CTL_LINK; ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ++ ("Set Network type to STA!\n")); ++ break; ++ case NL80211_IFTYPE_AP: ++ bt_msr |= (MSR_LINK_MASTER << MSR_LINK_SHIFT); ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ++ ("Set Network type to AP!\n")); ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Network type %d not support!\n", type)); ++ return 1; ++ break; ++ ++ } ++ ++ rtl_write_byte(rtlpriv, (MSR), bt_msr); ++ ++ temp = rtl_read_dword(rtlpriv, TCR); ++ rtl_write_dword(rtlpriv, TCR, temp & (~BIT(8))); ++ rtl_write_dword(rtlpriv, TCR, temp | BIT(8)); ++ ++ ++ return 0; ++} ++ ++/* HW_VAR_MEDIA_STATUS & HW_VAR_CECHK_BSSID */ ++int rtl92se_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ if (_rtl92se_set_media_status(hw, type)) ++ return -EOPNOTSUPP; ++ ++ if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { ++ if (type != NL80211_IFTYPE_AP) ++ rtl92se_set_check_bssid(hw, true); ++ } else { ++ rtl92se_set_check_bssid(hw, false); ++ } ++ ++ return 0; ++} ++ ++/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */ ++void rtl92se_set_qos(struct ieee80211_hw *hw, int aci) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ rtl92s_dm_init_edca_turbo(hw); ++ ++ switch (aci) { ++ case AC1_BK: ++ rtl_write_dword(rtlpriv, EDCAPARA_BK, 0xa44f); ++ break; ++ case AC0_BE: ++ /* rtl_write_dword(rtlpriv, EDCAPARA_BE, u4b_ac_param); */ ++ break; ++ case AC2_VI: ++ rtl_write_dword(rtlpriv, EDCAPARA_VI, 0x5e4322); ++ break; ++ case AC3_VO: ++ rtl_write_dword(rtlpriv, EDCAPARA_VO, 0x2f3222); ++ break; ++ default: ++ RT_ASSERT(false, ("invalid aci: %d !\n", aci)); ++ break; ++ } ++} ++ ++void rtl92se_enable_interrupt(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ ++ rtl_write_dword(rtlpriv, INTA_MASK, rtlpci->irq_mask[0]); ++ /* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */ ++ rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F); ++ ++ rtlpci->irq_enabled = true; ++} ++ ++void rtl92se_disable_interrupt(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ ++ rtl_write_dword(rtlpriv, INTA_MASK, 0); ++ rtl_write_dword(rtlpriv, INTA_MASK + 4, 0); ++ ++ rtlpci->irq_enabled = false; ++} ++ ++ ++static u8 _rtl92s_set_sysclk(struct ieee80211_hw *hw, u8 data) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u8 waitcnt = 100; ++ bool result = false; ++ u8 tmp; ++ ++ rtl_write_byte(rtlpriv, SYS_CLKR + 1, data); ++ ++ /* Wait the MAC synchronized. */ ++ udelay(400); ++ ++ /* Check if it is set ready. */ ++ tmp = rtl_read_byte(rtlpriv, SYS_CLKR + 1); ++ result = ((tmp & BIT(7)) == (data & BIT(7))); ++ ++ if ((data & (BIT(6) | BIT(7))) == false) { ++ waitcnt = 100; ++ tmp = 0; ++ ++ while (1) { ++ waitcnt--; ++ tmp = rtl_read_byte(rtlpriv, SYS_CLKR + 1); ++ ++ if ((tmp & BIT(6))) ++ break; ++ ++ printk(KERN_ERR "wait for BIT(6) return value %x\n", ++ tmp); ++ ++ if (waitcnt == 0) ++ break; ++ udelay(10); ++ } ++ ++ if (waitcnt == 0) ++ result = false; ++ else ++ result = true; ++ } ++ ++ return result; ++} ++ ++static void _rtl92s_phy_set_rfhalt(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ u8 u1btmp; ++ ++ if (rtlhal->driver_going2unload) ++ rtl_write_byte(rtlpriv, 0x560, 0x0); ++ ++ /* Power save for BB/RF */ ++ u1btmp = rtl_read_byte(rtlpriv, LDOV12D_CTRL); ++ u1btmp |= BIT(0); ++ rtl_write_byte(rtlpriv, LDOV12D_CTRL, u1btmp); ++ rtl_write_byte(rtlpriv, SPS1_CTRL, 0x0); ++ rtl_write_byte(rtlpriv, TXPAUSE, 0xFF); ++ rtl_write_word(rtlpriv, CMDR, 0x57FC); ++ udelay(100); ++ rtl_write_word(rtlpriv, CMDR, 0x77FC); ++ rtl_write_byte(rtlpriv, PHY_CCA, 0x0); ++ udelay(10); ++ rtl_write_word(rtlpriv, CMDR, 0x37FC); ++ udelay(10); ++ rtl_write_word(rtlpriv, CMDR, 0x77FC); ++ udelay(10); ++ rtl_write_word(rtlpriv, CMDR, 0x57FC); ++ rtl_write_word(rtlpriv, CMDR, 0x0000); ++ ++ if (rtlhal->driver_going2unload) { ++ u1btmp = rtl_read_byte(rtlpriv, (REG_SYS_FUNC_EN + 1)); ++ u1btmp &= ~(BIT(0)); ++ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1btmp); ++ } ++ ++ u1btmp = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); ++ ++ /* Add description. After switch control path. register ++ * after page1 will be invisible. We can not do any IO ++ * for register>0x40. After resume&MACIO reset, we need ++ * to remember previous reg content. */ ++ if (u1btmp & BIT(7)) { ++ u1btmp &= ~(BIT(6) | BIT(7)); ++ if (!_rtl92s_set_sysclk(hw, u1btmp)) { ++ printk(KERN_ERR "Switch ctrl path fail\n"); ++ return; ++ } ++ } ++ ++ /* Power save for MAC */ ++ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS && ++ !rtlhal->driver_going2unload) { ++ /* enable LED function */ ++ rtl_write_byte(rtlpriv, 0x03, 0xF9); ++ /* SW/HW radio off or halt adapter!! For example S3/S4 */ ++ } else { ++ /* LED function disable. Power range is about 8mA now. */ ++ /* if write 0xF1 disconnet_pci power ++ * ifconfig wlan0 down power are both high 35:70 */ ++ /* if write oxF9 disconnet_pci power ++ * ifconfig wlan0 down power are both low 12:45*/ ++ rtl_write_byte(rtlpriv, 0x03, 0xF9); ++ } ++ ++ rtl_write_byte(rtlpriv, SYS_CLKR + 1, 0x70); ++ rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, 0x68); ++ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x00); ++ rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); ++ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, 0x0E); ++ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); ++ ++} ++ ++static void _rtl92se_gen_refreshledstate(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); ++ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); ++ ++ if (rtlpci->up_first_time == 1) ++ return; ++ ++ if (rtlpriv->psc.rfoff_reason == RF_CHANGE_BY_IPS) ++ rtl92se_sw_led_on(hw, pLed0); ++ else ++ rtl92se_sw_led_off(hw, pLed0); ++} ++ ++ ++static void _rtl92se_power_domain_init(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u16 tmpu2b; ++ u8 tmpu1b; ++ ++ rtlpriv->psc.pwrdomain_protect = true; ++ ++ tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); ++ if (tmpu1b & BIT(7)) { ++ tmpu1b &= ~(BIT(6) | BIT(7)); ++ if (!_rtl92s_set_sysclk(hw, tmpu1b)) { ++ rtlpriv->psc.pwrdomain_protect = false; ++ return; ++ } ++ } ++ ++ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x0); ++ rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); ++ ++ /* Reset MAC-IO and CPU and Core Digital BIT10/11/15 */ ++ tmpu1b = rtl_read_byte(rtlpriv, SYS_FUNC_EN + 1); ++ ++ /* If IPS we need to turn LED on. So we not ++ * not disable BIT 3/7 of reg3. */ ++ if (rtlpriv->psc.rfoff_reason & (RF_CHANGE_BY_IPS | RF_CHANGE_BY_HW)) ++ tmpu1b &= 0xFB; ++ else ++ tmpu1b &= 0x73; ++ ++ rtl_write_byte(rtlpriv, SYS_FUNC_EN + 1, tmpu1b); ++ /* wait for BIT 10/11/15 to pull high automatically!! */ ++ mdelay(1); ++ ++ rtl_write_byte(rtlpriv, CMDR, 0); ++ rtl_write_byte(rtlpriv, TCR, 0); ++ ++ /* Data sheet not define 0x562!!! Copy from WMAC!!!!! */ ++ tmpu1b = rtl_read_byte(rtlpriv, 0x562); ++ tmpu1b |= 0x08; ++ rtl_write_byte(rtlpriv, 0x562, tmpu1b); ++ tmpu1b &= ~(BIT(3)); ++ rtl_write_byte(rtlpriv, 0x562, tmpu1b); ++ ++ /* Enable AFE clock source */ ++ tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL); ++ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, (tmpu1b | 0x01)); ++ /* Delay 1.5ms */ ++ udelay(1500); ++ tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL + 1); ++ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, (tmpu1b & 0xfb)); ++ ++ /* Enable AFE Macro Block's Bandgap */ ++ tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); ++ rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | BIT(0))); ++ mdelay(1); ++ ++ /* Enable AFE Mbias */ ++ tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); ++ rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | 0x02)); ++ mdelay(1); ++ ++ /* Enable LDOA15 block */ ++ tmpu1b = rtl_read_byte(rtlpriv, LDOA15_CTRL); ++ rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0))); ++ ++ /* Set Digital Vdd to Retention isolation Path. */ ++ tmpu2b = rtl_read_word(rtlpriv, SYS_ISO_CTRL); ++ rtl_write_word(rtlpriv, SYS_ISO_CTRL, (tmpu2b | BIT(11))); ++ ++ ++ /* For warm reboot NIC disappera bug. */ ++ tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN); ++ rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(13))); ++ ++ rtl_write_byte(rtlpriv, SYS_ISO_CTRL + 1, 0x68); ++ ++ /* Enable AFE PLL Macro Block */ ++ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL); ++ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4))); ++ /* Enable MAC 80MHZ clock */ ++ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL + 1); ++ rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, (tmpu1b | BIT(0))); ++ mdelay(1); ++ ++ /* Release isolation AFE PLL & MD */ ++ rtl_write_byte(rtlpriv, SYS_ISO_CTRL, 0xA6); ++ ++ /* Enable MAC clock */ ++ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); ++ rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11))); ++ ++ /* Enable Core digital and enable IOREG R/W */ ++ tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN); ++ rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11))); ++ /* enable REG_EN */ ++ rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15))); ++ ++ /* Switch the control path. */ ++ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); ++ rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b & (~BIT(2)))); ++ ++ tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); ++ tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6))); ++ if (!_rtl92s_set_sysclk(hw, tmpu1b)) { ++ rtlpriv->psc.pwrdomain_protect = false; ++ return; ++ } ++ ++ rtl_write_word(rtlpriv, CMDR, 0x37FC); ++ ++ /* After MACIO reset,we must refresh LED state. */ ++ _rtl92se_gen_refreshledstate(hw); ++ ++ rtlpriv->psc.pwrdomain_protect = false; ++} ++ ++void rtl92se_card_disable(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ enum nl80211_iftype opmode; ++ u8 wait = 30; ++ ++ rtlpriv->intf_ops->enable_aspm(hw); ++ ++ if (rtlpci->driver_is_goingto_unload || ++ ppsc->rfoff_reason > RF_CHANGE_BY_PS) ++ rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); ++ ++ /* we should chnge GPIO to input mode ++ * this will drop away current about 25mA*/ ++ rtl8192se_gpiobit3_cfg_inputmode(hw); ++ ++ /* this is very important for ips power save */ ++ while (wait-- >= 10 && rtlpriv->psc.pwrdomain_protect) { ++ if (rtlpriv->psc.pwrdomain_protect) ++ mdelay(20); ++ else ++ break; ++ } ++ ++ mac->link_state = MAC80211_NOLINK; ++ opmode = NL80211_IFTYPE_UNSPECIFIED; ++ _rtl92se_set_media_status(hw, opmode); ++ ++ _rtl92s_phy_set_rfhalt(hw); ++ udelay(100); ++} ++ ++void rtl92se_interrupt_recognized(struct ieee80211_hw *hw, u32 *p_inta, ++ u32 *p_intb) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ ++ *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0]; ++ rtl_write_dword(rtlpriv, ISR, *p_inta); ++ ++ *p_intb = rtl_read_dword(rtlpriv, ISR + 4) & rtlpci->irq_mask[1]; ++ rtl_write_dword(rtlpriv, ISR + 4, *p_intb); ++} ++ ++void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ u16 bcntime_cfg = 0; ++ u16 bcn_cw = 6, bcn_ifs = 0xf; ++ u16 atim_window = 2; ++ ++ /* ATIM Window (in unit of TU). */ ++ rtl_write_word(rtlpriv, ATIMWND, atim_window); ++ ++ /* Beacon interval (in unit of TU). */ ++ rtl_write_word(rtlpriv, BCN_INTERVAL, mac->beacon_interval); ++ ++ /* DrvErlyInt (in unit of TU). (Time to send ++ * interrupt to notify driver to change ++ * beacon content) */ ++ rtl_write_word(rtlpriv, BCN_DRV_EARLY_INT, 10 << 4); ++ ++ /* BcnDMATIM(in unit of us). Indicates the ++ * time before TBTT to perform beacon queue DMA */ ++ rtl_write_word(rtlpriv, BCN_DMATIME, 256); ++ ++ /* Force beacon frame transmission even ++ * after receiving beacon frame from ++ * other ad hoc STA */ ++ rtl_write_byte(rtlpriv, BCN_ERR_THRESH, 100); ++ ++ /* Beacon Time Configuration */ ++ if (mac->opmode == NL80211_IFTYPE_ADHOC) ++ bcntime_cfg |= (bcn_cw << BCN_TCFG_CW_SHIFT); ++ ++ /* TODO: bcn_ifs may required to be changed on ASIC */ ++ bcntime_cfg |= bcn_ifs << BCN_TCFG_IFS; ++ ++ /*for beacon changed */ ++ rtl92s_phy_set_beacon_hwreg(hw, mac->beacon_interval); ++} ++ ++void rtl92se_set_beacon_interval(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ u16 bcn_interval = mac->beacon_interval; ++ ++ /* Beacon interval (in unit of TU). */ ++ rtl_write_word(rtlpriv, BCN_INTERVAL, bcn_interval); ++ /* 2008.10.24 added by tynli for beacon changed. */ ++ rtl92s_phy_set_beacon_hwreg(hw, bcn_interval); ++} ++ ++void rtl92se_update_interrupt_mask(struct ieee80211_hw *hw, ++ u32 add_msr, u32 rm_msr) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ ++ RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, ++ ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr)); ++ ++ if (add_msr) ++ rtlpci->irq_mask[0] |= add_msr; ++ ++ if (rm_msr) ++ rtlpci->irq_mask[0] &= (~rm_msr); ++ ++ rtl92se_disable_interrupt(hw); ++ rtl92se_enable_interrupt(hw); ++} ++ ++static void _rtl8192se_get_IC_Inferiority(struct ieee80211_hw *hw) ++{ ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ u8 efuse_id; ++ ++ rtlhal->ic_class = IC_INFERIORITY_A; ++ ++ /* Only retrieving while using EFUSE. */ ++ if ((rtlefuse->epromtype == EEPROM_BOOT_EFUSE) && ++ !rtlefuse->autoload_failflag) { ++ efuse_id = efuse_read_1byte(hw, EFUSE_IC_ID_OFFSET); ++ ++ if (efuse_id == 0xfe) ++ rtlhal->ic_class = IC_INFERIORITY_B; ++ } ++} ++ ++static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ u16 i, usvalue; ++ u16 eeprom_id; ++ u8 tempval; ++ u8 hwinfo[HWSET_MAX_SIZE_92S]; ++ u8 rf_path, index; ++ ++ if (rtlefuse->epromtype == EEPROM_93C46) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("RTL819X Not boot from eeprom, check it !!")); ++ } else if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { ++ rtl_efuse_shadow_map_update(hw); ++ ++ memcpy((void *)hwinfo, (void *) ++ &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], ++ HWSET_MAX_SIZE_92S); ++ } ++ ++ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"), ++ hwinfo, HWSET_MAX_SIZE_92S); ++ ++ eeprom_id = *((u16 *)&hwinfo[0]); ++ if (eeprom_id != RTL8190_EEPROM_ID) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ++ ("EEPROM ID(%#x) is invalid!!\n", eeprom_id)); ++ rtlefuse->autoload_failflag = true; ++ } else { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n")); ++ rtlefuse->autoload_failflag = false; ++ } ++ ++ if (rtlefuse->autoload_failflag == true) ++ return; ++ ++ _rtl8192se_get_IC_Inferiority(hw); ++ ++ /* Read IC Version && Channel Plan */ ++ /* VID, DID SE 0xA-D */ ++ rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; ++ rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; ++ rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; ++ rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; ++ rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; ++ ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("EEPROMId = 0x%4x\n", eeprom_id)); ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid)); ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did)); ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid)); ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid)); ++ ++ for (i = 0; i < 6; i += 2) { ++ usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; ++ *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; ++ } ++ ++ for (i = 0; i < 6; i++) ++ rtl_write_byte(rtlpriv, MACIDR0 + i, rtlefuse->dev_addr[i]); ++ ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ++ (MAC_FMT "\n", MAC_ARG(rtlefuse->dev_addr))); ++ ++ /* Get Tx Power Level by Channel */ ++ /* Read Tx power of Channel 1 ~ 14 from EEPROM. */ ++ /* 92S suupport RF A & B */ ++ for (rf_path = 0; rf_path < 2; rf_path++) { ++ for (i = 0; i < 3; i++) { ++ /* Read CCK RF A & B Tx power */ ++ rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][i] = ++ hwinfo[EEPROM_TXPOWERBASE + rf_path * 3 + i]; ++ ++ /* Read OFDM RF A & B Tx power for 1T */ ++ rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] = ++ hwinfo[EEPROM_TXPOWERBASE + 6 + rf_path * 3 + i]; ++ ++ /* Read OFDM RF A & B Tx power for 2T */ ++ rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i] ++ = hwinfo[EEPROM_TXPOWERBASE + 12 + ++ rf_path * 3 + i]; ++ } ++ } ++ ++ for (rf_path = 0; rf_path < 2; rf_path++) ++ for (i = 0; i < 3; i++) ++ RTPRINT(rtlpriv, FINIT, INIT_EEPROM, ++ ("RF(%d) EEPROM CCK Area(%d) = 0x%x\n", rf_path, ++ i, rtlefuse->eeprom_chnlarea_txpwr_cck ++ [rf_path][i])); ++ for (rf_path = 0; rf_path < 2; rf_path++) ++ for (i = 0; i < 3; i++) ++ RTPRINT(rtlpriv, FINIT, INIT_EEPROM, ++ ("RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n", ++ rf_path, i, ++ rtlefuse->eeprom_chnlarea_txpwr_ht40_1s ++ [rf_path][i])); ++ for (rf_path = 0; rf_path < 2; rf_path++) ++ for (i = 0; i < 3; i++) ++ RTPRINT(rtlpriv, FINIT, INIT_EEPROM, ++ ("RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n", ++ rf_path, i, ++ rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif ++ [rf_path][i])); ++ ++ for (rf_path = 0; rf_path < 2; rf_path++) { ++ ++ /* Assign dedicated channel tx power */ ++ for (i = 0; i < 14; i++) { ++ /* channel 1~3 use the same Tx Power Level. */ ++ if (i < 3) ++ index = 0; ++ /* Channel 4-8 */ ++ else if (i < 8) ++ index = 1; ++ /* Channel 9-14 */ ++ else ++ index = 2; ++ ++ /* Record A & B CCK /OFDM - 1T/2T Channel area ++ * tx power */ ++ rtlefuse->txpwrlevel_cck[rf_path][i] = ++ rtlefuse->eeprom_chnlarea_txpwr_cck ++ [rf_path][index]; ++ rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = ++ rtlefuse->eeprom_chnlarea_txpwr_ht40_1s ++ [rf_path][index]; ++ rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = ++ rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif ++ [rf_path][index]; ++ } ++ ++ for (i = 0; i < 14; i++) { ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ++ ("RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = " ++ "[0x%x / 0x%x / 0x%x]\n", rf_path, i, ++ rtlefuse->txpwrlevel_cck[rf_path][i], ++ rtlefuse->txpwrlevel_ht40_1s[rf_path][i], ++ rtlefuse->txpwrlevel_ht40_2s[rf_path][i])); ++ } ++ } ++ ++ for (rf_path = 0; rf_path < 2; rf_path++) { ++ for (i = 0; i < 3; i++) { ++ /* Read Power diff limit. */ ++ rtlefuse->eeprom_pwrgroup[rf_path][i] = ++ hwinfo[EEPROM_TXPWRGROUP + rf_path * 3 + i]; ++ } ++ } ++ ++ for (rf_path = 0; rf_path < 2; rf_path++) { ++ /* Fill Pwr group */ ++ for (i = 0; i < 14; i++) { ++ /* Chanel 1-3 */ ++ if (i < 3) ++ index = 0; ++ /* Channel 4-8 */ ++ else if (i < 8) ++ index = 1; ++ /* Channel 9-13 */ ++ else ++ index = 2; ++ ++ rtlefuse->pwrgroup_ht20[rf_path][i] = ++ (rtlefuse->eeprom_pwrgroup[rf_path][index] & ++ 0xf); ++ rtlefuse->pwrgroup_ht40[rf_path][i] = ++ ((rtlefuse->eeprom_pwrgroup[rf_path][index] & ++ 0xf0) >> 4); ++ ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ++ ("RF-%d pwrgroup_ht20[%d] = 0x%x\n", ++ rf_path, i, ++ rtlefuse->pwrgroup_ht20[rf_path][i])); ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ++ ("RF-%d pwrgroup_ht40[%d] = 0x%x\n", ++ rf_path, i, ++ rtlefuse->pwrgroup_ht40[rf_path][i])); ++ } ++ } ++ ++ for (i = 0; i < 14; i++) { ++ /* Read tx power difference between HT OFDM 20/40 MHZ */ ++ /* channel 1-3 */ ++ if (i < 3) ++ index = 0; ++ /* Channel 4-8 */ ++ else if (i < 8) ++ index = 1; ++ /* Channel 9-14 */ ++ else ++ index = 2; ++ ++ tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_HT20_DIFF + ++ index]) & 0xff; ++ rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF); ++ rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] = ++ ((tempval >> 4) & 0xF); ++ ++ /* Read OFDM<->HT tx power diff */ ++ /* Channel 1-3 */ ++ if (i < 3) ++ index = 0; ++ /* Channel 4-8 */ ++ else if (i < 8) ++ index = 0x11; ++ /* Channel 9-14 */ ++ else ++ index = 1; ++ ++ tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_OFDM_DIFF + index]) ++ & 0xff; ++ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] = ++ (tempval & 0xF); ++ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] = ++ ((tempval >> 4) & 0xF); ++ ++ tempval = (*(u8 *)&hwinfo[TX_PWR_SAFETY_CHK]); ++ rtlefuse->txpwr_safetyflag = (tempval & 0x01); ++ } ++ ++ rtlefuse->eeprom_regulatory = 0; ++ if (rtlefuse->eeprom_version >= 2) { ++ /* BIT(0)~2 */ ++ if (rtlefuse->eeprom_version >= 4) ++ rtlefuse->eeprom_regulatory = ++ (hwinfo[EEPROM_REGULATORY] & 0x7); ++ else /* BIT(0) */ ++ rtlefuse->eeprom_regulatory = ++ (hwinfo[EEPROM_REGULATORY] & 0x1); ++ } ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ++ ("eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory)); ++ ++ for (i = 0; i < 14; i++) ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ++ ("RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i, ++ rtlefuse->txpwr_ht20diff[RF90_PATH_A][i])); ++ for (i = 0; i < 14; i++) ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ++ ("RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i, ++ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i])); ++ for (i = 0; i < 14; i++) ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ++ ("RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i, ++ rtlefuse->txpwr_ht20diff[RF90_PATH_B][i])); ++ for (i = 0; i < 14; i++) ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ++ ("RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i, ++ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i])); ++ ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TxPwrSafetyFlag = %d\n", ++ rtlefuse->txpwr_safetyflag)); ++ ++ /* Read RF-indication and Tx Power gain ++ * index diff of legacy to HT OFDM rate. */ ++ tempval = (*(u8 *)&hwinfo[EEPROM_RFIND_POWERDIFF]) & 0xff; ++ rtlefuse->eeprom_txpowerdiff = tempval; ++ rtlefuse->legacy_httxpowerdiff = ++ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][0]; ++ ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TxPowerDiff = %#x\n", ++ rtlefuse->eeprom_txpowerdiff)); ++ ++ /* Get TSSI value for each path. */ ++ usvalue = *(u16 *)&hwinfo[EEPROM_TSSI_A]; ++ rtlefuse->eeprom_tssi[RF90_PATH_A] = (u8)((usvalue & 0xff00) >> 8); ++ usvalue = *(u8 *)&hwinfo[EEPROM_TSSI_B]; ++ rtlefuse->eeprom_tssi[RF90_PATH_B] = (u8)(usvalue & 0xff); ++ ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TSSI_A = 0x%x, TSSI_B = 0x%x\n", ++ rtlefuse->eeprom_tssi[RF90_PATH_A], ++ rtlefuse->eeprom_tssi[RF90_PATH_B])); ++ ++ /* Read antenna tx power offset of B/C/D to A from EEPROM */ ++ /* and read ThermalMeter from EEPROM */ ++ tempval = *(u8 *)&hwinfo[EEPROM_THERMALMETER]; ++ rtlefuse->eeprom_thermalmeter = tempval; ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("thermalmeter = 0x%x\n", ++ rtlefuse->eeprom_thermalmeter)); ++ ++ /* ThermalMeter, BIT(0)~3 for RFIC1, BIT(4)~7 for RFIC2 */ ++ rtlefuse->thermalmeter[0] = (rtlefuse->eeprom_thermalmeter & 0x1f); ++ rtlefuse->tssi_13dbm = rtlefuse->eeprom_thermalmeter * 100; ++ ++ /* Read CrystalCap from EEPROM */ ++ tempval = (*(u8 *)&hwinfo[EEPROM_CRYSTALCAP]) >> 4; ++ rtlefuse->eeprom_crystalcap = tempval; ++ /* CrystalCap, BIT(12)~15 */ ++ rtlefuse->crystalcap = rtlefuse->eeprom_crystalcap; ++ ++ /* Read IC Version && Channel Plan */ ++ /* Version ID, Channel plan */ ++ rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; ++ rtlefuse->txpwr_fromeprom = true; ++ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("EEPROM ChannelPlan = 0x%4x\n", ++ rtlefuse->eeprom_channelplan)); ++ ++ /* Read Customer ID or Board Type!!! */ ++ tempval = *(u8 *)&hwinfo[EEPROM_BOARDTYPE]; ++ /* Change RF type definition */ ++ if (tempval == 0) ++ rtlphy->rf_type = RF_2T2R; ++ else if (tempval == 1) ++ rtlphy->rf_type = RF_1T2R; ++ else if (tempval == 2) ++ rtlphy->rf_type = RF_1T2R; ++ else if (tempval == 3) ++ rtlphy->rf_type = RF_1T1R; ++ ++ /* 1T2R but 1SS (1x1 receive combining) */ ++ rtlefuse->b1x1_recvcombine = false; ++ if (rtlphy->rf_type == RF_1T2R) { ++ tempval = rtl_read_byte(rtlpriv, 0x07); ++ if (!(tempval & BIT(0))) { ++ rtlefuse->b1x1_recvcombine = true; ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("RF_TYPE=1T2R but only 1SS\n")); ++ } ++ } ++ rtlefuse->b1ss_support = rtlefuse->b1x1_recvcombine; ++ rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMID]; ++ ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("EEPROM Customer ID: 0x%2x", ++ rtlefuse->eeprom_oemid)); ++ ++ /* set channel paln to world wide 13 */ ++ rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; ++} ++ ++void rtl92se_read_eeprom_info(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ u8 tmp_u1b = 0; ++ ++ tmp_u1b = rtl_read_byte(rtlpriv, EPROM_CMD); ++ ++ if (tmp_u1b & BIT(4)) { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EEPROM\n")); ++ rtlefuse->epromtype = EEPROM_93C46; ++ } else { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EFUSE\n")); ++ rtlefuse->epromtype = EEPROM_BOOT_EFUSE; ++ } ++ ++ if (tmp_u1b & BIT(5)) { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n")); ++ rtlefuse->autoload_failflag = false; ++ _rtl92se_read_adapter_info(hw); ++ } else { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n")); ++ rtlefuse->autoload_failflag = true; ++ } ++} ++ ++static void rtl92se_update_hal_rate_table(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ u32 ratr_value; ++ u8 ratr_index = 0; ++ u8 nmode = mac->ht_enable; ++ u8 mimo_ps = IEEE80211_SMPS_OFF; ++ u16 shortgi_rate = 0; ++ u32 tmp_ratr_value = 0; ++ u8 curtxbw_40mhz = mac->bw_40; ++ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? ++ 1 : 0; ++ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? ++ 1 : 0; ++ enum wireless_mode wirelessmode = mac->mode; ++ ++ if (rtlhal->current_bandtype == BAND_ON_5G) ++ ratr_value = sta->supp_rates[1] << 4; ++ else ++ ratr_value = sta->supp_rates[0]; ++ ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | ++ sta->ht_cap.mcs.rx_mask[0] << 12); ++ switch (wirelessmode) { ++ case WIRELESS_MODE_B: ++ ratr_value &= 0x0000000D; ++ break; ++ case WIRELESS_MODE_G: ++ ratr_value &= 0x00000FF5; ++ break; ++ case WIRELESS_MODE_N_24G: ++ case WIRELESS_MODE_N_5G: ++ nmode = 1; ++ if (mimo_ps == IEEE80211_SMPS_STATIC) { ++ ratr_value &= 0x0007F005; ++ } else { ++ u32 ratr_mask; ++ ++ if (get_rf_type(rtlphy) == RF_1T2R || ++ get_rf_type(rtlphy) == RF_1T1R) { ++ if (curtxbw_40mhz) ++ ratr_mask = 0x000ff015; ++ else ++ ratr_mask = 0x000ff005; ++ } else { ++ if (curtxbw_40mhz) ++ ratr_mask = 0x0f0ff015; ++ else ++ ratr_mask = 0x0f0ff005; ++ } ++ ++ ratr_value &= ratr_mask; ++ } ++ break; ++ default: ++ if (rtlphy->rf_type == RF_1T2R) ++ ratr_value &= 0x000ff0ff; ++ else ++ ratr_value &= 0x0f0ff0ff; ++ ++ break; ++ } ++ ++ if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT) ++ ratr_value &= 0x0FFFFFFF; ++ else if (rtlpriv->rtlhal.version == VERSION_8192S_ACUT) ++ ratr_value &= 0x0FFFFFF0; ++ ++ if (nmode && ((curtxbw_40mhz && ++ curshortgi_40mhz) || (!curtxbw_40mhz && ++ curshortgi_20mhz))) { ++ ++ ratr_value |= 0x10000000; ++ tmp_ratr_value = (ratr_value >> 12); ++ ++ for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { ++ if ((1 << shortgi_rate) & tmp_ratr_value) ++ break; ++ } ++ ++ shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | ++ (shortgi_rate << 4) | (shortgi_rate); ++ ++ rtl_write_byte(rtlpriv, SG_RATE, shortgi_rate); ++ } ++ ++ rtl_write_dword(rtlpriv, ARFR0 + ratr_index * 4, ratr_value); ++ if (ratr_value & 0xfffff000) ++ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_REFRESH_N); ++ else ++ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_REFRESH_BG); ++ ++ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, ++ ("%x\n", rtl_read_dword(rtlpriv, ARFR0))); ++} ++ ++static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, ++ u8 rssi_level) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_sta_info *sta_entry = NULL; ++ u32 ratr_bitmap; ++ u8 ratr_index = 0; ++ u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ++ ? 1 : 0; ++ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? ++ 1 : 0; ++ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? ++ 1 : 0; ++ enum wireless_mode wirelessmode = 0; ++ bool shortgi = false; ++ u32 ratr_value = 0; ++ u8 shortgi_rate = 0; ++ u32 mask = 0; ++ u32 band = 0; ++ bool bmulticast = false; ++ u8 macid = 0; ++ u8 mimo_ps = IEEE80211_SMPS_OFF; ++ ++ sta_entry = (struct rtl_sta_info *) sta->drv_priv; ++ wirelessmode = sta_entry->wireless_mode; ++ if (mac->opmode == NL80211_IFTYPE_STATION) ++ curtxbw_40mhz = mac->bw_40; ++ else if (mac->opmode == NL80211_IFTYPE_AP || ++ mac->opmode == NL80211_IFTYPE_ADHOC) ++ macid = sta->aid + 1; ++ ++ if (rtlhal->current_bandtype == BAND_ON_5G) ++ ratr_bitmap = sta->supp_rates[1] << 4; ++ else ++ ratr_bitmap = sta->supp_rates[0]; ++ ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | ++ sta->ht_cap.mcs.rx_mask[0] << 12); ++ switch (wirelessmode) { ++ case WIRELESS_MODE_B: ++ band |= WIRELESS_11B; ++ ratr_index = RATR_INX_WIRELESS_B; ++ if (ratr_bitmap & 0x0000000c) ++ ratr_bitmap &= 0x0000000d; ++ else ++ ratr_bitmap &= 0x0000000f; ++ break; ++ case WIRELESS_MODE_G: ++ band |= (WIRELESS_11G | WIRELESS_11B); ++ ratr_index = RATR_INX_WIRELESS_GB; ++ ++ if (rssi_level == 1) ++ ratr_bitmap &= 0x00000f00; ++ else if (rssi_level == 2) ++ ratr_bitmap &= 0x00000ff0; ++ else ++ ratr_bitmap &= 0x00000ff5; ++ break; ++ case WIRELESS_MODE_A: ++ band |= WIRELESS_11A; ++ ratr_index = RATR_INX_WIRELESS_A; ++ ratr_bitmap &= 0x00000ff0; ++ break; ++ case WIRELESS_MODE_N_24G: ++ case WIRELESS_MODE_N_5G: ++ band |= (WIRELESS_11N | WIRELESS_11G | WIRELESS_11B); ++ ratr_index = RATR_INX_WIRELESS_NGB; ++ ++ if (mimo_ps == IEEE80211_SMPS_STATIC) { ++ if (rssi_level == 1) ++ ratr_bitmap &= 0x00070000; ++ else if (rssi_level == 2) ++ ratr_bitmap &= 0x0007f000; ++ else ++ ratr_bitmap &= 0x0007f005; ++ } else { ++ if (rtlphy->rf_type == RF_1T2R || ++ rtlphy->rf_type == RF_1T1R) { ++ if (rssi_level == 1) { ++ ratr_bitmap &= 0x000f0000; ++ } else if (rssi_level == 3) { ++ ratr_bitmap &= 0x000fc000; ++ } else if (rssi_level == 5) { ++ ratr_bitmap &= 0x000ff000; ++ } else { ++ if (curtxbw_40mhz) ++ ratr_bitmap &= 0x000ff015; ++ else ++ ratr_bitmap &= 0x000ff005; ++ } ++ } else { ++ if (rssi_level == 1) { ++ ratr_bitmap &= 0x0f8f0000; ++ } else if (rssi_level == 3) { ++ ratr_bitmap &= 0x0f8fc000; ++ } else if (rssi_level == 5) { ++ ratr_bitmap &= 0x0f8ff000; ++ } else { ++ if (curtxbw_40mhz) ++ ratr_bitmap &= 0x0f8ff015; ++ else ++ ratr_bitmap &= 0x0f8ff005; ++ } ++ } ++ } ++ ++ if ((curtxbw_40mhz && curshortgi_40mhz) || ++ (!curtxbw_40mhz && curshortgi_20mhz)) { ++ if (macid == 0) ++ shortgi = true; ++ else if (macid == 1) ++ shortgi = false; ++ } ++ break; ++ default: ++ band |= (WIRELESS_11N | WIRELESS_11G | WIRELESS_11B); ++ ratr_index = RATR_INX_WIRELESS_NGB; ++ ++ if (rtlphy->rf_type == RF_1T2R) ++ ratr_bitmap &= 0x000ff0ff; ++ else ++ ratr_bitmap &= 0x0f8ff0ff; ++ break; ++ } ++ ++ if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT) ++ ratr_bitmap &= 0x0FFFFFFF; ++ else if (rtlpriv->rtlhal.version == VERSION_8192S_ACUT) ++ ratr_bitmap &= 0x0FFFFFF0; ++ ++ if (shortgi) { ++ ratr_bitmap |= 0x10000000; ++ /* Get MAX MCS available. */ ++ ratr_value = (ratr_bitmap >> 12); ++ for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { ++ if ((1 << shortgi_rate) & ratr_value) ++ break; ++ } ++ ++ shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | ++ (shortgi_rate << 4) | (shortgi_rate); ++ rtl_write_byte(rtlpriv, SG_RATE, shortgi_rate); ++ } ++ ++ mask |= (bmulticast ? 1 : 0) << 9 | (macid & 0x1f) << 4 | (band & 0xf); ++ ++ RT_TRACE(rtlpriv, COMP_RATR, DBG_TRACE, ("mask = %x, bitmap = %x\n", ++ mask, ratr_bitmap)); ++ rtl_write_dword(rtlpriv, 0x2c4, ratr_bitmap); ++ rtl_write_dword(rtlpriv, WFM5, (FW_RA_UPDATE_MASK | (mask << 8))); ++ ++ if (macid != 0) ++ sta_entry->ratr_index = ratr_index; ++} ++ ++void rtl92se_update_hal_rate_tbl(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, u8 rssi_level) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ if (rtlpriv->dm.useramask) ++ rtl92se_update_hal_rate_mask(hw, sta, rssi_level); ++ else ++ rtl92se_update_hal_rate_table(hw, sta); ++} ++ ++void rtl92se_update_channel_access_setting(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ u16 sifs_timer; ++ ++ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, ++ (u8 *)&mac->slot_time); ++ sifs_timer = 0x0e0e; ++ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); ++ ++} ++ ++/* this ifunction is for RFKILL, it's different with windows, ++ * because UI will disable wireless when GPIO Radio Off. ++ * And here we not check or Disable/Enable ASPM like windows*/ ++bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ enum rf_pwrstate rfpwr_toset, cur_rfstate; ++ unsigned long flag = 0; ++ bool actuallyset = false; ++ bool turnonbypowerdomain = false; ++ ++ /* just 8191se can check gpio before firstup, 92c/92d have fixed it */ ++ if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter)) ++ return false; ++ ++ if (ppsc->swrf_processing) ++ return false; ++ ++ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); ++ if (ppsc->rfchange_inprogress) { ++ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); ++ return false; ++ } else { ++ ppsc->rfchange_inprogress = true; ++ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); ++ } ++ ++ cur_rfstate = ppsc->rfpwr_state; ++ ++ /* because after _rtl92s_phy_set_rfhalt, all power ++ * closed, so we must open some power for GPIO check, ++ * or we will always check GPIO RFOFF here, ++ * And we should close power after GPIO check */ ++ if (RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { ++ _rtl92se_power_domain_init(hw); ++ turnonbypowerdomain = true; ++ } ++ ++ rfpwr_toset = _rtl92se_rf_onoff_detect(hw); ++ ++ if ((ppsc->hwradiooff == true) && (rfpwr_toset == ERFON)) { ++ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, ++ ("RFKILL-HW Radio ON, RF ON\n")); ++ ++ rfpwr_toset = ERFON; ++ ppsc->hwradiooff = false; ++ actuallyset = true; ++ } else if ((ppsc->hwradiooff == false) && (rfpwr_toset == ERFOFF)) { ++ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, ++ ("RFKILL-HW Radio OFF, RF OFF\n")); ++ ++ rfpwr_toset = ERFOFF; ++ ppsc->hwradiooff = true; ++ actuallyset = true; ++ } ++ ++ if (actuallyset) { ++ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); ++ ppsc->rfchange_inprogress = false; ++ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); ++ ++ /* this not include ifconfig wlan0 down case */ ++ /* } else if (rfpwr_toset == ERFOFF || cur_rfstate == ERFOFF) { */ ++ } else { ++ /* because power_domain_init may be happen when ++ * _rtl92s_phy_set_rfhalt, this will open some powers ++ * and cause current increasing about 40 mA for ips, ++ * rfoff and ifconfig down, so we set ++ * _rtl92s_phy_set_rfhalt again here */ ++ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC && ++ turnonbypowerdomain) { ++ _rtl92s_phy_set_rfhalt(hw); ++ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); ++ } ++ ++ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); ++ ppsc->rfchange_inprogress = false; ++ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); ++ } ++ ++ *valid = 1; ++ return !ppsc->hwradiooff; ++ ++} ++ ++/* Is_wepkey just used for WEP used as group & pairwise key ++ * if pairwise is AES ang group is WEP Is_wepkey == false.*/ ++void rtl92se_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr, ++ bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ u8 *macaddr = p_macaddr; ++ ++ u32 entry_id = 0; ++ bool is_pairwise = false; ++ ++ static u8 cam_const_addr[4][6] = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x03} ++ }; ++ static u8 cam_const_broad[] = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++ }; ++ ++ if (clear_all) { ++ u8 idx = 0; ++ u8 cam_offset = 0; ++ u8 clear_number = 5; ++ ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("clear_all\n")); ++ ++ for (idx = 0; idx < clear_number; idx++) { ++ rtl_cam_mark_invalid(hw, cam_offset + idx); ++ rtl_cam_empty_entry(hw, cam_offset + idx); ++ ++ if (idx < 5) { ++ memset(rtlpriv->sec.key_buf[idx], 0, ++ MAX_KEY_LEN); ++ rtlpriv->sec.key_len[idx] = 0; ++ } ++ } ++ ++ } else { ++ switch (enc_algo) { ++ case WEP40_ENCRYPTION: ++ enc_algo = CAM_WEP40; ++ break; ++ case WEP104_ENCRYPTION: ++ enc_algo = CAM_WEP104; ++ break; ++ case TKIP_ENCRYPTION: ++ enc_algo = CAM_TKIP; ++ break; ++ case AESCCMP_ENCRYPTION: ++ enc_algo = CAM_AES; ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("switch case not process\n")); ++ enc_algo = CAM_TKIP; ++ break; ++ } ++ ++ if (is_wepkey || rtlpriv->sec.use_defaultkey) { ++ macaddr = cam_const_addr[key_index]; ++ entry_id = key_index; ++ } else { ++ if (is_group) { ++ macaddr = cam_const_broad; ++ entry_id = key_index; ++ } else { ++ if (mac->opmode == NL80211_IFTYPE_AP) { ++ entry_id = rtl_cam_get_free_entry(hw, ++ p_macaddr); ++ if (entry_id >= TOTAL_CAM_ENTRY) { ++ RT_TRACE(rtlpriv, ++ COMP_SEC, DBG_EMERG, ++ ("Can not find free hw" ++ " security cam entry\n")); ++ return; ++ } ++ } else { ++ entry_id = CAM_PAIRWISE_KEY_POSITION; ++ } ++ ++ key_index = PAIRWISE_KEYIDX; ++ is_pairwise = true; ++ } ++ } ++ ++ if (rtlpriv->sec.key_len[key_index] == 0) { ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ++ ("delete one entry, entry_id is %d\n", ++ entry_id)); ++ if (mac->opmode == NL80211_IFTYPE_AP) ++ rtl_cam_del_entry(hw, p_macaddr); ++ rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); ++ } else { ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ++ ("The insert KEY length is %d\n", ++ rtlpriv->sec.key_len[PAIRWISE_KEYIDX])); ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ++ ("The insert KEY is %x %x\n", ++ rtlpriv->sec.key_buf[0][0], ++ rtlpriv->sec.key_buf[0][1])); ++ ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ++ ("add one entry\n")); ++ if (is_pairwise) { ++ RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD, ++ "Pairwiase Key content :", ++ rtlpriv->sec.pairwise_key, ++ rtlpriv->sec.key_len[PAIRWISE_KEYIDX]); ++ ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ++ ("set Pairwiase key\n")); ++ ++ rtl_cam_add_one_entry(hw, macaddr, key_index, ++ entry_id, enc_algo, ++ CAM_CONFIG_NO_USEDK, ++ rtlpriv->sec.key_buf[key_index]); ++ } else { ++ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ++ ("set group key\n")); ++ ++ if (mac->opmode == NL80211_IFTYPE_ADHOC) { ++ rtl_cam_add_one_entry(hw, ++ rtlefuse->dev_addr, ++ PAIRWISE_KEYIDX, ++ CAM_PAIRWISE_KEY_POSITION, ++ enc_algo, CAM_CONFIG_NO_USEDK, ++ rtlpriv->sec.key_buf[entry_id]); ++ } ++ ++ rtl_cam_add_one_entry(hw, macaddr, key_index, ++ entry_id, enc_algo, ++ CAM_CONFIG_NO_USEDK, ++ rtlpriv->sec.key_buf[entry_id]); ++ } ++ ++ } ++ } ++} ++ ++void rtl92se_suspend(struct ieee80211_hw *hw) ++{ ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ ++ rtlpci->up_first_time = true; ++} ++ ++void rtl92se_resume(struct ieee80211_hw *hw) ++{ ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ u32 val; ++ ++ pci_read_config_dword(rtlpci->pdev, 0x40, &val); ++ if ((val & 0x0000ff00) != 0) ++ pci_write_config_dword(rtlpci->pdev, 0x40, ++ val & 0xffff00ff); ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/hw.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/hw.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/hw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/hw.h 2011-05-05 23:29:49.280487717 +0200 +@@ -0,0 +1,79 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++#ifndef __REALTEK_PCI92SE_HW_H__ ++#define __REALTEK_PCI92SE_HW_H__ ++ ++#define MSR_LINK_MANAGED 2 ++#define MSR_LINK_NONE 0 ++#define MSR_LINK_SHIFT 0 ++#define MSR_LINK_ADHOC 1 ++#define MSR_LINK_MASTER 3 ++ ++enum WIRELESS_NETWORK_TYPE { ++ WIRELESS_11B = 1, ++ WIRELESS_11G = 2, ++ WIRELESS_11A = 4, ++ WIRELESS_11N = 8 ++}; ++ ++void rtl92se_get_hw_reg(struct ieee80211_hw *hw, ++ u8 variable, u8 *val); ++void rtl92se_read_eeprom_info(struct ieee80211_hw *hw); ++void rtl92se_interrupt_recognized(struct ieee80211_hw *hw, ++ u32 *inta, u32 *intb); ++int rtl92se_hw_init(struct ieee80211_hw *hw); ++void rtl92se_card_disable(struct ieee80211_hw *hw); ++void rtl92se_enable_interrupt(struct ieee80211_hw *hw); ++void rtl92se_disable_interrupt(struct ieee80211_hw *hw); ++int rtl92se_set_network_type(struct ieee80211_hw *hw, ++ enum nl80211_iftype type); ++void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); ++void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr); ++void rtl92se_set_qos(struct ieee80211_hw *hw, int aci); ++void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw); ++void rtl92se_set_beacon_interval(struct ieee80211_hw *hw); ++void rtl92se_update_interrupt_mask(struct ieee80211_hw *hw, ++ u32 add_msr, u32 rm_msr); ++void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, ++ u8 *val); ++void rtl92se_update_hal_rate_tbl(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, u8 rssi_level); ++void rtl92se_update_channel_access_setting(struct ieee80211_hw *hw); ++bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, ++ u8 *valid); ++void rtl8192se_gpiobit3_cfg_inputmode(struct ieee80211_hw *hw); ++void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw); ++void rtl92se_set_key(struct ieee80211_hw *hw, ++ u32 key_index, u8 *macaddr, bool is_group, ++ u8 enc_algo, bool is_wepkey, bool clear_all); ++void rtl92se_suspend(struct ieee80211_hw *hw); ++void rtl92se_resume(struct ieee80211_hw *hw); ++ ++#endif ++ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/led.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/led.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/led.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/led.c 2011-05-05 23:29:49.281487729 +0200 +@@ -0,0 +1,149 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#include "../wifi.h" ++#include "../pci.h" ++#include "reg.h" ++#include "led.h" ++ ++static void _rtl92se_init_led(struct ieee80211_hw *hw, ++ struct rtl_led *pled, enum rtl_led_pin ledpin) ++{ ++ pled->hw = hw; ++ pled->ledpin = ledpin; ++ pled->ledon = false; ++} ++ ++void rtl92se_init_sw_leds(struct ieee80211_hw *hw) ++{ ++ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); ++ _rtl92se_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); ++ _rtl92se_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); ++} ++ ++void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) ++{ ++ u8 ledcfg; ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ++ ("LedAddr:%X ledpin=%d\n", LEDCFG, pled->ledpin)); ++ ++ ledcfg = rtl_read_byte(rtlpriv, LEDCFG); ++ ++ switch (pled->ledpin) { ++ case LED_PIN_GPIO0: ++ break; ++ case LED_PIN_LED0: ++ rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0xf0); ++ break; ++ case LED_PIN_LED1: ++ rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0x0f); ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("switch case not process\n")); ++ break; ++ } ++ pled->ledon = true; ++} ++ ++void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); ++ u8 ledcfg; ++ ++ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ++ ("LedAddr:%X ledpin=%d\n", LEDCFG, pled->ledpin)); ++ ++ ledcfg = rtl_read_byte(rtlpriv, LEDCFG); ++ ++ switch (pled->ledpin) { ++ case LED_PIN_GPIO0: ++ break; ++ case LED_PIN_LED0: ++ ledcfg &= 0xf0; ++ if (pcipriv->ledctl.led_opendrain == true) ++ rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(1))); ++ else ++ rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3))); ++ break; ++ case LED_PIN_LED1: ++ ledcfg &= 0x0f; ++ rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3))); ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("switch case not process\n")); ++ break; ++ } ++ pled->ledon = false; ++} ++ ++static void _rtl92se_sw_led_control(struct ieee80211_hw *hw, ++ enum led_ctl_mode ledaction) ++{ ++ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); ++ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); ++ switch (ledaction) { ++ case LED_CTL_POWER_ON: ++ case LED_CTL_LINK: ++ case LED_CTL_NO_LINK: ++ rtl92se_sw_led_on(hw, pLed0); ++ break; ++ case LED_CTL_POWER_OFF: ++ rtl92se_sw_led_off(hw, pLed0); ++ break; ++ default: ++ break; ++ } ++} ++ ++void rtl92se_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ ++ if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) && ++ (ledaction == LED_CTL_TX || ++ ledaction == LED_CTL_RX || ++ ledaction == LED_CTL_SITE_SURVEY || ++ ledaction == LED_CTL_LINK || ++ ledaction == LED_CTL_NO_LINK || ++ ledaction == LED_CTL_START_TO_LINK || ++ ledaction == LED_CTL_POWER_ON)) { ++ return; ++ } ++ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n", ++ ledaction)); ++ ++ _rtl92se_sw_led_control(hw, ledaction); ++} ++ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/led.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/led.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/led.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/led.h 2011-05-05 23:29:49.280487717 +0200 +@@ -0,0 +1,37 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++#ifndef __REALTEK_PCI92SE_LED_H__ ++#define __REALTEK_PCI92SE_LED_H__ ++ ++void rtl92se_init_sw_leds(struct ieee80211_hw *hw); ++void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); ++void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); ++void rtl92se_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); ++ ++#endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/Makefile linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/Makefile +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/Makefile 2011-05-05 23:29:49.279487705 +0200 +@@ -0,0 +1,15 @@ ++rtl8192se-objs := \ ++ dm.o \ ++ fw.o \ ++ hw.o \ ++ led.o \ ++ phy.o \ ++ rf.o \ ++ sw.o \ ++ table.o \ ++ trx.o ++ ++obj-$(CONFIG_RTL8192SE) += rtl8192se.o ++ ++ccflags-y += -D__CHECK_ENDIAN__ ++ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/phy.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/phy.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/phy.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/phy.c 2011-05-05 23:29:49.277487681 +0200 +@@ -0,0 +1,1740 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#include "../wifi.h" ++#include "../pci.h" ++#include "../ps.h" ++#include "reg.h" ++#include "def.h" ++#include "phy.h" ++#include "rf.h" ++#include "dm.h" ++#include "fw.h" ++#include "hw.h" ++#include "table.h" ++ ++static u32 _rtl92s_phy_calculate_bit_shift(u32 bitmask) ++{ ++ u32 i; ++ ++ for (i = 0; i <= 31; i++) { ++ if (((bitmask >> i) & 0x1) == 1) ++ break; ++ } ++ ++ return i; ++} ++ ++u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u32 returnvalue = 0, originalvalue, bitshift; ++ ++ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)\n", ++ regaddr, bitmask)); ++ ++ originalvalue = rtl_read_dword(rtlpriv, regaddr); ++ bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); ++ returnvalue = (originalvalue & bitmask) >> bitshift; ++ ++ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ++ ("BBR MASK=0x%x Addr[0x%x]=0x%x\n", ++ bitmask, regaddr, originalvalue)); ++ ++ return returnvalue; ++ ++} ++ ++void rtl92s_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, ++ u32 data) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u32 originalvalue, bitshift; ++ ++ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," ++ " data(%#x)\n", regaddr, bitmask, data)); ++ ++ if (bitmask != MASKDWORD) { ++ originalvalue = rtl_read_dword(rtlpriv, regaddr); ++ bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); ++ data = ((originalvalue & (~bitmask)) | (data << bitshift)); ++ } ++ ++ rtl_write_dword(rtlpriv, regaddr, data); ++ ++ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," ++ " data(%#x)\n", regaddr, bitmask, data)); ++ ++} ++ ++static u32 _rtl92s_phy_rf_serial_read(struct ieee80211_hw *hw, ++ enum radio_path rfpath, u32 offset) ++{ ++ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; ++ u32 newoffset; ++ u32 tmplong, tmplong2; ++ u8 rfpi_enable = 0; ++ u32 retvalue = 0; ++ ++ offset &= 0x3f; ++ newoffset = offset; ++ ++ tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD); ++ ++ if (rfpath == RF90_PATH_A) ++ tmplong2 = tmplong; ++ else ++ tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD); ++ ++ tmplong2 = (tmplong2 & (~BLSSI_READADDRESS)) | (newoffset << 23) | ++ BLSSI_READEDGE; ++ ++ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, ++ tmplong & (~BLSSI_READEDGE)); ++ ++ mdelay(1); ++ ++ rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); ++ mdelay(1); ++ ++ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong | ++ BLSSI_READEDGE); ++ mdelay(1); ++ ++ if (rfpath == RF90_PATH_A) ++ rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, ++ BIT(8)); ++ else if (rfpath == RF90_PATH_B) ++ rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1, ++ BIT(8)); ++ ++ if (rfpi_enable) ++ retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi, ++ BLSSI_READBACK_DATA); ++ else ++ retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, ++ BLSSI_READBACK_DATA); ++ ++ retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, ++ BLSSI_READBACK_DATA); ++ ++ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFR-%d Addr[0x%x]=0x%x\n", ++ rfpath, pphyreg->rflssi_readback, retvalue)); ++ ++ return retvalue; ++ ++} ++ ++static void _rtl92s_phy_rf_serial_write(struct ieee80211_hw *hw, ++ enum radio_path rfpath, u32 offset, ++ u32 data) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; ++ u32 data_and_addr = 0; ++ u32 newoffset; ++ ++ offset &= 0x3f; ++ newoffset = offset; ++ ++ data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; ++ rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); ++ ++ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFW-%d Addr[0x%x]=0x%x\n", ++ rfpath, pphyreg->rf3wire_offset, data_and_addr)); ++} ++ ++ ++u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, ++ u32 regaddr, u32 bitmask) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u32 original_value, readback_value, bitshift; ++ unsigned long flags; ++ ++ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), " ++ "bitmask(%#x)\n", regaddr, rfpath, bitmask)); ++ ++ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); ++ ++ original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, regaddr); ++ ++ bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); ++ readback_value = (original_value & bitmask) >> bitshift; ++ ++ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); ++ ++ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), " ++ "bitmask(%#x), original_value(%#x)\n", regaddr, rfpath, ++ bitmask, original_value)); ++ ++ return readback_value; ++} ++ ++void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, ++ u32 regaddr, u32 bitmask, u32 data) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ u32 original_value, bitshift; ++ unsigned long flags; ++ ++ if (!((rtlphy->rf_pathmap >> rfpath) & 0x1)) ++ return; ++ ++ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," ++ " data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath)); ++ ++ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); ++ ++ if (bitmask != RFREG_OFFSET_MASK) { ++ original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, ++ regaddr); ++ bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); ++ data = ((original_value & (~bitmask)) | (data << bitshift)); ++ } ++ ++ _rtl92s_phy_rf_serial_write(hw, rfpath, regaddr, data); ++ ++ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); ++ ++ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x), " ++ "data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath)); ++ ++} ++ ++void rtl92s_phy_scan_operation_backup(struct ieee80211_hw *hw, ++ u8 operation) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ ++ if (!is_hal_stop(rtlhal)) { ++ switch (operation) { ++ case SCAN_OPT_BACKUP: ++ rtl92s_phy_set_fw_cmd(hw, FW_CMD_PAUSE_DM_BY_SCAN); ++ break; ++ case SCAN_OPT_RESTORE: ++ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RESUME_DM_BY_SCAN); ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Unknown operation.\n")); ++ break; ++ } ++ } ++} ++ ++void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw, ++ enum nl80211_channel_type ch_type) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ u8 reg_bw_opmode; ++ u8 reg_prsr_rsc; ++ ++ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("Switch to %s bandwidth\n", ++ rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? ++ "20MHz" : "40MHz")); ++ ++ if (rtlphy->set_bwmode_inprogress) ++ return; ++ if (is_hal_stop(rtlhal)) ++ return; ++ ++ rtlphy->set_bwmode_inprogress = true; ++ ++ reg_bw_opmode = rtl_read_byte(rtlpriv, BW_OPMODE); ++ reg_prsr_rsc = rtl_read_byte(rtlpriv, RRSR + 2); ++ ++ switch (rtlphy->current_chan_bw) { ++ case HT_CHANNEL_WIDTH_20: ++ reg_bw_opmode |= BW_OPMODE_20MHZ; ++ rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode); ++ break; ++ case HT_CHANNEL_WIDTH_20_40: ++ reg_bw_opmode &= ~BW_OPMODE_20MHZ; ++ rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode); ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("unknown bandwidth: %#X\n", ++ rtlphy->current_chan_bw)); ++ break; ++ } ++ ++ switch (rtlphy->current_chan_bw) { ++ case HT_CHANNEL_WIDTH_20: ++ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0); ++ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0); ++ ++ if (rtlhal->version >= VERSION_8192S_BCUT) ++ rtl_write_byte(rtlpriv, RFPGA0_ANALOGPARAMETER2, 0x58); ++ break; ++ case HT_CHANNEL_WIDTH_20_40: ++ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); ++ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); ++ ++ rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND, ++ (mac->cur_40_prime_sc >> 1)); ++ rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); ++ ++ if (rtlhal->version >= VERSION_8192S_BCUT) ++ rtl_write_byte(rtlpriv, RFPGA0_ANALOGPARAMETER2, 0x18); ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); ++ break; ++ } ++ ++ rtl92s_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); ++ rtlphy->set_bwmode_inprogress = false; ++ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); ++} ++ ++static bool _rtl92s_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, ++ u32 cmdtableidx, u32 cmdtablesz, enum swchnlcmd_id cmdid, ++ u32 para1, u32 para2, u32 msdelay) ++{ ++ struct swchnlcmd *pcmd; ++ ++ if (cmdtable == NULL) { ++ RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); ++ return false; ++ } ++ ++ if (cmdtableidx >= cmdtablesz) ++ return false; ++ ++ pcmd = cmdtable + cmdtableidx; ++ pcmd->cmdid = cmdid; ++ pcmd->para1 = para1; ++ pcmd->para2 = para2; ++ pcmd->msdelay = msdelay; ++ ++ return true; ++} ++ ++static bool _rtl92s_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, ++ u8 channel, u8 *stage, u8 *step, u32 *delay) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct swchnlcmd precommoncmd[MAX_PRECMD_CNT]; ++ u32 precommoncmdcnt; ++ struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT]; ++ u32 postcommoncmdcnt; ++ struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT]; ++ u32 rfdependcmdcnt; ++ struct swchnlcmd *currentcmd = NULL; ++ u8 rfpath; ++ u8 num_total_rfpath = rtlphy->num_total_rfpath; ++ ++ precommoncmdcnt = 0; ++ _rtl92s_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, ++ MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0); ++ _rtl92s_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, ++ MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); ++ ++ postcommoncmdcnt = 0; ++ ++ _rtl92s_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, ++ MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0); ++ ++ rfdependcmdcnt = 0; ++ ++ RT_ASSERT((channel >= 1 && channel <= 14), ++ ("illegal channel for Zebra: %d\n", channel)); ++ ++ _rtl92s_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, ++ MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG, ++ RF_CHNLBW, channel, 10); ++ ++ _rtl92s_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, ++ MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0); ++ ++ do { ++ switch (*stage) { ++ case 0: ++ currentcmd = &precommoncmd[*step]; ++ break; ++ case 1: ++ currentcmd = &rfdependcmd[*step]; ++ break; ++ case 2: ++ currentcmd = &postcommoncmd[*step]; ++ break; ++ } ++ ++ if (currentcmd->cmdid == CMDID_END) { ++ if ((*stage) == 2) { ++ return true; ++ } else { ++ (*stage)++; ++ (*step) = 0; ++ continue; ++ } ++ } ++ ++ switch (currentcmd->cmdid) { ++ case CMDID_SET_TXPOWEROWER_LEVEL: ++ rtl92s_phy_set_txpower(hw, channel); ++ break; ++ case CMDID_WRITEPORT_ULONG: ++ rtl_write_dword(rtlpriv, currentcmd->para1, ++ currentcmd->para2); ++ break; ++ case CMDID_WRITEPORT_USHORT: ++ rtl_write_word(rtlpriv, currentcmd->para1, ++ (u16)currentcmd->para2); ++ break; ++ case CMDID_WRITEPORT_UCHAR: ++ rtl_write_byte(rtlpriv, currentcmd->para1, ++ (u8)currentcmd->para2); ++ break; ++ case CMDID_RF_WRITEREG: ++ for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) { ++ rtlphy->rfreg_chnlval[rfpath] = ++ ((rtlphy->rfreg_chnlval[rfpath] & ++ 0xfffffc00) | currentcmd->para2); ++ rtl_set_rfreg(hw, (enum radio_path)rfpath, ++ currentcmd->para1, ++ RFREG_OFFSET_MASK, ++ rtlphy->rfreg_chnlval[rfpath]); ++ } ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("switch case not process\n")); ++ break; ++ } ++ ++ break; ++ } while (true); ++ ++ (*delay) = currentcmd->msdelay; ++ (*step)++; ++ return false; ++} ++ ++u8 rtl92s_phy_sw_chnl(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ u32 delay; ++ bool ret; ++ ++ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ++ ("switch to channel%d\n", ++ rtlphy->current_channel)); ++ ++ if (rtlphy->sw_chnl_inprogress) ++ return 0; ++ ++ if (rtlphy->set_bwmode_inprogress) ++ return 0; ++ ++ if (is_hal_stop(rtlhal)) ++ return 0; ++ ++ rtlphy->sw_chnl_inprogress = true; ++ rtlphy->sw_chnl_stage = 0; ++ rtlphy->sw_chnl_step = 0; ++ ++ do { ++ if (!rtlphy->sw_chnl_inprogress) ++ break; ++ ++ ret = _rtl92s_phy_sw_chnl_step_by_step(hw, ++ rtlphy->current_channel, ++ &rtlphy->sw_chnl_stage, ++ &rtlphy->sw_chnl_step, &delay); ++ if (!ret) { ++ if (delay > 0) ++ mdelay(delay); ++ else ++ continue; ++ } else { ++ rtlphy->sw_chnl_inprogress = false; ++ } ++ break; ++ } while (true); ++ ++ rtlphy->sw_chnl_inprogress = false; ++ ++ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); ++ ++ return 1; ++} ++ ++static void _rtl92se_phy_set_rf_sleep(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u8 u1btmp; ++ ++ u1btmp = rtl_read_byte(rtlpriv, LDOV12D_CTRL); ++ u1btmp |= BIT(0); ++ ++ rtl_write_byte(rtlpriv, LDOV12D_CTRL, u1btmp); ++ rtl_write_byte(rtlpriv, SPS1_CTRL, 0x0); ++ rtl_write_byte(rtlpriv, TXPAUSE, 0xFF); ++ rtl_write_word(rtlpriv, CMDR, 0x57FC); ++ udelay(100); ++ ++ rtl_write_word(rtlpriv, CMDR, 0x77FC); ++ rtl_write_byte(rtlpriv, PHY_CCA, 0x0); ++ udelay(10); ++ ++ rtl_write_word(rtlpriv, CMDR, 0x37FC); ++ udelay(10); ++ ++ rtl_write_word(rtlpriv, CMDR, 0x77FC); ++ udelay(10); ++ ++ rtl_write_word(rtlpriv, CMDR, 0x57FC); ++ ++ /* we should chnge GPIO to input mode ++ * this will drop away current about 25mA*/ ++ rtl8192se_gpiobit3_cfg_inputmode(hw); ++} ++ ++bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw, ++ enum rf_pwrstate rfpwr_state) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ bool bresult = true; ++ u8 i, queue_id; ++ struct rtl8192_tx_ring *ring = NULL; ++ ++ if (rfpwr_state == ppsc->rfpwr_state) ++ return false; ++ ++ ppsc->set_rfpowerstate_inprogress = true; ++ ++ switch (rfpwr_state) { ++ case ERFON:{ ++ if ((ppsc->rfpwr_state == ERFOFF) && ++ RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { ++ ++ bool rtstatus; ++ u32 InitializeCount = 0; ++ do { ++ InitializeCount++; ++ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, ++ ("IPS Set eRf nic enable\n")); ++ rtstatus = rtl_ps_enable_nic(hw); ++ } while ((rtstatus != true) && ++ (InitializeCount < 10)); ++ ++ RT_CLEAR_PS_LEVEL(ppsc, ++ RT_RF_OFF_LEVL_HALT_NIC); ++ } else { ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ++ ("awake, sleeped:%d ms " ++ "state_inap:%x\n", ++ jiffies_to_msecs(jiffies - ++ ppsc->last_sleep_jiffies), ++ rtlpriv->psc.state_inap)); ++ ppsc->last_awake_jiffies = jiffies; ++ rtl_write_word(rtlpriv, CMDR, 0x37FC); ++ rtl_write_byte(rtlpriv, TXPAUSE, 0x00); ++ rtl_write_byte(rtlpriv, PHY_CCA, 0x3); ++ } ++ ++ if (mac->link_state == MAC80211_LINKED) ++ rtlpriv->cfg->ops->led_control(hw, ++ LED_CTL_LINK); ++ else ++ rtlpriv->cfg->ops->led_control(hw, ++ LED_CTL_NO_LINK); ++ break; ++ } ++ case ERFOFF:{ ++ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { ++ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, ++ ("IPS Set eRf nic disable\n")); ++ rtl_ps_disable_nic(hw); ++ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); ++ } else { ++ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) ++ rtlpriv->cfg->ops->led_control(hw, ++ LED_CTL_NO_LINK); ++ else ++ rtlpriv->cfg->ops->led_control(hw, ++ LED_CTL_POWER_OFF); ++ } ++ break; ++ } ++ case ERFSLEEP: ++ if (ppsc->rfpwr_state == ERFOFF) ++ break; ++ ++ for (queue_id = 0, i = 0; ++ queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { ++ ring = &pcipriv->dev.tx_ring[queue_id]; ++ if (skb_queue_len(&ring->queue) == 0 || ++ queue_id == BEACON_QUEUE) { ++ queue_id++; ++ continue; ++ } else { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ++ ("eRf Off/Sleep: " ++ "%d times TcbBusyQueue[%d] = " ++ "%d before doze!\n", ++ (i + 1), queue_id, ++ skb_queue_len(&ring->queue))); ++ ++ udelay(10); ++ i++; ++ } ++ ++ if (i >= MAX_DOZE_WAITING_TIMES_9x) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ++ ("\nERFOFF: %d times" ++ "TcbBusyQueue[%d] = %d !\n", ++ MAX_DOZE_WAITING_TIMES_9x, ++ queue_id, ++ skb_queue_len(&ring->queue))); ++ break; ++ } ++ } ++ ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ++ ("Set ERFSLEEP awaked:%d ms\n", ++ jiffies_to_msecs(jiffies - ++ ppsc->last_awake_jiffies))); ++ ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ++ ("sleep awaked:%d ms " ++ "state_inap:%x\n", jiffies_to_msecs(jiffies - ++ ppsc->last_awake_jiffies), ++ rtlpriv->psc.state_inap)); ++ ppsc->last_sleep_jiffies = jiffies; ++ _rtl92se_phy_set_rf_sleep(hw); ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("switch case not process\n")); ++ bresult = false; ++ break; ++ } ++ ++ if (bresult) ++ ppsc->rfpwr_state = rfpwr_state; ++ ++ ppsc->set_rfpowerstate_inprogress = false; ++ ++ return bresult; ++} ++ ++static bool _rtl92s_phy_config_rfpa_bias_current(struct ieee80211_hw *hw, ++ enum radio_path rfpath) ++{ ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ bool rtstatus = true; ++ u32 tmpval = 0; ++ ++ /* If inferiority IC, we have to increase the PA bias current */ ++ if (rtlhal->ic_class != IC_INFERIORITY_A) { ++ tmpval = rtl92s_phy_query_rf_reg(hw, rfpath, RF_IPA, 0xf); ++ rtl92s_phy_set_rf_reg(hw, rfpath, RF_IPA, 0xf, tmpval + 1); ++ } ++ ++ return rtstatus; ++} ++ ++static void _rtl92s_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw, ++ u32 reg_addr, u32 bitmask, u32 data) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ ++ if (reg_addr == RTXAGC_RATE18_06) ++ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] = ++ data; ++ if (reg_addr == RTXAGC_RATE54_24) ++ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] = ++ data; ++ if (reg_addr == RTXAGC_CCK_MCS32) ++ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] = ++ data; ++ if (reg_addr == RTXAGC_MCS03_MCS00) ++ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] = ++ data; ++ if (reg_addr == RTXAGC_MCS07_MCS04) ++ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] = ++ data; ++ if (reg_addr == RTXAGC_MCS11_MCS08) ++ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] = ++ data; ++ if (reg_addr == RTXAGC_MCS15_MCS12) { ++ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] = ++ data; ++ rtlphy->pwrgroup_cnt++; ++ } ++} ++ ++static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ ++ /*RF Interface Sowrtware Control */ ++ rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW; ++ rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW; ++ rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW; ++ rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW; ++ ++ /* RF Interface Readback Value */ ++ rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB; ++ rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB; ++ rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB; ++ rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB; ++ ++ /* RF Interface Output (and Enable) */ ++ rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE; ++ rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE; ++ rtlphy->phyreg_def[RF90_PATH_C].rfintfo = RFPGA0_XC_RFINTERFACEOE; ++ rtlphy->phyreg_def[RF90_PATH_D].rfintfo = RFPGA0_XD_RFINTERFACEOE; ++ ++ /* RF Interface (Output and) Enable */ ++ rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE; ++ rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE; ++ rtlphy->phyreg_def[RF90_PATH_C].rfintfe = RFPGA0_XC_RFINTERFACEOE; ++ rtlphy->phyreg_def[RF90_PATH_D].rfintfe = RFPGA0_XD_RFINTERFACEOE; ++ ++ /* Addr of LSSI. Wirte RF register by driver */ ++ rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = ++ RFPGA0_XA_LSSIPARAMETER; ++ rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = ++ RFPGA0_XB_LSSIPARAMETER; ++ rtlphy->phyreg_def[RF90_PATH_C].rf3wire_offset = ++ RFPGA0_XC_LSSIPARAMETER; ++ rtlphy->phyreg_def[RF90_PATH_D].rf3wire_offset = ++ RFPGA0_XD_LSSIPARAMETER; ++ ++ /* RF parameter */ ++ rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = RFPGA0_XAB_RFPARAMETER; ++ rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = RFPGA0_XAB_RFPARAMETER; ++ rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = RFPGA0_XCD_RFPARAMETER; ++ rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = RFPGA0_XCD_RFPARAMETER; ++ ++ /* Tx AGC Gain Stage (same for all path. Should we remove this?) */ ++ rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE; ++ rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE; ++ rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE; ++ rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE; ++ ++ /* Tranceiver A~D HSSI Parameter-1 */ ++ rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1; ++ rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1; ++ rtlphy->phyreg_def[RF90_PATH_C].rfhssi_para1 = RFPGA0_XC_HSSIPARAMETER1; ++ rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para1 = RFPGA0_XD_HSSIPARAMETER1; ++ ++ /* Tranceiver A~D HSSI Parameter-2 */ ++ rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2; ++ rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2; ++ rtlphy->phyreg_def[RF90_PATH_C].rfhssi_para2 = RFPGA0_XC_HSSIPARAMETER2; ++ rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para2 = RFPGA0_XD_HSSIPARAMETER2; ++ ++ /* RF switch Control */ ++ rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control = ++ RFPGA0_XAB_SWITCHCONTROL; ++ rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control = ++ RFPGA0_XAB_SWITCHCONTROL; ++ rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control = ++ RFPGA0_XCD_SWITCHCONTROL; ++ rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control = ++ RFPGA0_XCD_SWITCHCONTROL; ++ ++ /* AGC control 1 */ ++ rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; ++ rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1; ++ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1; ++ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1; ++ ++ /* AGC control 2 */ ++ rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2; ++ rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2; ++ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2; ++ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2; ++ ++ /* RX AFE control 1 */ ++ rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance = ++ ROFDM0_XARXIQIMBALANCE; ++ rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance = ++ ROFDM0_XBRXIQIMBALANCE; ++ rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance = ++ ROFDM0_XCRXIQIMBALANCE; ++ rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance = ++ ROFDM0_XDRXIQIMBALANCE; ++ ++ /* RX AFE control 1 */ ++ rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; ++ rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE; ++ rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE; ++ rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE; ++ ++ /* Tx AFE control 1 */ ++ rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance = ++ ROFDM0_XATXIQIMBALANCE; ++ rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance = ++ ROFDM0_XBTXIQIMBALANCE; ++ rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance = ++ ROFDM0_XCTXIQIMBALANCE; ++ rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance = ++ ROFDM0_XDTXIQIMBALANCE; ++ ++ /* Tx AFE control 2 */ ++ rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE; ++ rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE; ++ rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE; ++ rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE; ++ ++ /* Tranceiver LSSI Readback */ ++ rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback = ++ RFPGA0_XA_LSSIREADBACK; ++ rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback = ++ RFPGA0_XB_LSSIREADBACK; ++ rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback = ++ RFPGA0_XC_LSSIREADBACK; ++ rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback = ++ RFPGA0_XD_LSSIREADBACK; ++ ++ /* Tranceiver LSSI Readback PI mode */ ++ rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = ++ TRANSCEIVERA_HSPI_READBACK; ++ rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = ++ TRANSCEIVERB_HSPI_READBACK; ++} ++ ++ ++static bool _rtl92s_phy_config_bb(struct ieee80211_hw *hw, u8 configtype) ++{ ++ int i; ++ u32 *phy_reg_table; ++ u32 *agc_table; ++ u16 phy_reg_len, agc_len; ++ ++ agc_len = AGCTAB_ARRAYLENGTH; ++ agc_table = rtl8192seagctab_array; ++ /* Default RF_type: 2T2R */ ++ phy_reg_len = PHY_REG_2T2RARRAYLENGTH; ++ phy_reg_table = rtl8192sephy_reg_2t2rarray; ++ ++ if (configtype == BASEBAND_CONFIG_PHY_REG) { ++ for (i = 0; i < phy_reg_len; i = i + 2) { ++ if (phy_reg_table[i] == 0xfe) ++ mdelay(50); ++ else if (phy_reg_table[i] == 0xfd) ++ mdelay(5); ++ else if (phy_reg_table[i] == 0xfc) ++ mdelay(1); ++ else if (phy_reg_table[i] == 0xfb) ++ udelay(50); ++ else if (phy_reg_table[i] == 0xfa) ++ udelay(5); ++ else if (phy_reg_table[i] == 0xf9) ++ udelay(1); ++ ++ /* Add delay for ECS T20 & LG malow platform, */ ++ udelay(1); ++ ++ rtl92s_phy_set_bb_reg(hw, phy_reg_table[i], MASKDWORD, ++ phy_reg_table[i + 1]); ++ } ++ } else if (configtype == BASEBAND_CONFIG_AGC_TAB) { ++ for (i = 0; i < agc_len; i = i + 2) { ++ rtl92s_phy_set_bb_reg(hw, agc_table[i], MASKDWORD, ++ agc_table[i + 1]); ++ ++ /* Add delay for ECS T20 & LG malow platform */ ++ udelay(1); ++ } ++ } ++ ++ return true; ++} ++ ++static bool _rtl92s_phy_set_bb_to_diff_rf(struct ieee80211_hw *hw, ++ u8 configtype) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ u32 *phy_regarray2xtxr_table; ++ u16 phy_regarray2xtxr_len; ++ int i; ++ ++ if (rtlphy->rf_type == RF_1T1R) { ++ phy_regarray2xtxr_table = rtl8192sephy_changeto_1t1rarray; ++ phy_regarray2xtxr_len = PHY_CHANGETO_1T1RARRAYLENGTH; ++ } else if (rtlphy->rf_type == RF_1T2R) { ++ phy_regarray2xtxr_table = rtl8192sephy_changeto_1t2rarray; ++ phy_regarray2xtxr_len = PHY_CHANGETO_1T2RARRAYLENGTH; ++ } else { ++ return false; ++ } ++ ++ if (configtype == BASEBAND_CONFIG_PHY_REG) { ++ for (i = 0; i < phy_regarray2xtxr_len; i = i + 3) { ++ if (phy_regarray2xtxr_table[i] == 0xfe) ++ mdelay(50); ++ else if (phy_regarray2xtxr_table[i] == 0xfd) ++ mdelay(5); ++ else if (phy_regarray2xtxr_table[i] == 0xfc) ++ mdelay(1); ++ else if (phy_regarray2xtxr_table[i] == 0xfb) ++ udelay(50); ++ else if (phy_regarray2xtxr_table[i] == 0xfa) ++ udelay(5); ++ else if (phy_regarray2xtxr_table[i] == 0xf9) ++ udelay(1); ++ ++ rtl92s_phy_set_bb_reg(hw, phy_regarray2xtxr_table[i], ++ phy_regarray2xtxr_table[i + 1], ++ phy_regarray2xtxr_table[i + 2]); ++ } ++ } ++ ++ return true; ++} ++ ++static bool _rtl92s_phy_config_bb_with_pg(struct ieee80211_hw *hw, ++ u8 configtype) ++{ ++ int i; ++ u32 *phy_table_pg; ++ u16 phy_pg_len; ++ ++ phy_pg_len = PHY_REG_ARRAY_PGLENGTH; ++ phy_table_pg = rtl8192sephy_reg_array_pg; ++ ++ if (configtype == BASEBAND_CONFIG_PHY_REG) { ++ for (i = 0; i < phy_pg_len; i = i + 3) { ++ if (phy_table_pg[i] == 0xfe) ++ mdelay(50); ++ else if (phy_table_pg[i] == 0xfd) ++ mdelay(5); ++ else if (phy_table_pg[i] == 0xfc) ++ mdelay(1); ++ else if (phy_table_pg[i] == 0xfb) ++ udelay(50); ++ else if (phy_table_pg[i] == 0xfa) ++ udelay(5); ++ else if (phy_table_pg[i] == 0xf9) ++ udelay(1); ++ ++ _rtl92s_store_pwrindex_diffrate_offset(hw, ++ phy_table_pg[i], ++ phy_table_pg[i + 1], ++ phy_table_pg[i + 2]); ++ rtl92s_phy_set_bb_reg(hw, phy_table_pg[i], ++ phy_table_pg[i + 1], ++ phy_table_pg[i + 2]); ++ } ++ } ++ ++ return true; ++} ++ ++static bool _rtl92s_phy_bb_config_parafile(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ bool rtstatus = true; ++ ++ /* 1. Read PHY_REG.TXT BB INIT!! */ ++ /* We will separate as 1T1R/1T2R/1T2R_GREEN/2T2R */ ++ if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_2T2R || ++ rtlphy->rf_type == RF_1T1R || rtlphy->rf_type == RF_2T2R_GREEN) { ++ rtstatus = _rtl92s_phy_config_bb(hw, BASEBAND_CONFIG_PHY_REG); ++ ++ if (rtlphy->rf_type != RF_2T2R && ++ rtlphy->rf_type != RF_2T2R_GREEN) ++ /* so we should reconfig BB reg with the right ++ * PHY parameters. */ ++ rtstatus = _rtl92s_phy_set_bb_to_diff_rf(hw, ++ BASEBAND_CONFIG_PHY_REG); ++ } else { ++ rtstatus = false; ++ } ++ ++ if (rtstatus != true) { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ++ ("Write BB Reg Fail!!")); ++ goto phy_BB8190_Config_ParaFile_Fail; ++ } ++ ++ /* 2. If EEPROM or EFUSE autoload OK, We must config by ++ * PHY_REG_PG.txt */ ++ if (rtlefuse->autoload_failflag == false) { ++ rtlphy->pwrgroup_cnt = 0; ++ ++ rtstatus = _rtl92s_phy_config_bb_with_pg(hw, ++ BASEBAND_CONFIG_PHY_REG); ++ } ++ if (rtstatus != true) { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ++ ("_rtl92s_phy_bb_config_parafile(): " ++ "BB_PG Reg Fail!!")); ++ goto phy_BB8190_Config_ParaFile_Fail; ++ } ++ ++ /* 3. BB AGC table Initialization */ ++ rtstatus = _rtl92s_phy_config_bb(hw, BASEBAND_CONFIG_AGC_TAB); ++ ++ if (rtstatus != true) { ++ printk(KERN_ERR "_rtl92s_phy_bb_config_parafile(): " ++ "AGC Table Fail\n"); ++ goto phy_BB8190_Config_ParaFile_Fail; ++ } ++ ++ /* Check if the CCK HighPower is turned ON. */ ++ /* This is used to calculate PWDB. */ ++ rtlphy->cck_high_power = (bool)(rtl92s_phy_query_bb_reg(hw, ++ RFPGA0_XA_HSSIPARAMETER2, 0x200)); ++ ++phy_BB8190_Config_ParaFile_Fail: ++ return rtstatus; ++} ++ ++u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ int i; ++ bool rtstatus = true; ++ u32 *radio_a_table; ++ u32 *radio_b_table; ++ u16 radio_a_tblen, radio_b_tblen; ++ ++ radio_a_tblen = RADIOA_1T_ARRAYLENGTH; ++ radio_a_table = rtl8192seradioa_1t_array; ++ ++ /* Using Green mode array table for RF_2T2R_GREEN */ ++ if (rtlphy->rf_type == RF_2T2R_GREEN) { ++ radio_b_table = rtl8192seradiob_gm_array; ++ radio_b_tblen = RADIOB_GM_ARRAYLENGTH; ++ } else { ++ radio_b_table = rtl8192seradiob_array; ++ radio_b_tblen = RADIOB_ARRAYLENGTH; ++ } ++ ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Radio No %x\n", rfpath)); ++ rtstatus = true; ++ ++ switch (rfpath) { ++ case RF90_PATH_A: ++ for (i = 0; i < radio_a_tblen; i = i + 2) { ++ if (radio_a_table[i] == 0xfe) ++ /* Delay specific ms. Only RF configuration ++ * requires delay. */ ++ mdelay(50); ++ else if (radio_a_table[i] == 0xfd) ++ mdelay(5); ++ else if (radio_a_table[i] == 0xfc) ++ mdelay(1); ++ else if (radio_a_table[i] == 0xfb) ++ udelay(50); ++ else if (radio_a_table[i] == 0xfa) ++ udelay(5); ++ else if (radio_a_table[i] == 0xf9) ++ udelay(1); ++ else ++ rtl92s_phy_set_rf_reg(hw, rfpath, ++ radio_a_table[i], ++ MASK20BITS, ++ radio_a_table[i + 1]); ++ ++ /* Add delay for ECS T20 & LG malow platform */ ++ udelay(1); ++ } ++ ++ /* PA Bias current for inferiority IC */ ++ _rtl92s_phy_config_rfpa_bias_current(hw, rfpath); ++ break; ++ case RF90_PATH_B: ++ for (i = 0; i < radio_b_tblen; i = i + 2) { ++ if (radio_b_table[i] == 0xfe) ++ /* Delay specific ms. Only RF configuration ++ * requires delay.*/ ++ mdelay(50); ++ else if (radio_b_table[i] == 0xfd) ++ mdelay(5); ++ else if (radio_b_table[i] == 0xfc) ++ mdelay(1); ++ else if (radio_b_table[i] == 0xfb) ++ udelay(50); ++ else if (radio_b_table[i] == 0xfa) ++ udelay(5); ++ else if (radio_b_table[i] == 0xf9) ++ udelay(1); ++ else ++ rtl92s_phy_set_rf_reg(hw, rfpath, ++ radio_b_table[i], ++ MASK20BITS, ++ radio_b_table[i + 1]); ++ ++ /* Add delay for ECS T20 & LG malow platform */ ++ udelay(1); ++ } ++ break; ++ case RF90_PATH_C: ++ ; ++ break; ++ case RF90_PATH_D: ++ ; ++ break; ++ default: ++ break; ++ } ++ ++ return rtstatus; ++} ++ ++ ++bool rtl92s_phy_mac_config(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u32 i; ++ u32 arraylength; ++ u32 *ptraArray; ++ ++ arraylength = MAC_2T_ARRAYLENGTH; ++ ptraArray = rtl8192semac_2t_array; ++ ++ for (i = 0; i < arraylength; i = i + 2) ++ rtl_write_byte(rtlpriv, ptraArray[i], (u8)ptraArray[i + 1]); ++ ++ return true; ++} ++ ++ ++bool rtl92s_phy_bb_config(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ bool rtstatus = true; ++ u8 pathmap, index, rf_num = 0; ++ u8 path1, path2; ++ ++ _rtl92s_phy_init_register_definition(hw); ++ ++ /* Config BB and AGC */ ++ rtstatus = _rtl92s_phy_bb_config_parafile(hw); ++ ++ ++ /* Check BB/RF confiuration setting. */ ++ /* We only need to configure RF which is turned on. */ ++ path1 = (u8)(rtl92s_phy_query_bb_reg(hw, RFPGA0_TXINFO, 0xf)); ++ mdelay(10); ++ path2 = (u8)(rtl92s_phy_query_bb_reg(hw, ROFDM0_TRXPATHENABLE, 0xf)); ++ pathmap = path1 | path2; ++ ++ rtlphy->rf_pathmap = pathmap; ++ for (index = 0; index < 4; index++) { ++ if ((pathmap >> index) & 0x1) ++ rf_num++; ++ } ++ ++ if ((rtlphy->rf_type == RF_1T1R && rf_num != 1) || ++ (rtlphy->rf_type == RF_1T2R && rf_num != 2) || ++ (rtlphy->rf_type == RF_2T2R && rf_num != 2) || ++ (rtlphy->rf_type == RF_2T2R_GREEN && rf_num != 2)) { ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ++ ("RF_Type(%x) does not match " ++ "RF_Num(%x)!!\n", rtlphy->rf_type, rf_num)); ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ++ ("path1 0x%x, path2 0x%x, pathmap " ++ "0x%x\n", path1, path2, pathmap)); ++ } ++ ++ return rtstatus; ++} ++ ++bool rtl92s_phy_rf_config(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ ++ /* Initialize general global value */ ++ if (rtlphy->rf_type == RF_1T1R) ++ rtlphy->num_total_rfpath = 1; ++ else ++ rtlphy->num_total_rfpath = 2; ++ ++ /* Config BB and RF */ ++ return rtl92s_phy_rf6052_config(hw); ++} ++ ++void rtl92s_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ ++ /* read rx initial gain */ ++ rtlphy->default_initialgain[0] = rtl_get_bbreg(hw, ++ ROFDM0_XAAGCCORE1, MASKBYTE0); ++ rtlphy->default_initialgain[1] = rtl_get_bbreg(hw, ++ ROFDM0_XBAGCCORE1, MASKBYTE0); ++ rtlphy->default_initialgain[2] = rtl_get_bbreg(hw, ++ ROFDM0_XCAGCCORE1, MASKBYTE0); ++ rtlphy->default_initialgain[3] = rtl_get_bbreg(hw, ++ ROFDM0_XDAGCCORE1, MASKBYTE0); ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Default initial gain " ++ "(c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x)\n", ++ rtlphy->default_initialgain[0], ++ rtlphy->default_initialgain[1], ++ rtlphy->default_initialgain[2], ++ rtlphy->default_initialgain[3])); ++ ++ /* read framesync */ ++ rtlphy->framesync = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3, MASKBYTE0); ++ rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2, ++ MASKDWORD); ++ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ++ ("Default framesync (0x%x) = 0x%x\n", ++ ROFDM0_RXDETECTOR3, rtlphy->framesync)); ++ ++} ++ ++static void _rtl92s_phy_get_txpower_index(struct ieee80211_hw *hw, u8 channel, ++ u8 *cckpowerlevel, u8 *ofdmpowerLevel) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ u8 index = (channel - 1); ++ ++ /* 1. CCK */ ++ /* RF-A */ ++ cckpowerlevel[0] = rtlefuse->txpwrlevel_cck[0][index]; ++ /* RF-B */ ++ cckpowerlevel[1] = rtlefuse->txpwrlevel_cck[1][index]; ++ ++ /* 2. OFDM for 1T or 2T */ ++ if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_1T1R) { ++ /* Read HT 40 OFDM TX power */ ++ ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_1s[0][index]; ++ ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_1s[1][index]; ++ } else if (rtlphy->rf_type == RF_2T2R) { ++ /* Read HT 40 OFDM TX power */ ++ ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_2s[0][index]; ++ ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_2s[1][index]; ++ } ++} ++ ++static void _rtl92s_phy_ccxpower_indexcheck(struct ieee80211_hw *hw, ++ u8 channel, u8 *cckpowerlevel, u8 *ofdmpowerlevel) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ ++ rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; ++ rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; ++} ++ ++void rtl92s_phy_set_txpower(struct ieee80211_hw *hw, u8 channel) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ /* [0]:RF-A, [1]:RF-B */ ++ u8 cckpowerlevel[2], ofdmpowerLevel[2]; ++ ++ if (rtlefuse->txpwr_fromeprom == false) ++ return; ++ ++ /* Mainly we use RF-A Tx Power to write the Tx Power registers, ++ * but the RF-B Tx Power must be calculated by the antenna diff. ++ * So we have to rewrite Antenna gain offset register here. ++ * Please refer to BB register 0x80c ++ * 1. For CCK. ++ * 2. For OFDM 1T or 2T */ ++ _rtl92s_phy_get_txpower_index(hw, channel, &cckpowerlevel[0], ++ &ofdmpowerLevel[0]); ++ ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("Channel-%d, cckPowerLevel (A / B) = " ++ "0x%x / 0x%x, ofdmPowerLevel (A / B) = 0x%x / 0x%x\n", ++ channel, cckpowerlevel[0], cckpowerlevel[1], ++ ofdmpowerLevel[0], ofdmpowerLevel[1])); ++ ++ _rtl92s_phy_ccxpower_indexcheck(hw, channel, &cckpowerlevel[0], ++ &ofdmpowerLevel[0]); ++ ++ rtl92s_phy_rf6052_set_ccktxpower(hw, cckpowerlevel[0]); ++ rtl92s_phy_rf6052_set_ofdmtxpower(hw, &ofdmpowerLevel[0], channel); ++ ++} ++ ++void rtl92s_phy_chk_fwcmd_iodone(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u16 pollingcnt = 10000; ++ u32 tmpvalue; ++ ++ /* Make sure that CMD IO has be accepted by FW. */ ++ do { ++ udelay(10); ++ ++ tmpvalue = rtl_read_dword(rtlpriv, WFM5); ++ if (tmpvalue == 0) ++ break; ++ } while (--pollingcnt); ++ ++ if (pollingcnt == 0) ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Set FW Cmd fail!!\n")); ++} ++ ++ ++static void _rtl92s_phy_set_fwcmd_io(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ u32 input, current_aid = 0; ++ ++ if (is_hal_stop(rtlhal)) ++ return; ++ ++ /* We re-map RA related CMD IO to combinational ones */ ++ /* if FW version is v.52 or later. */ ++ switch (rtlhal->current_fwcmd_io) { ++ case FW_CMD_RA_REFRESH_N: ++ rtlhal->current_fwcmd_io = FW_CMD_RA_REFRESH_N_COMB; ++ break; ++ case FW_CMD_RA_REFRESH_BG: ++ rtlhal->current_fwcmd_io = FW_CMD_RA_REFRESH_BG_COMB; ++ break; ++ default: ++ break; ++ } ++ ++ switch (rtlhal->current_fwcmd_io) { ++ case FW_CMD_RA_RESET: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ++ ("FW_CMD_RA_RESET\n")); ++ rtl_write_dword(rtlpriv, WFM5, FW_RA_RESET); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ break; ++ case FW_CMD_RA_ACTIVE: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ++ ("FW_CMD_RA_ACTIVE\n")); ++ rtl_write_dword(rtlpriv, WFM5, FW_RA_ACTIVE); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ break; ++ case FW_CMD_RA_REFRESH_N: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ++ ("FW_CMD_RA_REFRESH_N\n")); ++ input = FW_RA_REFRESH; ++ rtl_write_dword(rtlpriv, WFM5, input); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ rtl_write_dword(rtlpriv, WFM5, FW_RA_ENABLE_RSSI_MASK); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ break; ++ case FW_CMD_RA_REFRESH_BG: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ++ ("FW_CMD_RA_REFRESH_BG\n")); ++ rtl_write_dword(rtlpriv, WFM5, FW_RA_REFRESH); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ rtl_write_dword(rtlpriv, WFM5, FW_RA_DISABLE_RSSI_MASK); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ break; ++ case FW_CMD_RA_REFRESH_N_COMB: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ++ ("FW_CMD_RA_REFRESH_N_COMB\n")); ++ input = FW_RA_IOT_N_COMB; ++ rtl_write_dword(rtlpriv, WFM5, input); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ break; ++ case FW_CMD_RA_REFRESH_BG_COMB: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ++ ("FW_CMD_RA_REFRESH_BG_COMB\n")); ++ input = FW_RA_IOT_BG_COMB; ++ rtl_write_dword(rtlpriv, WFM5, input); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ break; ++ case FW_CMD_IQK_ENABLE: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ++ ("FW_CMD_IQK_ENABLE\n")); ++ rtl_write_dword(rtlpriv, WFM5, FW_IQK_ENABLE); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ break; ++ case FW_CMD_PAUSE_DM_BY_SCAN: ++ /* Lower initial gain */ ++ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, 0x17); ++ rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, 0x17); ++ /* CCA threshold */ ++ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x40); ++ break; ++ case FW_CMD_RESUME_DM_BY_SCAN: ++ /* CCA threshold */ ++ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); ++ rtl92s_phy_set_txpower(hw, rtlphy->current_channel); ++ break; ++ case FW_CMD_HIGH_PWR_DISABLE: ++ if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) ++ break; ++ ++ /* Lower initial gain */ ++ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, 0x17); ++ rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, 0x17); ++ /* CCA threshold */ ++ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x40); ++ break; ++ case FW_CMD_HIGH_PWR_ENABLE: ++ if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) || ++ (rtlpriv->dm.dynamic_txpower_enable == true)) ++ break; ++ ++ /* CCA threshold */ ++ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); ++ break; ++ case FW_CMD_LPS_ENTER: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ++ ("FW_CMD_LPS_ENTER\n")); ++ current_aid = rtlpriv->mac80211.assoc_id; ++ rtl_write_dword(rtlpriv, WFM5, (FW_LPS_ENTER | ++ ((current_aid | 0xc000) << 8))); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ /* FW set TXOP disable here, so disable EDCA ++ * turbo mode until driver leave LPS */ ++ break; ++ case FW_CMD_LPS_LEAVE: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ++ ("FW_CMD_LPS_LEAVE\n")); ++ rtl_write_dword(rtlpriv, WFM5, FW_LPS_LEAVE); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ break; ++ case FW_CMD_ADD_A2_ENTRY: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ++ ("FW_CMD_ADD_A2_ENTRY\n")); ++ rtl_write_dword(rtlpriv, WFM5, FW_ADD_A2_ENTRY); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ break; ++ case FW_CMD_CTRL_DM_BY_DRIVER: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ++ ("FW_CMD_CTRL_DM_BY_DRIVER\n")); ++ rtl_write_dword(rtlpriv, WFM5, FW_CTRL_DM_BY_DRIVER); ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ break; ++ ++ default: ++ break; ++ } ++ ++ rtl92s_phy_chk_fwcmd_iodone(hw); ++ ++ /* Clear FW CMD operation flag. */ ++ rtlhal->set_fwcmd_inprogress = false; ++} ++ ++bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ u32 fw_param = FW_CMD_IO_PARA_QUERY(rtlpriv); ++ u16 fw_cmdmap = FW_CMD_IO_QUERY(rtlpriv); ++ bool bPostProcessing = false; ++ ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ++ ("Set FW Cmd(%#x), set_fwcmd_inprogress(%d)\n", ++ fw_cmdio, rtlhal->set_fwcmd_inprogress)); ++ ++ do { ++ /* We re-map to combined FW CMD ones if firmware version */ ++ /* is v.53 or later. */ ++ switch (fw_cmdio) { ++ case FW_CMD_RA_REFRESH_N: ++ fw_cmdio = FW_CMD_RA_REFRESH_N_COMB; ++ break; ++ case FW_CMD_RA_REFRESH_BG: ++ fw_cmdio = FW_CMD_RA_REFRESH_BG_COMB; ++ break; ++ default: ++ break; ++ } ++ ++ /* If firmware version is v.62 or later, ++ * use FW_CMD_IO_SET for FW_CMD_CTRL_DM_BY_DRIVER */ ++ if (hal_get_firmwareversion(rtlpriv) >= 0x3E) { ++ if (fw_cmdio == FW_CMD_CTRL_DM_BY_DRIVER) ++ fw_cmdio = FW_CMD_CTRL_DM_BY_DRIVER_NEW; ++ } ++ ++ ++ /* We shall revise all FW Cmd IO into Reg0x364 ++ * DM map table in the future. */ ++ switch (fw_cmdio) { ++ case FW_CMD_RA_INIT: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("RA init!!\n")); ++ fw_cmdmap |= FW_RA_INIT_CTL; ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ /* Clear control flag to sync with FW. */ ++ FW_CMD_IO_CLR(rtlpriv, FW_RA_INIT_CTL); ++ break; ++ case FW_CMD_DIG_DISABLE: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ++ ("Set DIG disable!!\n")); ++ fw_cmdmap &= ~FW_DIG_ENABLE_CTL; ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ break; ++ case FW_CMD_DIG_ENABLE: ++ case FW_CMD_DIG_RESUME: ++ if (!(rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE)) { ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ++ ("Set DIG enable or resume!!\n")); ++ fw_cmdmap |= (FW_DIG_ENABLE_CTL | FW_SS_CTL); ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ } ++ break; ++ case FW_CMD_DIG_HALT: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ++ ("Set DIG halt!!\n")); ++ fw_cmdmap &= ~(FW_DIG_ENABLE_CTL | FW_SS_CTL); ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ break; ++ case FW_CMD_TXPWR_TRACK_THERMAL: { ++ u8 thermalval = 0; ++ fw_cmdmap |= FW_PWR_TRK_CTL; ++ ++ /* Clear FW parameter in terms of thermal parts. */ ++ fw_param &= FW_PWR_TRK_PARAM_CLR; ++ ++ thermalval = rtlpriv->dm.thermalvalue; ++ fw_param |= ((thermalval << 24) | ++ (rtlefuse->thermalmeter[0] << 16)); ++ ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ++ ("Set TxPwr tracking!! " ++ "FwCmdMap(%#x), FwParam(%#x)\n", ++ fw_cmdmap, fw_param)); ++ ++ FW_CMD_PARA_SET(rtlpriv, fw_param); ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ ++ /* Clear control flag to sync with FW. */ ++ FW_CMD_IO_CLR(rtlpriv, FW_PWR_TRK_CTL); ++ } ++ break; ++ /* The following FW CMDs are only compatible to ++ * v.53 or later. */ ++ case FW_CMD_RA_REFRESH_N_COMB: ++ fw_cmdmap |= FW_RA_N_CTL; ++ ++ /* Clear RA BG mode control. */ ++ fw_cmdmap &= ~(FW_RA_BG_CTL | FW_RA_INIT_CTL); ++ ++ /* Clear FW parameter in terms of RA parts. */ ++ fw_param &= FW_RA_PARAM_CLR; ++ ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ++ ("[FW CMD] [New Version] " ++ "Set RA/IOT Comb in n mode!! FwCmdMap(%#x), " ++ "FwParam(%#x)\n", fw_cmdmap, fw_param)); ++ ++ FW_CMD_PARA_SET(rtlpriv, fw_param); ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ ++ /* Clear control flag to sync with FW. */ ++ FW_CMD_IO_CLR(rtlpriv, FW_RA_N_CTL); ++ break; ++ case FW_CMD_RA_REFRESH_BG_COMB: ++ fw_cmdmap |= FW_RA_BG_CTL; ++ ++ /* Clear RA n-mode control. */ ++ fw_cmdmap &= ~(FW_RA_N_CTL | FW_RA_INIT_CTL); ++ /* Clear FW parameter in terms of RA parts. */ ++ fw_param &= FW_RA_PARAM_CLR; ++ ++ FW_CMD_PARA_SET(rtlpriv, fw_param); ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ ++ /* Clear control flag to sync with FW. */ ++ FW_CMD_IO_CLR(rtlpriv, FW_RA_BG_CTL); ++ break; ++ case FW_CMD_IQK_ENABLE: ++ fw_cmdmap |= FW_IQK_CTL; ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ /* Clear control flag to sync with FW. */ ++ FW_CMD_IO_CLR(rtlpriv, FW_IQK_CTL); ++ break; ++ /* The following FW CMD is compatible to v.62 or later. */ ++ case FW_CMD_CTRL_DM_BY_DRIVER_NEW: ++ fw_cmdmap |= FW_DRIVER_CTRL_DM_CTL; ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ break; ++ /* The followed FW Cmds needs post-processing later. */ ++ case FW_CMD_RESUME_DM_BY_SCAN: ++ fw_cmdmap |= (FW_DIG_ENABLE_CTL | ++ FW_HIGH_PWR_ENABLE_CTL | ++ FW_SS_CTL); ++ ++ if (rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE || ++ !digtable.dig_enable_flag) ++ fw_cmdmap &= ~FW_DIG_ENABLE_CTL; ++ ++ if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) || ++ (rtlpriv->dm.dynamic_txpower_enable == true)) ++ fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL; ++ ++ if ((digtable.dig_ext_port_stage == ++ DIG_EXT_PORT_STAGE_0) || ++ (digtable.dig_ext_port_stage == ++ DIG_EXT_PORT_STAGE_1)) ++ fw_cmdmap &= ~FW_DIG_ENABLE_CTL; ++ ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ bPostProcessing = true; ++ break; ++ case FW_CMD_PAUSE_DM_BY_SCAN: ++ fw_cmdmap &= ~(FW_DIG_ENABLE_CTL | ++ FW_HIGH_PWR_ENABLE_CTL | ++ FW_SS_CTL); ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ bPostProcessing = true; ++ break; ++ case FW_CMD_HIGH_PWR_DISABLE: ++ fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL; ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ bPostProcessing = true; ++ break; ++ case FW_CMD_HIGH_PWR_ENABLE: ++ if (!(rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) && ++ (rtlpriv->dm.dynamic_txpower_enable != true)) { ++ fw_cmdmap |= (FW_HIGH_PWR_ENABLE_CTL | ++ FW_SS_CTL); ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ bPostProcessing = true; ++ } ++ break; ++ case FW_CMD_DIG_MODE_FA: ++ fw_cmdmap |= FW_FA_CTL; ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ break; ++ case FW_CMD_DIG_MODE_SS: ++ fw_cmdmap &= ~FW_FA_CTL; ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ break; ++ case FW_CMD_PAPE_CONTROL: ++ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ++ ("[FW CMD] Set PAPE Control\n")); ++ fw_cmdmap &= ~FW_PAPE_CTL_BY_SW_HW; ++ ++ FW_CMD_IO_SET(rtlpriv, fw_cmdmap); ++ break; ++ default: ++ /* Pass to original FW CMD processing callback ++ * routine. */ ++ bPostProcessing = true; ++ break; ++ } ++ } while (false); ++ ++ /* We shall post processing these FW CMD if ++ * variable bPostProcessing is set. */ ++ if (bPostProcessing && !rtlhal->set_fwcmd_inprogress) { ++ rtlhal->set_fwcmd_inprogress = true; ++ /* Update current FW Cmd for callback use. */ ++ rtlhal->current_fwcmd_io = fw_cmdio; ++ } else { ++ return false; ++ } ++ ++ _rtl92s_phy_set_fwcmd_io(hw); ++ return true; ++} ++ ++static void _rtl92s_phy_check_ephy_switchready(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u32 delay = 100; ++ u8 regu1; ++ ++ regu1 = rtl_read_byte(rtlpriv, 0x554); ++ while ((regu1 & BIT(5)) && (delay > 0)) { ++ regu1 = rtl_read_byte(rtlpriv, 0x554); ++ delay--; ++ /* We delay only 50us to prevent ++ * being scheduled out. */ ++ udelay(50); ++ } ++} ++ ++void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); ++ ++ /* The way to be capable to switch clock request ++ * when the PG setting does not support clock request. ++ * This is the backdoor solution to switch clock ++ * request before ASPM or D3. */ ++ rtl_write_dword(rtlpriv, 0x540, 0x73c11); ++ rtl_write_dword(rtlpriv, 0x548, 0x2407c); ++ ++ /* Switch EPHY parameter!!!! */ ++ rtl_write_word(rtlpriv, 0x550, 0x1000); ++ rtl_write_byte(rtlpriv, 0x554, 0x20); ++ _rtl92s_phy_check_ephy_switchready(hw); ++ ++ rtl_write_word(rtlpriv, 0x550, 0xa0eb); ++ rtl_write_byte(rtlpriv, 0x554, 0x3e); ++ _rtl92s_phy_check_ephy_switchready(hw); ++ ++ rtl_write_word(rtlpriv, 0x550, 0xff80); ++ rtl_write_byte(rtlpriv, 0x554, 0x39); ++ _rtl92s_phy_check_ephy_switchready(hw); ++ ++ /* Delay L1 enter time */ ++ if (ppsc->support_aspm && !ppsc->support_backdoor) ++ rtl_write_byte(rtlpriv, 0x560, 0x40); ++ else ++ rtl_write_byte(rtlpriv, 0x560, 0x00); ++ ++} ++ ++void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 BeaconInterval) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ rtl_write_dword(rtlpriv, WFM5, 0xF1000000 | (BeaconInterval << 8)); ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/phy.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/phy.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/phy.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/phy.h 2011-05-05 23:29:49.278487693 +0200 +@@ -0,0 +1,101 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++#ifndef __RTL92S_PHY_H__ ++#define __RTL92S_PHY_H__ ++ ++#define MAX_TXPWR_IDX_NMODE_92S 63 ++#define MAX_DOZE_WAITING_TIMES_9x 64 ++ ++/* 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 RF90_PATH_MAX 4 ++ ++enum version_8192s { ++ VERSION_8192S_ACUT, ++ VERSION_8192S_BCUT, ++ VERSION_8192S_CCUT ++}; ++ ++enum swchnlcmd_id { ++ CMDID_END, ++ CMDID_SET_TXPOWEROWER_LEVEL, ++ CMDID_BBREGWRITE10, ++ CMDID_WRITEPORT_ULONG, ++ CMDID_WRITEPORT_USHORT, ++ CMDID_WRITEPORT_UCHAR, ++ CMDID_RF_WRITEREG, ++}; ++ ++struct swchnlcmd { ++ enum swchnlcmd_id cmdid; ++ u32 para1; ++ u32 para2; ++ u32 msdelay; ++}; ++ ++enum baseband_config_type { ++ /* Radio Path A */ ++ BASEBAND_CONFIG_PHY_REG = 0, ++ /* Radio Path B */ ++ BASEBAND_CONFIG_AGC_TAB = 1, ++}; ++ ++#define hal_get_firmwareversion(rtlpriv) \ ++ (((struct rt_firmware *)(rtlpriv->rtlhal.pfirmware))->firmwareversion) ++ ++u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); ++void rtl92s_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, ++ u32 data); ++void rtl92s_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); ++u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, ++ u32 regaddr, u32 bitmask); ++void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, ++ u32 regaddr, u32 bitmask, u32 data); ++void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw, ++ enum nl80211_channel_type ch_type); ++u8 rtl92s_phy_sw_chnl(struct ieee80211_hw *hw); ++bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw, ++ enum rf_pwrstate rfpower_state); ++bool rtl92s_phy_mac_config(struct ieee80211_hw *hw); ++void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw); ++bool rtl92s_phy_bb_config(struct ieee80211_hw *hw); ++bool rtl92s_phy_rf_config(struct ieee80211_hw *hw); ++void rtl92s_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); ++void rtl92s_phy_set_txpower(struct ieee80211_hw *hw, u8 channel); ++bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fwcmd_io); ++void rtl92s_phy_chk_fwcmd_iodone(struct ieee80211_hw *hw); ++void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 beaconinterval); ++u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) ; ++ ++#endif ++ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/reg.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/reg.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/reg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/reg.h 2011-05-05 23:29:49.283487753 +0200 +@@ -0,0 +1,1188 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++#ifndef __REALTEK_92S_REG_H__ ++#define __REALTEK_92S_REG_H__ ++ ++/* 1. System Configuration Registers */ ++#define REG_SYS_ISO_CTRL 0x0000 ++#define REG_SYS_FUNC_EN 0x0002 ++#define PMC_FSM 0x0004 ++#define SYS_CLKR 0x0008 ++#define EPROM_CMD 0x000A ++#define EE_VPD 0x000C ++#define AFE_MISC 0x0010 ++#define SPS0_CTRL 0x0011 ++#define SPS1_CTRL 0x0018 ++#define RF_CTRL 0x001F ++#define LDOA15_CTRL 0x0020 ++#define LDOV12D_CTRL 0x0021 ++#define LDOHCI12_CTRL 0x0022 ++#define LDO_USB_SDIO 0x0023 ++#define LPLDO_CTRL 0x0024 ++#define AFE_XTAL_CTRL 0x0026 ++#define AFE_PLL_CTRL 0x0028 ++#define REG_EFUSE_CTRL 0x0030 ++#define REG_EFUSE_TEST 0x0034 ++#define PWR_DATA 0x0038 ++#define DBG_PORT 0x003A ++#define DPS_TIMER 0x003C ++#define RCLK_MON 0x003E ++ ++/* 2. Command Control Registers */ ++#define CMDR 0x0040 ++#define TXPAUSE 0x0042 ++#define LBKMD_SEL 0x0043 ++#define TCR 0x0044 ++#define RCR 0x0048 ++#define MSR 0x004C ++#define SYSF_CFG 0x004D ++#define RX_PKY_LIMIT 0x004E ++#define MBIDCTRL 0x004F ++ ++/* 3. MACID Setting Registers */ ++#define MACIDR 0x0050 ++#define MACIDR0 0x0050 ++#define MACIDR4 0x0054 ++#define BSSIDR 0x0058 ++#define HWVID 0x005E ++#define MAR 0x0060 ++#define MBIDCAMCONTENT 0x0068 ++#define MBIDCAMCFG 0x0070 ++#define BUILDTIME 0x0074 ++#define BUILDUSER 0x0078 ++ ++#define IDR0 MACIDR0 ++#define IDR4 MACIDR4 ++ ++/* 4. Timing Control Registers */ ++#define TSFR 0x0080 ++#define SLOT_TIME 0x0089 ++#define USTIME 0x008A ++#define SIFS_CCK 0x008C ++#define SIFS_OFDM 0x008E ++#define PIFS_TIME 0x0090 ++#define ACK_TIMEOUT 0x0091 ++#define EIFSTR 0x0092 ++#define BCN_INTERVAL 0x0094 ++#define ATIMWND 0x0096 ++#define BCN_DRV_EARLY_INT 0x0098 ++#define BCN_DMATIME 0x009A ++#define BCN_ERR_THRESH 0x009C ++#define MLT 0x009D ++#define RSVD_MAC_TUNE_US 0x009E ++ ++/* 5. FIFO Control Registers */ ++#define RQPN 0x00A0 ++#define RQPN1 0x00A0 ++#define RQPN2 0x00A1 ++#define RQPN3 0x00A2 ++#define RQPN4 0x00A3 ++#define RQPN5 0x00A4 ++#define RQPN6 0x00A5 ++#define RQPN7 0x00A6 ++#define RQPN8 0x00A7 ++#define RQPN9 0x00A8 ++#define RQPN10 0x00A9 ++#define LD_RQPN 0x00AB ++#define RXFF_BNDY 0x00AC ++#define RXRPT_BNDY 0x00B0 ++#define TXPKTBUF_PGBNDY 0x00B4 ++#define PBP 0x00B5 ++#define RXDRVINFO_SZ 0x00B6 ++#define TXFF_STATUS 0x00B7 ++#define RXFF_STATUS 0x00B8 ++#define TXFF_EMPTY_TH 0x00B9 ++#define SDIO_RX_BLKSZ 0x00BC ++#define RXDMA 0x00BD ++#define RXPKT_NUM 0x00BE ++#define C2HCMD_UDT_SIZE 0x00C0 ++#define C2HCMD_UDT_ADDR 0x00C2 ++#define FIFOPAGE1 0x00C4 ++#define FIFOPAGE2 0x00C8 ++#define FIFOPAGE3 0x00CC ++#define FIFOPAGE4 0x00D0 ++#define FIFOPAGE5 0x00D4 ++#define FW_RSVD_PG_CRTL 0x00D8 ++#define RXDMA_AGG_PG_TH 0x00D9 ++#define TXDESC_MSK 0x00DC ++#define TXRPTFF_RDPTR 0x00E0 ++#define TXRPTFF_WTPTR 0x00E4 ++#define C2HFF_RDPTR 0x00E8 ++#define C2HFF_WTPTR 0x00EC ++#define RXFF0_RDPTR 0x00F0 ++#define RXFF0_WTPTR 0x00F4 ++#define RXFF1_RDPTR 0x00F8 ++#define RXFF1_WTPTR 0x00FC ++#define RXRPT0_RDPTR 0x0100 ++#define RXRPT0_WTPTR 0x0104 ++#define RXRPT1_RDPTR 0x0108 ++#define RXRPT1_WTPTR 0x010C ++#define RX0_UDT_SIZE 0x0110 ++#define RX1PKTNUM 0x0114 ++#define RXFILTERMAP 0x0116 ++#define RXFILTERMAP_GP1 0x0118 ++#define RXFILTERMAP_GP2 0x011A ++#define RXFILTERMAP_GP3 0x011C ++#define BCNQ_CTRL 0x0120 ++#define MGTQ_CTRL 0x0124 ++#define HIQ_CTRL 0x0128 ++#define VOTID7_CTRL 0x012c ++#define VOTID6_CTRL 0x0130 ++#define VITID5_CTRL 0x0134 ++#define VITID4_CTRL 0x0138 ++#define BETID3_CTRL 0x013c ++#define BETID0_CTRL 0x0140 ++#define BKTID2_CTRL 0x0144 ++#define BKTID1_CTRL 0x0148 ++#define CMDQ_CTRL 0x014c ++#define TXPKT_NUM_CTRL 0x0150 ++#define TXQ_PGADD 0x0152 ++#define TXFF_PG_NUM 0x0154 ++#define TRXDMA_STATUS 0x0156 ++ ++/* 6. Adaptive Control Registers */ ++#define INIMCS_SEL 0x0160 ++#define TX_RATE_REG INIMCS_SEL ++#define INIRTSMCS_SEL 0x0180 ++#define RRSR 0x0181 ++#define ARFR0 0x0184 ++#define ARFR1 0x0188 ++#define ARFR2 0x018C ++#define ARFR3 0x0190 ++#define ARFR4 0x0194 ++#define ARFR5 0x0198 ++#define ARFR6 0x019C ++#define ARFR7 0x01A0 ++#define AGGLEN_LMT_H 0x01A7 ++#define AGGLEN_LMT_L 0x01A8 ++#define DARFRC 0x01B0 ++#define RARFRC 0x01B8 ++#define MCS_TXAGC 0x01C0 ++#define CCK_TXAGC 0x01C8 ++ ++/* 7. EDCA Setting Registers */ ++#define EDCAPARA_VO 0x01D0 ++#define EDCAPARA_VI 0x01D4 ++#define EDCAPARA_BE 0x01D8 ++#define EDCAPARA_BK 0x01DC ++#define BCNTCFG 0x01E0 ++#define CWRR 0x01E2 ++#define ACMAVG 0x01E4 ++#define AcmHwCtrl 0x01E7 ++#define VO_ADMTM 0x01E8 ++#define VI_ADMTM 0x01EC ++#define BE_ADMTM 0x01F0 ++#define RETRY_LIMIT 0x01F4 ++#define SG_RATE 0x01F6 ++ ++/* 8. WMAC, BA and CCX related Register. */ ++#define NAV_CTRL 0x0200 ++#define BW_OPMODE 0x0203 ++#define BACAMCMD 0x0204 ++#define BACAMCONTENT 0x0208 ++ ++/* the 0x2xx register WMAC definition */ ++#define LBDLY 0x0210 ++#define FWDLY 0x0211 ++#define HWPC_RX_CTRL 0x0218 ++#define MQIR 0x0220 ++#define MAIR 0x0222 ++#define MSIR 0x0224 ++#define CLM_RESULT 0x0227 ++#define NHM_RPI_CNT 0x0228 ++#define RXERR_RPT 0x0230 ++#define NAV_PROT_LEN 0x0234 ++#define CFEND_TH 0x0236 ++#define AMPDU_MIN_SPACE 0x0237 ++#define TXOP_STALL_CTRL 0x0238 ++ ++/* 9. Security Control Registers */ ++#define REG_RWCAM 0x0240 ++#define REG_WCAMI 0x0244 ++#define REG_RCAMO 0x0248 ++#define REG_CAMDBG 0x024C ++#define REG_SECR 0x0250 ++ ++/* 10. Power Save Control Registers */ ++#define WOW_CTRL 0x0260 ++#define PSSTATUS 0x0261 ++#define PSSWITCH 0x0262 ++#define MIMOPS_WAIT_PERIOD 0x0263 ++#define LPNAV_CTRL 0x0264 ++#define WFM0 0x0270 ++#define WFM1 0x0280 ++#define WFM2 0x0290 ++#define WFM3 0x02A0 ++#define WFM4 0x02B0 ++#define WFM5 0x02C0 ++#define WFCRC 0x02D0 ++#define FW_RPT_REG 0x02c4 ++ ++/* 11. General Purpose Registers */ ++#define PSTIME 0x02E0 ++#define TIMER0 0x02E4 ++#define TIMER1 0x02E8 ++#define GPIO_CTRL 0x02EC ++#define GPIO_IN 0x02EC ++#define GPIO_OUT 0x02ED ++#define GPIO_IO_SEL 0x02EE ++#define GPIO_MOD 0x02EF ++#define GPIO_INTCTRL 0x02F0 ++#define MAC_PINMUX_CFG 0x02F1 ++#define LEDCFG 0x02F2 ++#define PHY_REG 0x02F3 ++#define PHY_REG_DATA 0x02F4 ++#define REG_EFUSE_CLK 0x02F8 ++ ++/* 12. Host Interrupt Status Registers */ ++#define INTA_MASK 0x0300 ++#define ISR 0x0308 ++ ++/* 13. Test Mode and Debug Control Registers */ ++#define DBG_PORT_SWITCH 0x003A ++#define BIST 0x0310 ++#define DBS 0x0314 ++#define CPUINST 0x0318 ++#define CPUCAUSE 0x031C ++#define LBUS_ERR_ADDR 0x0320 ++#define LBUS_ERR_CMD 0x0324 ++#define LBUS_ERR_DATA_L 0x0328 ++#define LBUS_ERR_DATA_H 0x032C ++#define LX_EXCEPTION_ADDR 0x0330 ++#define WDG_CTRL 0x0334 ++#define INTMTU 0x0338 ++#define INTM 0x033A ++#define FDLOCKTURN0 0x033C ++#define FDLOCKTURN1 0x033D ++#define TRXPKTBUF_DBG_DATA 0x0340 ++#define TRXPKTBUF_DBG_CTRL 0x0348 ++#define DPLL 0x034A ++#define CBUS_ERR_ADDR 0x0350 ++#define CBUS_ERR_CMD 0x0354 ++#define CBUS_ERR_DATA_L 0x0358 ++#define CBUS_ERR_DATA_H 0x035C ++#define USB_SIE_INTF_ADDR 0x0360 ++#define USB_SIE_INTF_WD 0x0361 ++#define USB_SIE_INTF_RD 0x0362 ++#define USB_SIE_INTF_CTRL 0x0363 ++#define LBUS_MON_ADDR 0x0364 ++#define LBUS_ADDR_MASK 0x0368 ++ ++/* Boundary is 0x37F */ ++ ++/* 14. PCIE config register */ ++#define TP_POLL 0x0500 ++#define PM_CTRL 0x0502 ++#define PCIF 0x0503 ++ ++#define THPDA 0x0514 ++#define TMDA 0x0518 ++#define TCDA 0x051C ++#define HDA 0x0520 ++#define TVODA 0x0524 ++#define TVIDA 0x0528 ++#define TBEDA 0x052C ++#define TBKDA 0x0530 ++#define TBDA 0x0534 ++#define RCDA 0x0538 ++#define RDQDA 0x053C ++#define DBI_WDATA 0x0540 ++#define DBI_RDATA 0x0544 ++#define DBI_CTRL 0x0548 ++#define MDIO_DATA 0x0550 ++#define MDIO_CTRL 0x0554 ++#define PCI_RPWM 0x0561 ++#define PCI_CPWM 0x0563 ++ ++/* Config register (Offset 0x800-) */ ++#define PHY_CCA 0x803 ++ ++/* Min Spacing related settings. */ ++#define MAX_MSS_DENSITY_2T 0x13 ++#define MAX_MSS_DENSITY_1T 0x0A ++ ++/* Rx DMA Control related settings */ ++#define RXDMA_AGG_EN BIT(7) ++ ++#define RPWM PCI_RPWM ++ ++/* Regsiter Bit and Content definition */ ++ ++#define ISO_MD2PP BIT(0) ++#define ISO_PA2PCIE BIT(3) ++#define ISO_PLL2MD BIT(4) ++#define ISO_PWC_DV2RP BIT(11) ++#define ISO_PWC_RV2RP BIT(12) ++ ++ ++#define FEN_MREGEN BIT(15) ++#define FEN_DCORE BIT(11) ++#define FEN_CPUEN BIT(10) ++ ++#define PAD_HWPD_IDN BIT(22) ++ ++#define SYS_CLKSEL_80M BIT(0) ++#define SYS_PS_CLKSEL BIT(1) ++#define SYS_CPU_CLKSEL BIT(2) ++#define SYS_MAC_CLK_EN BIT(11) ++#define SYS_SWHW_SEL BIT(14) ++#define SYS_FWHW_SEL BIT(15) ++ ++#define CmdEEPROM_En BIT(5) ++#define CmdEERPOMSEL BIT(4) ++#define Cmd9346CR_9356SEL BIT(4) ++ ++#define AFE_MBEN BIT(1) ++#define AFE_BGEN BIT(0) ++ ++#define SPS1_SWEN BIT(1) ++#define SPS1_LDEN BIT(0) ++ ++#define RF_EN BIT(0) ++#define RF_RSTB BIT(1) ++#define RF_SDMRSTB BIT(2) ++ ++#define LDA15_EN BIT(0) ++ ++#define LDV12_EN BIT(0) ++#define LDV12_SDBY BIT(1) ++ ++#define XTAL_GATE_AFE BIT(10) ++ ++#define APLL_EN BIT(0) ++ ++#define AFR_CardBEn BIT(0) ++#define AFR_CLKRUN_SEL BIT(1) ++#define AFR_FuncRegEn BIT(2) ++ ++#define APSDOFF_STATUS BIT(15) ++#define APSDOFF BIT(14) ++#define BBRSTN BIT(13) ++#define BB_GLB_RSTN BIT(12) ++#define SCHEDULE_EN BIT(10) ++#define MACRXEN BIT(9) ++#define MACTXEN BIT(8) ++#define DDMA_EN BIT(7) ++#define FW2HW_EN BIT(6) ++#define RXDMA_EN BIT(5) ++#define TXDMA_EN BIT(4) ++#define HCI_RXDMA_EN BIT(3) ++#define HCI_TXDMA_EN BIT(2) ++ ++#define StopHCCA BIT(6) ++#define StopHigh BIT(5) ++#define StopMgt BIT(4) ++#define StopVO BIT(3) ++#define StopVI BIT(2) ++#define StopBE BIT(1) ++#define StopBK BIT(0) ++ ++#define LBK_NORMAL 0x00 ++#define LBK_MAC_LB (BIT(0) | BIT(1) | BIT(3)) ++#define LBK_MAC_DLB (BIT(0) | BIT(1)) ++#define LBK_DMA_LB (BIT(0) | BIT(1) | BIT(2)) ++ ++#define TCP_OFDL_EN BIT(25) ++#define HWPC_TX_EN BIT(24) ++#define TXDMAPRE2FULL BIT(23) ++#define DISCW BIT(20) ++#define TCRICV BIT(19) ++#define CfendForm BIT(17) ++#define TCRCRC BIT(16) ++#define FAKE_IMEM_EN BIT(15) ++#define TSFRST BIT(9) ++#define TSFEN BIT(8) ++#define FWALLRDY (BIT(0) | BIT(1) | BIT(2) | \ ++ BIT(3) | BIT(4) | BIT(5) | \ ++ BIT(6) | BIT(7)) ++#define FWRDY BIT(7) ++#define BASECHG BIT(6) ++#define IMEM BIT(5) ++#define DMEM_CODE_DONE BIT(4) ++#define EXT_IMEM_CHK_RPT BIT(3) ++#define EXT_IMEM_CODE_DONE BIT(2) ++#define IMEM_CHK_RPT BIT(1) ++#define IMEM_CODE_DONE BIT(0) ++#define IMEM_CODE_DONE BIT(0) ++#define IMEM_CHK_RPT BIT(1) ++#define EMEM_CODE_DONE BIT(2) ++#define EMEM_CHK_RPT BIT(3) ++#define DMEM_CODE_DONE BIT(4) ++#define IMEM_RDY BIT(5) ++#define BASECHG BIT(6) ++#define FWRDY BIT(7) ++#define LOAD_FW_READY (IMEM_CODE_DONE | \ ++ IMEM_CHK_RPT | \ ++ EMEM_CODE_DONE | \ ++ EMEM_CHK_RPT | \ ++ DMEM_CODE_DONE | \ ++ IMEM_RDY | \ ++ BASECHG | \ ++ FWRDY) ++#define TCR_TSFEN BIT(8) ++#define TCR_TSFRST BIT(9) ++#define TCR_FAKE_IMEM_EN BIT(15) ++#define TCR_CRC BIT(16) ++#define TCR_ICV BIT(19) ++#define TCR_DISCW BIT(20) ++#define TCR_HWPC_TX_EN BIT(24) ++#define TCR_TCP_OFDL_EN BIT(25) ++#define TXDMA_INIT_VALUE (IMEM_CHK_RPT | \ ++ EXT_IMEM_CHK_RPT) ++ ++#define RCR_APPFCS BIT(31) ++#define RCR_DIS_ENC_2BYTE BIT(30) ++#define RCR_DIS_AES_2BYTE BIT(29) ++#define RCR_HTC_LOC_CTRL BIT(28) ++#define RCR_ENMBID BIT(27) ++#define RCR_RX_TCPOFDL_EN BIT(26) ++#define RCR_APP_PHYST_RXFF BIT(25) ++#define RCR_APP_PHYST_STAFF BIT(24) ++#define RCR_CBSSID BIT(23) ++#define RCR_APWRMGT BIT(22) ++#define RCR_ADD3 BIT(21) ++#define RCR_AMF BIT(20) ++#define RCR_ACF BIT(19) ++#define RCR_ADF BIT(18) ++#define RCR_APP_MIC BIT(17) ++#define RCR_APP_ICV BIT(16) ++#define RCR_RXFTH BIT(13) ++#define RCR_AICV BIT(12) ++#define RCR_RXDESC_LK_EN BIT(11) ++#define RCR_APP_BA_SSN BIT(6) ++#define RCR_ACRC32 BIT(5) ++#define RCR_RXSHFT_EN BIT(4) ++#define RCR_AB BIT(3) ++#define RCR_AM BIT(2) ++#define RCR_APM BIT(1) ++#define RCR_AAP BIT(0) ++#define RCR_MXDMA_OFFSET 8 ++#define RCR_FIFO_OFFSET 13 ++ ++ ++#define MSR_LINK_MASK ((1 << 0) | (1 << 1)) ++#define MSR_LINK_MANAGED 2 ++#define MSR_LINK_NONE 0 ++#define MSR_LINK_SHIFT 0 ++#define MSR_LINK_ADHOC 1 ++#define MSR_LINK_MASTER 3 ++#define MSR_NOLINK 0x00 ++#define MSR_ADHOC 0x01 ++#define MSR_INFRA 0x02 ++#define MSR_AP 0x03 ++ ++#define ENUART BIT(7) ++#define ENJTAG BIT(3) ++#define BTMODE (BIT(2) | BIT(1)) ++#define ENBT BIT(0) ++ ++#define ENMBID BIT(7) ++#define BCNUM (BIT(6) | BIT(5) | BIT(4)) ++ ++#define USTIME_EDCA 0xFF00 ++#define USTIME_TSF 0x00FF ++ ++#define SIFS_TRX 0xFF00 ++#define SIFS_CTX 0x00FF ++ ++#define ENSWBCN BIT(15) ++#define DRVERLY_TU 0x0FF0 ++#define DRVERLY_US 0x000F ++#define BCN_TCFG_CW_SHIFT 8 ++#define BCN_TCFG_IFS 0 ++ ++#define RRSR_RSC_OFFSET 21 ++#define RRSR_SHORT_OFFSET 23 ++#define RRSR_RSC_BW_40M 0x600000 ++#define RRSR_RSC_UPSUBCHNL 0x400000 ++#define RRSR_RSC_LOWSUBCHNL 0x200000 ++#define RRSR_SHORT 0x800000 ++#define RRSR_1M BIT(0) ++#define RRSR_2M BIT(1) ++#define RRSR_5_5M BIT(2) ++#define RRSR_11M BIT(3) ++#define RRSR_6M BIT(4) ++#define RRSR_9M BIT(5) ++#define RRSR_12M BIT(6) ++#define RRSR_18M BIT(7) ++#define RRSR_24M BIT(8) ++#define RRSR_36M BIT(9) ++#define RRSR_48M BIT(10) ++#define RRSR_54M BIT(11) ++#define RRSR_MCS0 BIT(12) ++#define RRSR_MCS1 BIT(13) ++#define RRSR_MCS2 BIT(14) ++#define RRSR_MCS3 BIT(15) ++#define RRSR_MCS4 BIT(16) ++#define RRSR_MCS5 BIT(17) ++#define RRSR_MCS6 BIT(18) ++#define RRSR_MCS7 BIT(19) ++#define BRSR_AckShortPmb BIT(23) ++ ++#define RATR_1M 0x00000001 ++#define RATR_2M 0x00000002 ++#define RATR_55M 0x00000004 ++#define RATR_11M 0x00000008 ++#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 ++#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 ++#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 ++ ++#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 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 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) ++ ++#define RETRY_LIMIT_SHORT_SHIFT 8 ++#define RETRY_LIMIT_LONG_SHIFT 0 ++ ++#define NAV_UPPER_EN BIT(16) ++#define NAV_UPPER 0xFF00 ++#define NAV_RTSRST 0xFF ++ ++#define BW_OPMODE_20MHZ BIT(2) ++#define BW_OPMODE_5G BIT(1) ++#define BW_OPMODE_11J BIT(0) ++ ++#define RXERR_RPT_RST BIT(27) ++#define RXERR_OFDM_PPDU 0 ++#define RXERR_OFDM_FALSE_ALARM 1 ++#define RXERR_OFDM_MPDU_OK 2 ++#define RXERR_OFDM_MPDU_FAIL 3 ++#define RXERR_CCK_PPDU 4 ++#define RXERR_CCK_FALSE_ALARM 5 ++#define RXERR_CCK_MPDU_OK 6 ++#define RXERR_CCK_MPDU_FAIL 7 ++#define RXERR_HT_PPDU 8 ++#define RXERR_HT_FALSE_ALARM 9 ++#define RXERR_HT_MPDU_TOTAL 10 ++#define RXERR_HT_MPDU_OK 11 ++#define RXERR_HT_MPDU_FAIL 12 ++#define RXERR_RX_FULL_DROP 15 ++ ++#define SCR_TXUSEDK BIT(0) ++#define SCR_RXUSEDK BIT(1) ++#define SCR_TXENCENABLE BIT(2) ++#define SCR_RXENCENABLE BIT(3) ++#define SCR_SKBYA2 BIT(4) ++#define SCR_NOSKMC BIT(5) ++ ++#define CAM_VALID BIT(15) ++#define CAM_NOTVALID 0x0000 ++#define CAM_USEDK BIT(5) ++ ++#define CAM_NONE 0x0 ++#define CAM_WEP40 0x01 ++#define CAM_TKIP 0x02 ++#define CAM_AES 0x04 ++#define CAM_WEP104 0x05 ++ ++#define TOTAL_CAM_ENTRY 32 ++#define HALF_CAM_ENTRY 16 ++ ++#define CAM_WRITE BIT(16) ++#define CAM_READ 0x00000000 ++#define CAM_POLLINIG BIT(31) ++ ++#define WOW_PMEN BIT(0) ++#define WOW_WOMEN BIT(1) ++#define WOW_MAGIC BIT(2) ++#define WOW_UWF BIT(3) ++ ++#define GPIOMUX_EN BIT(3) ++#define GPIOSEL_GPIO 0 ++#define GPIOSEL_PHYDBG 1 ++#define GPIOSEL_BT 2 ++#define GPIOSEL_WLANDBG 3 ++#define GPIOSEL_GPIO_MASK (~(BIT(0)|BIT(1))) ++ ++#define HST_RDBUSY BIT(0) ++#define CPU_WTBUSY BIT(1) ++ ++#define IMR8190_DISABLED 0x0 ++#define IMR_CPUERR BIT(5) ++#define IMR_ATIMEND BIT(4) ++#define IMR_TBDOK BIT(3) ++#define IMR_TBDER BIT(2) ++#define IMR_BCNDMAINT8 BIT(1) ++#define IMR_BCNDMAINT7 BIT(0) ++#define IMR_BCNDMAINT6 BIT(31) ++#define IMR_BCNDMAINT5 BIT(30) ++#define IMR_BCNDMAINT4 BIT(29) ++#define IMR_BCNDMAINT3 BIT(28) ++#define IMR_BCNDMAINT2 BIT(27) ++#define IMR_BCNDMAINT1 BIT(26) ++#define IMR_BCNDOK8 BIT(25) ++#define IMR_BCNDOK7 BIT(24) ++#define IMR_BCNDOK6 BIT(23) ++#define IMR_BCNDOK5 BIT(22) ++#define IMR_BCNDOK4 BIT(21) ++#define IMR_BCNDOK3 BIT(20) ++#define IMR_BCNDOK2 BIT(19) ++#define IMR_BCNDOK1 BIT(18) ++#define IMR_TIMEOUT2 BIT(17) ++#define IMR_TIMEOUT1 BIT(16) ++#define IMR_TXFOVW BIT(15) ++#define IMR_PSTIMEOUT BIT(14) ++#define IMR_BCNINT BIT(13) ++#define IMR_RXFOVW BIT(12) ++#define IMR_RDU BIT(11) ++#define IMR_RXCMDOK BIT(10) ++#define IMR_BDOK BIT(9) ++#define IMR_HIGHDOK BIT(8) ++#define IMR_COMDOK BIT(7) ++#define IMR_MGNTDOK BIT(6) ++#define IMR_HCCADOK BIT(5) ++#define IMR_BKDOK BIT(4) ++#define IMR_BEDOK BIT(3) ++#define IMR_VIDOK BIT(2) ++#define IMR_VODOK BIT(1) ++#define IMR_ROK BIT(0) ++ ++#define TPPOLL_BKQ BIT(0) ++#define TPPOLL_BEQ BIT(1) ++#define TPPOLL_VIQ BIT(2) ++#define TPPOLL_VOQ BIT(3) ++#define TPPOLL_BQ BIT(4) ++#define TPPOLL_CQ BIT(5) ++#define TPPOLL_MQ BIT(6) ++#define TPPOLL_HQ BIT(7) ++#define TPPOLL_HCCAQ BIT(8) ++#define TPPOLL_STOPBK BIT(9) ++#define TPPOLL_STOPBE BIT(10) ++#define TPPOLL_STOPVI BIT(11) ++#define TPPOLL_STOPVO BIT(12) ++#define TPPOLL_STOPMGT BIT(13) ++#define TPPOLL_STOPHIGH BIT(14) ++#define TPPOLL_STOPHCCA BIT(15) ++#define TPPOLL_SHIFT 8 ++ ++#define CCX_CMD_CLM_ENABLE BIT(0) ++#define CCX_CMD_NHM_ENABLE BIT(1) ++#define CCX_CMD_FUNCTION_ENABLE BIT(8) ++#define CCX_CMD_IGNORE_CCA BIT(9) ++#define CCX_CMD_IGNORE_TXON BIT(10) ++#define CCX_CLM_RESULT_READY BIT(16) ++#define CCX_NHM_RESULT_READY BIT(16) ++#define CCX_CMD_RESET 0x0 ++ ++ ++#define HWSET_MAX_SIZE_92S 128 ++#define EFUSE_MAX_SECTION 16 ++#define EFUSE_REAL_CONTENT_LEN 512 ++ ++#define RTL8190_EEPROM_ID 0x8129 ++#define EEPROM_HPON 0x02 ++#define EEPROM_CLK 0x06 ++#define EEPROM_TESTR 0x08 ++ ++#define EEPROM_VID 0x0A ++#define EEPROM_DID 0x0C ++#define EEPROM_SVID 0x0E ++#define EEPROM_SMID 0x10 ++ ++#define EEPROM_MAC_ADDR 0x12 ++#define EEPROM_NODE_ADDRESS_BYTE_0 0x12 ++ ++#define EEPROM_PWDIFF 0x54 ++ ++#define EEPROM_TXPOWERBASE 0x50 ++#define EEPROM_TX_PWR_INDEX_RANGE 28 ++ ++#define EEPROM_TX_PWR_HT20_DIFF 0x62 ++#define DEFAULT_HT20_TXPWR_DIFF 2 ++#define EEPROM_TX_PWR_OFDM_DIFF 0x65 ++ ++#define EEPROM_TXPWRGROUP 0x67 ++#define EEPROM_REGULATORY 0x6D ++ ++#define TX_PWR_SAFETY_CHK 0x6D ++#define EEPROM_TXPWINDEX_CCK_24G 0x5D ++#define EEPROM_TXPWINDEX_OFDM_24G 0x6B ++#define EEPROM_HT2T_CH1_A 0x6c ++#define EEPROM_HT2T_CH7_A 0x6d ++#define EEPROM_HT2T_CH13_A 0x6e ++#define EEPROM_HT2T_CH1_B 0x6f ++#define EEPROM_HT2T_CH7_B 0x70 ++#define EEPROM_HT2T_CH13_B 0x71 ++ ++#define EEPROM_TSSI_A 0x74 ++#define EEPROM_TSSI_B 0x75 ++ ++#define EEPROM_RFIND_POWERDIFF 0x76 ++#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3 ++ ++#define EEPROM_THERMALMETER 0x77 ++#define EEPROM_BLUETOOTH_COEXIST 0x78 ++#define EEPROM_BLUETOOTH_TYPE 0x4f ++ ++#define EEPROM_OPTIONAL 0x78 ++#define EEPROM_WOWLAN 0x78 ++ ++#define EEPROM_CRYSTALCAP 0x79 ++#define EEPROM_CHANNELPLAN 0x7B ++#define EEPROM_VERSION 0x7C ++#define EEPROM_CUSTOMID 0x7A ++#define EEPROM_BOARDTYPE 0x7E ++ ++#define EEPROM_CHANNEL_PLAN_FCC 0x0 ++#define EEPROM_CHANNEL_PLAN_IC 0x1 ++#define EEPROM_CHANNEL_PLAN_ETSI 0x2 ++#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 ++#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 ++#define EEPROM_CHANNEL_PLAN_MKK 0x5 ++#define EEPROM_CHANNEL_PLAN_MKK1 0x6 ++#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 ++#define EEPROM_CHANNEL_PLAN_TELEC 0x8 ++#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 ++#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA ++#define EEPROM_CHANNEL_PLAN_NCC 0xB ++#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 ++ ++#define FW_DIG_DISABLE 0xfd00cc00 ++#define FW_DIG_ENABLE 0xfd000000 ++#define FW_DIG_HALT 0xfd000001 ++#define FW_DIG_RESUME 0xfd000002 ++#define FW_HIGH_PWR_DISABLE 0xfd000008 ++#define FW_HIGH_PWR_ENABLE 0xfd000009 ++#define FW_ADD_A2_ENTRY 0xfd000016 ++#define FW_TXPWR_TRACK_ENABLE 0xfd000017 ++#define FW_TXPWR_TRACK_DISABLE 0xfd000018 ++#define FW_TXPWR_TRACK_THERMAL 0xfd000019 ++#define FW_TXANT_SWITCH_ENABLE 0xfd000023 ++#define FW_TXANT_SWITCH_DISABLE 0xfd000024 ++#define FW_RA_INIT 0xfd000026 ++#define FW_CTRL_DM_BY_DRIVER 0Xfd00002a ++#define FW_RA_IOT_BG_COMB 0xfd000030 ++#define FW_RA_IOT_N_COMB 0xfd000031 ++#define FW_RA_REFRESH 0xfd0000a0 ++#define FW_RA_UPDATE_MASK 0xfd0000a2 ++#define FW_RA_DISABLE 0xfd0000a4 ++#define FW_RA_ACTIVE 0xfd0000a6 ++#define FW_RA_DISABLE_RSSI_MASK 0xfd0000ac ++#define FW_RA_ENABLE_RSSI_MASK 0xfd0000ad ++#define FW_RA_RESET 0xfd0000af ++#define FW_DM_DISABLE 0xfd00aa00 ++#define FW_IQK_ENABLE 0xf0000020 ++#define FW_IQK_SUCCESS 0x0000dddd ++#define FW_IQK_FAIL 0x0000ffff ++#define FW_OP_FAILURE 0xffffffff ++#define FW_TX_FEEDBACK_NONE 0xfb000000 ++#define FW_TX_FEEDBACK_DTM_ENABLE (FW_TX_FEEDBACK_NONE | 0x1) ++#define FW_TX_FEEDBACK_CCX_ENABL (FW_TX_FEEDBACK_NONE | 0x2) ++#define FW_BB_RESET_ENABLE 0xff00000d ++#define FW_BB_RESET_DISABLE 0xff00000e ++#define FW_CCA_CHK_ENABLE 0xff000011 ++#define FW_CCK_RESET_CNT 0xff000013 ++#define FW_LPS_ENTER 0xfe000010 ++#define FW_LPS_LEAVE 0xfe000011 ++#define FW_INDIRECT_READ 0xf2000000 ++#define FW_INDIRECT_WRITE 0xf2000001 ++#define FW_CHAN_SET 0xf3000001 ++ ++#define RFPC 0x5F ++#define RCR_9356SEL BIT(6) ++#define TCR_LRL_OFFSET 0 ++#define TCR_SRL_OFFSET 8 ++#define TCR_MXDMA_OFFSET 21 ++#define TCR_SAT BIT(24) ++#define RCR_MXDMA_OFFSET 8 ++#define RCR_FIFO_OFFSET 13 ++#define RCR_OnlyErlPkt BIT(31) ++#define CWR 0xDC ++#define RETRYCTR 0xDE ++ ++#define CPU_GEN_SYSTEM_RESET 0x00000001 ++ ++#define CCX_COMMAND_REG 0x890 ++#define CLM_PERIOD_REG 0x894 ++#define NHM_PERIOD_REG 0x896 ++ ++#define NHM_THRESHOLD0 0x898 ++#define NHM_THRESHOLD1 0x899 ++#define NHM_THRESHOLD2 0x89A ++#define NHM_THRESHOLD3 0x89B ++#define NHM_THRESHOLD4 0x89C ++#define NHM_THRESHOLD5 0x89D ++#define NHM_THRESHOLD6 0x89E ++#define CLM_RESULT_REG 0x8D0 ++#define NHM_RESULT_REG 0x8D4 ++#define NHM_RPI_COUNTER0 0x8D8 ++#define NHM_RPI_COUNTER1 0x8D9 ++#define NHM_RPI_COUNTER2 0x8DA ++#define NHM_RPI_COUNTER3 0x8DB ++#define NHM_RPI_COUNTER4 0x8DC ++#define NHM_RPI_COUNTER5 0x8DD ++#define NHM_RPI_COUNTER6 0x8DE ++#define NHM_RPI_COUNTER7 0x8DF ++ ++#define HAL_8192S_HW_GPIO_OFF_BIT BIT(3) ++#define HAL_8192S_HW_GPIO_OFF_MASK 0xF7 ++#define HAL_8192S_HW_GPIO_WPS_BIT BIT(4) ++ ++#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_TXPACKETNNM 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 ++ ++#define RF_BB_CMD_ADDR 0x02c0 ++#define RF_BB_CMD_DATA 0x02c4 ++ ++#define RFPGA0_RFMOD 0x800 ++ ++#define RFPGA0_TXINFO 0x804 ++#define RFPGA0_PSDFUNCTION 0x808 ++ ++#define RFPGA0_TXGAINSTAGE 0x80c ++ ++#define RFPGA0_RFTIMING1 0x810 ++#define RFPGA0_RFTIMING2 0x814 ++#define RFPGA0_XA_HSSIPARAMETER1 0x820 ++#define RFPGA0_XA_HSSIPARAMETER2 0x824 ++#define RFPGA0_XB_HSSIPARAMETER1 0x828 ++#define RFPGA0_XB_HSSIPARAMETER2 0x82c ++#define RFPGA0_XC_HSSIPARAMETER1 0x830 ++#define RFPGA0_XC_HSSIPARAMETER2 0x834 ++#define RFPGA0_XD_HSSIPARAMETER1 0x838 ++#define RFPGA0_XD_HSSIPARAMETER2 0x83c ++#define RFPGA0_XA_LSSIPARAMETER 0x840 ++#define RFPGA0_XB_LSSIPARAMETER 0x844 ++#define RFPGA0_XC_LSSIPARAMETER 0x848 ++#define RFPGA0_XD_LSSIPARAMETER 0x84c ++ ++#define RFPGA0_RFWAKEUP_PARAMETER 0x850 ++#define RFPGA0_RFSLEEPUP_PARAMETER 0x854 ++ ++#define RFPGA0_XAB_SWITCHCONTROL 0x858 ++#define RFPGA0_XCD_SWITCHCONTROL 0x85c ++ ++#define RFPGA0_XA_RFINTERFACEOE 0x860 ++#define RFPGA0_XB_RFINTERFACEOE 0x864 ++#define RFPGA0_XC_RFINTERFACEOE 0x868 ++#define RFPGA0_XD_RFINTERFACEOE 0x86c ++ ++#define RFPGA0_XAB_RFINTERFACESW 0x870 ++#define RFPGA0_XCD_RFINTERFACESW 0x874 ++ ++#define RFPGA0_XAB_RFPARAMETER 0x878 ++#define RFPGA0_XCD_RFPARAMETER 0x87c ++ ++#define RFPGA0_ANALOGPARAMETER1 0x880 ++#define RFPGA0_ANALOGPARAMETER2 0x884 ++#define RFPGA0_ANALOGPARAMETER3 0x888 ++#define RFPGA0_ANALOGPARAMETER4 0x88c ++ ++#define RFPGA0_XA_LSSIREADBACK 0x8a0 ++#define RFPGA0_XB_LSSIREADBACK 0x8a4 ++#define RFPGA0_XC_LSSIREADBACK 0x8a8 ++#define RFPGA0_XD_LSSIREADBACK 0x8ac ++ ++#define RFPGA0_PSDREPORT 0x8b4 ++#define TRANSCEIVERA_HSPI_READBACK 0x8b8 ++#define TRANSCEIVERB_HSPI_READBACK 0x8bc ++#define RFPGA0_XAB_RFINTERFACERB 0x8e0 ++#define RFPGA0_XCD_RFINTERFACERB 0x8e4 ++#define RFPGA1_RFMOD 0x900 ++ ++#define RFPGA1_TXBLOCK 0x904 ++#define RFPGA1_DEBUGSELECT 0x908 ++#define RFPGA1_TXINFO 0x90c ++ ++#define RCCK0_SYSTEM 0xa00 ++ ++#define RCCK0_AFESETTING 0xa04 ++#define RCCK0_CCA 0xa08 ++ ++#define RCCK0_RXAGC1 0xa0c ++#define RCCK0_RXAGC2 0xa10 ++ ++#define RCCK0_RXHP 0xa14 ++ ++#define RCCK0_DSPPARAMETER1 0xa18 ++#define RCCK0_DSPPARAMETER2 0xa1c ++ ++#define RCCK0_TXFILTER1 0xa20 ++#define RCCK0_TXFILTER2 0xa24 ++#define RCCK0_DEBUGPORT 0xa28 ++#define RCCK0_FALSEALARMREPORT 0xa2c ++#define RCCK0_TRSSIREPORT 0xa50 ++#define RCCK0_RXREPORT 0xa54 ++#define RCCK0_FACOUNTERLOWER 0xa5c ++#define RCCK0_FACOUNTERUPPER 0xa58 ++ ++#define ROFDM0_LSTF 0xc00 ++ ++#define ROFDM0_TRXPATHENABLE 0xc04 ++#define ROFDM0_TRMUXPAR 0xc08 ++#define ROFDM0_TRSWISOLATION 0xc0c ++ ++#define ROFDM0_XARXAFE 0xc10 ++#define ROFDM0_XARXIQIMBALANCE 0xc14 ++#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 ++#define ROFDM0_RXDETECTOR2 0xc34 ++#define ROFDM0_RXDETECTOR3 0xc38 ++#define ROFDM0_RXDETECTOR4 0xc3c ++ ++#define ROFDM0_RXDSP 0xc40 ++#define ROFDM0_CFO_AND_DAGC 0xc44 ++#define ROFDM0_CCADROP_THRESHOLD 0xc48 ++#define ROFDM0_ECCA_THRESHOLD 0xc4c ++ ++#define ROFDM0_XAAGCCORE1 0xc50 ++#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 ++#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_RXHP_PARAMETER 0xce0 ++#define ROFDM0_TXPSEUDO_NOISE_WGT 0xce4 ++#define ROFDM0_FRAME_SYNC 0xcf0 ++#define ROFDM0_DFSREPORT 0xcf4 ++#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 ROFDM1_LSTF 0xd00 ++#define ROFDM1_TRXPATHENABLE 0xd04 ++ ++#define ROFDM1_CFO 0xd08 ++#define ROFDM1_CSI1 0xd10 ++#define ROFDM1_SBD 0xd14 ++#define ROFDM1_CSI2 0xd18 ++#define ROFDM1_CFOTRACKING 0xd2c ++#define ROFDM1_TRXMESAURE1 0xd34 ++#define ROFDM1_INTF_DET 0xd3c ++#define ROFDM1_PSEUDO_NOISESTATEAB 0xd50 ++#define ROFDM1_PSEUDO_NOISESTATECD 0xd54 ++#define ROFDM1_RX_PSEUDO_NOISE_WGT 0xd58 ++ ++#define ROFDM_PHYCOUNTER1 0xda0 ++#define ROFDM_PHYCOUNTER2 0xda4 ++#define ROFDM_PHYCOUNTER3 0xda8 ++ ++#define ROFDM_SHORT_CFOAB 0xdac ++#define ROFDM_SHORT_CFOCD 0xdb0 ++#define ROFDM_LONG_CFOAB 0xdb4 ++#define ROFDM_LONG_CFOCD 0xdb8 ++#define ROFDM_TAIL_CFOAB 0xdbc ++#define ROFDM_TAIL_CFOCD 0xdc0 ++#define ROFDM_PW_MEASURE1 0xdc4 ++#define ROFDM_PW_MEASURE2 0xdc8 ++#define ROFDM_BW_REPORT 0xdcc ++#define ROFDM_AGC_REPORT 0xdd0 ++#define ROFDM_RXSNR 0xdd4 ++#define ROFDM_RXEVMCSI 0xdd8 ++#define ROFDM_SIG_REPORT 0xddc ++ ++ ++#define RTXAGC_RATE18_06 0xe00 ++#define RTXAGC_RATE54_24 0xe04 ++#define RTXAGC_CCK_MCS32 0xe08 ++#define RTXAGC_MCS03_MCS00 0xe10 ++#define RTXAGC_MCS07_MCS04 0xe14 ++#define RTXAGC_MCS11_MCS08 0xe18 ++#define RTXAGC_MCS15_MCS12 0xe1c ++ ++ ++#define RF_AC 0x00 ++#define RF_IQADJ_G1 0x01 ++#define RF_IQADJ_G2 0x02 ++#define RF_POW_TRSW 0x05 ++#define RF_GAIN_RX 0x06 ++#define RF_GAIN_TX 0x07 ++#define RF_TXM_IDAC 0x08 ++#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_POW_ABILITY 0x17 ++#define RF_MODE_AG 0x18 ++#define RF_CHANNEL 0x18 ++#define RF_CHNLBW 0x18 ++#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 ++#define RF_SYN_G2 0x26 ++#define RF_SYN_G3 0x27 ++#define RF_SYN_G4 0x28 ++#define RF_SYN_G5 0x29 ++#define RF_SYN_G6 0x2A ++#define RF_SYN_G7 0x2B ++#define RF_SYN_G8 0x2C ++ ++#define RF_RCK_OS 0x30 ++#define RF_TXPA_G1 0x31 ++#define RF_TXPA_G2 0x32 ++#define RF_TXPA_G3 0x33 ++ ++#define BRFMOD 0x1 ++#define BCCKEN 0x1000000 ++#define BOFDMEN 0x2000000 ++ ++#define BXBTXAGC 0xf00 ++#define BXCTXAGC 0xf000 ++#define BXDTXAGC 0xf0000 ++ ++#define B3WIRE_DATALENGTH 0x800 ++#define B3WIRE_ADDRESSLENGTH 0x400 ++ ++#define BRFSI_RFENV 0x10 ++ ++#define BLSSI_READADDRESS 0x7f800000 ++#define BLSSI_READEDGE 0x80000000 ++#define BLSSI_READBACK_DATA 0xfffff ++ ++#define BADCLKPHASE 0x4000000 ++ ++#define BCCK_SIDEBAND 0x10 ++ ++#define BTX_AGCRATECCK 0x7f00 ++ ++#define MASKBYTE0 0xff ++#define MASKBYTE1 0xff00 ++#define MASKBYTE2 0xff0000 ++#define MASKBYTE3 0xff000000 ++#define MASKHWORD 0xffff0000 ++#define MASKLWORD 0x0000ffff ++#define MASKDWORD 0xffffffff ++ ++#define MAKS12BITS 0xfffff ++#define MASK20BITS 0xfffff ++#define RFREG_OFFSET_MASK 0xfffff ++ ++#endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/rf.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/rf.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/rf.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/rf.c 2011-05-05 23:29:49.279487705 +0200 +@@ -0,0 +1,546 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#include "../wifi.h" ++#include "reg.h" ++#include "def.h" ++#include "phy.h" ++#include "rf.h" ++#include "dm.h" ++ ++ ++static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel, ++ u8 chnl, u32 *ofdmbase, u32 *mcsbase, ++ u8 *p_final_pwridx) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ u32 pwrbase0, pwrbase1; ++ u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0; ++ u8 i, pwrlevel[4]; ++ ++ for (i = 0; i < 2; i++) ++ pwrlevel[i] = p_pwrlevel[i]; ++ ++ /* We only care about the path A for legacy. */ ++ if (rtlefuse->eeprom_version < 2) { ++ pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_httxpowerdiff & 0xf); ++ } else if (rtlefuse->eeprom_version >= 2) { ++ legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff ++ [RF90_PATH_A][chnl - 1]; ++ ++ /* For legacy OFDM, tx pwr always > HT OFDM pwr. ++ * We do not care Path B ++ * legacy OFDM pwr diff. NO BB register ++ * to notify HW. */ ++ pwrbase0 = pwrlevel[0] + legacy_pwrdiff; ++ } ++ ++ pwrbase0 = (pwrbase0 << 24) | (pwrbase0 << 16) | (pwrbase0 << 8) | ++ pwrbase0; ++ *ofdmbase = pwrbase0; ++ ++ /* MCS rates */ ++ if (rtlefuse->eeprom_version >= 2) { ++ /* Check HT20 to HT40 diff */ ++ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { ++ for (i = 0; i < 2; i++) { ++ /* rf-A, rf-B */ ++ /* HT 20<->40 pwr diff */ ++ ht20_pwrdiff = rtlefuse->txpwr_ht20diff ++ [i][chnl - 1]; ++ ++ if (ht20_pwrdiff < 8) /* 0~+7 */ ++ pwrlevel[i] += ht20_pwrdiff; ++ else /* index8-15=-8~-1 */ ++ pwrlevel[i] -= (16 - ht20_pwrdiff); ++ } ++ } ++ } ++ ++ /* use index of rf-A */ ++ pwrbase1 = pwrlevel[0]; ++ pwrbase1 = (pwrbase1 << 24) | (pwrbase1 << 16) | (pwrbase1 << 8) | ++ pwrbase1; ++ *mcsbase = pwrbase1; ++ ++ /* The following is for Antenna ++ * diff from Ant-B to Ant-A */ ++ p_final_pwridx[0] = pwrlevel[0]; ++ p_final_pwridx[1] = pwrlevel[1]; ++ ++ switch (rtlefuse->eeprom_regulatory) { ++ case 3: ++ /* The following is for calculation ++ * of the power diff for Ant-B to Ant-A. */ ++ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { ++ p_final_pwridx[0] += rtlefuse->pwrgroup_ht40 ++ [RF90_PATH_A][ ++ chnl - 1]; ++ p_final_pwridx[1] += rtlefuse->pwrgroup_ht40 ++ [RF90_PATH_B][ ++ chnl - 1]; ++ } else { ++ p_final_pwridx[0] += rtlefuse->pwrgroup_ht20 ++ [RF90_PATH_A][ ++ chnl - 1]; ++ p_final_pwridx[1] += rtlefuse->pwrgroup_ht20 ++ [RF90_PATH_B][ ++ chnl - 1]; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("40MHz finalpwr_idx " ++ "(A / B) = 0x%x / 0x%x\n", p_final_pwridx[0], ++ p_final_pwridx[1])); ++ } else { ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("20MHz finalpwr_idx " ++ "(A / B) = 0x%x / 0x%x\n", p_final_pwridx[0], ++ p_final_pwridx[1])); ++ } ++} ++ ++static void _rtl92s_set_antennadiff(struct ieee80211_hw *hw, ++ u8 *p_final_pwridx) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ char ant_pwr_diff = 0; ++ u32 u4reg_val = 0; ++ ++ if (rtlphy->rf_type == RF_2T2R) { ++ ant_pwr_diff = p_final_pwridx[1] - p_final_pwridx[0]; ++ ++ /* range is from 7~-8, ++ * index = 0x0~0xf */ ++ if (ant_pwr_diff > 7) ++ ant_pwr_diff = 7; ++ if (ant_pwr_diff < -8) ++ ant_pwr_diff = -8; ++ ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("Antenna Diff from RF-B " ++ "to RF-A = %d (0x%x)\n", ant_pwr_diff, ++ ant_pwr_diff & 0xf)); ++ ++ ant_pwr_diff &= 0xf; ++ } ++ ++ /* Antenna TX power difference */ ++ rtlefuse->antenna_txpwdiff[2] = 0;/* RF-D, don't care */ ++ rtlefuse->antenna_txpwdiff[1] = 0;/* RF-C, don't care */ ++ rtlefuse->antenna_txpwdiff[0] = (u8)(ant_pwr_diff); /* RF-B */ ++ ++ u4reg_val = rtlefuse->antenna_txpwdiff[2] << 8 | ++ rtlefuse->antenna_txpwdiff[1] << 4 | ++ rtlefuse->antenna_txpwdiff[0]; ++ ++ rtl_set_bbreg(hw, RFPGA0_TXGAINSTAGE, (BXBTXAGC | BXCTXAGC | BXDTXAGC), ++ u4reg_val); ++ ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("Write BCD-Diff(0x%x) = 0x%x\n", ++ RFPGA0_TXGAINSTAGE, u4reg_val)); ++} ++ ++static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw, ++ u8 chnl, u8 index, ++ u32 pwrbase0, ++ u32 pwrbase1, ++ u32 *p_outwrite_val) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ u8 i, chnlgroup, pwrdiff_limit[4]; ++ u32 writeval, customer_limit; ++ ++ /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */ ++ switch (rtlefuse->eeprom_regulatory) { ++ case 0: ++ /* Realtek better performance increase power diff ++ * defined by Realtek for large power */ ++ chnlgroup = 0; ++ ++ writeval = rtlphy->mcs_txpwrlevel_origoffset ++ [chnlgroup][index] + ++ ((index < 2) ? pwrbase0 : pwrbase1); ++ ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("RTK better performance, " ++ "writeval = 0x%x\n", writeval)); ++ break; ++ case 1: ++ /* Realtek regulatory increase power diff defined ++ * by Realtek for regulatory */ ++ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { ++ writeval = ((index < 2) ? pwrbase0 : pwrbase1); ++ ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("Realtek regulatory, " ++ "40MHz, writeval = 0x%x\n", writeval)); ++ } else { ++ if (rtlphy->pwrgroup_cnt == 1) ++ chnlgroup = 0; ++ ++ if (rtlphy->pwrgroup_cnt >= 3) { ++ if (chnl <= 3) ++ chnlgroup = 0; ++ else if (chnl >= 4 && chnl <= 8) ++ chnlgroup = 1; ++ else if (chnl > 8) ++ chnlgroup = 2; ++ if (rtlphy->pwrgroup_cnt == 4) ++ chnlgroup++; ++ } ++ ++ writeval = rtlphy->mcs_txpwrlevel_origoffset ++ [chnlgroup][index] ++ + ((index < 2) ? ++ pwrbase0 : pwrbase1); ++ ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("Realtek regulatory, " ++ "20MHz, writeval = 0x%x\n", writeval)); ++ } ++ break; ++ case 2: ++ /* Better regulatory don't increase any power diff */ ++ writeval = ((index < 2) ? pwrbase0 : pwrbase1); ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("Better regulatory, " ++ "writeval = 0x%x\n", writeval)); ++ break; ++ case 3: ++ /* Customer defined power diff. increase power diff ++ defined by customer. */ ++ chnlgroup = 0; ++ ++ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("customer's limit, 40MHz = 0x%x\n", ++ rtlefuse->pwrgroup_ht40 ++ [RF90_PATH_A][chnl - 1])); ++ } else { ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("customer's limit, 20MHz = 0x%x\n", ++ rtlefuse->pwrgroup_ht20 ++ [RF90_PATH_A][chnl - 1])); ++ } ++ ++ for (i = 0; i < 4; i++) { ++ pwrdiff_limit[i] = ++ (u8)((rtlphy->mcs_txpwrlevel_origoffset ++ [chnlgroup][index] & (0x7f << (i * 8))) ++ >> (i * 8)); ++ ++ if (rtlphy->current_chan_bw == ++ HT_CHANNEL_WIDTH_20_40) { ++ if (pwrdiff_limit[i] > ++ rtlefuse->pwrgroup_ht40 ++ [RF90_PATH_A][chnl - 1]) { ++ pwrdiff_limit[i] = ++ rtlefuse->pwrgroup_ht20 ++ [RF90_PATH_A][chnl - 1]; ++ } ++ } else { ++ if (pwrdiff_limit[i] > ++ rtlefuse->pwrgroup_ht20 ++ [RF90_PATH_A][chnl - 1]) { ++ pwrdiff_limit[i] = ++ rtlefuse->pwrgroup_ht20 ++ [RF90_PATH_A][chnl - 1]; ++ } ++ } ++ } ++ ++ customer_limit = (pwrdiff_limit[3] << 24) | ++ (pwrdiff_limit[2] << 16) | ++ (pwrdiff_limit[1] << 8) | ++ (pwrdiff_limit[0]); ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("Customer's limit = 0x%x\n", ++ customer_limit)); ++ ++ writeval = customer_limit + ((index < 2) ? ++ pwrbase0 : pwrbase1); ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("Customer, writeval = " ++ "0x%x\n", writeval)); ++ break; ++ default: ++ chnlgroup = 0; ++ writeval = rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index] + ++ ((index < 2) ? pwrbase0 : pwrbase1); ++ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ++ ("RTK better performance, " ++ "writeval = 0x%x\n", writeval)); ++ break; ++ } ++ ++ if (rtlpriv->dm.dynamic_txhighpower_lvl == TX_HIGH_PWR_LEVEL_LEVEL1) ++ writeval = 0x10101010; ++ else if (rtlpriv->dm.dynamic_txhighpower_lvl == ++ TX_HIGH_PWR_LEVEL_LEVEL2) ++ writeval = 0x0; ++ ++ *p_outwrite_val = writeval; ++ ++} ++ ++static void _rtl92s_write_ofdm_powerreg(struct ieee80211_hw *hw, ++ u8 index, u32 val) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ u16 regoffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c}; ++ u8 i, rfa_pwr[4]; ++ u8 rfa_lower_bound = 0, rfa_upper_bound = 0, rf_pwr_diff = 0; ++ u32 writeval = val; ++ ++ /* If path A and Path B coexist, we must limit Path A tx power. ++ * Protect Path B pwr over or under flow. We need to calculate ++ * upper and lower bound of path A tx power. */ ++ if (rtlphy->rf_type == RF_2T2R) { ++ rf_pwr_diff = rtlefuse->antenna_txpwdiff[0]; ++ ++ /* Diff=-8~-1 */ ++ if (rf_pwr_diff >= 8) { ++ /* Prevent underflow!! */ ++ rfa_lower_bound = 0x10 - rf_pwr_diff; ++ /* if (rf_pwr_diff >= 0) Diff = 0-7 */ ++ } else { ++ rfa_upper_bound = RF6052_MAX_TX_PWR - rf_pwr_diff; ++ } ++ } ++ ++ for (i = 0; i < 4; i++) { ++ rfa_pwr[i] = (u8)((writeval & (0x7f << (i * 8))) >> (i * 8)); ++ if (rfa_pwr[i] > RF6052_MAX_TX_PWR) ++ rfa_pwr[i] = RF6052_MAX_TX_PWR; ++ ++ /* If path A and Path B coexist, we must limit Path A tx power. ++ * Protect Path B pwr over or under flow. We need to calculate ++ * upper and lower bound of path A tx power. */ ++ if (rtlphy->rf_type == RF_2T2R) { ++ /* Diff=-8~-1 */ ++ if (rf_pwr_diff >= 8) { ++ /* Prevent underflow!! */ ++ if (rfa_pwr[i] < rfa_lower_bound) ++ rfa_pwr[i] = rfa_lower_bound; ++ /* Diff = 0-7 */ ++ } else if (rf_pwr_diff >= 1) { ++ /* Prevent overflow */ ++ if (rfa_pwr[i] > rfa_upper_bound) ++ rfa_pwr[i] = rfa_upper_bound; ++ } ++ } ++ ++ } ++ ++ writeval = (rfa_pwr[3] << 24) | (rfa_pwr[2] << 16) | (rfa_pwr[1] << 8) | ++ rfa_pwr[0]; ++ ++ rtl_set_bbreg(hw, regoffset[index], 0x7f7f7f7f, writeval); ++} ++ ++void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw, ++ u8 *p_pwrlevel, u8 chnl) ++{ ++ u32 writeval, pwrbase0, pwrbase1; ++ u8 index = 0; ++ u8 finalpwr_idx[4]; ++ ++ _rtl92s_get_powerbase(hw, p_pwrlevel, chnl, &pwrbase0, &pwrbase1, ++ &finalpwr_idx[0]); ++ _rtl92s_set_antennadiff(hw, &finalpwr_idx[0]); ++ ++ for (index = 0; index < 6; index++) { ++ _rtl92s_get_txpower_writeval_byregulatory(hw, chnl, index, ++ pwrbase0, pwrbase1, &writeval); ++ ++ _rtl92s_write_ofdm_powerreg(hw, index, writeval); ++ } ++} ++ ++void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, u8 pwrlevel) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ u32 txagc = 0; ++ bool dont_inc_cck_or_turboscanoff = false; ++ ++ if (((rtlefuse->eeprom_version >= 2) && ++ (rtlefuse->txpwr_safetyflag == 1)) || ++ ((rtlefuse->eeprom_version >= 2) && ++ (rtlefuse->eeprom_regulatory != 0))) ++ dont_inc_cck_or_turboscanoff = true; ++ ++ if (mac->act_scanning == true) { ++ txagc = 0x3f; ++ if (dont_inc_cck_or_turboscanoff) ++ txagc = pwrlevel; ++ } else { ++ txagc = pwrlevel; ++ ++ if (rtlpriv->dm.dynamic_txhighpower_lvl == ++ TX_HIGH_PWR_LEVEL_LEVEL1) ++ txagc = 0x10; ++ else if (rtlpriv->dm.dynamic_txhighpower_lvl == ++ TX_HIGH_PWR_LEVEL_LEVEL2) ++ txagc = 0x0; ++ } ++ ++ if (txagc > RF6052_MAX_TX_PWR) ++ txagc = RF6052_MAX_TX_PWR; ++ ++ rtl_set_bbreg(hw, RTXAGC_CCK_MCS32, BTX_AGCRATECCK, txagc); ++ ++} ++ ++bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ u32 u4reg_val = 0; ++ u8 rfpath; ++ bool rtstatus = true; ++ struct bb_reg_def *pphyreg; ++ ++ /* Initialize RF */ ++ for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { ++ ++ pphyreg = &rtlphy->phyreg_def[rfpath]; ++ ++ /* Store original RFENV control type */ ++ switch (rfpath) { ++ case RF90_PATH_A: ++ case RF90_PATH_C: ++ u4reg_val = rtl92s_phy_query_bb_reg(hw, ++ pphyreg->rfintfs, ++ BRFSI_RFENV); ++ break; ++ case RF90_PATH_B: ++ case RF90_PATH_D: ++ u4reg_val = rtl92s_phy_query_bb_reg(hw, ++ pphyreg->rfintfs, ++ BRFSI_RFENV << 16); ++ break; ++ } ++ ++ /* Set RF_ENV enable */ ++ rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfe, ++ BRFSI_RFENV << 16, 0x1); ++ ++ /* Set RF_ENV output high */ ++ rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); ++ ++ /* Set bit number of Address and Data for RF register */ ++ rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2, ++ B3WIRE_ADDRESSLENGTH, 0x0); ++ rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2, ++ B3WIRE_DATALENGTH, 0x0); ++ ++ /* Initialize RF fom connfiguration file */ ++ switch (rfpath) { ++ case RF90_PATH_A: ++ rtstatus = rtl92s_phy_config_rf(hw, ++ (enum radio_path)rfpath); ++ break; ++ case RF90_PATH_B: ++ rtstatus = rtl92s_phy_config_rf(hw, ++ (enum radio_path)rfpath); ++ break; ++ case RF90_PATH_C: ++ break; ++ case RF90_PATH_D: ++ break; ++ } ++ ++ /* Restore RFENV control type */ ++ switch (rfpath) { ++ case RF90_PATH_A: ++ case RF90_PATH_C: ++ rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, BRFSI_RFENV, ++ u4reg_val); ++ break; ++ case RF90_PATH_B: ++ case RF90_PATH_D: ++ rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, ++ BRFSI_RFENV << 16, ++ u4reg_val); ++ break; ++ } ++ ++ if (rtstatus != true) { ++ printk(KERN_ERR "Radio[%d] Fail!!", rfpath); ++ goto fail; ++ } ++ ++ } ++ ++ return rtstatus; ++ ++fail: ++ return rtstatus; ++} ++ ++void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ ++ switch (bandwidth) { ++ case HT_CHANNEL_WIDTH_20: ++ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & ++ 0xfffff3ff) | 0x0400); ++ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, ++ rtlphy->rfreg_chnlval[0]); ++ break; ++ case HT_CHANNEL_WIDTH_20_40: ++ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & ++ 0xfffff3ff)); ++ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, ++ rtlphy->rfreg_chnlval[0]); ++ break; ++ default: ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("unknown bandwidth: %#X\n", ++ bandwidth)); ++ break; ++ } ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/rf.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/rf.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/rf.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/rf.h 2011-05-05 23:29:49.280487717 +0200 +@@ -0,0 +1,43 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++#ifndef __INC_RTL92S_RF_H ++#define __INC_RTL92S_RF_H ++ ++#define RF6052_MAX_TX_PWR 0x3F ++ ++void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, ++ u8 bandwidth); ++bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) ; ++void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, ++ u8 powerlevel); ++void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw, ++ u8 *p_pwrlevel, u8 chnl); ++ ++#endif ++ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/sw.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/sw.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/sw.c 2011-05-05 23:29:49.284487765 +0200 +@@ -0,0 +1,421 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#include ++ ++#include "../wifi.h" ++#include "../core.h" ++#include "../pci.h" ++#include "reg.h" ++#include "def.h" ++#include "phy.h" ++#include "dm.h" ++#include "fw.h" ++#include "hw.h" ++#include "sw.h" ++#include "trx.h" ++#include "led.h" ++ ++static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) ++{ ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ ++ /*close ASPM for AMD defaultly */ ++ rtlpci->const_amdpci_aspm = 0; ++ ++ /* ++ * ASPM PS mode. ++ * 0 - Disable ASPM, ++ * 1 - Enable ASPM without Clock Req, ++ * 2 - Enable ASPM with Clock Req, ++ * 3 - Alwyas Enable ASPM with Clock Req, ++ * 4 - Always Enable ASPM without Clock Req. ++ * set defult to RTL8192CE:3 RTL8192E:2 ++ * */ ++ rtlpci->const_pci_aspm = 0; /* changed from 2 due to crashes */ ++ ++ /*Setting for PCI-E device */ ++ rtlpci->const_devicepci_aspm_setting = 0x03; ++ ++ /*Setting for PCI-E bridge */ ++ rtlpci->const_hostpci_aspm_setting = 0x02; ++ ++ /* ++ * In Hw/Sw Radio Off situation. ++ * 0 - Default, ++ * 1 - From ASPM setting without low Mac Pwr, ++ * 2 - From ASPM setting with low Mac Pwr, ++ * 3 - Bus D3 ++ * set default to RTL8192CE:0 RTL8192SE:2 ++ */ ++ rtlpci->const_hwsw_rfoff_d3 = 2; ++ ++ /* ++ * This setting works for those device with ++ * backdoor ASPM setting such as EPHY setting. ++ * 0 - Not support ASPM, ++ * 1 - Support ASPM, ++ * 2 - According to chipset. ++ */ ++ rtlpci->const_support_pciaspm = 2; ++} ++ ++static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ const struct firmware *firmware; ++ struct rt_firmware *pfirmware = NULL; ++ int err = 0; ++ u16 earlyrxthreshold = 7; ++ ++ rtlpriv->dm.dm_initialgain_enable = 1; ++ rtlpriv->dm.dm_flag = 0; ++ rtlpriv->dm.disable_framebursting = 0; ++ rtlpriv->dm.thermalvalue = 0; ++ rtlpriv->dm.useramask = true; ++ ++ /* compatible 5G band 91se just 2.4G band & smsp */ ++ rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; ++ rtlpriv->rtlhal.bandset = BAND_ON_2_4G; ++ rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; ++ ++ rtlpci->transmit_config = 0; ++ ++ rtlpci->receive_config = ++ RCR_APPFCS | ++ RCR_APWRMGT | ++ /*RCR_ADD3 |*/ ++ RCR_AMF | ++ RCR_ADF | ++ RCR_APP_MIC | ++ RCR_APP_ICV | ++ RCR_AICV | ++ /* Accept ICV error, CRC32 Error */ ++ RCR_ACRC32 | ++ RCR_AB | ++ /* Accept Broadcast, Multicast */ ++ RCR_AM | ++ /* Accept Physical match */ ++ RCR_APM | ++ /* Accept Destination Address packets */ ++ /*RCR_AAP |*/ ++ RCR_APP_PHYST_STAFF | ++ /* Accept PHY status */ ++ RCR_APP_PHYST_RXFF | ++ (earlyrxthreshold << RCR_FIFO_OFFSET); ++ ++ rtlpci->irq_mask[0] = (u32) ++ (IMR_ROK | ++ IMR_VODOK | ++ IMR_VIDOK | ++ IMR_BEDOK | ++ IMR_BKDOK | ++ IMR_HCCADOK | ++ IMR_MGNTDOK | ++ IMR_COMDOK | ++ IMR_HIGHDOK | ++ IMR_BDOK | ++ IMR_RXCMDOK | ++ /*IMR_TIMEOUT0 |*/ ++ IMR_RDU | ++ IMR_RXFOVW | ++ IMR_BCNINT ++ /*| IMR_TXFOVW*/ ++ /*| IMR_TBDOK | ++ IMR_TBDER*/); ++ ++ rtlpci->irq_mask[1] = (u32) 0; ++ ++ rtlpci->shortretry_limit = 0x30; ++ rtlpci->longretry_limit = 0x30; ++ ++ rtlpci->first_init = true; ++ ++ /* for LPS & IPS */ ++ rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; ++ rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; ++ rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; ++ rtlpriv->psc.reg_fwctrl_lps = 3; ++ rtlpriv->psc.reg_max_lps_awakeintvl = 5; ++ /* for ASPM, you can close aspm through ++ * set const_support_pciaspm = 0 */ ++ rtl92s_init_aspm_vars(hw); ++ ++ if (rtlpriv->psc.reg_fwctrl_lps == 1) ++ rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; ++ else if (rtlpriv->psc.reg_fwctrl_lps == 2) ++ rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; ++ else if (rtlpriv->psc.reg_fwctrl_lps == 3) ++ rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; ++ ++ /* for firmware buf */ ++ rtlpriv->rtlhal.pfirmware = vzalloc(sizeof(struct rt_firmware)); ++ if (!rtlpriv->rtlhal.pfirmware) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Can't alloc buffer for fw.\n")); ++ return 1; ++ } ++ ++ /* request fw */ ++ err = request_firmware(&firmware, rtlpriv->cfg->fw_name, ++ rtlpriv->io.dev); ++ if (err) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Failed to request firmware!\n")); ++ return 1; ++ } ++ if (firmware->size > sizeof(struct rt_firmware)) { ++ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ++ ("Firmware is too big!\n")); ++ release_firmware(firmware); ++ return 1; ++ } ++ ++ pfirmware = (struct rt_firmware *)rtlpriv->rtlhal.pfirmware; ++ memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size); ++ pfirmware->sz_fw_tmpbufferlen = firmware->size; ++ release_firmware(firmware); ++ ++ return err; ++} ++ ++static void rtl92s_deinit_sw_vars(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ if (rtlpriv->rtlhal.pfirmware) { ++ vfree(rtlpriv->rtlhal.pfirmware); ++ rtlpriv->rtlhal.pfirmware = NULL; ++ } ++} ++ ++static struct rtl_hal_ops rtl8192se_hal_ops = { ++ .init_sw_vars = rtl92s_init_sw_vars, ++ .deinit_sw_vars = rtl92s_deinit_sw_vars, ++ .read_eeprom_info = rtl92se_read_eeprom_info, ++ .interrupt_recognized = rtl92se_interrupt_recognized, ++ .hw_init = rtl92se_hw_init, ++ .hw_disable = rtl92se_card_disable, ++ .hw_suspend = rtl92se_suspend, ++ .hw_resume = rtl92se_resume, ++ .enable_interrupt = rtl92se_enable_interrupt, ++ .disable_interrupt = rtl92se_disable_interrupt, ++ .set_network_type = rtl92se_set_network_type, ++ .set_chk_bssid = rtl92se_set_check_bssid, ++ .set_qos = rtl92se_set_qos, ++ .set_bcn_reg = rtl92se_set_beacon_related_registers, ++ .set_bcn_intv = rtl92se_set_beacon_interval, ++ .update_interrupt_mask = rtl92se_update_interrupt_mask, ++ .get_hw_reg = rtl92se_get_hw_reg, ++ .set_hw_reg = rtl92se_set_hw_reg, ++ .update_rate_tbl = rtl92se_update_hal_rate_tbl, ++ .fill_tx_desc = rtl92se_tx_fill_desc, ++ .fill_tx_cmddesc = rtl92se_tx_fill_cmddesc, ++ .query_rx_desc = rtl92se_rx_query_desc, ++ .set_channel_access = rtl92se_update_channel_access_setting, ++ .radio_onoff_checking = rtl92se_gpio_radio_on_off_checking, ++ .set_bw_mode = rtl92s_phy_set_bw_mode, ++ .switch_channel = rtl92s_phy_sw_chnl, ++ .dm_watchdog = rtl92s_dm_watchdog, ++ .scan_operation_backup = rtl92s_phy_scan_operation_backup, ++ .set_rf_power_state = rtl92s_phy_set_rf_power_state, ++ .led_control = rtl92se_led_control, ++ .set_desc = rtl92se_set_desc, ++ .get_desc = rtl92se_get_desc, ++ .tx_polling = rtl92se_tx_polling, ++ .enable_hw_sec = rtl92se_enable_hw_security_config, ++ .set_key = rtl92se_set_key, ++ .init_sw_leds = rtl92se_init_sw_leds, ++ .get_bbreg = rtl92s_phy_query_bb_reg, ++ .set_bbreg = rtl92s_phy_set_bb_reg, ++ .get_rfreg = rtl92s_phy_query_rf_reg, ++ .set_rfreg = rtl92s_phy_set_rf_reg, ++}; ++ ++static struct rtl_mod_params rtl92se_mod_params = { ++ .sw_crypto = false, ++ .inactiveps = true, ++ .swctrl_lps = true, ++ .fwctrl_lps = false, ++}; ++ ++/* Because memory R/W bursting will cause system hang/crash ++ * for 92se, so we don't read back after every write action */ ++static struct rtl_hal_cfg rtl92se_hal_cfg = { ++ .bar_id = 1, ++ .write_readback = false, ++ .name = "rtl92s_pci", ++ .fw_name = "rtlwifi/rtl8192sefw.bin", ++ .ops = &rtl8192se_hal_ops, ++ .mod_params = &rtl92se_mod_params, ++ ++ .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, ++ .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN, ++ .maps[SYS_CLK] = SYS_CLKR, ++ .maps[MAC_RCR_AM] = RCR_AM, ++ .maps[MAC_RCR_AB] = RCR_AB, ++ .maps[MAC_RCR_ACRC32] = RCR_ACRC32, ++ .maps[MAC_RCR_ACF] = RCR_ACF, ++ .maps[MAC_RCR_AAP] = RCR_AAP, ++ ++ .maps[EFUSE_TEST] = REG_EFUSE_TEST, ++ .maps[EFUSE_CTRL] = REG_EFUSE_CTRL, ++ .maps[EFUSE_CLK] = REG_EFUSE_CLK, ++ .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL, ++ .maps[EFUSE_PWC_EV12V] = 0, /* nouse for 8192se */ ++ .maps[EFUSE_FEN_ELDR] = 0, /* nouse for 8192se */ ++ .maps[EFUSE_LOADER_CLK_EN] = 0,/* nouse for 8192se */ ++ .maps[EFUSE_ANA8M] = EFUSE_ANA8M, ++ .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE_92S, ++ .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, ++ .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, ++ ++ .maps[RWCAM] = REG_RWCAM, ++ .maps[WCAMI] = REG_WCAMI, ++ .maps[RCAMO] = REG_RCAMO, ++ .maps[CAMDBG] = REG_CAMDBG, ++ .maps[SECR] = REG_SECR, ++ .maps[SEC_CAM_NONE] = CAM_NONE, ++ .maps[SEC_CAM_WEP40] = CAM_WEP40, ++ .maps[SEC_CAM_TKIP] = CAM_TKIP, ++ .maps[SEC_CAM_AES] = CAM_AES, ++ .maps[SEC_CAM_WEP104] = CAM_WEP104, ++ ++ .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6, ++ .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5, ++ .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4, ++ .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3, ++ .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2, ++ .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1, ++ .maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8, ++ .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7, ++ .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6, ++ .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5, ++ .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4, ++ .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3, ++ .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2, ++ .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1, ++ .maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2, ++ .maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1, ++ ++ .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW, ++ .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT, ++ .maps[RTL_IMR_BcnInt] = IMR_BCNINT, ++ .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, ++ .maps[RTL_IMR_RDU] = IMR_RDU, ++ .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, ++ .maps[RTL_IMR_BDOK] = IMR_BDOK, ++ .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK, ++ .maps[RTL_IMR_TBDER] = IMR_TBDER, ++ .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK, ++ .maps[RTL_IMR_COMDOK] = IMR_COMDOK, ++ .maps[RTL_IMR_TBDOK] = IMR_TBDOK, ++ .maps[RTL_IMR_BKDOK] = IMR_BKDOK, ++ .maps[RTL_IMR_BEDOK] = IMR_BEDOK, ++ .maps[RTL_IMR_VIDOK] = IMR_VIDOK, ++ .maps[RTL_IMR_VODOK] = IMR_VODOK, ++ .maps[RTL_IMR_ROK] = IMR_ROK, ++ .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), ++ ++ .maps[RTL_RC_CCK_RATE1M] = DESC92S_RATE1M, ++ .maps[RTL_RC_CCK_RATE2M] = DESC92S_RATE2M, ++ .maps[RTL_RC_CCK_RATE5_5M] = DESC92S_RATE5_5M, ++ .maps[RTL_RC_CCK_RATE11M] = DESC92S_RATE11M, ++ .maps[RTL_RC_OFDM_RATE6M] = DESC92S_RATE6M, ++ .maps[RTL_RC_OFDM_RATE9M] = DESC92S_RATE9M, ++ .maps[RTL_RC_OFDM_RATE12M] = DESC92S_RATE12M, ++ .maps[RTL_RC_OFDM_RATE18M] = DESC92S_RATE18M, ++ .maps[RTL_RC_OFDM_RATE24M] = DESC92S_RATE24M, ++ .maps[RTL_RC_OFDM_RATE36M] = DESC92S_RATE36M, ++ .maps[RTL_RC_OFDM_RATE48M] = DESC92S_RATE48M, ++ .maps[RTL_RC_OFDM_RATE54M] = DESC92S_RATE54M, ++ ++ .maps[RTL_RC_HT_RATEMCS7] = DESC92S_RATEMCS7, ++ .maps[RTL_RC_HT_RATEMCS15] = DESC92S_RATEMCS15, ++}; ++ ++static struct pci_device_id rtl92se_pci_ids[] __devinitdata = { ++ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8192, rtl92se_hal_cfg)}, ++ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8171, rtl92se_hal_cfg)}, ++ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8172, rtl92se_hal_cfg)}, ++ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8173, rtl92se_hal_cfg)}, ++ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8174, rtl92se_hal_cfg)}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(pci, rtl92se_pci_ids); ++ ++MODULE_AUTHOR("lizhaoming "); ++MODULE_AUTHOR("Realtek WlanFAE "); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Realtek 8192S/8191S 802.11n PCI wireless"); ++MODULE_FIRMWARE("rtlwifi/rtl8192sefw.bin"); ++ ++module_param_named(swenc, rtl92se_mod_params.sw_crypto, bool, 0444); ++module_param_named(ips, rtl92se_mod_params.inactiveps, bool, 0444); ++module_param_named(swlps, rtl92se_mod_params.swctrl_lps, bool, 0444); ++module_param_named(fwlps, rtl92se_mod_params.fwctrl_lps, bool, 0444); ++MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); ++MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); ++MODULE_PARM_DESC(swlps, "using linked sw control power save (default 1 is " ++ "open)\n"); ++ ++ ++static struct pci_driver rtl92se_driver = { ++ .name = KBUILD_MODNAME, ++ .id_table = rtl92se_pci_ids, ++ .probe = rtl_pci_probe, ++ .remove = rtl_pci_disconnect, ++ ++#ifdef CONFIG_PM ++ .suspend = rtl_pci_suspend, ++ .resume = rtl_pci_resume, ++#endif ++ ++}; ++ ++static int __init rtl92se_module_init(void) ++{ ++ int ret = 0; ++ ++ ret = pci_register_driver(&rtl92se_driver); ++ if (ret) ++ RT_ASSERT(false, (": No device found\n")); ++ ++ return ret; ++} ++ ++static void __exit rtl92se_module_exit(void) ++{ ++ pci_unregister_driver(&rtl92se_driver); ++} ++ ++module_init(rtl92se_module_init); ++module_exit(rtl92se_module_exit); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/sw.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/sw.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/sw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/sw.h 2011-05-05 23:29:49.275487657 +0200 +@@ -0,0 +1,36 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ *****************************************************************************/ ++#ifndef __REALTEK_PCI92SE_SW_H__ ++#define __REALTEK_PCI92SE_SW_H__ ++ ++#define EFUSE_MAX_SECTION 16 ++ ++int rtl92se_init_sw(struct ieee80211_hw *hw); ++void rtl92se_deinit_sw(struct ieee80211_hw *hw); ++void rtl92se_init_var_map(struct ieee80211_hw *hw); ++ ++#endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/table.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/table.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/table.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/table.c 2011-05-05 23:29:49.277487681 +0200 +@@ -0,0 +1,634 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ * Created on 2010/ 5/18, 1:41 ++ *****************************************************************************/ ++ ++#include "table.h" ++ ++u32 rtl8192sephy_reg_2t2rarray[PHY_REG_2T2RARRAYLENGTH] = { ++ 0x01c, 0x07000000, ++ 0x800, 0x00040000, ++ 0x804, 0x00008003, ++ 0x808, 0x0000fc00, ++ 0x80c, 0x0000000a, ++ 0x810, 0x10005088, ++ 0x814, 0x020c3d10, ++ 0x818, 0x00200185, ++ 0x81c, 0x00000000, ++ 0x820, 0x01000000, ++ 0x824, 0x00390004, ++ 0x828, 0x01000000, ++ 0x82c, 0x00390004, ++ 0x830, 0x00000004, ++ 0x834, 0x00690200, ++ 0x838, 0x00000004, ++ 0x83c, 0x00690200, ++ 0x840, 0x00010000, ++ 0x844, 0x00010000, ++ 0x848, 0x00000000, ++ 0x84c, 0x00000000, ++ 0x850, 0x00000000, ++ 0x854, 0x00000000, ++ 0x858, 0x48484848, ++ 0x85c, 0x65a965a9, ++ 0x860, 0x0f7f0130, ++ 0x864, 0x0f7f0130, ++ 0x868, 0x0f7f0130, ++ 0x86c, 0x0f7f0130, ++ 0x870, 0x03000700, ++ 0x874, 0x03000300, ++ 0x878, 0x00020002, ++ 0x87c, 0x004f0201, ++ 0x880, 0xa8300ac1, ++ 0x884, 0x00000058, ++ 0x888, 0x00000008, ++ 0x88c, 0x00000004, ++ 0x890, 0x00000000, ++ 0x894, 0xfffffffe, ++ 0x898, 0x40302010, ++ 0x89c, 0x00706050, ++ 0x8b0, 0x00000000, ++ 0x8e0, 0x00000000, ++ 0x8e4, 0x00000000, ++ 0xe00, 0x30333333, ++ 0xe04, 0x2a2d2e2f, ++ 0xe08, 0x00003232, ++ 0xe10, 0x30333333, ++ 0xe14, 0x2a2d2e2f, ++ 0xe18, 0x30333333, ++ 0xe1c, 0x2a2d2e2f, ++ 0xe30, 0x01007c00, ++ 0xe34, 0x01004800, ++ 0xe38, 0x1000dc1f, ++ 0xe3c, 0x10008c1f, ++ 0xe40, 0x021400a0, ++ 0xe44, 0x281600a0, ++ 0xe48, 0xf8000001, ++ 0xe4c, 0x00002910, ++ 0xe50, 0x01007c00, ++ 0xe54, 0x01004800, ++ 0xe58, 0x1000dc1f, ++ 0xe5c, 0x10008c1f, ++ 0xe60, 0x021400a0, ++ 0xe64, 0x281600a0, ++ 0xe6c, 0x00002910, ++ 0xe70, 0x31ed92fb, ++ 0xe74, 0x361536fb, ++ 0xe78, 0x361536fb, ++ 0xe7c, 0x361536fb, ++ 0xe80, 0x361536fb, ++ 0xe84, 0x000d92fb, ++ 0xe88, 0x000d92fb, ++ 0xe8c, 0x31ed92fb, ++ 0xed0, 0x31ed92fb, ++ 0xed4, 0x31ed92fb, ++ 0xed8, 0x000d92fb, ++ 0xedc, 0x000d92fb, ++ 0xee0, 0x000d92fb, ++ 0xee4, 0x015e5448, ++ 0xee8, 0x21555448, ++ 0x900, 0x00000000, ++ 0x904, 0x00000023, ++ 0x908, 0x00000000, ++ 0x90c, 0x01121313, ++ 0xa00, 0x00d047c8, ++ 0xa04, 0x80ff0008, ++ 0xa08, 0x8ccd8300, ++ 0xa0c, 0x2e62120f, ++ 0xa10, 0x9500bb78, ++ 0xa14, 0x11144028, ++ 0xa18, 0x00881117, ++ 0xa1c, 0x89140f00, ++ 0xa20, 0x1a1b0000, ++ 0xa24, 0x090e1317, ++ 0xa28, 0x00000204, ++ 0xa2c, 0x10d30000, ++ 0xc00, 0x40071d40, ++ 0xc04, 0x00a05633, ++ 0xc08, 0x000000e4, ++ 0xc0c, 0x6c6c6c6c, ++ 0xc10, 0x08800000, ++ 0xc14, 0x40000100, ++ 0xc18, 0x08000000, ++ 0xc1c, 0x40000100, ++ 0xc20, 0x08000000, ++ 0xc24, 0x40000100, ++ 0xc28, 0x08000000, ++ 0xc2c, 0x40000100, ++ 0xc30, 0x6de9ac44, ++ 0xc34, 0x469652cf, ++ 0xc38, 0x49795994, ++ 0xc3c, 0x0a979764, ++ 0xc40, 0x1f7c403f, ++ 0xc44, 0x000100b7, ++ 0xc48, 0xec020000, ++ 0xc4c, 0x007f037f, ++ 0xc50, 0x69543420, ++ 0xc54, 0x433c0094, ++ 0xc58, 0x69543420, ++ 0xc5c, 0x433c0094, ++ 0xc60, 0x69543420, ++ 0xc64, 0x433c0094, ++ 0xc68, 0x69543420, ++ 0xc6c, 0x433c0094, ++ 0xc70, 0x2c7f000d, ++ 0xc74, 0x0186155b, ++ 0xc78, 0x0000001f, ++ 0xc7c, 0x00b91612, ++ 0xc80, 0x40000100, ++ 0xc84, 0x20f60000, ++ 0xc88, 0x20000080, ++ 0xc8c, 0x20200000, ++ 0xc90, 0x40000100, ++ 0xc94, 0x00000000, ++ 0xc98, 0x40000100, ++ 0xc9c, 0x00000000, ++ 0xca0, 0x00492492, ++ 0xca4, 0x00000000, ++ 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, 0x00000750, ++ 0xd04, 0x00000403, ++ 0xd08, 0x0000907f, ++ 0xd0c, 0x00000001, ++ 0xd10, 0xa0633333, ++ 0xd14, 0x33333c63, ++ 0xd18, 0x6a8f5b6b, ++ 0xd1c, 0x00000000, ++ 0xd20, 0x00000000, ++ 0xd24, 0x00000000, ++ 0xd28, 0x00000000, ++ 0xd2c, 0xcc979975, ++ 0xd30, 0x00000000, ++ 0xd34, 0x00000000, ++ 0xd38, 0x00000000, ++ 0xd3c, 0x00027293, ++ 0xd40, 0x00000000, ++ 0xd44, 0x00000000, ++ 0xd48, 0x00000000, ++ 0xd50, 0x6437140a, ++ 0xd54, 0x024dbd02, ++ 0xd58, 0x00000000, ++ 0xd5c, 0x30032064, ++ 0xd60, 0x4653de68, ++ 0xd64, 0x00518a3c, ++ 0xd68, 0x00002101, ++ 0xf14, 0x00000003, ++ 0xf4c, 0x00000000, ++ 0xf00, 0x00000300, ++}; ++ ++u32 rtl8192sephy_changeto_1t1rarray[PHY_CHANGETO_1T1RARRAYLENGTH] = { ++ 0x844, 0xffffffff, 0x00010000, ++ 0x804, 0x0000000f, 0x00000001, ++ 0x824, 0x00f0000f, 0x00300004, ++ 0x82c, 0x00f0000f, 0x00100002, ++ 0x870, 0x04000000, 0x00000001, ++ 0x864, 0x00000400, 0x00000000, ++ 0x878, 0x000f000f, 0x00000002, ++ 0xe74, 0x0f000000, 0x00000002, ++ 0xe78, 0x0f000000, 0x00000002, ++ 0xe7c, 0x0f000000, 0x00000002, ++ 0xe80, 0x0f000000, 0x00000002, ++ 0x90c, 0x000000ff, 0x00000011, ++ 0xc04, 0x000000ff, 0x00000011, ++ 0xd04, 0x0000000f, 0x00000001, ++ 0x1f4, 0xffff0000, 0x00007777, ++ 0x234, 0xf8000000, 0x0000000a, ++}; ++ ++u32 rtl8192sephy_changeto_1t2rarray[PHY_CHANGETO_1T2RARRAYLENGTH] = { ++ 0x804, 0x0000000f, 0x00000003, ++ 0x824, 0x00f0000f, 0x00300004, ++ 0x82c, 0x00f0000f, 0x00300002, ++ 0x870, 0x04000000, 0x00000001, ++ 0x864, 0x00000400, 0x00000000, ++ 0x878, 0x000f000f, 0x00000002, ++ 0xe74, 0x0f000000, 0x00000002, ++ 0xe78, 0x0f000000, 0x00000002, ++ 0xe7c, 0x0f000000, 0x00000002, ++ 0xe80, 0x0f000000, 0x00000002, ++ 0x90c, 0x000000ff, 0x00000011, ++ 0xc04, 0x000000ff, 0x00000033, ++ 0xd04, 0x0000000f, 0x00000003, ++ 0x1f4, 0xffff0000, 0x00007777, ++ 0x234, 0xf8000000, 0x0000000a, ++}; ++ ++u32 rtl8192sephy_reg_array_pg[PHY_REG_ARRAY_PGLENGTH] = { ++ 0xe00, 0xffffffff, 0x06090909, ++ 0xe04, 0xffffffff, 0x00030406, ++ 0xe08, 0x0000ff00, 0x00000000, ++ 0xe10, 0xffffffff, 0x0a0c0d0e, ++ 0xe14, 0xffffffff, 0x04070809, ++ 0xe18, 0xffffffff, 0x0a0c0d0e, ++ 0xe1c, 0xffffffff, 0x04070809, ++ 0xe00, 0xffffffff, 0x04040404, ++ 0xe04, 0xffffffff, 0x00020204, ++ 0xe08, 0x0000ff00, 0x00000000, ++ 0xe10, 0xffffffff, 0x02040404, ++ 0xe14, 0xffffffff, 0x00000002, ++ 0xe18, 0xffffffff, 0x02040404, ++ 0xe1c, 0xffffffff, 0x00000002, ++ 0xe00, 0xffffffff, 0x04040404, ++ 0xe04, 0xffffffff, 0x00020204, ++ 0xe08, 0x0000ff00, 0x00000000, ++ 0xe10, 0xffffffff, 0x02040404, ++ 0xe14, 0xffffffff, 0x00000002, ++ 0xe18, 0xffffffff, 0x02040404, ++ 0xe1c, 0xffffffff, 0x00000002, ++ 0xe00, 0xffffffff, 0x02020202, ++ 0xe04, 0xffffffff, 0x00020202, ++ 0xe08, 0x0000ff00, 0x00000000, ++ 0xe10, 0xffffffff, 0x02020202, ++ 0xe14, 0xffffffff, 0x00000002, ++ 0xe18, 0xffffffff, 0x02020202, ++ 0xe1c, 0xffffffff, 0x00000002, ++}; ++ ++u32 rtl8192seradioa_1t_array[RADIOA_1T_ARRAYLENGTH] = { ++ 0x000, 0x00030159, ++ 0x001, 0x00030250, ++ 0x002, 0x00010000, ++ 0x010, 0x0008000f, ++ 0x011, 0x000231fc, ++ 0x010, 0x000c000f, ++ 0x011, 0x0003f9f8, ++ 0x010, 0x0002000f, ++ 0x011, 0x00020101, ++ 0x014, 0x0001093e, ++ 0x014, 0x0009093e, ++ 0x015, 0x0000f8f4, ++ 0x017, 0x000f6500, ++ 0x01a, 0x00013056, ++ 0x01b, 0x00060000, ++ 0x01c, 0x00000300, ++ 0x01e, 0x00031059, ++ 0x021, 0x00054000, ++ 0x022, 0x0000083c, ++ 0x023, 0x00001558, ++ 0x024, 0x00000060, ++ 0x025, 0x00022583, ++ 0x026, 0x0000f200, ++ 0x027, 0x000eacf1, ++ 0x028, 0x0009bd54, ++ 0x029, 0x00004582, ++ 0x02a, 0x00000001, ++ 0x02b, 0x00021334, ++ 0x02a, 0x00000000, ++ 0x02b, 0x0000000a, ++ 0x02a, 0x00000001, ++ 0x02b, 0x00000808, ++ 0x02b, 0x00053333, ++ 0x02c, 0x0000000c, ++ 0x02a, 0x00000002, ++ 0x02b, 0x00000808, ++ 0x02b, 0x0005b333, ++ 0x02c, 0x0000000d, ++ 0x02a, 0x00000003, ++ 0x02b, 0x00000808, ++ 0x02b, 0x00063333, ++ 0x02c, 0x0000000d, ++ 0x02a, 0x00000004, ++ 0x02b, 0x00000808, ++ 0x02b, 0x0006b333, ++ 0x02c, 0x0000000d, ++ 0x02a, 0x00000005, ++ 0x02b, 0x00000709, ++ 0x02b, 0x00053333, ++ 0x02c, 0x0000000d, ++ 0x02a, 0x00000006, ++ 0x02b, 0x00000709, ++ 0x02b, 0x0005b333, ++ 0x02c, 0x0000000d, ++ 0x02a, 0x00000007, ++ 0x02b, 0x00000709, ++ 0x02b, 0x00063333, ++ 0x02c, 0x0000000d, ++ 0x02a, 0x00000008, ++ 0x02b, 0x00000709, ++ 0x02b, 0x0006b333, ++ 0x02c, 0x0000000d, ++ 0x02a, 0x00000009, ++ 0x02b, 0x0000060a, ++ 0x02b, 0x00053333, ++ 0x02c, 0x0000000d, ++ 0x02a, 0x0000000a, ++ 0x02b, 0x0000060a, ++ 0x02b, 0x0005b333, ++ 0x02c, 0x0000000d, ++ 0x02a, 0x0000000b, ++ 0x02b, 0x0000060a, ++ 0x02b, 0x00063333, ++ 0x02c, 0x0000000d, ++ 0x02a, 0x0000000c, ++ 0x02b, 0x0000060a, ++ 0x02b, 0x0006b333, ++ 0x02c, 0x0000000d, ++ 0x02a, 0x0000000d, ++ 0x02b, 0x0000050b, ++ 0x02b, 0x00053333, ++ 0x02c, 0x0000000d, ++ 0x02a, 0x0000000e, ++ 0x02b, 0x0000050b, ++ 0x02b, 0x00066623, ++ 0x02c, 0x0000001a, ++ 0x02a, 0x000e4000, ++ 0x030, 0x00020000, ++ 0x031, 0x000b9631, ++ 0x032, 0x0000130d, ++ 0x033, 0x00000187, ++ 0x013, 0x00019e6c, ++ 0x013, 0x00015e94, ++ 0x000, 0x00010159, ++ 0x018, 0x0000f401, ++ 0x0fe, 0x00000000, ++ 0x01e, 0x0003105b, ++ 0x0fe, 0x00000000, ++ 0x000, 0x00030159, ++ 0x010, 0x0004000f, ++ 0x011, 0x000203f9, ++}; ++ ++u32 rtl8192seradiob_array[RADIOB_ARRAYLENGTH] = { ++ 0x000, 0x00030159, ++ 0x001, 0x00001041, ++ 0x002, 0x00011000, ++ 0x005, 0x00080fc0, ++ 0x007, 0x000fc803, ++ 0x013, 0x00017cb0, ++ 0x013, 0x00011cc0, ++ 0x013, 0x0000dc60, ++ 0x013, 0x00008c60, ++ 0x013, 0x00004450, ++ 0x013, 0x00000020, ++}; ++ ++u32 rtl8192seradiob_gm_array[RADIOB_GM_ARRAYLENGTH] = { ++ 0x000, 0x00030159, ++ 0x001, 0x00001041, ++ 0x002, 0x00011000, ++ 0x005, 0x00080fc0, ++ 0x007, 0x000fc803, ++}; ++ ++u32 rtl8192semac_2t_array[MAC_2T_ARRAYLENGTH] = { ++ 0x020, 0x00000035, ++ 0x048, 0x0000000e, ++ 0x049, 0x000000f0, ++ 0x04a, 0x00000077, ++ 0x04b, 0x00000083, ++ 0x0b5, 0x00000021, ++ 0x0dc, 0x000000ff, ++ 0x0dd, 0x000000ff, ++ 0x0de, 0x000000ff, ++ 0x0df, 0x000000ff, ++ 0x116, 0x00000000, ++ 0x117, 0x00000000, ++ 0x118, 0x00000000, ++ 0x119, 0x00000000, ++ 0x11a, 0x00000000, ++ 0x11b, 0x00000000, ++ 0x11c, 0x00000000, ++ 0x11d, 0x00000000, ++ 0x160, 0x0000000b, ++ 0x161, 0x0000000b, ++ 0x162, 0x0000000b, ++ 0x163, 0x0000000b, ++ 0x164, 0x0000000b, ++ 0x165, 0x0000000b, ++ 0x166, 0x0000000b, ++ 0x167, 0x0000000b, ++ 0x168, 0x0000000b, ++ 0x169, 0x0000000b, ++ 0x16a, 0x0000000b, ++ 0x16b, 0x0000000b, ++ 0x16c, 0x0000000b, ++ 0x16d, 0x0000000b, ++ 0x16e, 0x0000000b, ++ 0x16f, 0x0000000b, ++ 0x170, 0x0000000b, ++ 0x171, 0x0000000b, ++ 0x172, 0x0000000b, ++ 0x173, 0x0000000b, ++ 0x174, 0x0000000b, ++ 0x175, 0x0000000b, ++ 0x176, 0x0000000b, ++ 0x177, 0x0000000b, ++ 0x178, 0x0000000b, ++ 0x179, 0x0000000b, ++ 0x17a, 0x0000000b, ++ 0x17b, 0x0000000b, ++ 0x17c, 0x0000000b, ++ 0x17d, 0x0000000b, ++ 0x17e, 0x0000000b, ++ 0x17f, 0x0000000b, ++ 0x236, 0x0000000c, ++ 0x503, 0x00000022, ++ 0x560, 0x00000000, ++}; ++ ++u32 rtl8192seagctab_array[AGCTAB_ARRAYLENGTH] = { ++ 0xc78, 0x7f000001, ++ 0xc78, 0x7f010001, ++ 0xc78, 0x7e020001, ++ 0xc78, 0x7d030001, ++ 0xc78, 0x7c040001, ++ 0xc78, 0x7b050001, ++ 0xc78, 0x7a060001, ++ 0xc78, 0x79070001, ++ 0xc78, 0x78080001, ++ 0xc78, 0x77090001, ++ 0xc78, 0x760a0001, ++ 0xc78, 0x750b0001, ++ 0xc78, 0x740c0001, ++ 0xc78, 0x730d0001, ++ 0xc78, 0x720e0001, ++ 0xc78, 0x710f0001, ++ 0xc78, 0x70100001, ++ 0xc78, 0x6f110001, ++ 0xc78, 0x6f120001, ++ 0xc78, 0x6e130001, ++ 0xc78, 0x6d140001, ++ 0xc78, 0x6d150001, ++ 0xc78, 0x6c160001, ++ 0xc78, 0x6b170001, ++ 0xc78, 0x6a180001, ++ 0xc78, 0x6a190001, ++ 0xc78, 0x691a0001, ++ 0xc78, 0x681b0001, ++ 0xc78, 0x671c0001, ++ 0xc78, 0x661d0001, ++ 0xc78, 0x651e0001, ++ 0xc78, 0x641f0001, ++ 0xc78, 0x63200001, ++ 0xc78, 0x4c210001, ++ 0xc78, 0x4b220001, ++ 0xc78, 0x4a230001, ++ 0xc78, 0x49240001, ++ 0xc78, 0x48250001, ++ 0xc78, 0x47260001, ++ 0xc78, 0x46270001, ++ 0xc78, 0x45280001, ++ 0xc78, 0x44290001, ++ 0xc78, 0x2c2a0001, ++ 0xc78, 0x2b2b0001, ++ 0xc78, 0x2a2c0001, ++ 0xc78, 0x292d0001, ++ 0xc78, 0x282e0001, ++ 0xc78, 0x272f0001, ++ 0xc78, 0x26300001, ++ 0xc78, 0x25310001, ++ 0xc78, 0x24320001, ++ 0xc78, 0x23330001, ++ 0xc78, 0x22340001, ++ 0xc78, 0x09350001, ++ 0xc78, 0x08360001, ++ 0xc78, 0x07370001, ++ 0xc78, 0x06380001, ++ 0xc78, 0x05390001, ++ 0xc78, 0x043a0001, ++ 0xc78, 0x033b0001, ++ 0xc78, 0x023c0001, ++ 0xc78, 0x013d0001, ++ 0xc78, 0x003e0001, ++ 0xc78, 0x003f0001, ++ 0xc78, 0x7f400001, ++ 0xc78, 0x7f410001, ++ 0xc78, 0x7e420001, ++ 0xc78, 0x7d430001, ++ 0xc78, 0x7c440001, ++ 0xc78, 0x7b450001, ++ 0xc78, 0x7a460001, ++ 0xc78, 0x79470001, ++ 0xc78, 0x78480001, ++ 0xc78, 0x77490001, ++ 0xc78, 0x764a0001, ++ 0xc78, 0x754b0001, ++ 0xc78, 0x744c0001, ++ 0xc78, 0x734d0001, ++ 0xc78, 0x724e0001, ++ 0xc78, 0x714f0001, ++ 0xc78, 0x70500001, ++ 0xc78, 0x6f510001, ++ 0xc78, 0x6f520001, ++ 0xc78, 0x6e530001, ++ 0xc78, 0x6d540001, ++ 0xc78, 0x6d550001, ++ 0xc78, 0x6c560001, ++ 0xc78, 0x6b570001, ++ 0xc78, 0x6a580001, ++ 0xc78, 0x6a590001, ++ 0xc78, 0x695a0001, ++ 0xc78, 0x685b0001, ++ 0xc78, 0x675c0001, ++ 0xc78, 0x665d0001, ++ 0xc78, 0x655e0001, ++ 0xc78, 0x645f0001, ++ 0xc78, 0x63600001, ++ 0xc78, 0x4c610001, ++ 0xc78, 0x4b620001, ++ 0xc78, 0x4a630001, ++ 0xc78, 0x49640001, ++ 0xc78, 0x48650001, ++ 0xc78, 0x47660001, ++ 0xc78, 0x46670001, ++ 0xc78, 0x45680001, ++ 0xc78, 0x44690001, ++ 0xc78, 0x2c6a0001, ++ 0xc78, 0x2b6b0001, ++ 0xc78, 0x2a6c0001, ++ 0xc78, 0x296d0001, ++ 0xc78, 0x286e0001, ++ 0xc78, 0x276f0001, ++ 0xc78, 0x26700001, ++ 0xc78, 0x25710001, ++ 0xc78, 0x24720001, ++ 0xc78, 0x23730001, ++ 0xc78, 0x22740001, ++ 0xc78, 0x09750001, ++ 0xc78, 0x08760001, ++ 0xc78, 0x07770001, ++ 0xc78, 0x06780001, ++ 0xc78, 0x05790001, ++ 0xc78, 0x047a0001, ++ 0xc78, 0x037b0001, ++ 0xc78, 0x027c0001, ++ 0xc78, 0x017d0001, ++ 0xc78, 0x007e0001, ++ 0xc78, 0x007f0001, ++ 0xc78, 0x3000001e, ++ 0xc78, 0x3001001e, ++ 0xc78, 0x3002001e, ++ 0xc78, 0x3003001e, ++ 0xc78, 0x3004001e, ++ 0xc78, 0x3405001e, ++ 0xc78, 0x3806001e, ++ 0xc78, 0x3e07001e, ++ 0xc78, 0x3e08001e, ++ 0xc78, 0x4409001e, ++ 0xc78, 0x460a001e, ++ 0xc78, 0x480b001e, ++ 0xc78, 0x480c001e, ++ 0xc78, 0x4e0d001e, ++ 0xc78, 0x560e001e, ++ 0xc78, 0x5a0f001e, ++ 0xc78, 0x5e10001e, ++ 0xc78, 0x6211001e, ++ 0xc78, 0x6c12001e, ++ 0xc78, 0x7213001e, ++ 0xc78, 0x7214001e, ++ 0xc78, 0x7215001e, ++ 0xc78, 0x7216001e, ++ 0xc78, 0x7217001e, ++ 0xc78, 0x7218001e, ++ 0xc78, 0x7219001e, ++ 0xc78, 0x721a001e, ++ 0xc78, 0x721b001e, ++ 0xc78, 0x721c001e, ++ 0xc78, 0x721d001e, ++ 0xc78, 0x721e001e, ++ 0xc78, 0x721f001e, ++}; ++ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/table.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/table.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/table.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/table.h 2011-05-05 23:29:49.276487669 +0200 +@@ -0,0 +1,49 @@ ++/****************************************************************************** ++ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * ++ * Larry Finger ++ * ++ ******************************************************************************/ ++#ifndef __INC_HAL8192SE_FW_IMG_H ++#define __INC_HAL8192SE_FW_IMG_H ++ ++#include ++ ++/*Created on 2010/ 4/12, 5:56*/ ++ ++#define PHY_REG_2T2RARRAYLENGTH 372 ++extern u32 rtl8192sephy_reg_2t2rarray[PHY_REG_2T2RARRAYLENGTH]; ++#define PHY_CHANGETO_1T1RARRAYLENGTH 48 ++extern u32 rtl8192sephy_changeto_1t1rarray[PHY_CHANGETO_1T1RARRAYLENGTH]; ++#define PHY_CHANGETO_1T2RARRAYLENGTH 45 ++extern u32 rtl8192sephy_changeto_1t2rarray[PHY_CHANGETO_1T2RARRAYLENGTH]; ++#define PHY_REG_ARRAY_PGLENGTH 84 ++extern u32 rtl8192sephy_reg_array_pg[PHY_REG_ARRAY_PGLENGTH]; ++#define RADIOA_1T_ARRAYLENGTH 202 ++extern u32 rtl8192seradioa_1t_array[RADIOA_1T_ARRAYLENGTH]; ++#define RADIOB_ARRAYLENGTH 22 ++extern u32 rtl8192seradiob_array[RADIOB_ARRAYLENGTH]; ++#define RADIOB_GM_ARRAYLENGTH 10 ++extern u32 rtl8192seradiob_gm_array[RADIOB_GM_ARRAYLENGTH]; ++#define MAC_2T_ARRAYLENGTH 106 ++extern u32 rtl8192semac_2t_array[MAC_2T_ARRAYLENGTH]; ++#define AGCTAB_ARRAYLENGTH 320 ++extern u32 rtl8192seagctab_array[AGCTAB_ARRAYLENGTH]; ++ ++#endif ++ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/trx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/trx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/trx.c 2011-05-05 23:29:49.278487693 +0200 +@@ -0,0 +1,976 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++ ++#include "../wifi.h" ++#include "../pci.h" ++#include "../base.h" ++#include "reg.h" ++#include "def.h" ++#include "phy.h" ++#include "fw.h" ++#include "trx.h" ++#include "led.h" ++ ++static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue) ++{ ++ __le16 fc = rtl_get_fc(skb); ++ ++ if (unlikely(ieee80211_is_beacon(fc))) ++ return QSLT_BEACON; ++ if (ieee80211_is_mgmt(fc)) ++ return QSLT_MGNT; ++ if (ieee80211_is_nullfunc(fc)) ++ return QSLT_HIGH; ++ ++ return skb->priority; ++} ++ ++static int _rtl92se_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu) ++{ ++ int rate_idx = 0; ++ ++ if (first_ampdu) { ++ if (false == isht) { ++ switch (desc_rate) { ++ case DESC92S_RATE1M: ++ rate_idx = 0; ++ break; ++ case DESC92S_RATE2M: ++ rate_idx = 1; ++ break; ++ case DESC92S_RATE5_5M: ++ rate_idx = 2; ++ break; ++ case DESC92S_RATE11M: ++ rate_idx = 3; ++ break; ++ case DESC92S_RATE6M: ++ rate_idx = 4; ++ break; ++ case DESC92S_RATE9M: ++ rate_idx = 5; ++ break; ++ case DESC92S_RATE12M: ++ rate_idx = 6; ++ break; ++ case DESC92S_RATE18M: ++ rate_idx = 7; ++ break; ++ case DESC92S_RATE24M: ++ rate_idx = 8; ++ break; ++ case DESC92S_RATE36M: ++ rate_idx = 9; ++ break; ++ case DESC92S_RATE48M: ++ rate_idx = 10; ++ break; ++ case DESC92S_RATE54M: ++ rate_idx = 11; ++ break; ++ default: ++ rate_idx = 0; ++ break; ++ } ++ } else { ++ rate_idx = 11; ++ } ++ ++ return rate_idx; ++ } ++ ++ switch (desc_rate) { ++ case DESC92S_RATE1M: ++ rate_idx = 0; ++ break; ++ case DESC92S_RATE2M: ++ rate_idx = 1; ++ break; ++ case DESC92S_RATE5_5M: ++ rate_idx = 2; ++ break; ++ case DESC92S_RATE11M: ++ rate_idx = 3; ++ break; ++ case DESC92S_RATE6M: ++ rate_idx = 4; ++ break; ++ case DESC92S_RATE9M: ++ rate_idx = 5; ++ break; ++ case DESC92S_RATE12M: ++ rate_idx = 6; ++ break; ++ case DESC92S_RATE18M: ++ rate_idx = 7; ++ break; ++ case DESC92S_RATE24M: ++ rate_idx = 8; ++ break; ++ case DESC92S_RATE36M: ++ rate_idx = 9; ++ break; ++ case DESC92S_RATE48M: ++ rate_idx = 10; ++ break; ++ case DESC92S_RATE54M: ++ rate_idx = 11; ++ break; ++ default: ++ rate_idx = 11; ++ break; ++ } ++ return rate_idx; ++} ++ ++static u8 _rtl92s_query_rxpwrpercentage(char antpower) ++{ ++ if ((antpower <= -100) || (antpower >= 20)) ++ return 0; ++ else if (antpower >= 0) ++ return 100; ++ else ++ return 100 + antpower; ++} ++ ++static u8 _rtl92s_evm_db_to_percentage(char value) ++{ ++ char ret_val; ++ ret_val = value; ++ ++ 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 long _rtl92se_translate_todbm(struct ieee80211_hw *hw, ++ u8 signal_strength_index) ++{ ++ long signal_power; ++ ++ signal_power = (long)((signal_strength_index + 1) >> 1); ++ signal_power -= 95; ++ return signal_power; ++} ++ ++static long _rtl92se_signal_scale_mapping(struct ieee80211_hw *hw, ++ long currsig) ++{ ++ long retsig = 0; ++ ++ /* Step 1. Scale mapping. */ ++ if (currsig > 47) ++ retsig = 100; ++ else if (currsig > 14 && currsig <= 47) ++ retsig = 100 - ((47 - currsig) * 3) / 2; ++ else if (currsig > 2 && currsig <= 14) ++ retsig = 48 - ((14 - currsig) * 15) / 7; ++ else if (currsig >= 0) ++ retsig = currsig * 9 + 1; ++ ++ return retsig; ++} ++ ++ ++static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, ++ struct rtl_stats *pstats, u8 *pdesc, ++ struct rx_fwinfo *p_drvinfo, ++ bool packet_match_bssid, ++ bool packet_toself, ++ bool packet_beacon) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct phy_sts_cck_8192s_t *cck_buf; ++ s8 rx_pwr_all = 0, rx_pwr[4]; ++ u8 rf_rx_num = 0, evm, pwdb_all; ++ u8 i, max_spatial_stream; ++ u32 rssi, total_rssi = 0; ++ bool in_powersavemode = false; ++ bool is_cck_rate; ++ ++ is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); ++ pstats->packet_matchbssid = packet_match_bssid; ++ pstats->packet_toself = packet_toself; ++ pstats->is_cck = is_cck_rate; ++ pstats->packet_beacon = packet_beacon; ++ pstats->is_cck = is_cck_rate; ++ pstats->rx_mimo_signalquality[0] = -1; ++ pstats->rx_mimo_signalquality[1] = -1; ++ ++ if (is_cck_rate) { ++ u8 report, cck_highpwr; ++ cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; ++ ++ if (!in_powersavemode) ++ cck_highpwr = (u8) rtl_get_bbreg(hw, ++ RFPGA0_XA_HSSIPARAMETER2, ++ 0x200); ++ else ++ cck_highpwr = false; ++ ++ if (!cck_highpwr) { ++ u8 cck_agc_rpt = cck_buf->cck_agc_rpt; ++ report = cck_buf->cck_agc_rpt & 0xc0; ++ report = report >> 6; ++ switch (report) { ++ case 0x3: ++ rx_pwr_all = -40 - (cck_agc_rpt & 0x3e); ++ break; ++ case 0x2: ++ rx_pwr_all = -20 - (cck_agc_rpt & 0x3e); ++ break; ++ case 0x1: ++ rx_pwr_all = -2 - (cck_agc_rpt & 0x3e); ++ break; ++ case 0x0: ++ rx_pwr_all = 14 - (cck_agc_rpt & 0x3e); ++ break; ++ } ++ } else { ++ u8 cck_agc_rpt = cck_buf->cck_agc_rpt; ++ report = p_drvinfo->cfosho[0] & 0x60; ++ report = report >> 5; ++ switch (report) { ++ case 0x3: ++ rx_pwr_all = -40 - ((cck_agc_rpt & 0x1f) << 1); ++ break; ++ case 0x2: ++ rx_pwr_all = -20 - ((cck_agc_rpt & 0x1f) << 1); ++ break; ++ case 0x1: ++ rx_pwr_all = -2 - ((cck_agc_rpt & 0x1f) << 1); ++ break; ++ case 0x0: ++ rx_pwr_all = 14 - ((cck_agc_rpt & 0x1f) << 1); ++ break; ++ } ++ } ++ ++ pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all); ++ ++ /* CCK gain is smaller than OFDM/MCS gain, */ ++ /* so we add gain diff by experiences, the val is 6 */ ++ pwdb_all += 6; ++ if (pwdb_all > 100) ++ pwdb_all = 100; ++ /* modify the offset to make the same gain index with OFDM. */ ++ if (pwdb_all > 34 && pwdb_all <= 42) ++ pwdb_all -= 2; ++ else if (pwdb_all > 26 && pwdb_all <= 34) ++ pwdb_all -= 6; ++ else if (pwdb_all > 14 && pwdb_all <= 26) ++ pwdb_all -= 8; ++ else if (pwdb_all > 4 && pwdb_all <= 14) ++ pwdb_all -= 4; ++ ++ pstats->rx_pwdb_all = pwdb_all; ++ pstats->recvsignalpower = rx_pwr_all; ++ ++ if (packet_match_bssid) { ++ u8 sq; ++ if (pstats->rx_pwdb_all > 40) { ++ sq = 100; ++ } else { ++ sq = cck_buf->sq_rpt; ++ if (sq > 64) ++ sq = 0; ++ else if (sq < 20) ++ sq = 100; ++ else ++ sq = ((64 - sq) * 100) / 44; ++ } ++ ++ pstats->signalquality = sq; ++ pstats->rx_mimo_signalquality[0] = sq; ++ pstats->rx_mimo_signalquality[1] = -1; ++ } ++ } else { ++ rtlpriv->dm.rfpath_rxenable[0] = ++ rtlpriv->dm.rfpath_rxenable[1] = true; ++ for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) { ++ if (rtlpriv->dm.rfpath_rxenable[i]) ++ rf_rx_num++; ++ ++ rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & ++ 0x3f) * 2) - 110; ++ rssi = _rtl92s_query_rxpwrpercentage(rx_pwr[i]); ++ total_rssi += rssi; ++ rtlpriv->stats.rx_snr_db[i] = ++ (long)(p_drvinfo->rxsnr[i] / 2); ++ ++ if (packet_match_bssid) ++ pstats->rx_mimo_signalstrength[i] = (u8) rssi; ++ } ++ ++ rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110; ++ pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all); ++ pstats->rx_pwdb_all = pwdb_all; ++ pstats->rxpower = rx_pwr_all; ++ pstats->recvsignalpower = rx_pwr_all; ++ ++ if (GET_RX_STATUS_DESC_RX_HT(pdesc) && ++ GET_RX_STATUS_DESC_RX_MCS(pdesc) >= DESC92S_RATEMCS8 && ++ GET_RX_STATUS_DESC_RX_MCS(pdesc) <= DESC92S_RATEMCS15) ++ max_spatial_stream = 2; ++ else ++ max_spatial_stream = 1; ++ ++ for (i = 0; i < max_spatial_stream; i++) { ++ evm = _rtl92s_evm_db_to_percentage(p_drvinfo->rxevm[i]); ++ ++ if (packet_match_bssid) { ++ if (i == 0) ++ pstats->signalquality = (u8)(evm & ++ 0xff); ++ pstats->rx_mimo_signalquality[i] = ++ (u8) (evm & 0xff); ++ } ++ } ++ } ++ ++ if (is_cck_rate) ++ pstats->signalstrength = (u8)(_rtl92se_signal_scale_mapping(hw, ++ pwdb_all)); ++ else if (rf_rx_num != 0) ++ pstats->signalstrength = (u8) (_rtl92se_signal_scale_mapping(hw, ++ total_rssi /= rf_rx_num)); ++} ++ ++static void _rtl92se_process_ui_rssi(struct ieee80211_hw *hw, ++ struct rtl_stats *pstats) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_phy *rtlphy = &(rtlpriv->phy); ++ u8 rfpath; ++ u32 last_rssi, tmpval; ++ ++ if (pstats->packet_toself || pstats->packet_beacon) { ++ rtlpriv->stats.rssi_calculate_cnt++; ++ ++ if (rtlpriv->stats.ui_rssi.total_num++ >= ++ PHY_RSSI_SLID_WIN_MAX) { ++ rtlpriv->stats.ui_rssi.total_num = ++ PHY_RSSI_SLID_WIN_MAX; ++ last_rssi = rtlpriv->stats.ui_rssi.elements[ ++ rtlpriv->stats.ui_rssi.index]; ++ rtlpriv->stats.ui_rssi.total_val -= last_rssi; ++ } ++ ++ rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength; ++ rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++] ++ = pstats->signalstrength; ++ ++ if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX) ++ rtlpriv->stats.ui_rssi.index = 0; ++ ++ tmpval = rtlpriv->stats.ui_rssi.total_val / ++ rtlpriv->stats.ui_rssi.total_num; ++ rtlpriv->stats.signal_strength = _rtl92se_translate_todbm(hw, ++ (u8) tmpval); ++ pstats->rssi = rtlpriv->stats.signal_strength; ++ } ++ ++ if (!pstats->is_cck && pstats->packet_toself) { ++ for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; ++ rfpath++) { ++ if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { ++ rtlpriv->stats.rx_rssi_percentage[rfpath] = ++ pstats->rx_mimo_signalstrength[rfpath]; ++ ++ } ++ ++ if (pstats->rx_mimo_signalstrength[rfpath] > ++ rtlpriv->stats.rx_rssi_percentage[rfpath]) { ++ rtlpriv->stats.rx_rssi_percentage[rfpath] = ++ ((rtlpriv->stats.rx_rssi_percentage[rfpath] ++ * (RX_SMOOTH_FACTOR - 1)) + ++ (pstats->rx_mimo_signalstrength[rfpath])) / ++ (RX_SMOOTH_FACTOR); ++ ++ rtlpriv->stats.rx_rssi_percentage[rfpath] = ++ rtlpriv->stats.rx_rssi_percentage[rfpath] ++ + 1; ++ } else { ++ rtlpriv->stats.rx_rssi_percentage[rfpath] = ++ ((rtlpriv->stats.rx_rssi_percentage[rfpath] ++ * (RX_SMOOTH_FACTOR - 1)) + ++ (pstats->rx_mimo_signalstrength[rfpath])) / ++ (RX_SMOOTH_FACTOR); ++ } ++ ++ } ++ } ++} ++ ++static void _rtl92se_update_rxsignalstatistics(struct ieee80211_hw *hw, ++ struct rtl_stats *pstats) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ int weighting = 0; ++ ++ if (rtlpriv->stats.recv_signal_power == 0) ++ rtlpriv->stats.recv_signal_power = pstats->recvsignalpower; ++ ++ if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power) ++ weighting = 5; ++ else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power) ++ weighting = (-5); ++ ++ rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * 5 ++ + pstats->recvsignalpower + ++ weighting) / 6; ++} ++ ++static void _rtl92se_process_pwdb(struct ieee80211_hw *hw, ++ struct rtl_stats *pstats) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ long undec_sm_pwdb = 0; ++ ++ if (mac->opmode == NL80211_IFTYPE_ADHOC) { ++ return; ++ } else { ++ undec_sm_pwdb = ++ rtlpriv->dm.undecorated_smoothed_pwdb; ++ } ++ ++ if (pstats->packet_toself || pstats->packet_beacon) { ++ if (undec_sm_pwdb < 0) ++ undec_sm_pwdb = pstats->rx_pwdb_all; ++ ++ if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) { ++ undec_sm_pwdb = ++ (((undec_sm_pwdb) * ++ (RX_SMOOTH_FACTOR - 1)) + ++ (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); ++ ++ undec_sm_pwdb = undec_sm_pwdb + 1; ++ } else { ++ undec_sm_pwdb = (((undec_sm_pwdb) * ++ (RX_SMOOTH_FACTOR - 1)) + (pstats->rx_pwdb_all)) / ++ (RX_SMOOTH_FACTOR); ++ } ++ ++ rtlpriv->dm.undecorated_smoothed_pwdb = undec_sm_pwdb; ++ _rtl92se_update_rxsignalstatistics(hw, pstats); ++ } ++} ++ ++static void rtl_92s_process_streams(struct ieee80211_hw *hw, ++ struct rtl_stats *pstats) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u32 stream; ++ ++ for (stream = 0; stream < 2; stream++) { ++ if (pstats->rx_mimo_signalquality[stream] != -1) { ++ if (rtlpriv->stats.rx_evm_percentage[stream] == 0) { ++ rtlpriv->stats.rx_evm_percentage[stream] = ++ pstats->rx_mimo_signalquality[stream]; ++ } ++ ++ rtlpriv->stats.rx_evm_percentage[stream] = ++ ((rtlpriv->stats.rx_evm_percentage[stream] * ++ (RX_SMOOTH_FACTOR - 1)) + ++ (pstats->rx_mimo_signalquality[stream] * ++ 1)) / (RX_SMOOTH_FACTOR); ++ } ++ } ++} ++ ++static void _rtl92se_process_ui_link_quality(struct ieee80211_hw *hw, ++ struct rtl_stats *pstats) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ u32 last_evm = 0, tmpval; ++ ++ if (pstats->signalquality != 0) { ++ if (pstats->packet_toself || pstats->packet_beacon) { ++ ++ if (rtlpriv->stats.ui_link_quality.total_num++ >= ++ PHY_LINKQUALITY_SLID_WIN_MAX) { ++ rtlpriv->stats.ui_link_quality.total_num = ++ PHY_LINKQUALITY_SLID_WIN_MAX; ++ last_evm = ++ rtlpriv->stats.ui_link_quality.elements[ ++ rtlpriv->stats.ui_link_quality.index]; ++ rtlpriv->stats.ui_link_quality.total_val -= ++ last_evm; ++ } ++ ++ rtlpriv->stats.ui_link_quality.total_val += ++ pstats->signalquality; ++ rtlpriv->stats.ui_link_quality.elements[ ++ rtlpriv->stats.ui_link_quality.index++] = ++ pstats->signalquality; ++ ++ if (rtlpriv->stats.ui_link_quality.index >= ++ PHY_LINKQUALITY_SLID_WIN_MAX) ++ rtlpriv->stats.ui_link_quality.index = 0; ++ ++ tmpval = rtlpriv->stats.ui_link_quality.total_val / ++ rtlpriv->stats.ui_link_quality.total_num; ++ rtlpriv->stats.signal_quality = tmpval; ++ ++ rtlpriv->stats.last_sigstrength_inpercent = tmpval; ++ ++ rtl_92s_process_streams(hw, pstats); ++ ++ } ++ } ++} ++ ++static void _rtl92se_process_phyinfo(struct ieee80211_hw *hw, ++ u8 *buffer, ++ struct rtl_stats *pcurrent_stats) ++{ ++ ++ if (!pcurrent_stats->packet_matchbssid && ++ !pcurrent_stats->packet_beacon) ++ return; ++ ++ _rtl92se_process_ui_rssi(hw, pcurrent_stats); ++ _rtl92se_process_pwdb(hw, pcurrent_stats); ++ _rtl92se_process_ui_link_quality(hw, pcurrent_stats); ++} ++ ++static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw, ++ struct sk_buff *skb, struct rtl_stats *pstats, ++ u8 *pdesc, struct rx_fwinfo *p_drvinfo) ++{ ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); ++ ++ struct ieee80211_hdr *hdr; ++ u8 *tmp_buf; ++ u8 *praddr; ++ u8 *psaddr; ++ __le16 fc; ++ u16 type, cfc; ++ bool packet_matchbssid, packet_toself, packet_beacon; ++ ++ tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; ++ ++ hdr = (struct ieee80211_hdr *)tmp_buf; ++ fc = hdr->frame_control; ++ cfc = le16_to_cpu(fc); ++ type = WLAN_FC_GET_TYPE(fc); ++ praddr = hdr->addr1; ++ psaddr = hdr->addr2; ++ ++ packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && ++ (!compare_ether_addr(mac->bssid, (cfc & IEEE80211_FCTL_TODS) ? ++ hdr->addr1 : (cfc & IEEE80211_FCTL_FROMDS) ? ++ hdr->addr2 : hdr->addr3)) && (!pstats->hwerror) && ++ (!pstats->crc) && (!pstats->icv)); ++ ++ packet_toself = packet_matchbssid && ++ (!compare_ether_addr(praddr, rtlefuse->dev_addr)); ++ ++ if (ieee80211_is_beacon(fc)) ++ packet_beacon = true; ++ ++ _rtl92se_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, ++ packet_matchbssid, packet_toself, packet_beacon); ++ _rtl92se_process_phyinfo(hw, tmp_buf, pstats); ++} ++ ++bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, ++ struct ieee80211_rx_status *rx_status, u8 *pdesc, ++ struct sk_buff *skb) ++{ ++ struct rx_fwinfo *p_drvinfo; ++ u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc); ++ ++ stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc); ++ stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8; ++ stats->rx_bufshift = (u8)(GET_RX_STATUS_DESC_SHIFT(pdesc) & 0x03); ++ stats->icv = (u16)GET_RX_STATUS_DESC_ICV(pdesc); ++ stats->crc = (u16)GET_RX_STATUS_DESC_CRC32(pdesc); ++ stats->hwerror = (u16)(stats->crc | stats->icv); ++ stats->decrypted = !GET_RX_STATUS_DESC_SWDEC(pdesc); ++ ++ stats->rate = (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc); ++ stats->shortpreamble = (u16)GET_RX_STATUS_DESC_SPLCP(pdesc); ++ stats->isampdu = (bool)(GET_RX_STATUS_DESC_PAGGR(pdesc) == 1); ++ stats->timestamp_low = GET_RX_STATUS_DESC_TSFL(pdesc); ++ stats->rx_is40Mhzpacket = (bool)GET_RX_STATUS_DESC_BW(pdesc); ++ ++ if (stats->hwerror) ++ return false; ++ ++ rx_status->freq = hw->conf.channel->center_freq; ++ rx_status->band = hw->conf.channel->band; ++ ++ if (GET_RX_STATUS_DESC_CRC32(pdesc)) ++ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; ++ ++ if (!GET_RX_STATUS_DESC_SWDEC(pdesc)) ++ rx_status->flag |= RX_FLAG_DECRYPTED; ++ ++ if (GET_RX_STATUS_DESC_BW(pdesc)) ++ rx_status->flag |= RX_FLAG_40MHZ; ++ ++ if (GET_RX_STATUS_DESC_RX_HT(pdesc)) ++ rx_status->flag |= RX_FLAG_HT; ++ ++ rx_status->flag |= RX_FLAG_MACTIME_MPDU; ++ ++ if (stats->decrypted) ++ rx_status->flag |= RX_FLAG_DECRYPTED; ++ ++ rx_status->rate_idx = _rtl92se_rate_mapping((bool) ++ GET_RX_STATUS_DESC_RX_HT(pdesc), ++ (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc), ++ (bool)GET_RX_STATUS_DESC_PAGGR(pdesc)); ++ ++ ++ rx_status->mactime = GET_RX_STATUS_DESC_TSFL(pdesc); ++ if (phystatus == true) { ++ p_drvinfo = (struct rx_fwinfo *)(skb->data + ++ stats->rx_bufshift); ++ _rtl92se_translate_rx_signal_stuff(hw, skb, stats, pdesc, ++ p_drvinfo); ++ } ++ ++ /*rx_status->qual = stats->signal; */ ++ rx_status->signal = stats->rssi + 10; ++ /*rx_status->noise = -stats->noise; */ ++ ++ return true; ++} ++ ++void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, ++ struct ieee80211_hdr *hdr, u8 *pdesc_tx, ++ struct ieee80211_tx_info *info, struct sk_buff *skb, ++ u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct ieee80211_sta *sta = info->control.sta; ++ u8 *pdesc = (u8 *) pdesc_tx; ++ u16 seq_number; ++ __le16 fc = hdr->frame_control; ++ u8 reserved_macid = 0; ++ u8 fw_qsel = _rtl92se_map_hwqueue_to_fwqueue(skb, hw_queue); ++ bool firstseg = (!(hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG))); ++ bool lastseg = (!(hdr->frame_control & ++ cpu_to_le16(IEEE80211_FCTL_MOREFRAGS))); ++ dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, ++ PCI_DMA_TODEVICE); ++ u8 bw_40 = 0; ++ ++ if (mac->opmode == NL80211_IFTYPE_STATION) { ++ bw_40 = mac->bw_40; ++ } else if (mac->opmode == NL80211_IFTYPE_AP || ++ mac->opmode == NL80211_IFTYPE_ADHOC) { ++ if (sta) ++ bw_40 = sta->ht_cap.cap & ++ IEEE80211_HT_CAP_SUP_WIDTH_20_40; ++ } ++ ++ seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; ++ ++ rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); ++ ++ CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE_RTL8192S); ++ ++ if (firstseg) { ++ if (rtlpriv->dm.useramask) { ++ /* set txdesc macId */ ++ if (ptcb_desc->mac_id < 32) { ++ SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id); ++ reserved_macid |= ptcb_desc->mac_id; ++ } ++ } ++ SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid); ++ ++ SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >= ++ DESC92S_RATEMCS0) ? 1 : 0)); ++ ++ if (rtlhal->version == VERSION_8192S_ACUT) { ++ if (ptcb_desc->hw_rate == DESC92S_RATE1M || ++ ptcb_desc->hw_rate == DESC92S_RATE2M || ++ ptcb_desc->hw_rate == DESC92S_RATE5_5M || ++ ptcb_desc->hw_rate == DESC92S_RATE11M) { ++ ptcb_desc->hw_rate = DESC92S_RATE12M; ++ } ++ } ++ ++ SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); ++ ++ if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble) ++ SET_TX_DESC_TX_SHORT(pdesc, 0); ++ ++ /* Aggregation related */ ++ if (info->flags & IEEE80211_TX_CTL_AMPDU) ++ SET_TX_DESC_AGG_ENABLE(pdesc, 1); ++ ++ /* For AMPDU, we must insert SSN into TX_DESC */ ++ SET_TX_DESC_SEQ(pdesc, seq_number); ++ ++ /* Protection mode related */ ++ /* For 92S, if RTS/CTS are set, HW will execute RTS. */ ++ /* We choose only one protection mode to execute */ ++ SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable && ++ !ptcb_desc->cts_enable) ? 1 : 0)); ++ SET_TX_DESC_CTS_ENABLE(pdesc, ((ptcb_desc->cts_enable) ? ++ 1 : 0)); ++ SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); ++ ++ SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); ++ SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0); ++ SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc); ++ SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= ++ DESC92S_RATE54M) ? ++ (ptcb_desc->rts_use_shortpreamble ? 1 : 0) ++ : (ptcb_desc->rts_use_shortgi ? 1 : 0))); ++ ++ ++ /* Set Bandwidth and sub-channel settings. */ ++ if (bw_40) { ++ if (ptcb_desc->packet_bw) { ++ SET_TX_DESC_TX_BANDWIDTH(pdesc, 1); ++ /* use duplicated mode */ ++ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); ++ } else { ++ SET_TX_DESC_TX_BANDWIDTH(pdesc, 0); ++ SET_TX_DESC_TX_SUB_CARRIER(pdesc, ++ mac->cur_40_prime_sc); ++ } ++ } else { ++ SET_TX_DESC_TX_BANDWIDTH(pdesc, 0); ++ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); ++ } ++ ++ /* 3 Fill necessary field in First Descriptor */ ++ /*DWORD 0*/ ++ SET_TX_DESC_LINIP(pdesc, 0); ++ SET_TX_DESC_OFFSET(pdesc, 32); ++ SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); ++ ++ /*DWORD 1*/ ++ SET_TX_DESC_RA_BRSR_ID(pdesc, ptcb_desc->ratr_index); ++ ++ /* Fill security related */ ++ if (info->control.hw_key) { ++ struct ieee80211_key_conf *keyconf; ++ ++ keyconf = info->control.hw_key; ++ switch (keyconf->cipher) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ case WLAN_CIPHER_SUITE_WEP104: ++ SET_TX_DESC_SEC_TYPE(pdesc, 0x1); ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ SET_TX_DESC_SEC_TYPE(pdesc, 0x2); ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ SET_TX_DESC_SEC_TYPE(pdesc, 0x3); ++ break; ++ default: ++ SET_TX_DESC_SEC_TYPE(pdesc, 0x0); ++ break; ++ ++ } ++ } ++ ++ /* Set Packet ID */ ++ SET_TX_DESC_PACKET_ID(pdesc, 0); ++ ++ /* We will assign magement queue to BK. */ ++ SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel); ++ ++ /* Alwasy enable all rate fallback range */ ++ SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); ++ ++ /* Fix: I don't kown why hw use 6.5M to tx when set it */ ++ SET_TX_DESC_USER_RATE(pdesc, ++ ptcb_desc->use_driver_rate ? 1 : 0); ++ ++ /* Set NON_QOS bit. */ ++ if (!ieee80211_is_data_qos(fc)) ++ SET_TX_DESC_NON_QOS(pdesc, 1); ++ ++ } ++ ++ /* Fill fields that are required to be initialized ++ * in all of the descriptors */ ++ /*DWORD 0 */ ++ SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); ++ SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); ++ ++ /* DWORD 7 */ ++ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); ++ ++ /* DOWRD 8 */ ++ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); ++ ++ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, ("\n")); ++} ++ ++void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, ++ bool firstseg, bool lastseg, struct sk_buff *skb) ++{ ++ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ struct rtl_tcb_desc *tcb_desc = (struct rtl_tcb_desc *)(skb->cb); ++ ++ dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, ++ PCI_DMA_TODEVICE); ++ ++ /* Clear all status */ ++ CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_CMDDESC_SIZE_RTL8192S); ++ ++ /* This bit indicate this packet is used for FW download. */ ++ if (tcb_desc->cmd_or_init == DESC_PACKET_TYPE_INIT) { ++ /* For firmware downlaod we only need to set LINIP */ ++ SET_TX_DESC_LINIP(pdesc, tcb_desc->last_inipkt); ++ ++ /* 92SE must set as 1 for firmware download HW DMA error */ ++ SET_TX_DESC_FIRST_SEG(pdesc, 1); ++ SET_TX_DESC_LAST_SEG(pdesc, 1); ++ ++ /* 92SE need not to set TX packet size when firmware download */ ++ SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len)); ++ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); ++ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); ++ ++ SET_TX_DESC_OWN(pdesc, 1); ++ } else { /* H2C Command Desc format (Host TXCMD) */ ++ /* 92SE must set as 1 for firmware download HW DMA error */ ++ SET_TX_DESC_FIRST_SEG(pdesc, 1); ++ SET_TX_DESC_LAST_SEG(pdesc, 1); ++ ++ SET_TX_DESC_OFFSET(pdesc, 0x20); ++ ++ /* Buffer size + command header */ ++ SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len)); ++ /* Fixed queue of H2C command */ ++ SET_TX_DESC_QUEUE_SEL(pdesc, 0x13); ++ ++ SET_BITS_TO_LE_4BYTE(skb->data, 24, 7, rtlhal->h2c_txcmd_seq); ++ ++ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); ++ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); ++ ++ SET_TX_DESC_OWN(pdesc, 1); ++ ++ } ++} ++ ++void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) ++{ ++ if (istx == true) { ++ switch (desc_name) { ++ case HW_DESC_OWN: ++ SET_TX_DESC_OWN(pdesc, 1); ++ break; ++ case HW_DESC_TX_NEXTDESC_ADDR: ++ SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val); ++ break; ++ default: ++ RT_ASSERT(false, ("ERR txdesc :%d not process\n", ++ desc_name)); ++ break; ++ } ++ } else { ++ switch (desc_name) { ++ case HW_DESC_RXOWN: ++ SET_RX_STATUS_DESC_OWN(pdesc, 1); ++ break; ++ case HW_DESC_RXBUFF_ADDR: ++ SET_RX_STATUS__DESC_BUFF_ADDR(pdesc, *(u32 *) val); ++ break; ++ case HW_DESC_RXPKT_LEN: ++ SET_RX_STATUS_DESC_PKT_LEN(pdesc, *(u32 *) val); ++ break; ++ case HW_DESC_RXERO: ++ SET_RX_STATUS_DESC_EOR(pdesc, 1); ++ break; ++ default: ++ RT_ASSERT(false, ("ERR rxdesc :%d not process\n", ++ desc_name)); ++ break; ++ } ++ } ++} ++ ++u32 rtl92se_get_desc(u8 *desc, bool istx, u8 desc_name) ++{ ++ u32 ret = 0; ++ ++ if (istx == true) { ++ switch (desc_name) { ++ case HW_DESC_OWN: ++ ret = GET_TX_DESC_OWN(desc); ++ break; ++ case HW_DESC_TXBUFF_ADDR: ++ ret = GET_TX_DESC_TX_BUFFER_ADDRESS(desc); ++ break; ++ default: ++ RT_ASSERT(false, ("ERR txdesc :%d not process\n", ++ desc_name)); ++ break; ++ } ++ } else { ++ switch (desc_name) { ++ case HW_DESC_OWN: ++ ret = GET_RX_STATUS_DESC_OWN(desc); ++ break; ++ case HW_DESC_RXPKT_LEN: ++ ret = GET_RX_STATUS_DESC_PKT_LEN(desc); ++ break; ++ default: ++ RT_ASSERT(false, ("ERR rxdesc :%d not process\n", ++ desc_name)); ++ break; ++ } ++ } ++ return ret; ++} ++ ++void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ rtl_write_word(rtlpriv, TP_POLL, BIT(0) << (hw_queue)); ++} +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/trx.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/trx.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/rtl8192se/trx.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/rtl8192se/trx.h 2011-05-05 23:29:49.282487741 +0200 +@@ -0,0 +1,45 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * wlanfae ++ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, ++ * Hsinchu 300, Taiwan. ++ * ++ * Larry Finger ++ * ++ *****************************************************************************/ ++#ifndef __REALTEK_PCI92SE_TRX_H__ ++#define __REALTEK_PCI92SE_TRX_H__ ++ ++void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, ++ u8 *pdesc, struct ieee80211_tx_info *info, ++ struct sk_buff *skb, u8 hw_queue, ++ struct rtl_tcb_desc *ptcb_desc); ++void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, ++ bool lastseg, struct sk_buff *skb); ++bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, ++ struct ieee80211_rx_status *rx_status, u8 *pdesc, ++ struct sk_buff *skb); ++void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); ++u32 rtl92se_get_desc(u8 *pdesc, bool istx, u8 desc_name); ++void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); ++ ++#endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/usb.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/usb.c +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/usb.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/usb.c 2011-05-05 23:29:49.302487983 +0200 +@@ -852,6 +852,7 @@ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl_tx_desc *pdesc = NULL; ++ struct rtl_tcb_desc tcb_desc; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + __le16 fc = hdr->frame_control; + u8 *pda_addr = hdr->addr1; +@@ -860,8 +861,17 @@ + u8 tid = 0; + u16 seq_number = 0; + +- if (ieee80211_is_mgmt(fc)) +- rtl_tx_mgmt_proc(hw, skb); ++ if (ieee80211_is_auth(fc)) { ++ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); ++ rtl_ips_nic_on(hw); ++ } ++ ++ if (rtlpriv->psc.sw_ps_enabled) { ++ if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && ++ !ieee80211_has_pm(fc)) ++ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); ++ } ++ + rtl_action_proc(hw, skb, true); + if (is_multicast_ether_addr(pda_addr)) + rtlpriv->stats.txbytesmulticast += skb->len; +@@ -878,7 +888,7 @@ + seq_number <<= 4; + } + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, skb, +- hw_queue); ++ hw_queue, &tcb_desc); + if (!ieee80211_has_morefrags(hdr->frame_control)) { + if (qc) + mac->tids[tid].seq_number = seq_number; +@@ -887,7 +897,8 @@ + rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); + } + +-static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ++static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb, ++ struct rtl_tcb_desc *dummy) + { + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/usb.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/usb.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/usb.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/usb.h 2011-05-05 23:29:49.301487971 +0200 +@@ -31,6 +31,8 @@ + #include + #include + ++#define RTL_RX_DESC_SIZE 24 ++ + #define RTL_USB_DEVICE(vend, prod, cfg) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ + .idVendor = (vend), \ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/wifi.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/wifi.h +--- linux-2.6.39-rc6/drivers/net/wireless/rtlwifi/wifi.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/rtlwifi/wifi.h 2011-05-05 23:29:49.309488067 +0200 +@@ -68,6 +68,8 @@ + #define QBSS_LOAD_SIZE 5 + #define MAX_WMMELE_LENGTH 64 + ++#define TOTAL_CAM_ENTRY 32 ++ + /*slot time for 11g. */ + #define RTL_SLOT_TIME_9 9 + #define RTL_SLOT_TIME_20 20 +@@ -94,8 +96,10 @@ + #define CHANNEL_GROUP_MAX_5G 9 + #define CHANNEL_MAX_NUMBER_2G 14 + #define AVG_THERMAL_NUM 8 ++#define MAX_TID_COUNT 9 + + /* for early mode */ ++#define FCS_LEN 4 + #define EM_HDR_LEN 8 + enum intf_type { + INTF_PCI = 0, +@@ -159,6 +163,8 @@ + (IS_HARDWARE_TYPE_8192DE(rtlhal) || IS_HARDWARE_TYPE_8192DU(rtlhal)) + #define IS_HARDWARE_TYPE_8723(rtlhal) \ + (IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal)) ++#define IS_HARDWARE_TYPE_8723U(rtlhal) \ ++ (rtlhal->hw_type == HARDWARE_TYPE_RTL8723U) + + enum scan_operation_backup_opt { + SCAN_OPT_BACKUP = 0, +@@ -297,6 +303,9 @@ + HW_VAR_DATA_FILTER, + }; + ++#define HWSET_MAX_SIZE 128 ++#define EFUSE_MAX_SECTION 16 ++ + enum _RT_MEDIA_STATUS { + RT_MEDIA_DISCONNECT = 0, + RT_MEDIA_CONNECT = 1 +@@ -766,7 +775,7 @@ + #define IQK_MATRIX_REG_NUM 8 + #define IQK_MATRIX_SETTINGS_NUM (1 + 24 + 21) + struct iqk_matrix_regs { +- bool b_iqk_done; ++ bool iqk_done; + long value[1][IQK_MATRIX_REG_NUM]; + }; + +@@ -843,6 +852,7 @@ + bool apk_done; + u32 reg_rf3c[2]; /* pathA / pathB */ + ++ /* bfsync */ + u8 framesync; + u32 framesync_c34; + +@@ -852,6 +862,10 @@ + }; + + #define MAX_TID_COUNT 9 ++#define RTL_AGG_STOP 0 ++#define RTL_AGG_PROGRESS 1 ++#define RTL_AGG_START 2 ++#define RTL_AGG_OPERATIONAL 3 + #define RTL_AGG_OFF 0 + #define RTL_AGG_ON 1 + #define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA 2 +@@ -871,6 +885,13 @@ + struct rtl_ht_agg agg; + }; + ++struct rtl_sta_info { ++ u8 ratr_index; ++ u8 wireless_mode; ++ u8 mimo_ps; ++ struct rtl_tid_data tids[MAX_TID_COUNT]; ++} __packed; ++ + struct rtl_priv; + struct rtl_io { + struct device *dev; +@@ -894,6 +915,7 @@ + u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr); + int (*readN_sync) (struct rtl_priv *rtlpriv, u32 addr, u16 len, + u8 *pdata); ++ + }; + + struct rtl_mac { +@@ -916,6 +938,8 @@ + int n_channels; + int n_bitrates; + ++ bool offchan_deley; ++ + /*filters */ + u32 rx_conf; + u16 rx_mgt_filter; +@@ -1032,7 +1056,9 @@ + enum rt_enc_alg pairwise_enc_algorithm; + /*Encryption Algorithm for Brocast/Multicast */ + enum rt_enc_alg group_enc_algorithm; +- ++ /*Cam Entry Bitmap */ ++ u32 hwsec_cam_bitmap; ++ u8 hwsec_cam_sta_addr[TOTAL_CAM_ENTRY][ETH_ALEN]; + /*local Key buffer, indx 0 is for + pairwise key 1-4 is for agoup key. */ + u8 key_buf[KEY_BUF_SIZE][MAX_KEY_LEN]; +@@ -1053,7 +1079,7 @@ + bool current_turbo_edca; + bool is_any_nonbepkts; /*out dm */ + bool is_cur_rdlstate; +- bool txpower_trackingInit; ++ bool txpower_trackinginit; + bool disable_framebursting; + bool cck_inch14; + bool txpower_tracking; +@@ -1079,7 +1105,6 @@ + bool disable_tx_int; + char ofdm_index[2]; + char cck_index; +- u8 power_index_backup[6]; + }; + + #define EFUSE_MAX_LOGICAL_SIZE 256 +@@ -1175,6 +1200,7 @@ + * otherwise Offset[560h] = 0x00. + * */ + bool support_aspm; ++ + bool support_backdoor; + + /*for LPS */ +@@ -1201,7 +1227,6 @@ + + /*just for PCIE ASPM */ + u8 const_amdpci_aspm; +- + bool pwrdown_mode; + + enum rf_pwrstate inactive_pwrstate; +@@ -1282,6 +1307,10 @@ + bool busytraffic; + bool higher_busytraffic; + bool higher_busyrxtraffic; ++ ++ u32 tidtx_in4period[MAX_TID_COUNT][4]; ++ u32 tidtx_inperiod[MAX_TID_COUNT]; ++ bool higher_busytxtraffic[MAX_TID_COUNT]; + }; + + struct rtl_tcb_desc { +@@ -1344,13 +1373,15 @@ + u32 add_msr, u32 rm_msr); + void (*get_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); + void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); +- void (*update_rate_table) (struct ieee80211_hw *hw); ++ void (*update_rate_tbl) (struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, u8 rssi_level); + void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level); + void (*fill_tx_desc) (struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, +- struct sk_buff *skb, unsigned int queue_index); +- void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 * pDesc, ++ struct sk_buff *skb, u8 hw_queue, ++ struct rtl_tcb_desc *ptcb_desc); ++ void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 *pDesc, + u32 buffer_len, bool bIsPsPoll); + void (*fill_tx_cmddesc) (struct ieee80211_hw *hw, u8 *pdesc, + bool firstseg, bool lastseg, +@@ -1370,10 +1401,10 @@ + enum led_ctl_mode ledaction); + void (*set_desc) (u8 *pdesc, bool istx, u8 desc_name, u8 *val); + u32 (*get_desc) (u8 *pdesc, bool istx, u8 desc_name); +- void (*tx_polling) (struct ieee80211_hw *hw, unsigned int hw_queue); ++ void (*tx_polling) (struct ieee80211_hw *hw, u8 hw_queue); + void (*enable_hw_sec) (struct ieee80211_hw *hw); + void (*set_key) (struct ieee80211_hw *hw, u32 key_index, +- u8 *p_macaddr, bool is_group, u8 enc_algo, ++ u8 *macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all); + void (*init_sw_leds) (struct ieee80211_hw *hw); + void (*deinit_sw_leds) (struct ieee80211_hw *hw); +@@ -1384,6 +1415,7 @@ + u32 regaddr, u32 bitmask); + void (*set_rfreg) (struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); ++ void (*linked_set_reg) (struct ieee80211_hw *hw); + bool (*phy_rf6052_config) (struct ieee80211_hw *hw); + void (*phy_rf6052_set_cck_txpower) (struct ieee80211_hw *hw, + u8 *powerlevel); +@@ -1404,7 +1436,9 @@ + int (*adapter_start) (struct ieee80211_hw *hw); + void (*adapter_stop) (struct ieee80211_hw *hw); + +- int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb); ++ int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb, ++ struct rtl_tcb_desc *ptcb_desc); ++ void (*flush)(struct ieee80211_hw *hw, bool drop); + int (*reset_trx_ring) (struct ieee80211_hw *hw); + bool (*waitq_insert) (struct ieee80211_hw *hw, struct sk_buff *skb); + +@@ -1418,6 +1452,15 @@ + struct rtl_mod_params { + /* default: 0 = using hardware encryption */ + int sw_crypto; ++ ++ /* default: 1 = using no linked power save */ ++ bool inactiveps; ++ ++ /* default: 1 = using linked sw power save */ ++ bool swctrl_lps; ++ ++ /* default: 1 = using linked fw power save */ ++ bool fwctrl_lps; + }; + + struct rtl_hal_usbint_cfg { +@@ -1445,6 +1488,7 @@ + + struct rtl_hal_cfg { + u8 bar_id; ++ bool write_readback; + char *name; + char *fw_name; + struct rtl_hal_ops *ops; +@@ -1469,7 +1513,6 @@ + spinlock_t rf_lock; + spinlock_t lps_lock; + spinlock_t waitq_lock; +- spinlock_t tx_urb_lock; + + /*Dual mac*/ + spinlock_t cck_and_rw_pagea_lock; +@@ -1621,19 +1664,19 @@ + u32 bt_edca_ul; + u32 bt_edca_dl; + +- bool b_init_set; +- bool b_bt_busy_traffic; +- bool b_bt_traffic_mode_set; +- bool b_bt_non_traffic_mode_set; ++ bool init_set; ++ bool bt_busy_traffic; ++ bool bt_traffic_mode_set; ++ bool bt_non_traffic_mode_set; + +- bool b_fw_coexist_all_off; +- bool b_sw_coexist_all_off; ++ bool fw_coexist_all_off; ++ bool sw_coexist_all_off; + u32 current_state; + u32 previous_state; + u8 bt_pre_rssi_state; + +- u8 b_reg_bt_iso; +- u8 b_reg_bt_sco; ++ u8 reg_bt_iso; ++ u8 reg_bt_sco; + + }; + +@@ -1653,13 +1696,23 @@ + #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(*((u16 *)(_ptr))) ++#define READEF4BYTE(_ptr) \ ++ EF4BYTE(*((u32 *)(_ptr))) + ++/* Write data to memory */ ++#define WRITEEF1BYTE(_ptr, _val) \ ++ (*((u8 *)(_ptr))) = EF1BYTE(_val) + /* Write le16 data to memory in host ordering */ + #define WRITEEF2BYTE(_ptr, _val) \ + (*((u16 *)(_ptr))) = EF2BYTE(_val) ++#define WRITEEF4BYTE(_ptr, _val) \ ++ (*((u16 *)(_ptr))) = EF2BYTE(_val) + + /* Create a bit mask + * Examples: +@@ -1698,6 +1751,25 @@ + #define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \ + (EF1BYTE(*((u8 *)(__pstart)))) + ++/*Description: ++Translate subfield (continuous bits in little-endian) of 4-byte ++value to 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 + * and return the result in 4-byte value in host byte ordering. +@@ -1721,6 +1793,18 @@ + /* Description: + * Set subfield of little-endian 4-byte value to specified value. + */ ++#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \ ++ *((u32 *)(__pstart)) = EF4BYTE \ ++ ( \ ++ 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)) = EF2BYTE \ ++ ( \ ++ 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 \ + ( \ +@@ -1728,12 +1812,16 @@ + ((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \ + ); + ++#define N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \ ++ (__value) : (((__value + __aligment - 1) / __aligment) * __aligment)) ++ + /**************************************** + mem access macro define end + ****************************************/ + + #define byte(x, n) ((x >> (8 * n)) & 0xff) + ++#define packet_get_type(_packet) (EF1BYTE((_packet).octet[0]) & 0xFC) + #define RTL_WATCH_DOG_TIME 2000 + #define MSECS(t) msecs_to_jiffies(t) + #define WLAN_FC_GET_VERS(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_VERS) +@@ -1768,6 +1856,15 @@ + #define container_of_dwork_rtl(x, y, z) \ + container_of(container_of(x, struct delayed_work, work), y, z) + ++#define FILL_OCTET_STRING(_os, _octet, _len) \ ++ (_os).octet = (u8 *)(_octet); \ ++ (_os).length = (_len); ++ ++#define CP_MACADDR(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]) ++ + static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr) + { + return rtlpriv->io.read8_sync(rtlpriv, addr); +@@ -1786,17 +1883,26 @@ + static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8) + { + rtlpriv->io.write8_async(rtlpriv, addr, val8); ++ ++ if (rtlpriv->cfg->write_readback) ++ rtlpriv->io.read8_sync(rtlpriv, addr); + } + + static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16) + { + rtlpriv->io.write16_async(rtlpriv, addr, val16); ++ ++ if (rtlpriv->cfg->write_readback) ++ rtlpriv->io.read16_sync(rtlpriv, addr); + } + + static inline void rtl_write_dword(struct rtl_priv *rtlpriv, + u32 addr, u32 val32) + { + rtlpriv->io.write32_async(rtlpriv, addr, val32); ++ ++ if (rtlpriv->cfg->write_readback) ++ rtlpriv->io.read32_sync(rtlpriv, addr); + } + + static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw, +@@ -1855,4 +1961,31 @@ + return rtlphy->rf_type; + } + ++static inline struct ieee80211_hdr *rtl_get_hdr(struct sk_buff *skb) ++{ ++ return (struct ieee80211_hdr *)(skb->data); ++} ++ ++static inline __le16 rtl_get_fc(struct sk_buff *skb) ++{ ++ return rtl_get_hdr(skb)->frame_control; ++} ++ ++static inline u16 rtl_get_tid_h(struct ieee80211_hdr *hdr) ++{ ++ return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; ++} ++ ++static inline u16 rtl_get_tid(struct sk_buff *skb) ++{ ++ return rtl_get_tid_h(rtl_get_hdr(skb)); ++} ++ ++static inline struct ieee80211_sta *get_sta(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ u8 *bssid) ++{ ++ return ieee80211_find_sta(vif, bssid); ++} ++ + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl1251/cmd.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl1251/cmd.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl1251/cmd.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl1251/cmd.h 2011-05-05 23:29:46.501454141 +0200 +@@ -313,8 +313,8 @@ + } __packed; + + enum wl1251_cmd_ps_mode { +- STATION_ACTIVE_MODE, +- STATION_POWER_SAVE_MODE ++ CHIP_ACTIVE_MODE, ++ CHIP_POWER_SAVE_MODE + }; + + struct wl1251_cmd_ps_params { +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl1251/event.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl1251/event.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl1251/event.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl1251/event.c 2011-05-05 23:29:46.341452207 +0200 +@@ -68,14 +68,16 @@ + if (vector & BSS_LOSE_EVENT_ID) { + wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); + +- if (wl->psm_requested && wl->psm) { ++ if (wl->psm_requested && ++ wl->station_mode != STATION_ACTIVE_MODE) { + ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + } + } + +- if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) { ++ if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && ++ wl->station_mode != STATION_ACTIVE_MODE) { + wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); + + /* indicate to the stack, that beacons have been lost */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl1251/main.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl1251/main.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl1251/main.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl1251/main.c 2011-05-05 23:29:46.498454104 +0200 +@@ -497,7 +497,7 @@ + wl->rx_last_id = 0; + wl->next_tx_complete = 0; + wl->elp = false; +- wl->psm = 0; ++ wl->station_mode = STATION_ACTIVE_MODE; + wl->tx_queue_stopped = false; + wl->power_level = WL1251_DEFAULT_POWER_LEVEL; + wl->rssi_thold = 0; +@@ -632,13 +632,29 @@ + + wl->psm_requested = false; + +- if (wl->psm) { ++ if (wl->station_mode != STATION_ACTIVE_MODE) { + ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + goto out_sleep; + } + } + ++ if (changed & IEEE80211_CONF_CHANGE_IDLE) { ++ if (conf->flags & IEEE80211_CONF_IDLE) { ++ ret = wl1251_ps_set_mode(wl, STATION_IDLE); ++ if (ret < 0) ++ goto out_sleep; ++ } else { ++ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); ++ if (ret < 0) ++ goto out_sleep; ++ ret = wl1251_join(wl, wl->bss_type, wl->channel, ++ wl->beacon_int, wl->dtim_period); ++ if (ret < 0) ++ goto out_sleep; ++ } ++ } ++ + if (conf->power_level != wl->power_level) { + ret = wl1251_acx_tx_power(wl, conf->power_level); + if (ret < 0) +@@ -1384,7 +1400,7 @@ + wl->rx_config = WL1251_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1251_DEFAULT_RX_FILTER; + wl->elp = false; +- wl->psm = 0; ++ wl->station_mode = STATION_ACTIVE_MODE; + wl->psm_requested = false; + wl->tx_queue_stopped = false; + wl->power_level = WL1251_DEFAULT_POWER_LEVEL; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl1251/ps.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl1251/ps.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl1251/ps.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl1251/ps.c 2011-05-05 23:29:46.498454104 +0200 +@@ -39,7 +39,7 @@ + + mutex_lock(&wl->mutex); + +- if (wl->elp || !wl->psm) ++ if (wl->elp || wl->station_mode == STATION_ACTIVE_MODE) + goto out; + + wl1251_debug(DEBUG_PSM, "chip to elp"); +@@ -57,7 +57,7 @@ + { + unsigned long delay; + +- if (wl->psm) { ++ if (wl->station_mode != STATION_ACTIVE_MODE) { + delay = msecs_to_jiffies(ELP_ENTRY_DELAY); + ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); + } +@@ -104,7 +104,7 @@ + return 0; + } + +-int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) ++int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode) + { + int ret; + +@@ -128,15 +128,24 @@ + if (ret < 0) + return ret; + +- ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); ++ ret = wl1251_cmd_ps_mode(wl, CHIP_POWER_SAVE_MODE); + if (ret < 0) + return ret; + + ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); + if (ret < 0) + return ret; ++ break; ++ case STATION_IDLE: ++ wl1251_debug(DEBUG_PSM, "entering idle"); + +- wl->psm = 1; ++ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); ++ if (ret < 0) ++ return ret; ++ ++ ret = wl1251_cmd_template_set(wl, CMD_DISCONNECT, NULL, 0); ++ if (ret < 0) ++ return ret; + break; + case STATION_ACTIVE_MODE: + default: +@@ -163,13 +172,13 @@ + if (ret < 0) + return ret; + +- ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); ++ ret = wl1251_cmd_ps_mode(wl, CHIP_ACTIVE_MODE); + if (ret < 0) + return ret; + +- wl->psm = 0; + break; + } ++ wl->station_mode = mode; + + return ret; + } +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl1251/ps.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl1251/ps.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl1251/ps.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl1251/ps.h 2011-05-05 23:29:46.352452339 +0200 +@@ -26,7 +26,7 @@ + #include "wl1251.h" + #include "acx.h" + +-int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode); ++int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode); + void wl1251_ps_elp_sleep(struct wl1251 *wl); + int wl1251_ps_elp_wakeup(struct wl1251 *wl); + void wl1251_elp_work(struct work_struct *work); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl1251/wl1251.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl1251/wl1251.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl1251/wl1251.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl1251/wl1251.h 2011-05-05 23:29:46.341452207 +0200 +@@ -129,6 +129,12 @@ + PART_TABLE_LEN + }; + ++enum wl1251_station_mode { ++ STATION_ACTIVE_MODE, ++ STATION_POWER_SAVE_MODE, ++ STATION_IDLE, ++}; ++ + struct wl1251_partition { + u32 size; + u32 start; +@@ -358,8 +364,7 @@ + + struct delayed_work elp_work; + +- /* we can be in psm, but not in elp, we have to differentiate */ +- bool psm; ++ enum wl1251_station_mode station_mode; + + /* PSM mode requested */ + bool psm_requested; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/acx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/acx.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/acx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/acx.c 2011-05-05 23:29:45.984447893 +0200 +@@ -965,10 +965,13 @@ + } + + /* memory config */ +- mem_conf->num_stations = wl->conf.mem.num_stations; +- mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num; +- mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num; +- mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles; ++ /* FIXME: for now we always use mem_wl127x for AP, because it ++ * doesn't support dynamic memory and we don't have the ++ * optimal values for wl128x without dynamic memory yet */ ++ mem_conf->num_stations = wl->conf.mem_wl127x.num_stations; ++ mem_conf->rx_mem_block_num = wl->conf.mem_wl127x.rx_block_num; ++ mem_conf->tx_min_mem_block_num = wl->conf.mem_wl127x.tx_min_block_num; ++ mem_conf->num_ssid_profiles = wl->conf.mem_wl127x.ssid_profiles; + mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); + + ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, +@@ -986,6 +989,7 @@ + int wl1271_acx_sta_mem_cfg(struct wl1271 *wl) + { + struct wl1271_acx_sta_config_memory *mem_conf; ++ struct conf_memory_settings *mem; + int ret; + + wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); +@@ -996,16 +1000,21 @@ + goto out; + } + ++ if (wl->chip.id == CHIP_ID_1283_PG20) ++ mem = &wl->conf.mem_wl128x; ++ else ++ mem = &wl->conf.mem_wl127x; ++ + /* memory config */ +- mem_conf->num_stations = wl->conf.mem.num_stations; +- mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num; +- mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num; +- mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles; ++ mem_conf->num_stations = mem->num_stations; ++ mem_conf->rx_mem_block_num = mem->rx_block_num; ++ mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; ++ mem_conf->num_ssid_profiles = mem->ssid_profiles; + mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); +- mem_conf->dyn_mem_enable = wl->conf.mem.dynamic_memory; +- mem_conf->tx_free_req = wl->conf.mem.min_req_tx_blocks; +- mem_conf->rx_free_req = wl->conf.mem.min_req_rx_blocks; +- mem_conf->tx_min = wl->conf.mem.tx_min; ++ mem_conf->dyn_mem_enable = mem->dynamic_memory; ++ mem_conf->tx_free_req = mem->min_req_tx_blocks; ++ mem_conf->rx_free_req = mem->min_req_rx_blocks; ++ mem_conf->tx_min = mem->tx_min; + + ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + sizeof(*mem_conf)); +@@ -1019,6 +1028,32 @@ + return ret; + } + ++int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap) ++{ ++ struct wl1271_acx_host_config_bitmap *bitmap_conf; ++ int ret; ++ ++ bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL); ++ if (!bitmap_conf) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap); ++ ++ ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP, ++ bitmap_conf, sizeof(*bitmap_conf)); ++ if (ret < 0) { ++ wl1271_warning("wl1271 bitmap config opt failed: %d", ret); ++ goto out; ++ } ++ ++out: ++ kfree(bitmap_conf); ++ ++ return ret; ++} ++ + int wl1271_acx_init_mem_config(struct wl1271 *wl) + { + int ret; +@@ -1489,22 +1524,46 @@ + return ret; + } + +-int wl1271_acx_max_tx_retry(struct wl1271 *wl) ++int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl) + { +- struct wl1271_acx_max_tx_retry *acx = NULL; ++ struct wl1271_acx_ap_max_tx_retry *acx = NULL; + int ret; + +- wl1271_debug(DEBUG_ACX, "acx max tx retry"); ++ wl1271_debug(DEBUG_ACX, "acx ap max tx retry"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + +- acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries); ++ acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); + + ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); + if (ret < 0) { +- wl1271_warning("acx max tx retry failed: %d", ret); ++ wl1271_warning("acx ap max tx retry failed: %d", ret); ++ goto out; ++ } ++ ++out: ++ kfree(acx); ++ return ret; ++} ++ ++int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl) ++{ ++ struct wl1271_acx_sta_max_tx_retry *acx = NULL; ++ int ret; ++ ++ wl1271_debug(DEBUG_ACX, "acx sta max tx retry"); ++ ++ acx = kzalloc(sizeof(*acx), GFP_KERNEL); ++ if (!acx) ++ return -ENOMEM; ++ ++ acx->max_tx_retry = wl->conf.tx.max_tx_retries; ++ ++ ret = wl1271_cmd_configure(wl, ACX_CONS_TX_FAILURE, acx, sizeof(*acx)); ++ if (ret < 0) { ++ wl1271_warning("acx sta max tx retry failed: %d", ret); + goto out; + } + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/acx.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/acx.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/acx.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/acx.h 2011-05-05 23:29:45.887446721 +0200 +@@ -939,6 +939,16 @@ + u8 padding; + } __packed; + ++#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0) ++#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1) ++#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3) ++ ++struct wl1271_acx_host_config_bitmap { ++ struct acx_header header; ++ ++ __le32 host_cfg_bitmap; ++} __packed; ++ + enum { + WL1271_ACX_TRIG_TYPE_LEVEL = 0, + WL1271_ACX_TRIG_TYPE_EDGE, +@@ -1135,7 +1145,7 @@ + u8 padding[3]; + } __packed; + +-struct wl1271_acx_max_tx_retry { ++struct wl1271_acx_ap_max_tx_retry { + struct acx_header header; + + /* +@@ -1146,6 +1156,13 @@ + u8 padding_1[2]; + } __packed; + ++struct wl1271_acx_sta_max_tx_retry { ++ struct acx_header header; ++ ++ u8 max_tx_retry; ++ u8 padding_1[3]; ++} __packed; ++ + struct wl1271_acx_config_ps { + struct acx_header header; + +@@ -1275,6 +1292,7 @@ + int wl1271_acx_ap_mem_cfg(struct wl1271 *wl); + int wl1271_acx_sta_mem_cfg(struct wl1271 *wl); + int wl1271_acx_init_mem_config(struct wl1271 *wl); ++int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap); + int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); + int wl1271_acx_smart_reflex(struct wl1271 *wl); + int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); +@@ -1296,7 +1314,8 @@ + int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, + bool enable); + int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); +-int wl1271_acx_max_tx_retry(struct wl1271 *wl); ++int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); ++int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl); + int wl1271_acx_config_ps(struct wl1271 *wl); + int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/boot.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/boot.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/boot.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/boot.c 2011-05-05 23:29:45.879446625 +0200 +@@ -22,6 +22,7 @@ + */ + + #include ++#include + + #include "acx.h" + #include "reg.h" +@@ -243,33 +244,57 @@ + if (wl->nvs == NULL) + return -ENODEV; + +- /* +- * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band +- * configurations) can be removed when those NVS files stop floating +- * around. +- */ +- if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || +- wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { +- /* for now 11a is unsupported in AP mode */ +- if (wl->bss_type != BSS_TYPE_AP_BSS && +- wl->nvs->general_params.dual_mode_select) +- wl->enable_11a = true; +- } +- +- if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && +- (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || +- wl->enable_11a)) { +- wl1271_error("nvs size is not as expected: %zu != %zu", +- wl->nvs_len, sizeof(struct wl1271_nvs_file)); +- kfree(wl->nvs); +- wl->nvs = NULL; +- wl->nvs_len = 0; +- return -EILSEQ; +- } +- +- /* only the first part of the NVS needs to be uploaded */ +- nvs_len = sizeof(wl->nvs->nvs); +- nvs_ptr = (u8 *)wl->nvs->nvs; ++ if (wl->chip.id == CHIP_ID_1283_PG20) { ++ struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; ++ ++ if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) { ++ if (nvs->general_params.dual_mode_select) ++ wl->enable_11a = true; ++ } else { ++ wl1271_error("nvs size is not as expected: %zu != %zu", ++ wl->nvs_len, ++ sizeof(struct wl128x_nvs_file)); ++ kfree(wl->nvs); ++ wl->nvs = NULL; ++ wl->nvs_len = 0; ++ return -EILSEQ; ++ } ++ ++ /* only the first part of the NVS needs to be uploaded */ ++ nvs_len = sizeof(nvs->nvs); ++ nvs_ptr = (u8 *)nvs->nvs; ++ ++ } else { ++ struct wl1271_nvs_file *nvs = ++ (struct wl1271_nvs_file *)wl->nvs; ++ /* ++ * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz ++ * band configurations) can be removed when those NVS files stop ++ * floating around. ++ */ ++ if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || ++ wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { ++ /* for now 11a is unsupported in AP mode */ ++ if (wl->bss_type != BSS_TYPE_AP_BSS && ++ nvs->general_params.dual_mode_select) ++ wl->enable_11a = true; ++ } ++ ++ if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && ++ (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || ++ wl->enable_11a)) { ++ wl1271_error("nvs size is not as expected: %zu != %zu", ++ wl->nvs_len, sizeof(struct wl1271_nvs_file)); ++ kfree(wl->nvs); ++ wl->nvs = NULL; ++ wl->nvs_len = 0; ++ return -EILSEQ; ++ } ++ ++ /* only the first part of the NVS needs to be uploaded */ ++ nvs_len = sizeof(nvs->nvs); ++ nvs_ptr = (u8 *) nvs->nvs; ++ } + + /* update current MAC address to NVS */ + nvs_ptr[11] = wl->mac_addr[0]; +@@ -319,10 +344,13 @@ + /* + * We've reached the first zero length, the first NVS table + * is located at an aligned offset which is at least 7 bytes further. ++ * NOTE: The wl->nvs->nvs element must be first, in order to ++ * simplify the casting, we assume it is at the beginning of ++ * the wl->nvs structure. + */ +- nvs_ptr = (u8 *)wl->nvs->nvs + +- ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4); +- nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; ++ nvs_ptr = (u8 *)wl->nvs + ++ ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4); ++ nvs_len -= nvs_ptr - (u8 *)wl->nvs; + + /* Now we must set the partition correctly */ + wl1271_set_partition(wl, &part_table[PART_WORK]); +@@ -450,10 +478,14 @@ + DISCONNECT_EVENT_COMPLETE_ID | + RSSI_SNR_TRIGGER_0_EVENT_ID | + PSPOLL_DELIVERY_FAILURE_EVENT_ID | +- SOFT_GEMINI_SENSE_EVENT_ID; ++ SOFT_GEMINI_SENSE_EVENT_ID | ++ MAX_TX_RETRY_EVENT_ID; + + if (wl->bss_type == BSS_TYPE_AP_BSS) +- wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; ++ wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID | ++ INACTIVE_STA_EVENT_ID; ++ else ++ wl->event_mask |= DUMMY_PACKET_EVENT_ID; + + ret = wl1271_event_unmask(wl); + if (ret < 0) { +@@ -493,24 +525,159 @@ + wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; + } + +-/* uploads NVS and firmware */ +-int wl1271_load_firmware(struct wl1271 *wl) ++static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) + { +- int ret = 0; +- u32 tmp, clk, pause; ++ u16 spare_reg; ++ ++ /* Mask bits [2] & [8:4] in the sys_clk_cfg register */ ++ spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG); ++ if (spare_reg == 0xFFFF) ++ return -EFAULT; ++ spare_reg |= (BIT(3) | BIT(5) | BIT(6)); ++ wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); ++ ++ /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */ ++ wl1271_top_reg_write(wl, SYS_CLK_CFG_REG, ++ WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); ++ ++ /* Delay execution for 15msec, to let the HW settle */ ++ mdelay(15); ++ ++ return 0; ++} ++ ++static bool wl128x_is_tcxo_valid(struct wl1271 *wl) ++{ ++ u16 tcxo_detection; ++ ++ tcxo_detection = wl1271_top_reg_read(wl, TCXO_CLK_DETECT_REG); ++ if (tcxo_detection & TCXO_DET_FAILED) ++ return false; ++ ++ return true; ++} ++ ++static bool wl128x_is_fref_valid(struct wl1271 *wl) ++{ ++ u16 fref_detection; ++ ++ fref_detection = wl1271_top_reg_read(wl, FREF_CLK_DETECT_REG); ++ if (fref_detection & FREF_CLK_DETECT_FAIL) ++ return false; ++ ++ return true; ++} ++ ++static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl) ++{ ++ wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); ++ wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); ++ wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL); ++ ++ return 0; ++} ++ ++static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) ++{ ++ u16 spare_reg; ++ u16 pll_config; ++ u8 input_freq; ++ ++ /* Mask bits [3:1] in the sys_clk_cfg register */ ++ spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG); ++ if (spare_reg == 0xFFFF) ++ return -EFAULT; ++ spare_reg |= BIT(2); ++ wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); ++ ++ /* Handle special cases of the TCXO clock */ ++ if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || ++ wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6) ++ return wl128x_manually_configure_mcs_pll(wl); ++ ++ /* Set the input frequency according to the selected clock source */ ++ input_freq = (clk & 1) + 1; ++ ++ pll_config = wl1271_top_reg_read(wl, MCS_PLL_CONFIG_REG); ++ if (pll_config == 0xFFFF) ++ return -EFAULT; ++ pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); ++ pll_config |= MCS_PLL_ENABLE_HP; ++ wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); ++ ++ return 0; ++} ++ ++/* ++ * WL128x has two clocks input - TCXO and FREF. ++ * TCXO is the main clock of the device, while FREF is used to sync ++ * between the GPS and the cellular modem. ++ * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used ++ * as the WLAN/BT main clock. ++ */ ++static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) ++{ ++ u16 sys_clk_cfg; ++ ++ /* For XTAL-only modes, FREF will be used after switching from TCXO */ ++ if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL || ++ wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) { ++ if (!wl128x_switch_tcxo_to_fref(wl)) ++ return -EINVAL; ++ goto fref_clk; ++ } ++ ++ /* Query the HW, to determine which clock source we should use */ ++ sys_clk_cfg = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG); ++ if (sys_clk_cfg == 0xFFFF) ++ return -EINVAL; ++ if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) ++ goto fref_clk; ++ ++ /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */ ++ if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 || ++ wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) { ++ if (!wl128x_switch_tcxo_to_fref(wl)) ++ return -EINVAL; ++ goto fref_clk; ++ } ++ ++ /* TCXO clock is selected */ ++ if (!wl128x_is_tcxo_valid(wl)) ++ return -EINVAL; ++ *selected_clock = wl->tcxo_clock; ++ goto config_mcs_pll; ++ ++fref_clk: ++ /* FREF clock is selected */ ++ if (!wl128x_is_fref_valid(wl)) ++ return -EINVAL; ++ *selected_clock = wl->ref_clock; ++ ++config_mcs_pll: ++ return wl128x_configure_mcs_pll(wl, *selected_clock); ++} ++ ++static int wl127x_boot_clk(struct wl1271 *wl) ++{ ++ u32 pause; ++ u32 clk; + + wl1271_boot_hw_version(wl); + +- if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4) ++ if (wl->ref_clock == CONF_REF_CLK_19_2_E || ++ wl->ref_clock == CONF_REF_CLK_38_4_E || ++ wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) + /* ref clk: 19.2/38.4/38.4-XTAL */ + clk = 0x3; +- else if (wl->ref_clock == 1 || wl->ref_clock == 3) ++ else if (wl->ref_clock == CONF_REF_CLK_26_E || ++ wl->ref_clock == CONF_REF_CLK_52_E) + /* ref clk: 26/52 */ + clk = 0x5; + else + return -EINVAL; + +- if (wl->ref_clock != 0) { ++ if (wl->ref_clock != CONF_REF_CLK_19_2_E) { + u16 val; + /* Set clock type (open drain) */ + val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); +@@ -540,6 +707,26 @@ + pause |= WU_COUNTER_PAUSE_VAL; + wl1271_write32(wl, WU_COUNTER_PAUSE, pause); + ++ return 0; ++} ++ ++/* uploads NVS and firmware */ ++int wl1271_load_firmware(struct wl1271 *wl) ++{ ++ int ret = 0; ++ u32 tmp, clk; ++ int selected_clock = -1; ++ ++ if (wl->chip.id == CHIP_ID_1283_PG20) { ++ ret = wl128x_boot_clk(wl, &selected_clock); ++ if (ret < 0) ++ goto out; ++ } else { ++ ret = wl127x_boot_clk(wl); ++ if (ret < 0) ++ goto out; ++ } ++ + /* Continue the ELP wake up sequence */ + wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + udelay(500); +@@ -555,7 +742,12 @@ + + wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); + +- clk |= (wl->ref_clock << 1) << 4; ++ if (wl->chip.id == CHIP_ID_1283_PG20) { ++ clk |= ((selected_clock & 0x3) << 1) << 4; ++ } else { ++ clk |= (wl->ref_clock << 1) << 4; ++ } ++ + wl1271_write32(wl, DRPW_SCRATCH_START, clk); + + wl1271_set_partition(wl, &part_table[PART_WORK]); +@@ -585,16 +777,12 @@ + /* 6. read the EEPROM parameters */ + tmp = wl1271_read32(wl, SCR_PAD2); + +- ret = wl1271_boot_write_irq_polarity(wl); +- if (ret < 0) +- goto out; +- +- wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, +- WL1271_ACX_ALL_EVENTS_VECTOR); +- + /* WL1271: The reference driver skips steps 7 to 10 (jumps directly + * to upload_fw) */ + ++ if (wl->chip.id == CHIP_ID_1283_PG20) ++ wl1271_top_reg_write(wl, SDIO_IO_DS, wl->conf.hci_io_ds); ++ + ret = wl1271_boot_upload_firmware(wl); + if (ret < 0) + goto out; +@@ -618,6 +806,13 @@ + if (ret < 0) + goto out; + ++ ret = wl1271_boot_write_irq_polarity(wl); ++ if (ret < 0) ++ goto out; ++ ++ wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, ++ WL1271_ACX_ALL_EVENTS_VECTOR); ++ + /* Enable firmware interrupts now */ + wl1271_boot_enable_interrupts(wl); + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/boot.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/boot.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/boot.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/boot.h 2011-05-05 23:29:45.968447701 +0200 +@@ -74,4 +74,56 @@ + #define FREF_CLK_POLARITY_BITS 0xfffff8ff + #define CLK_REQ_OUTN_SEL 0x700 + ++/* PLL configuration algorithm for wl128x */ ++#define SYS_CLK_CFG_REG 0x2200 ++/* Bit[0] - 0-TCXO, 1-FREF */ ++#define MCS_PLL_CLK_SEL_FREF BIT(0) ++/* Bit[3:2] - 01-TCXO, 10-FREF */ ++#define WL_CLK_REQ_TYPE_FREF BIT(3) ++#define WL_CLK_REQ_TYPE_PG2 (BIT(3) | BIT(2)) ++/* Bit[4] - 0-TCXO, 1-FREF */ ++#define PRCM_CM_EN_MUX_WLAN_FREF BIT(4) ++ ++#define TCXO_ILOAD_INT_REG 0x2264 ++#define TCXO_CLK_DETECT_REG 0x2266 ++ ++#define TCXO_DET_FAILED BIT(4) ++ ++#define FREF_ILOAD_INT_REG 0x2084 ++#define FREF_CLK_DETECT_REG 0x2086 ++#define FREF_CLK_DETECT_FAIL BIT(4) ++ ++/* Use this reg for masking during driver access */ ++#define WL_SPARE_REG 0x2320 ++#define WL_SPARE_VAL BIT(2) ++/* Bit[6:5:3] - mask wl write SYS_CLK_CFG[8:5:2:4] */ ++#define WL_SPARE_MASK_8526 (BIT(6) | BIT(5) | BIT(3)) ++ ++#define PLL_LOCK_COUNTERS_REG 0xD8C ++#define PLL_LOCK_COUNTERS_COEX 0x0F ++#define PLL_LOCK_COUNTERS_MCS 0xF0 ++#define MCS_PLL_OVERRIDE_REG 0xD90 ++#define MCS_PLL_CONFIG_REG 0xD92 ++#define MCS_SEL_IN_FREQ_MASK 0x0070 ++#define MCS_SEL_IN_FREQ_SHIFT 4 ++#define MCS_PLL_CONFIG_REG_VAL 0x73 ++#define MCS_PLL_ENABLE_HP (BIT(0) | BIT(1)) ++ ++#define MCS_PLL_M_REG 0xD94 ++#define MCS_PLL_N_REG 0xD96 ++#define MCS_PLL_M_REG_VAL 0xC8 ++#define MCS_PLL_N_REG_VAL 0x07 ++ ++#define SDIO_IO_DS 0xd14 ++ ++/* SDIO/wSPI DS configuration values */ ++enum { ++ HCI_IO_DS_8MA = 0, ++ HCI_IO_DS_4MA = 1, /* default */ ++ HCI_IO_DS_6MA = 2, ++ HCI_IO_DS_2MA = 3, ++}; ++ ++/* end PLL configuration algorithm for wl128x */ ++ + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/cmd.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/cmd.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/cmd.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/cmd.c 2011-05-05 23:29:45.918447097 +0200 +@@ -110,7 +110,47 @@ + int wl1271_cmd_general_parms(struct wl1271 *wl) + { + struct wl1271_general_parms_cmd *gen_parms; +- struct wl1271_ini_general_params *gp = &wl->nvs->general_params; ++ struct wl1271_ini_general_params *gp = ++ &((struct wl1271_nvs_file *)wl->nvs)->general_params; ++ bool answer = false; ++ int ret; ++ ++ if (!wl->nvs) ++ return -ENODEV; ++ ++ gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); ++ if (!gen_parms) ++ return -ENOMEM; ++ ++ gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; ++ ++ memcpy(&gen_parms->general_params, gp, sizeof(*gp)); ++ ++ if (gp->tx_bip_fem_auto_detect) ++ answer = true; ++ ++ ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); ++ if (ret < 0) { ++ wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); ++ goto out; ++ } ++ ++ gp->tx_bip_fem_manufacturer = ++ gen_parms->general_params.tx_bip_fem_manufacturer; ++ ++ wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", ++ answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); ++ ++out: ++ kfree(gen_parms); ++ return ret; ++} ++ ++int wl128x_cmd_general_parms(struct wl1271 *wl) ++{ ++ struct wl128x_general_parms_cmd *gen_parms; ++ struct wl128x_ini_general_params *gp = ++ &((struct wl128x_nvs_file *)wl->nvs)->general_params; + bool answer = false; + int ret; + +@@ -147,8 +187,9 @@ + + int wl1271_cmd_radio_parms(struct wl1271 *wl) + { ++ struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; + struct wl1271_radio_parms_cmd *radio_parms; +- struct wl1271_ini_general_params *gp = &wl->nvs->general_params; ++ struct wl1271_ini_general_params *gp = &nvs->general_params; + int ret; + + if (!wl->nvs) +@@ -161,18 +202,18 @@ + radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; + + /* 2.4GHz parameters */ +- memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2, ++ memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, + sizeof(struct wl1271_ini_band_params_2)); + memcpy(&radio_parms->dyn_params_2, +- &wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, ++ &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, + sizeof(struct wl1271_ini_fem_params_2)); + + /* 5GHz parameters */ + memcpy(&radio_parms->static_params_5, +- &wl->nvs->stat_radio_params_5, ++ &nvs->stat_radio_params_5, + sizeof(struct wl1271_ini_band_params_5)); + memcpy(&radio_parms->dyn_params_5, +- &wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, ++ &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, + sizeof(struct wl1271_ini_fem_params_5)); + + wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", +@@ -186,6 +227,50 @@ + return ret; + } + ++int wl128x_cmd_radio_parms(struct wl1271 *wl) ++{ ++ struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; ++ struct wl128x_radio_parms_cmd *radio_parms; ++ struct wl128x_ini_general_params *gp = &nvs->general_params; ++ int ret; ++ ++ if (!wl->nvs) ++ return -ENODEV; ++ ++ radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); ++ if (!radio_parms) ++ return -ENOMEM; ++ ++ radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; ++ ++ /* 2.4GHz parameters */ ++ memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, ++ sizeof(struct wl128x_ini_band_params_2)); ++ memcpy(&radio_parms->dyn_params_2, ++ &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, ++ sizeof(struct wl128x_ini_fem_params_2)); ++ ++ /* 5GHz parameters */ ++ memcpy(&radio_parms->static_params_5, ++ &nvs->stat_radio_params_5, ++ sizeof(struct wl128x_ini_band_params_5)); ++ memcpy(&radio_parms->dyn_params_5, ++ &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, ++ sizeof(struct wl128x_ini_fem_params_5)); ++ ++ radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; ++ ++ wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", ++ radio_parms, sizeof(*radio_parms)); ++ ++ ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); ++ if (ret < 0) ++ wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); ++ ++ kfree(radio_parms); ++ return ret; ++} ++ + int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) + { + struct wl1271_ext_radio_parms_cmd *ext_radio_parms; +@@ -985,7 +1070,7 @@ + + memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); + +- cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC); ++ cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); + cmd->bss_index = WL1271_AP_BSS_INDEX; + cmd->global_hlid = WL1271_AP_GLOBAL_HLID; + cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/cmd.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/cmd.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/cmd.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/cmd.h 2011-05-05 23:29:45.998448063 +0200 +@@ -32,7 +32,9 @@ + int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, + size_t res_len); + int wl1271_cmd_general_parms(struct wl1271 *wl); ++int wl128x_cmd_general_parms(struct wl1271 *wl); + int wl1271_cmd_radio_parms(struct wl1271 *wl); ++int wl128x_cmd_radio_parms(struct wl1271 *wl); + int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); + int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type); + int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); +@@ -415,6 +417,21 @@ + u8 padding[3]; + } __packed; + ++struct wl128x_general_parms_cmd { ++ struct wl1271_cmd_header header; ++ ++ struct wl1271_cmd_test_header test; ++ ++ struct wl128x_ini_general_params general_params; ++ ++ u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM]; ++ u8 sr_sen_n_p; ++ u8 sr_sen_n_p_gain; ++ u8 sr_sen_nrn; ++ u8 sr_sen_prn; ++ u8 padding[3]; ++} __packed; ++ + struct wl1271_radio_parms_cmd { + struct wl1271_cmd_header header; + +@@ -431,6 +448,23 @@ + u8 padding3[2]; + } __packed; + ++struct wl128x_radio_parms_cmd { ++ struct wl1271_cmd_header header; ++ ++ struct wl1271_cmd_test_header test; ++ ++ /* Static radio parameters */ ++ struct wl128x_ini_band_params_2 static_params_2; ++ struct wl128x_ini_band_params_5 static_params_5; ++ ++ u8 fem_vendor_and_options; ++ ++ /* Dynamic radio parameters */ ++ struct wl128x_ini_fem_params_2 dyn_params_2; ++ u8 padding2; ++ struct wl128x_ini_fem_params_5 dyn_params_5; ++} __packed; ++ + struct wl1271_ext_radio_parms_cmd { + struct wl1271_cmd_header header; + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/conf.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/conf.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/conf.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/conf.h 2011-05-05 23:29:46.005448147 +0200 +@@ -683,10 +683,18 @@ + struct conf_tx_rate_class ap_bcst_conf; + + /* +- * AP-mode - allow this number of TX retries to a station before an ++ * Allow this number of TX retries to a connected station/AP before an + * event is triggered from FW. ++ * In AP-mode the hlids of unreachable stations are given in the ++ * "sta_tx_retry_exceeded" member in the event mailbox. + */ +- u16 ap_max_tx_retries; ++ u8 max_tx_retries; ++ ++ /* ++ * AP-mode - after this number of seconds a connected station is ++ * considered inactive. ++ */ ++ u16 ap_aging_period; + + /* + * Configuration for TID parameters. +@@ -1004,7 +1012,9 @@ + CONF_REF_CLK_19_2_E, + CONF_REF_CLK_26_E, + CONF_REF_CLK_38_4_E, +- CONF_REF_CLK_52_E ++ CONF_REF_CLK_52_E, ++ CONF_REF_CLK_38_4_M_XTAL, ++ CONF_REF_CLK_26_M_XTAL, + }; + + enum single_dual_band_enum { +@@ -1018,15 +1028,6 @@ + #define CONF_NUMBER_OF_CHANNELS_2_4 14 + #define CONF_NUMBER_OF_CHANNELS_5 35 + +-struct conf_radio_parms { +- /* +- * FEM parameter set to use +- * +- * Range: 0 or 1 +- */ +- u8 fem; +-}; +- + struct conf_itrim_settings { + /* enable dco itrim */ + u8 enable; +@@ -1202,7 +1203,9 @@ + struct conf_scan_settings scan; + struct conf_rf_settings rf; + struct conf_ht_setting ht; +- struct conf_memory_settings mem; ++ struct conf_memory_settings mem_wl127x; ++ struct conf_memory_settings mem_wl128x; ++ u8 hci_io_ds; + }; + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/debugfs.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/debugfs.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/debugfs.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/debugfs.c 2011-05-05 23:29:45.977447809 +0200 +@@ -267,7 +267,7 @@ + } + buf[len] = '\0'; + +- ret = strict_strtoul(buf, 0, &value); ++ ret = kstrtoul(buf, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value in gpio_power"); + return -EINVAL; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/event.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/event.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/event.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/event.c 2011-05-05 23:29:45.901446891 +0200 +@@ -33,6 +33,7 @@ + { + struct delayed_work *dwork; + struct wl1271 *wl; ++ int ret; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1271, pspoll_work); +@@ -55,8 +56,13 @@ + * delivery failure occurred, and no-one changed state since, so + * we should go back to powersave. + */ ++ ret = wl1271_ps_elp_wakeup(wl); ++ if (ret < 0) ++ goto out; ++ + wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); + ++ wl1271_ps_elp_sleep(wl); + out: + mutex_unlock(&wl->mutex); + }; +@@ -129,11 +135,6 @@ + + /* enable beacon early termination */ + ret = wl1271_acx_bet_enable(wl, true); +- if (ret < 0) +- break; +- +- /* go to extremely low power mode */ +- wl1271_ps_elp_sleep(wl); + break; + default: + break; +@@ -173,6 +174,8 @@ + u32 vector; + bool beacon_loss = false; + bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); ++ bool disconnect_sta = false; ++ unsigned long sta_bitmap = 0; + + wl1271_event_mbox_dump(mbox); + +@@ -228,9 +231,60 @@ + wl1271_event_rssi_trigger(wl, mbox); + } + ++ if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) { ++ wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); ++ if (wl->vif) ++ wl1271_tx_dummy_packet(wl); ++ } ++ ++ /* ++ * "TX retries exceeded" has a different meaning according to mode. ++ * In AP mode the offending station is disconnected. In STA mode we ++ * report connection loss. ++ */ ++ if (vector & MAX_TX_RETRY_EVENT_ID) { ++ wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); ++ if (is_ap) { ++ sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); ++ disconnect_sta = true; ++ } else { ++ beacon_loss = true; ++ } ++ } ++ ++ if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) { ++ wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); ++ sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); ++ disconnect_sta = true; ++ } ++ + if (wl->vif && beacon_loss) + ieee80211_connection_loss(wl->vif); + ++ if (is_ap && disconnect_sta) { ++ u32 num_packets = wl->conf.tx.max_tx_retries; ++ struct ieee80211_sta *sta; ++ const u8 *addr; ++ int h; ++ ++ for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS); ++ h < AP_MAX_LINKS; ++ h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) { ++ if (!wl1271_is_active_sta(wl, h)) ++ continue; ++ ++ addr = wl->links[h].addr; ++ ++ rcu_read_lock(); ++ sta = ieee80211_find_sta(wl->vif, addr); ++ if (sta) { ++ wl1271_debug(DEBUG_EVENT, "remove sta %d", h); ++ ieee80211_report_low_ack(sta, num_packets); ++ } ++ rcu_read_unlock(); ++ } ++ } ++ + return 0; + } + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/event.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/event.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/event.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/event.h 2011-05-05 23:29:45.970447725 +0200 +@@ -58,10 +58,16 @@ + CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), + BSS_LOSE_EVENT_ID = BIT(18), + REGAINED_BSS_EVENT_ID = BIT(19), +- ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), +- STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), /* AP */ ++ MAX_TX_RETRY_EVENT_ID = BIT(20), ++ /* STA: dummy paket for dynamic mem blocks */ ++ DUMMY_PACKET_EVENT_ID = BIT(21), ++ /* AP: STA remove complete */ ++ STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), + SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), ++ /* STA: SG prediction */ + SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), ++ /* AP: Inactive STA */ ++ INACTIVE_STA_EVENT_ID = BIT(23), + SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), + PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), + DBG_EVENT_ID = BIT(26), +@@ -116,7 +122,11 @@ + + /* AP FW only */ + u8 hlid_removed; ++ ++ /* a bitmap of hlids for stations that have been inactive too long */ + __le16 sta_aging_status; ++ ++ /* a bitmap of hlids for stations which didn't respond to TX */ + __le16 sta_tx_retry_exceeded; + + u8 reserved_5[24]; +@@ -127,4 +137,7 @@ + int wl1271_event_handle(struct wl1271 *wl, u8 mbox); + void wl1271_pspoll_work(struct work_struct *work); + ++/* Functions from main.c */ ++bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid); ++ + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/ini.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/ini.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/ini.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/ini.h 2011-05-05 23:29:45.978447821 +0200 +@@ -41,6 +41,28 @@ + u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + } __packed; + ++#define WL128X_INI_MAX_SETTINGS_PARAM 4 ++ ++struct wl128x_ini_general_params { ++ u8 ref_clock; ++ u8 settling_time; ++ u8 clk_valid_on_wakeup; ++ u8 tcxo_ref_clock; ++ u8 tcxo_settling_time; ++ u8 tcxo_valid_on_wakeup; ++ u8 tcxo_ldo_voltage; ++ u8 xtal_itrim_val; ++ u8 platform_conf; ++ u8 dual_mode_select; ++ u8 tx_bip_fem_auto_detect; ++ u8 tx_bip_fem_manufacturer; ++ u8 general_settings[WL128X_INI_MAX_SETTINGS_PARAM]; ++ u8 sr_state; ++ u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM]; ++ u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM]; ++ u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM]; ++} __packed; ++ + #define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15 + + struct wl1271_ini_band_params_2 { +@@ -49,9 +71,16 @@ + u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; + } __packed; + +-#define WL1271_INI_RATE_GROUP_COUNT 6 + #define WL1271_INI_CHANNEL_COUNT_2 14 + ++struct wl128x_ini_band_params_2 { ++ u8 rx_trace_insertion_loss; ++ u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_2]; ++ u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; ++} __packed; ++ ++#define WL1271_INI_RATE_GROUP_COUNT 6 ++ + struct wl1271_ini_fem_params_2 { + __le16 tx_bip_ref_pd_voltage; + u8 tx_bip_ref_power; +@@ -68,6 +97,28 @@ + u8 normal_to_degraded_high_thr; + } __packed; + ++#define WL128X_INI_RATE_GROUP_COUNT 7 ++/* low and high temperatures */ ++#define WL128X_INI_PD_VS_TEMPERATURE_RANGES 2 ++ ++struct wl128x_ini_fem_params_2 { ++ __le16 tx_bip_ref_pd_voltage; ++ u8 tx_bip_ref_power; ++ u8 tx_bip_ref_offset; ++ u8 tx_per_rate_pwr_limits_normal[WL128X_INI_RATE_GROUP_COUNT]; ++ u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT]; ++ u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT]; ++ u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2]; ++ u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2]; ++ u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT]; ++ u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT + 1]; ++ u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_2]; ++ u8 tx_pd_vs_temperature[WL128X_INI_PD_VS_TEMPERATURE_RANGES]; ++ u8 rx_fem_insertion_loss; ++ u8 degraded_low_to_normal_thr; ++ u8 normal_to_degraded_high_thr; ++} __packed; ++ + #define WL1271_INI_CHANNEL_COUNT_5 35 + #define WL1271_INI_SUB_BAND_COUNT_5 7 + +@@ -77,6 +128,12 @@ + u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; + } __packed; + ++struct wl128x_ini_band_params_5 { ++ u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; ++ u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_5]; ++ u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; ++} __packed; ++ + struct wl1271_ini_fem_params_5 { + __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5]; +@@ -92,6 +149,23 @@ + u8 normal_to_degraded_high_thr; + } __packed; + ++struct wl128x_ini_fem_params_5 { ++ __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5]; ++ u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5]; ++ u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5]; ++ u8 tx_per_rate_pwr_limits_normal[WL128X_INI_RATE_GROUP_COUNT]; ++ u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT]; ++ u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT]; ++ u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5]; ++ u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT]; ++ u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT]; ++ u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_5]; ++ u8 tx_pd_vs_temperature[WL1271_INI_SUB_BAND_COUNT_5 * ++ WL128X_INI_PD_VS_TEMPERATURE_RANGES]; ++ u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; ++ u8 degraded_low_to_normal_thr; ++ u8 normal_to_degraded_high_thr; ++} __packed; + + /* NVS data structure */ + #define WL1271_INI_NVS_SECTION_SIZE 468 +@@ -100,7 +174,7 @@ + #define WL1271_INI_LEGACY_NVS_FILE_SIZE 800 + + struct wl1271_nvs_file { +- /* NVS section */ ++ /* NVS section - must be first! */ + u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; + + /* INI section */ +@@ -120,4 +194,24 @@ + } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; + } __packed; + ++struct wl128x_nvs_file { ++ /* NVS section - must be first! */ ++ u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; ++ ++ /* INI section */ ++ struct wl128x_ini_general_params general_params; ++ u8 fem_vendor_and_options; ++ struct wl128x_ini_band_params_2 stat_radio_params_2; ++ u8 padding2; ++ struct { ++ struct wl128x_ini_fem_params_2 params; ++ u8 padding; ++ } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT]; ++ struct wl128x_ini_band_params_5 stat_radio_params_5; ++ u8 padding3; ++ struct { ++ struct wl128x_ini_fem_params_5 params; ++ u8 padding; ++ } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; ++} __packed; + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/init.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/init.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/init.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/init.c 2011-05-05 23:29:45.970447725 +0200 +@@ -31,6 +31,7 @@ + #include "cmd.h" + #include "reg.h" + #include "tx.h" ++#include "io.h" + + int wl1271_sta_init_templates_config(struct wl1271 *wl) + { +@@ -321,9 +322,11 @@ + { + int ret; + +- ret = wl1271_cmd_ext_radio_parms(wl); +- if (ret < 0) +- return ret; ++ if (wl->chip.id != CHIP_ID_1283_PG20) { ++ ret = wl1271_cmd_ext_radio_parms(wl); ++ if (ret < 0) ++ return ret; ++ } + + /* PS config */ + ret = wl1271_acx_config_ps(wl); +@@ -372,6 +375,10 @@ + if (ret < 0) + return ret; + ++ ret = wl1271_acx_sta_max_tx_retry(wl); ++ if (ret < 0) ++ return ret; ++ + ret = wl1271_acx_sta_mem_cfg(wl); + if (ret < 0) + return ret; +@@ -438,7 +445,7 @@ + if (ret < 0) + return ret; + +- ret = wl1271_acx_max_tx_retry(wl); ++ ret = wl1271_acx_ap_max_tx_retry(wl); + if (ret < 0) + return ret; + +@@ -504,6 +511,27 @@ + return ret; + } + ++int wl1271_chip_specific_init(struct wl1271 *wl) ++{ ++ int ret = 0; ++ ++ if (wl->chip.id == CHIP_ID_1283_PG20) { ++ u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; ++ ++ if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) ++ /* Enable SDIO padding */ ++ host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; ++ ++ /* Must be before wl1271_acx_init_mem_config() */ ++ ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap); ++ if (ret < 0) ++ goto out; ++ } ++out: ++ return ret; ++} ++ ++ + int wl1271_hw_init(struct wl1271 *wl) + { + struct conf_tx_ac_category *conf_ac; +@@ -511,11 +539,22 @@ + int ret, i; + bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + +- ret = wl1271_cmd_general_parms(wl); ++ if (wl->chip.id == CHIP_ID_1283_PG20) ++ ret = wl128x_cmd_general_parms(wl); ++ else ++ ret = wl1271_cmd_general_parms(wl); ++ if (ret < 0) ++ return ret; ++ ++ if (wl->chip.id == CHIP_ID_1283_PG20) ++ ret = wl128x_cmd_radio_parms(wl); ++ else ++ ret = wl1271_cmd_radio_parms(wl); + if (ret < 0) + return ret; + +- ret = wl1271_cmd_radio_parms(wl); ++ /* Chip-specific init */ ++ ret = wl1271_chip_specific_init(wl); + if (ret < 0) + return ret; + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/init.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/init.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/init.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/init.h 2011-05-05 23:29:45.969447713 +0200 +@@ -31,6 +31,7 @@ + int wl1271_init_phy_config(struct wl1271 *wl); + int wl1271_init_pta(struct wl1271 *wl); + int wl1271_init_energy_detection(struct wl1271 *wl); ++int wl1271_chip_specific_init(struct wl1271 *wl); + int wl1271_hw_init(struct wl1271 *wl); + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/io.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/io.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/io.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/io.c 2011-05-05 23:29:45.917447084 +0200 +@@ -29,6 +29,7 @@ + #include "wl12xx.h" + #include "wl12xx_80211.h" + #include "io.h" ++#include "tx.h" + + #define OCP_CMD_LOOP 32 + +@@ -43,6 +44,16 @@ + #define OCP_STATUS_REQ_FAILED 0x20000 + #define OCP_STATUS_RESP_ERROR 0x30000 + ++bool wl1271_set_block_size(struct wl1271 *wl) ++{ ++ if (wl->if_ops->set_block_size) { ++ wl->if_ops->set_block_size(wl, WL12XX_BUS_BLOCK_SIZE); ++ return true; ++ } ++ ++ return false; ++} ++ + void wl1271_disable_interrupts(struct wl1271 *wl) + { + wl->if_ops->disable_irq(wl); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/io.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/io.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/io.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/io.h 2011-05-05 23:29:45.952447507 +0200 +@@ -169,5 +169,8 @@ + struct ieee80211_hw *wl1271_alloc_hw(void); + int wl1271_free_hw(struct wl1271 *wl); + irqreturn_t wl1271_irq(int irq, void *data); ++bool wl1271_set_block_size(struct wl1271 *wl); ++int wl1271_tx_dummy_packet(struct wl1271 *wl); ++void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters); + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/Kconfig linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/Kconfig +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/Kconfig 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/Kconfig 2011-05-05 23:29:46.010448207 +0200 +@@ -3,7 +3,7 @@ + depends on MAC80211 && EXPERIMENTAL + ---help--- + This will enable TI wl12xx driver support for the following chips: +- wl1271 and wl1273. ++ wl1271, wl1273, wl1281 and wl1283. + The drivers make use of the mac80211 stack. + + config WL12XX +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/main.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/main.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/main.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/main.c 2011-05-05 23:29:45.982447869 +0200 +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + #include "wl12xx.h" + #include "wl12xx_80211.h" +@@ -54,7 +55,7 @@ + [CONF_SG_BT_PER_THRESHOLD] = 7500, + [CONF_SG_HV3_MAX_OVERRIDE] = 0, + [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, +- [CONF_SG_BT_LOAD_RATIO] = 50, ++ [CONF_SG_BT_LOAD_RATIO] = 200, + [CONF_SG_AUTO_PS_MODE] = 1, + [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, +@@ -191,7 +192,8 @@ + .long_retry_limit = 10, + .aflags = 0, + }, +- .ap_max_tx_retries = 100, ++ .max_tx_retries = 100, ++ .ap_aging_period = 300, + .tid_conf_count = 4, + .tid_conf = { + [CONF_TX_AC_BE] = { +@@ -254,7 +256,7 @@ + .ps_poll_threshold = 10, + .ps_poll_recovery_period = 700, + .bet_enable = CONF_BET_MODE_ENABLE, +- .bet_max_consecutive = 10, ++ .bet_max_consecutive = 50, + .psm_entry_retries = 5, + .psm_exit_retries = 255, + .psm_entry_nullfunc_retries = 3, +@@ -298,7 +300,7 @@ + .tx_ba_win_size = 64, + .inactivity_timeout = 10000, + }, +- .mem = { ++ .mem_wl127x = { + .num_stations = 1, + .ssid_profiles = 1, + .rx_block_num = 70, +@@ -307,7 +309,18 @@ + .min_req_tx_blocks = 100, + .min_req_rx_blocks = 22, + .tx_min = 27, +- } ++ }, ++ .mem_wl128x = { ++ .num_stations = 1, ++ .ssid_profiles = 1, ++ .rx_block_num = 40, ++ .tx_min_block_num = 40, ++ .dynamic_memory = 1, ++ .min_req_tx_blocks = 45, ++ .min_req_rx_blocks = 22, ++ .tx_min = 27, ++ }, ++ .hci_io_ds = HCI_IO_DS_6MA, + }; + + static void __wl1271_op_remove_interface(struct wl1271 *wl); +@@ -329,6 +342,7 @@ + }, + }; + ++static DEFINE_MUTEX(wl_list_mutex); + static LIST_HEAD(wl_list); + + static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, +@@ -359,10 +373,12 @@ + return NOTIFY_DONE; + + wl_temp = hw->priv; ++ mutex_lock(&wl_list_mutex); + list_for_each_entry(wl, &wl_list, list) { + if (wl == wl_temp) + break; + } ++ mutex_unlock(&wl_list_mutex); + if (wl != wl_temp) + return NOTIFY_DONE; + +@@ -438,15 +454,30 @@ + struct conf_tx_tid *conf_tid; + int ret, i; + +- ret = wl1271_cmd_general_parms(wl); ++ if (wl->chip.id == CHIP_ID_1283_PG20) ++ ret = wl128x_cmd_general_parms(wl); ++ else ++ ret = wl1271_cmd_general_parms(wl); + if (ret < 0) + return ret; + +- ret = wl1271_cmd_radio_parms(wl); ++ if (wl->chip.id == CHIP_ID_1283_PG20) ++ ret = wl128x_cmd_radio_parms(wl); ++ else ++ ret = wl1271_cmd_radio_parms(wl); ++ if (ret < 0) ++ return ret; ++ ++ if (wl->chip.id != CHIP_ID_1283_PG20) { ++ ret = wl1271_cmd_ext_radio_parms(wl); ++ if (ret < 0) ++ return ret; ++ } + if (ret < 0) + return ret; + +- ret = wl1271_cmd_ext_radio_parms(wl); ++ /* Chip-specific initializations */ ++ ret = wl1271_chip_specific_init(wl); + if (ret < 0) + return ret; + +@@ -593,15 +624,17 @@ + { + struct wl1271_fw_common_status *status = &full_status->common; + struct timespec ts; +- u32 total = 0; ++ u32 old_tx_blk_count = wl->tx_blocks_available; ++ u32 freed_blocks = 0; + int i; + +- if (wl->bss_type == BSS_TYPE_AP_BSS) ++ if (wl->bss_type == BSS_TYPE_AP_BSS) { + wl1271_raw_read(wl, FW_STATUS_ADDR, status, + sizeof(struct wl1271_fw_ap_status), false); +- else ++ } else { + wl1271_raw_read(wl, FW_STATUS_ADDR, status, + sizeof(struct wl1271_fw_sta_status), false); ++ } + + wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " + "drv_rx_counter = %d, tx_results_counter = %d)", +@@ -612,22 +645,37 @@ + + /* update number of available TX blocks */ + for (i = 0; i < NUM_TX_QUEUES; i++) { +- u32 cnt = le32_to_cpu(status->tx_released_blks[i]) - +- wl->tx_blocks_freed[i]; ++ freed_blocks += le32_to_cpu(status->tx_released_blks[i]) - ++ wl->tx_blocks_freed[i]; + + wl->tx_blocks_freed[i] = + le32_to_cpu(status->tx_released_blks[i]); +- wl->tx_blocks_available += cnt; +- total += cnt; + } + +- /* if more blocks are available now, tx work can be scheduled */ +- if (total) +- clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); ++ wl->tx_allocated_blocks -= freed_blocks; + +- /* for AP update num of allocated TX blocks per link and ps status */ +- if (wl->bss_type == BSS_TYPE_AP_BSS) ++ if (wl->bss_type == BSS_TYPE_AP_BSS) { ++ /* Update num of allocated TX blocks per link and ps status */ + wl1271_irq_update_links_status(wl, &full_status->ap); ++ wl->tx_blocks_available += freed_blocks; ++ } else { ++ int avail = full_status->sta.tx_total - wl->tx_allocated_blocks; ++ ++ /* ++ * The FW might change the total number of TX memblocks before ++ * we get a notification about blocks being released. Thus, the ++ * available blocks calculation might yield a temporary result ++ * which is lower than the actual available blocks. Keeping in ++ * mind that only blocks that were allocated can be moved from ++ * TX to RX, tx_blocks_available should never decrease here. ++ */ ++ wl->tx_blocks_available = max((int)wl->tx_blocks_available, ++ avail); ++ } ++ ++ /* if more blocks are available now, tx work can be scheduled */ ++ if (wl->tx_blocks_available > old_tx_blk_count) ++ clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); + + /* update the host-chipset time offset */ + getnstimeofday(&ts); +@@ -674,6 +722,13 @@ + set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); + cancel_work_sync(&wl->tx_work); + ++ /* ++ * In case edge triggered interrupt must be used, we cannot iterate ++ * more than once without introducing race conditions with the hardirq. ++ */ ++ if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) ++ loopcount = 1; ++ + mutex_lock(&wl->mutex); + + wl1271_debug(DEBUG_IRQ, "IRQ work"); +@@ -785,11 +840,17 @@ + + switch (wl->bss_type) { + case BSS_TYPE_AP_BSS: +- fw_name = WL1271_AP_FW_NAME; ++ if (wl->chip.id == CHIP_ID_1283_PG20) ++ fw_name = WL128X_AP_FW_NAME; ++ else ++ fw_name = WL127X_AP_FW_NAME; + break; + case BSS_TYPE_IBSS: + case BSS_TYPE_STA_BSS: +- fw_name = WL1271_FW_NAME; ++ if (wl->chip.id == CHIP_ID_1283_PG20) ++ fw_name = WL128X_FW_NAME; ++ else ++ fw_name = WL1271_FW_NAME; + break; + default: + wl1271_error("no compatible firmware for bss_type %d", +@@ -838,14 +899,14 @@ + const struct firmware *fw; + int ret; + +- ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl)); ++ ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl)); + + if (ret < 0) { + wl1271_error("could not get nvs file: %d", ret); + return ret; + } + +- wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); ++ wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); + + if (!wl->nvs) { + wl1271_error("could not allocate memory for the nvs file"); +@@ -954,6 +1015,17 @@ + if (ret < 0) + goto out; + break; ++ case CHIP_ID_1283_PG20: ++ wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)", ++ wl->chip.id); ++ ++ ret = wl1271_setup(wl); ++ if (ret < 0) ++ goto out; ++ if (wl1271_set_block_size(wl)) ++ wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT; ++ break; ++ case CHIP_ID_1283_PG10: + default: + wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); + ret = -ENODEV; +@@ -978,6 +1050,24 @@ + return ret; + } + ++static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl) ++{ ++ unsigned int quirks = 0; ++ unsigned int *fw_ver = wl->chip.fw_ver; ++ ++ /* Only for wl127x */ ++ if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) && ++ /* Check STA version */ ++ (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && ++ (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) || ++ /* Check AP version */ ++ ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) && ++ (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN)))) ++ quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS; ++ ++ return quirks; ++} ++ + int wl1271_plt_start(struct wl1271 *wl) + { + int retries = WL1271_BOOT_RETRIES; +@@ -1013,6 +1103,9 @@ + wl->state = WL1271_STATE_PLT; + wl1271_notice("firmware booted in PLT mode (%s)", + wl->chip.fw_ver_str); ++ ++ /* Check if any quirks are needed with older fw versions */ ++ wl->quirks |= wl1271_get_fw_ver_quirks(wl); + goto out; + + irq_disable: +@@ -1040,7 +1133,7 @@ + return ret; + } + +-int __wl1271_plt_stop(struct wl1271 *wl) ++static int __wl1271_plt_stop(struct wl1271 *wl) + { + int ret = 0; + +@@ -1124,6 +1217,69 @@ + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + ++int wl1271_tx_dummy_packet(struct wl1271 *wl) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&wl->wl_lock, flags); ++ set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); ++ wl->tx_queue_count++; ++ spin_unlock_irqrestore(&wl->wl_lock, flags); ++ ++ /* The FW is low on RX memory blocks, so send the dummy packet asap */ ++ if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) ++ wl1271_tx_work_locked(wl); ++ ++ /* ++ * If the FW TX is busy, TX work will be scheduled by the threaded ++ * interrupt handler function ++ */ ++ return 0; ++} ++ ++/* ++ * The size of the dummy packet should be at least 1400 bytes. However, in ++ * order to minimize the number of bus transactions, aligning it to 512 bytes ++ * boundaries could be beneficial, performance wise ++ */ ++#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512)) ++ ++static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_hdr_3addr *hdr; ++ unsigned int dummy_packet_size; ++ ++ dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE - ++ sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr); ++ ++ skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE); ++ if (!skb) { ++ wl1271_warning("Failed to allocate a dummy packet skb"); ++ return NULL; ++ } ++ ++ skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr)); ++ ++ hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); ++ memset(hdr, 0, sizeof(*hdr)); ++ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | ++ IEEE80211_STYPE_NULLFUNC | ++ IEEE80211_FCTL_TODS); ++ ++ memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size); ++ ++ /* Dummy packets require the TID to be management */ ++ skb->priority = WL1271_TID_MGMT; ++ ++ /* Initialize all fields that might be used */ ++ skb->queue_mapping = 0; ++ memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info)); ++ ++ return skb; ++} ++ ++ + static struct notifier_block wl1271_dev_notifier = { + .notifier_call = wl1271_dev_notify, + }; +@@ -1174,6 +1330,16 @@ + goto out; + } + ++ /* ++ * in some very corner case HW recovery scenarios its possible to ++ * get here before __wl1271_op_remove_interface is complete, so ++ * opt out if that is the case. ++ */ ++ if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) { ++ ret = -EBUSY; ++ goto out; ++ } ++ + switch (vif->type) { + case NL80211_IFTYPE_STATION: + wl->bss_type = BSS_TYPE_STA_BSS; +@@ -1242,6 +1408,7 @@ + + wl->vif = vif; + wl->state = WL1271_STATE_ON; ++ set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags); + wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str); + + /* update hw/fw version info in wiphy struct */ +@@ -1249,6 +1416,9 @@ + strncpy(wiphy->fw_version, wl->chip.fw_ver_str, + sizeof(wiphy->fw_version)); + ++ /* Check if any quirks are needed with older fw versions */ ++ wl->quirks |= wl1271_get_fw_ver_quirks(wl); ++ + /* + * Now we know if 11a is supported (info from the NVS), so disable + * 11a channels if not supported +@@ -1262,8 +1432,10 @@ + out: + mutex_unlock(&wl->mutex); + ++ mutex_lock(&wl_list_mutex); + if (!ret) + list_add(&wl->list, &wl_list); ++ mutex_unlock(&wl_list_mutex); + + return ret; + } +@@ -1274,11 +1446,15 @@ + + wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); + ++ /* because of hardware recovery, we may get here twice */ ++ if (wl->state != WL1271_STATE_ON) ++ return; ++ + wl1271_info("down"); + ++ mutex_lock(&wl_list_mutex); + list_del(&wl->list); +- +- WARN_ON(wl->state != WL1271_STATE_ON); ++ mutex_unlock(&wl_list_mutex); + + /* enable dyn ps just in case (if left on due to fw crash etc) */ + if (wl->bss_type == BSS_TYPE_STA_BSS) +@@ -1286,12 +1462,15 @@ + + if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { + wl->scan.state = WL1271_SCAN_STATE_IDLE; +- kfree(wl->scan.scanned_ch); +- wl->scan.scanned_ch = NULL; ++ memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); + wl->scan.req = NULL; + ieee80211_scan_completed(wl->hw, true); + } + ++ /* ++ * this must be before the cancel_work calls below, so that the work ++ * functions don't perform further work. ++ */ + wl->state = WL1271_STATE_OFF; + + mutex_unlock(&wl->mutex); +@@ -1321,6 +1500,7 @@ + wl->psm_entry_retry = 0; + wl->power_level = WL1271_DEFAULT_POWER_LEVEL; + wl->tx_blocks_available = 0; ++ wl->tx_allocated_blocks = 0; + wl->tx_results_count = 0; + wl->tx_packets_count = 0; + wl->tx_security_last_seq = 0; +@@ -1328,7 +1508,6 @@ + wl->time_offset = 0; + wl->session_counter = 0; + wl->rate_set = CONF_TX_RATE_MASK_BASIC; +- wl->flags = 0; + wl->vif = NULL; + wl->filters = 0; + wl1271_free_ap_keys(wl); +@@ -1336,6 +1515,13 @@ + wl->ap_fw_ps_map = 0; + wl->ap_ps_map = 0; + ++ /* ++ * this is performed after the cancel_work calls and the associated ++ * mutex_lock, so that wl1271_op_add_interface does not accidentally ++ * get executed before all these vars have been reset. ++ */ ++ wl->flags = 0; ++ + for (i = 0; i < NUM_TX_QUEUES; i++) + wl->tx_blocks_freed[i] = 0; + +@@ -1368,7 +1554,7 @@ + cancel_work_sync(&wl->recovery_work); + } + +-static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) ++void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) + { + wl1271_set_default_filters(wl); + +@@ -1431,10 +1617,10 @@ + * One of the side effects of the JOIN command is that is clears + * WPA/WPA2 keys from the chipset. Performing a JOIN while associated + * to a WPA/WPA2 access point will therefore kill the data-path. +- * Currently there is no supported scenario for JOIN during +- * association - if it becomes a supported scenario, the WPA/WPA2 keys +- * must be handled somehow. +- * ++ * Currently the only valid scenario for JOIN during association ++ * is on roaming, in which case we will also be given new keys. ++ * Keep the below message for now, unless it starts bothering ++ * users who really like to roam a lot :) + */ + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + wl1271_info("JOIN while associated."); +@@ -1490,7 +1676,7 @@ + clear_bit(WL1271_FLAG_JOINED, &wl->flags); + memset(wl->bssid, 0, ETH_ALEN); + +- /* stop filterting packets based on bssid */ ++ /* stop filtering packets based on bssid */ + wl1271_configure_filters(wl, FIF_OTHER_BSS); + + out: +@@ -1569,7 +1755,12 @@ + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { +- ret = -EAGAIN; ++ /* we support configuring the channel and band while off */ ++ if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) { ++ wl->band = conf->channel->band; ++ wl->channel = channel; ++ } ++ + goto out; + } + +@@ -2650,32 +2841,31 @@ + conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY; + conf_tid->apsd_conf[0] = 0; + conf_tid->apsd_conf[1] = 0; +- } else { +- ret = wl1271_ps_elp_wakeup(wl); +- if (ret < 0) +- goto out; ++ goto out; ++ } + +- /* +- * the txop is confed in units of 32us by the mac80211, +- * we need us +- */ +- ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), +- params->cw_min, params->cw_max, +- params->aifs, params->txop << 5); +- if (ret < 0) +- goto out_sleep; ++ ret = wl1271_ps_elp_wakeup(wl); ++ if (ret < 0) ++ goto out; + +- ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), +- CONF_CHANNEL_TYPE_EDCF, +- wl1271_tx_get_queue(queue), +- ps_scheme, CONF_ACK_POLICY_LEGACY, +- 0, 0); +- if (ret < 0) +- goto out_sleep; ++ /* ++ * the txop is confed in units of 32us by the mac80211, ++ * we need us ++ */ ++ ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), ++ params->cw_min, params->cw_max, ++ params->aifs, params->txop << 5); ++ if (ret < 0) ++ goto out_sleep; ++ ++ ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), ++ CONF_CHANNEL_TYPE_EDCF, ++ wl1271_tx_get_queue(queue), ++ ps_scheme, CONF_ACK_POLICY_LEGACY, ++ 0, 0); + + out_sleep: +- wl1271_ps_elp_sleep(wl); +- } ++ wl1271_ps_elp_sleep(wl); + + out: + mutex_unlock(&wl->mutex); +@@ -2764,6 +2954,12 @@ + __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + } + ++bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid) ++{ ++ int id = hlid - WL1271_AP_STA_HLID_START; ++ return test_bit(id, wl->ap_hlid_map); ++} ++ + static int wl1271_op_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +@@ -2847,10 +3043,11 @@ + return ret; + } + +-int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size) ++static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ enum ieee80211_ampdu_mlme_action action, ++ struct ieee80211_sta *sta, u16 tid, u16 *ssn, ++ u8 buf_size) + { + struct wl1271 *wl = hw->priv; + int ret; +@@ -3003,7 +3200,8 @@ + + #ifdef CONFIG_WL12XX_HT + #define WL12XX_HT_CAP { \ +- .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \ ++ .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \ ++ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \ + .ht_supported = true, \ + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \ + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \ +@@ -3207,8 +3405,7 @@ + unsigned long res; + int ret; + +- ret = strict_strtoul(buf, 10, &res); +- ++ ret = kstrtoul(buf, 10, &res); + if (ret < 0) { + wl1271_warning("incorrect value written to bt_coex_mode"); + return count; +@@ -3273,7 +3470,11 @@ + + ret = wl1271_fetch_nvs(wl); + if (ret == 0) { +- u8 *nvs_ptr = (u8 *)wl->nvs->nvs; ++ /* NOTE: The wl->nvs->nvs element must be first, in ++ * order to simplify the casting, we assume it is at ++ * the beginning of the wl->nvs structure. ++ */ ++ u8 *nvs_ptr = (u8 *)wl->nvs; + + wl->mac_addr[0] = nvs_ptr[11]; + wl->mac_addr[1] = nvs_ptr[10]; +@@ -3341,7 +3542,6 @@ + IEEE80211_HW_HAS_RATE_CONTROL | + IEEE80211_HW_CONNECTION_MONITOR | + IEEE80211_HW_SUPPORTS_CQM_RSSI | +- IEEE80211_HW_REPORTS_TX_ACK_STATUS | + IEEE80211_HW_AP_LINK_PS; + + wl->hw->wiphy->cipher_suites = cipher_suites; +@@ -3358,6 +3558,10 @@ + wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - + sizeof(struct ieee80211_header); + ++ /* make sure all our channels fit in the scanned_ch bitmask */ ++ BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + ++ ARRAY_SIZE(wl1271_channels_5ghz) > ++ WL1271_MAX_CHANNELS); + /* + * We keep local copies of the band structs because we need to + * modify them on a per-device basis. +@@ -3458,6 +3662,7 @@ + wl->ap_ps_map = 0; + wl->ap_fw_ps_map = 0; + wl->quirks = 0; ++ wl->platform_quirks = 0; + + memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); + for (i = 0; i < ACX_TX_DESCRIPTORS; i++) +@@ -3478,11 +3683,17 @@ + goto err_hw; + } + ++ wl->dummy_packet = wl12xx_alloc_dummy_packet(wl); ++ if (!wl->dummy_packet) { ++ ret = -ENOMEM; ++ goto err_aggr; ++ } ++ + /* Register platform device */ + ret = platform_device_register(wl->plat_dev); + if (ret) { + wl1271_error("couldn't register platform device"); +- goto err_aggr; ++ goto err_dummy_packet; + } + dev_set_drvdata(&wl->plat_dev->dev, wl); + +@@ -3508,6 +3719,9 @@ + err_platform: + platform_device_unregister(wl->plat_dev); + ++err_dummy_packet: ++ dev_kfree_skb(wl->dummy_packet); ++ + err_aggr: + free_pages((unsigned long)wl->aggr_buf, order); + +@@ -3527,6 +3741,7 @@ + int wl1271_free_hw(struct wl1271 *wl) + { + platform_device_unregister(wl->plat_dev); ++ dev_kfree_skb(wl->dummy_packet); + free_pages((unsigned long)wl->aggr_buf, + get_order(WL1271_AGGR_BUFFER_SIZE)); + kfree(wl->plat_dev); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/ps.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/ps.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/ps.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/ps.c 2011-05-05 23:29:45.983447881 +0200 +@@ -149,9 +149,6 @@ + case STATION_ACTIVE_MODE: + default: + wl1271_debug(DEBUG_PSM, "leaving psm"); +- ret = wl1271_ps_elp_wakeup(wl); +- if (ret < 0) +- return ret; + + /* disable beacon early termination */ + ret = wl1271_acx_bet_enable(wl, false); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/reg.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/reg.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/reg.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/reg.h 2011-05-05 23:29:46.009448195 +0200 +@@ -207,6 +207,8 @@ + + #define CHIP_ID_1271_PG10 (0x4030101) + #define CHIP_ID_1271_PG20 (0x4030111) ++#define CHIP_ID_1283_PG10 (0x05030101) ++#define CHIP_ID_1283_PG20 (0x05030111) + + #define ENABLE (REGISTERS_BASE + 0x5450) + +@@ -452,24 +454,11 @@ + #define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 + #define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 + +-/* +- * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile +- * for platforms using active high interrupt level +- */ +-#ifdef USE_ACTIVE_HIGH + #define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) +-#else +-#define HI_CFG_DEF_VAL \ +- (HI_CFG_UART_ENABLE | \ +- HI_CFG_RST232_ENABLE | \ +- HI_CFG_CLOCK_REQ_SELECT | \ +- HI_CFG_HOST_INT_ENABLE) +- +-#endif + + #define REF_FREQ_19_2 0 + #define REF_FREQ_26_0 1 +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/rx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/rx.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/rx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/rx.c 2011-05-05 23:29:45.942447386 +0200 +@@ -48,18 +48,14 @@ + struct ieee80211_rx_status *status, + u8 beacon) + { +- enum ieee80211_band desc_band; +- + memset(status, 0, sizeof(struct ieee80211_rx_status)); + +- status->band = wl->band; +- + if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) +- desc_band = IEEE80211_BAND_2GHZ; ++ status->band = IEEE80211_BAND_2GHZ; + else +- desc_band = IEEE80211_BAND_5GHZ; ++ status->band = IEEE80211_BAND_5GHZ; + +- status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band); ++ status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band); + + #ifdef CONFIG_WL12XX_HT + /* 11n support */ +@@ -76,7 +72,8 @@ + */ + wl->noise = desc->rssi - (desc->snr >> 1); + +- status->freq = ieee80211_channel_to_frequency(desc->channel, desc_band); ++ status->freq = ieee80211_channel_to_frequency(desc->channel, ++ status->band); + + if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; +@@ -163,18 +160,25 @@ + break; + } + +- /* +- * Choose the block we want to read +- * For aggregated packets, only the first memory block should +- * be retrieved. The FW takes care of the rest. +- */ +- mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); +- wl->rx_mem_pool_addr.addr = (mem_block << 8) + +- le32_to_cpu(wl_mem_map->packet_memory_pool_start); +- wl->rx_mem_pool_addr.addr_extra = +- wl->rx_mem_pool_addr.addr + 4; +- wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr, +- sizeof(wl->rx_mem_pool_addr), false); ++ if (wl->chip.id != CHIP_ID_1283_PG20) { ++ /* ++ * Choose the block we want to read ++ * For aggregated packets, only the first memory block ++ * should be retrieved. The FW takes care of the rest. ++ */ ++ mem_block = wl1271_rx_get_mem_block(status, ++ drv_rx_counter); ++ ++ wl->rx_mem_pool_addr.addr = (mem_block << 8) + ++ le32_to_cpu(wl_mem_map->packet_memory_pool_start); ++ ++ wl->rx_mem_pool_addr.addr_extra = ++ wl->rx_mem_pool_addr.addr + 4; ++ ++ wl1271_write(wl, WL1271_SLV_REG_DATA, ++ &wl->rx_mem_pool_addr, ++ sizeof(wl->rx_mem_pool_addr), false); ++ } + + /* Read all available packets at once */ + wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/scan.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/scan.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/scan.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/scan.c 2011-05-05 23:29:45.913447035 +0200 +@@ -48,8 +48,7 @@ + goto out; + + wl->scan.state = WL1271_SCAN_STATE_IDLE; +- kfree(wl->scan.scanned_ch); +- wl->scan.scanned_ch = NULL; ++ memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); + wl->scan.req = NULL; + ieee80211_scan_completed(wl->hw, false); + +@@ -87,7 +86,7 @@ + + flags = req->channels[i]->flags; + +- if (!wl->scan.scanned_ch[i] && ++ if (!test_bit(i, wl->scan.scanned_ch) && + !(flags & IEEE80211_CHAN_DISABLED) && + ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && + (req->channels[i]->band == band)) { +@@ -124,7 +123,7 @@ + memset(&channels[j].bssid_msb, 0xff, 2); + + /* Mark the channels we already used */ +- wl->scan.scanned_ch[i] = true; ++ set_bit(i, wl->scan.scanned_ch); + + j++; + } +@@ -291,6 +290,12 @@ + int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, + struct cfg80211_scan_request *req) + { ++ /* ++ * cfg80211 should guarantee that we don't get more channels ++ * than what we have registered. ++ */ ++ BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); ++ + if (wl->scan.state != WL1271_SCAN_STATE_IDLE) + return -EBUSY; + +@@ -304,10 +309,8 @@ + } + + wl->scan.req = req; ++ memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); + +- wl->scan.scanned_ch = kcalloc(req->n_channels, +- sizeof(*wl->scan.scanned_ch), +- GFP_KERNEL); + /* we assume failure so that timeout scenarios are handled correctly */ + wl->scan.failed = true; + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/sdio.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/sdio.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/sdio.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/sdio.c 2011-05-05 23:29:46.011448219 +0200 +@@ -51,6 +51,13 @@ + }; + MODULE_DEVICE_TABLE(sdio, wl1271_devices); + ++static void wl1271_sdio_set_block_size(struct wl1271 *wl, unsigned int blksz) ++{ ++ sdio_claim_host(wl->if_priv); ++ sdio_set_block_size(wl->if_priv, blksz); ++ sdio_release_host(wl->if_priv); ++} ++ + static inline struct sdio_func *wl_to_func(struct wl1271 *wl) + { + return wl->if_priv; +@@ -203,7 +210,8 @@ + .power = wl1271_sdio_set_power, + .dev = wl1271_sdio_wl_to_dev, + .enable_irq = wl1271_sdio_enable_interrupts, +- .disable_irq = wl1271_sdio_disable_interrupts ++ .disable_irq = wl1271_sdio_disable_interrupts, ++ .set_block_size = wl1271_sdio_set_block_size, + }; + + static int __devinit wl1271_probe(struct sdio_func *func, +@@ -212,6 +220,7 @@ + struct ieee80211_hw *hw; + const struct wl12xx_platform_data *wlan_data; + struct wl1271 *wl; ++ unsigned long irqflags; + int ret; + + /* We are only able to handle the wlan function */ +@@ -230,6 +239,9 @@ + /* Grab access to FN0 for ELP reg. */ + func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + ++ /* Use block mode for transferring over one block size of data */ ++ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; ++ + wlan_data = wl12xx_get_platform_data(); + if (IS_ERR(wlan_data)) { + ret = PTR_ERR(wlan_data); +@@ -239,9 +251,16 @@ + + wl->irq = wlan_data->irq; + wl->ref_clock = wlan_data->board_ref_clock; ++ wl->tcxo_clock = wlan_data->board_tcxo_clock; ++ wl->platform_quirks = wlan_data->platform_quirks; ++ ++ if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) ++ irqflags = IRQF_TRIGGER_RISING; ++ else ++ irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; + + ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, +- IRQF_TRIGGER_HIGH | IRQF_ONESHOT, ++ irqflags, + DRIVER_NAME, wl); + if (ret < 0) { + wl1271_error("request_irq() failed: %d", ret); +@@ -343,4 +362,6 @@ + MODULE_AUTHOR("Luciano Coelho "); + MODULE_AUTHOR("Juuso Oikarinen "); + MODULE_FIRMWARE(WL1271_FW_NAME); +-MODULE_FIRMWARE(WL1271_AP_FW_NAME); ++MODULE_FIRMWARE(WL128X_FW_NAME); ++MODULE_FIRMWARE(WL127X_AP_FW_NAME); ++MODULE_FIRMWARE(WL128X_AP_FW_NAME); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/sdio_test.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/sdio_test.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/sdio_test.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/sdio_test.c 2011-05-05 23:29:45.942447386 +0200 +@@ -189,7 +189,12 @@ + const struct firmware *fw; + int ret; + +- ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl)); ++ if (wl->chip.id == CHIP_ID_1283_PG20) ++ ret = request_firmware(&fw, WL128X_FW_NAME, ++ wl1271_wl_to_dev(wl)); ++ else ++ ret = request_firmware(&fw, WL1271_FW_NAME, ++ wl1271_wl_to_dev(wl)); + + if (ret < 0) { + wl1271_error("could not get firmware: %d", ret); +@@ -227,14 +232,14 @@ + const struct firmware *fw; + int ret; + +- ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl)); ++ ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl)); + + if (ret < 0) { + wl1271_error("could not get nvs file: %d", ret); + return ret; + } + +- wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); ++ wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); + + if (!wl->nvs) { + wl1271_error("could not allocate memory for the nvs file"); +@@ -288,6 +293,11 @@ + wl1271_notice("chip id 0x%x (1271 PG20)", + wl->chip.id); + break; ++ case CHIP_ID_1283_PG20: ++ wl1271_notice("chip id 0x%x (1283 PG20)", ++ wl->chip.id); ++ break; ++ case CHIP_ID_1283_PG10: + default: + wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); + return -ENODEV; +@@ -407,6 +417,9 @@ + /* Grab access to FN0 for ELP reg. */ + func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + ++ /* Use block mode for transferring over one block size of data */ ++ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; ++ + wlan_data = wl12xx_get_platform_data(); + if (IS_ERR(wlan_data)) { + ret = PTR_ERR(wlan_data); +@@ -416,6 +429,7 @@ + + wl->irq = wlan_data->irq; + wl->ref_clock = wlan_data->board_ref_clock; ++ wl->tcxo_clock = wlan_data->board_tcxo_clock; + + sdio_set_drvdata(func, wl_test); + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/spi.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/spi.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/spi.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/spi.c 2011-05-05 23:29:46.010448207 +0200 +@@ -355,7 +355,8 @@ + .power = wl1271_spi_set_power, + .dev = wl1271_spi_wl_to_dev, + .enable_irq = wl1271_spi_enable_interrupts, +- .disable_irq = wl1271_spi_disable_interrupts ++ .disable_irq = wl1271_spi_disable_interrupts, ++ .set_block_size = NULL, + }; + + static int __devinit wl1271_probe(struct spi_device *spi) +@@ -363,6 +364,7 @@ + struct wl12xx_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl1271 *wl; ++ unsigned long irqflags; + int ret; + + pdata = spi->dev.platform_data; +@@ -400,6 +402,13 @@ + } + + wl->ref_clock = pdata->board_ref_clock; ++ wl->tcxo_clock = pdata->board_tcxo_clock; ++ wl->platform_quirks = pdata->platform_quirks; ++ ++ if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) ++ irqflags = IRQF_TRIGGER_RISING; ++ else ++ irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; + + wl->irq = spi->irq; + if (wl->irq < 0) { +@@ -409,7 +418,7 @@ + } + + ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, +- IRQF_TRIGGER_HIGH | IRQF_ONESHOT, ++ irqflags, + DRIVER_NAME, wl); + if (ret < 0) { + wl1271_error("request_irq() failed: %d", ret); +@@ -490,5 +499,7 @@ + MODULE_AUTHOR("Luciano Coelho "); + MODULE_AUTHOR("Juuso Oikarinen "); + MODULE_FIRMWARE(WL1271_FW_NAME); +-MODULE_FIRMWARE(WL1271_AP_FW_NAME); ++MODULE_FIRMWARE(WL128X_FW_NAME); ++MODULE_FIRMWARE(WL127X_AP_FW_NAME); ++MODULE_FIRMWARE(WL128X_AP_FW_NAME); + MODULE_ALIAS("spi:wl1271"); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/testmode.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/testmode.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/testmode.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/testmode.c 2011-05-05 23:29:45.983447881 +0200 +@@ -27,6 +27,7 @@ + + #include "wl12xx.h" + #include "acx.h" ++#include "reg.h" + + #define WL1271_TM_MAX_DATA_LENGTH 1024 + +@@ -204,7 +205,10 @@ + + kfree(wl->nvs); + +- if (len != sizeof(struct wl1271_nvs_file)) ++ if ((wl->chip.id == CHIP_ID_1283_PG20) && ++ (len != sizeof(struct wl128x_nvs_file))) ++ return -EINVAL; ++ else if (len != sizeof(struct wl1271_nvs_file)) + return -EINVAL; + + wl->nvs = kzalloc(len, GFP_KERNEL); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/tx.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/tx.c +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/tx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/tx.c 2011-05-05 23:29:45.893446794 +0200 +@@ -70,6 +70,28 @@ + } + } + ++static int wl1271_tx_update_filters(struct wl1271 *wl, ++ struct sk_buff *skb) ++{ ++ struct ieee80211_hdr *hdr; ++ ++ hdr = (struct ieee80211_hdr *)(skb->data + ++ sizeof(struct wl1271_tx_hw_descr)); ++ ++ /* ++ * stop bssid-based filtering before transmitting authentication ++ * requests. this way the hw will never drop authentication ++ * responses coming from BSSIDs it isn't familiar with (e.g. on ++ * roaming) ++ */ ++ if (!ieee80211_is_auth(hdr->frame_control)) ++ return 0; ++ ++ wl1271_configure_filters(wl, FIF_OTHER_BSS); ++ ++ return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); ++} ++ + static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, + struct sk_buff *skb) + { +@@ -127,13 +149,29 @@ + } + } + ++static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, ++ unsigned int packet_length) ++{ ++ if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) ++ return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); ++ else ++ return ALIGN(packet_length, WL1271_TX_ALIGN_TO); ++} ++ + static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, + u32 buf_offset, u8 hlid) + { + struct wl1271_tx_hw_descr *desc; + u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; ++ u32 len; + u32 total_blocks; + int id, ret = -EBUSY; ++ u32 spare_blocks; ++ ++ if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS)) ++ spare_blocks = 2; ++ else ++ spare_blocks = 1; + + if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) + return -EAGAIN; +@@ -145,17 +183,27 @@ + + /* approximate the number of blocks required for this packet + in the firmware */ +- total_blocks = total_len + TX_HW_BLOCK_SIZE - 1; +- total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE; ++ len = wl12xx_calc_packet_alignment(wl, total_len); ++ ++ total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + ++ spare_blocks; ++ + if (total_blocks <= wl->tx_blocks_available) { + desc = (struct wl1271_tx_hw_descr *)skb_push( + skb, total_len - skb->len); + +- desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; +- desc->total_mem_blocks = total_blocks; ++ /* HW descriptor fields change between wl127x and wl128x */ ++ if (wl->chip.id == CHIP_ID_1283_PG20) { ++ desc->wl128x_mem.total_mem_blocks = total_blocks; ++ } else { ++ desc->wl127x_mem.extra_blocks = spare_blocks; ++ desc->wl127x_mem.total_mem_blocks = total_blocks; ++ } ++ + desc->id = id; + + wl->tx_blocks_available -= total_blocks; ++ wl->tx_allocated_blocks += total_blocks; + + if (wl->bss_type == BSS_TYPE_AP_BSS) + wl->links[hlid].allocated_blks += total_blocks; +@@ -172,13 +220,18 @@ + return ret; + } + ++static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) ++{ ++ return wl->dummy_packet == skb; ++} ++ + static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, + u32 extra, struct ieee80211_tx_info *control, + u8 hlid) + { + struct timespec ts; + struct wl1271_tx_hw_descr *desc; +- int pad, ac, rate_idx; ++ int aligned_len, ac, rate_idx; + s64 hosttime; + u16 tx_attr; + +@@ -202,12 +255,25 @@ + else + desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); + +- /* configure the tx attributes */ +- tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; +- +- /* queue (we use same identifiers for tid's and ac's */ ++ /* queue */ + ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); +- desc->tid = ac; ++ desc->tid = skb->priority; ++ ++ if (wl12xx_is_dummy_packet(wl, skb)) { ++ /* ++ * FW expects the dummy packet to have an invalid session id - ++ * any session id that is different than the one set in the join ++ */ ++ tx_attr = ((~wl->session_counter) << ++ TX_HW_ATTR_OFST_SESSION_COUNTER) & ++ TX_HW_ATTR_SESSION_COUNTER; ++ ++ tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; ++ } else { ++ /* configure the tx attributes */ ++ tx_attr = ++ wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; ++ } + + if (wl->bss_type != BSS_TYPE_AP_BSS) { + desc->aid = hlid; +@@ -237,20 +303,37 @@ + tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; + desc->reserved = 0; + +- /* align the length (and store in terms of words) */ +- pad = ALIGN(skb->len, WL1271_TX_ALIGN_TO); +- desc->length = cpu_to_le16(pad >> 2); +- +- /* calculate number of padding bytes */ +- pad = pad - skb->len; +- tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; ++ aligned_len = wl12xx_calc_packet_alignment(wl, skb->len); + +- desc->tx_attr = cpu_to_le16(tx_attr); ++ if (wl->chip.id == CHIP_ID_1283_PG20) { ++ desc->wl128x_mem.extra_bytes = aligned_len - skb->len; ++ desc->length = cpu_to_le16(aligned_len >> 2); ++ ++ wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d " ++ "tx_attr: 0x%x len: %d life: %d mem: %d", ++ desc->hlid, tx_attr, ++ le16_to_cpu(desc->length), ++ le16_to_cpu(desc->life_time), ++ desc->wl128x_mem.total_mem_blocks); ++ } else { ++ int pad; ++ ++ /* Store the aligned length in terms of words */ ++ desc->length = cpu_to_le16(aligned_len >> 2); + +- wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " +- "tx_attr: 0x%x len: %d life: %d mem: %d", pad, desc->hlid, +- le16_to_cpu(desc->tx_attr), le16_to_cpu(desc->length), +- le16_to_cpu(desc->life_time), desc->total_mem_blocks); ++ /* calculate number of padding bytes */ ++ pad = aligned_len - skb->len; ++ tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; ++ ++ wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " ++ "tx_attr: 0x%x len: %d life: %d mem: %d", pad, ++ desc->hlid, tx_attr, ++ le16_to_cpu(desc->length), ++ le16_to_cpu(desc->life_time), ++ desc->wl127x_mem.total_mem_blocks); ++ } ++ ++ desc->tx_attr = cpu_to_le16(tx_attr); + } + + /* caller must hold wl->mutex */ +@@ -300,19 +383,29 @@ + if (wl->bss_type == BSS_TYPE_AP_BSS) { + wl1271_tx_ap_update_inconnection_sta(wl, skb); + wl1271_tx_regulate_link(wl, hlid); ++ } else { ++ wl1271_tx_update_filters(wl, skb); + } + + wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); + + /* +- * The length of each packet is stored in terms of words. Thus, we must +- * pad the skb data to make sure its length is aligned. +- * The number of padding bytes is computed and set in wl1271_tx_fill_hdr ++ * The length of each packet is stored in terms of ++ * words. Thus, we must pad the skb data to make sure its ++ * length is aligned. The number of padding bytes is computed ++ * and set in wl1271_tx_fill_hdr. ++ * In special cases, we want to align to a specific block size ++ * (eg. for wl128x with SDIO we align to 256). + */ +- total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); ++ total_len = wl12xx_calc_packet_alignment(wl, skb->len); ++ + memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); + memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); + ++ /* Revert side effects in the dummy packet skb, so it can be reused */ ++ if (wl12xx_is_dummy_packet(wl, skb)) ++ skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); ++ + return total_len; + } + +@@ -425,10 +518,23 @@ + + static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) + { ++ unsigned long flags; ++ struct sk_buff *skb = NULL; ++ + if (wl->bss_type == BSS_TYPE_AP_BSS) +- return wl1271_ap_skb_dequeue(wl); ++ skb = wl1271_ap_skb_dequeue(wl); ++ else ++ skb = wl1271_sta_skb_dequeue(wl); ++ ++ if (!skb && ++ test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { ++ skb = wl->dummy_packet; ++ spin_lock_irqsave(&wl->wl_lock, flags); ++ wl->tx_queue_count--; ++ spin_unlock_irqrestore(&wl->wl_lock, flags); ++ } + +- return wl1271_sta_skb_dequeue(wl); ++ return skb; + } + + static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) +@@ -436,7 +542,9 @@ + unsigned long flags; + int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); + +- if (wl->bss_type == BSS_TYPE_AP_BSS) { ++ if (wl12xx_is_dummy_packet(wl, skb)) { ++ set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); ++ } else if (wl->bss_type == BSS_TYPE_AP_BSS) { + u8 hlid = wl1271_tx_get_hlid(skb); + skb_queue_head(&wl->links[hlid].tx_queue[q], skb); + +@@ -454,22 +562,14 @@ + void wl1271_tx_work_locked(struct wl1271 *wl) + { + struct sk_buff *skb; +- bool woken_up = false; + u32 buf_offset = 0; + bool sent_packets = false; + int ret; + + if (unlikely(wl->state == WL1271_STATE_OFF)) +- goto out; ++ return; + + while ((skb = wl1271_skb_dequeue(wl))) { +- if (!woken_up) { +- ret = wl1271_ps_elp_wakeup(wl); +- if (ret < 0) +- goto out_ack; +- woken_up = true; +- } +- + ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); + if (ret == -EAGAIN) { + /* +@@ -516,18 +616,22 @@ + + wl1271_handle_tx_low_watermark(wl); + } +- +-out: +- if (woken_up) +- wl1271_ps_elp_sleep(wl); + } + + void wl1271_tx_work(struct work_struct *work) + { + struct wl1271 *wl = container_of(work, struct wl1271, tx_work); ++ int ret; + + mutex_lock(&wl->mutex); ++ ret = wl1271_ps_elp_wakeup(wl); ++ if (ret < 0) ++ goto out; ++ + wl1271_tx_work_locked(wl); ++ ++ wl1271_ps_elp_wakeup(wl); ++out: + mutex_unlock(&wl->mutex); + } + +@@ -549,6 +653,11 @@ + skb = wl->tx_frames[id]; + info = IEEE80211_SKB_CB(skb); + ++ if (wl12xx_is_dummy_packet(wl, skb)) { ++ wl1271_free_tx_id(wl, id); ++ return; ++ } ++ + /* update the TX status info */ + if (result->status == TX_SUCCESS) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) +@@ -678,10 +787,13 @@ + while ((skb = skb_dequeue(&wl->tx_queue[i]))) { + wl1271_debug(DEBUG_TX, "freeing skb 0x%p", + skb); +- info = IEEE80211_SKB_CB(skb); +- info->status.rates[0].idx = -1; +- info->status.rates[0].count = 0; +- ieee80211_tx_status(wl->hw, skb); ++ ++ if (!wl12xx_is_dummy_packet(wl, skb)) { ++ info = IEEE80211_SKB_CB(skb); ++ info->status.rates[0].idx = -1; ++ info->status.rates[0].count = 0; ++ ieee80211_tx_status(wl->hw, skb); ++ } + } + } + } +@@ -702,21 +814,27 @@ + wl1271_free_tx_id(wl, i); + wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); + +- /* Remove private headers before passing the skb to mac80211 */ +- info = IEEE80211_SKB_CB(skb); +- skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); +- if (info->control.hw_key && +- info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { +- int hdrlen = ieee80211_get_hdrlen_from_skb(skb); +- memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, +- hdrlen); +- skb_pull(skb, WL1271_TKIP_IV_SPACE); +- } ++ if (!wl12xx_is_dummy_packet(wl, skb)) { ++ /* ++ * Remove private headers before passing the skb to ++ * mac80211 ++ */ ++ info = IEEE80211_SKB_CB(skb); ++ skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); ++ if (info->control.hw_key && ++ info->control.hw_key->cipher == ++ WLAN_CIPHER_SUITE_TKIP) { ++ int hdrlen = ieee80211_get_hdrlen_from_skb(skb); ++ memmove(skb->data + WL1271_TKIP_IV_SPACE, ++ skb->data, hdrlen); ++ skb_pull(skb, WL1271_TKIP_IV_SPACE); ++ } + +- info->status.rates[0].idx = -1; +- info->status.rates[0].count = 0; ++ info->status.rates[0].idx = -1; ++ info->status.rates[0].count = 0; + +- ieee80211_tx_status(wl->hw, skb); ++ ieee80211_tx_status(wl->hw, skb); ++ } + } + } + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/tx.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/tx.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/tx.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/tx.h 2011-05-05 23:29:45.953447519 +0200 +@@ -25,7 +25,6 @@ + #ifndef __TX_H__ + #define __TX_H__ + +-#define TX_HW_BLOCK_SPARE 2 + #define TX_HW_BLOCK_SIZE 252 + + #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 +@@ -41,6 +40,7 @@ + BIT(8) | BIT(9)) + #define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) + #define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) ++#define TX_HW_ATTR_TX_DUMMY_REQ BIT(13) + + #define TX_HW_ATTR_OFST_SAVE_RETRIES 0 + #define TX_HW_ATTR_OFST_HEADER_PAD 1 +@@ -55,20 +55,60 @@ + #define WL1271_TX_ALIGN_TO 4 + #define WL1271_TKIP_IV_SPACE 4 + ++/* Used for management frames and dummy packets */ ++#define WL1271_TID_MGMT 7 ++ ++struct wl127x_tx_mem { ++ /* ++ * Number of extra memory blocks to allocate for this packet ++ * in addition to the number of blocks derived from the packet ++ * length. ++ */ ++ u8 extra_blocks; ++ /* ++ * Total number of memory blocks allocated by the host for ++ * this packet. Must be equal or greater than the actual ++ * blocks number allocated by HW. ++ */ ++ u8 total_mem_blocks; ++} __packed; ++ ++struct wl128x_tx_mem { ++ /* ++ * Total number of memory blocks allocated by the host for ++ * this packet. ++ */ ++ u8 total_mem_blocks; ++ /* ++ * Number of extra bytes, at the end of the frame. the host ++ * uses this padding to complete each frame to integer number ++ * of SDIO blocks. ++ */ ++ u8 extra_bytes; ++} __packed; ++ ++/* ++ * On wl128x based devices, when TX packets are aggregated, each packet ++ * size must be aligned to the SDIO block size. The maximum block size ++ * is bounded by the type of the padded bytes field that is sent to the ++ * FW. Currently the type is u8, so the maximum block size is 256 bytes. ++ */ ++#define WL12XX_BUS_BLOCK_SIZE min(512u, \ ++ (1u << (8 * sizeof(((struct wl128x_tx_mem *) 0)->extra_bytes)))) ++ + struct wl1271_tx_hw_descr { + /* Length of packet in words, including descriptor+header+data */ + __le16 length; +- /* Number of extra memory blocks to allocate for this packet in +- addition to the number of blocks derived from the packet length */ +- u8 extra_mem_blocks; +- /* Total number of memory blocks allocated by the host for this packet. +- Must be equal or greater than the actual blocks number allocated by +- HW!! */ +- u8 total_mem_blocks; ++ union { ++ struct wl127x_tx_mem wl127x_mem; ++ struct wl128x_tx_mem wl128x_mem; ++ } __packed; + /* Device time (in us) when the packet arrived to the driver */ + __le32 start_time; +- /* Max delay in TUs until transmission. The last device time the +- packet can be transmitted is: startTime+(1024*LifeTime) */ ++ /* ++ * Max delay in TUs until transmission. The last device time the ++ * packet can be transmitted is: start_time + (1024 * life_time) ++ */ + __le16 life_time; + /* Bitwise fields - see TX_ATTR... definitions above. */ + __le16 tx_attr; +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/wl12xx/wl12xx.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/wl12xx.h +--- linux-2.6.39-rc6/drivers/net/wireless/wl12xx/wl12xx.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/wl12xx/wl12xx.h 2011-05-05 23:29:45.977447809 +0200 +@@ -131,9 +131,16 @@ + + + #define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin" +-#define WL1271_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin" ++#define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin" ++#define WL127X_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin" ++#define WL128X_AP_FW_NAME "ti-connectivity/wl128x-fw-ap.bin" + +-#define WL1271_NVS_NAME "ti-connectivity/wl1271-nvs.bin" ++/* ++ * wl127x and wl128x are using the same NVS file name. However, the ++ * ini parameters between them are different. The driver validates ++ * the correct NVS size in wl1271_boot_upload_nvs(). ++ */ ++#define WL12XX_NVS_NAME "ti-connectivity/wl1271-nvs.bin" + + #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) + #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) +@@ -165,7 +172,6 @@ + #define WL1271_PS_STA_MAX_BLOCKS (2 * 9) + + #define WL1271_AP_BSS_INDEX 0 +-#define WL1271_AP_DEF_INACTIV_SEC 300 + #define WL1271_AP_DEF_BEACON_EXP 20 + + #define ACX_TX_DESCRIPTORS 32 +@@ -200,13 +206,29 @@ + + struct wl1271; + +-#define WL12XX_NUM_FW_VER 5 ++enum { ++ FW_VER_CHIP, ++ FW_VER_IF_TYPE, ++ FW_VER_MAJOR, ++ FW_VER_SUBTYPE, ++ FW_VER_MINOR, ++ ++ NUM_FW_VER ++}; ++ ++#define FW_VER_CHIP_WL127X 6 ++#define FW_VER_CHIP_WL128X 7 ++ ++#define FW_VER_IF_TYPE_STA 1 ++#define FW_VER_IF_TYPE_AP 2 ++ ++#define FW_VER_MINOR_1_SPARE_STA_MIN 58 ++#define FW_VER_MINOR_1_SPARE_AP_MIN 47 + +-/* FIXME: I'm not sure about this structure name */ + struct wl1271_chip { + u32 id; + char fw_ver_str[ETHTOOL_BUSINFO_LEN]; +- unsigned int fw_ver[WL12XX_NUM_FW_VER]; ++ unsigned int fw_ver[NUM_FW_VER]; + }; + + struct wl1271_stats { +@@ -261,6 +283,8 @@ + u8 tx_total; + u8 reserved1; + __le16 reserved2; ++ /* Total structure size is 68 bytes */ ++ u32 padding; + } __packed; + + struct wl1271_fw_full_status { +@@ -277,9 +301,10 @@ + u32 addr_extra; + }; + ++#define WL1271_MAX_CHANNELS 64 + struct wl1271_scan { + struct cfg80211_scan_request *req; +- bool *scanned_ch; ++ unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)]; + bool failed; + u8 state; + u8 ssid[IW_ESSID_MAX_SIZE+1]; +@@ -297,6 +322,7 @@ + struct device* (*dev)(struct wl1271 *wl); + void (*enable_irq)(struct wl1271 *wl); + void (*disable_irq)(struct wl1271 *wl); ++ void (*set_block_size) (struct wl1271 *wl, unsigned int blksz); + }; + + #define MAX_NUM_KEYS 14 +@@ -327,7 +353,9 @@ + WL1271_FLAG_PSPOLL_FAILURE, + WL1271_FLAG_STA_STATE_SENT, + WL1271_FLAG_FW_TX_BUSY, +- WL1271_FLAG_AP_STARTED ++ WL1271_FLAG_AP_STARTED, ++ WL1271_FLAG_IF_INITIALIZED, ++ WL1271_FLAG_DUMMY_PACKET_PENDING, + }; + + struct wl1271_link { +@@ -371,7 +399,7 @@ + u8 *fw; + size_t fw_len; + u8 fw_bss_type; +- struct wl1271_nvs_file *nvs; ++ void *nvs; + size_t nvs_len; + + s8 hw_pg_ver; +@@ -389,6 +417,7 @@ + /* Accounting for allocated / available TX blocks on HW */ + u32 tx_blocks_freed[NUM_TX_QUEUES]; + u32 tx_blocks_available; ++ u32 tx_allocated_blocks; + u32 tx_results_count; + + /* Transmitted TX packets counter for chipset interface */ +@@ -430,6 +459,9 @@ + /* Intermediate buffer, used for packet aggregation */ + u8 *aggr_buf; + ++ /* Reusable dummy packet template */ ++ struct sk_buff *dummy_packet; ++ + /* Network stack work */ + struct work_struct netstack_work; + +@@ -527,6 +559,8 @@ + bool ba_support; + u8 ba_rx_bitmap; + ++ int tcxo_clock; ++ + /* + * AP-mode - links indexed by HLID. The global and broadcast links + * are always active. +@@ -544,6 +578,9 @@ + + /* Quirks of specific hardware revisions */ + unsigned int quirks; ++ ++ /* Platform limitations */ ++ unsigned int platform_quirks; + }; + + struct wl1271_station { +@@ -576,6 +613,15 @@ + /* Quirks */ + + /* Each RX/TX transaction requires an end-of-transaction transfer */ +-#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) ++#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) ++ ++/* ++ * Older firmwares use 2 spare TX blocks ++ * (for STA < 6.1.3.50.58 or for AP < 6.2.0.0.47) ++ */ ++#define WL12XX_QUIRK_USE_2_SPARE_BLOCKS BIT(1) ++ ++/* WL128X requires aggregated packets to be aligned to the SDIO block size */ ++#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2) + + #endif +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_chip.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_chip.c +--- linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_chip.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_chip.c 2011-05-05 23:29:45.554442697 +0200 +@@ -557,7 +557,7 @@ + return r; + } + +-/* CR157 can be optionally patched by the EEPROM for original ZD1211 */ ++/* ZD_CR157 can be optionally patched by the EEPROM for original ZD1211 */ + static int patch_cr157(struct zd_chip *chip) + { + int r; +@@ -571,7 +571,7 @@ + return r; + + dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8); +- return zd_iowrite32_locked(chip, value >> 8, CR157); ++ return zd_iowrite32_locked(chip, value >> 8, ZD_CR157); + } + + /* +@@ -593,8 +593,8 @@ + int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) + { + struct zd_ioreq16 ioreqs[] = { +- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, +- { CR47, 0x1e }, ++ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, ++ { ZD_CR47, 0x1e }, + }; + + /* FIXME: Channel 11 is not the edge for all regulatory domains. */ +@@ -608,69 +608,69 @@ + static int zd1211_hw_reset_phy(struct zd_chip *chip) + { + static const struct zd_ioreq16 ioreqs[] = { +- { CR0, 0x0a }, { CR1, 0x06 }, { CR2, 0x26 }, +- { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xa0 }, +- { CR10, 0x81 }, { CR11, 0x00 }, { CR12, 0x7f }, +- { CR13, 0x8c }, { CR14, 0x80 }, { CR15, 0x3d }, +- { CR16, 0x20 }, { CR17, 0x1e }, { CR18, 0x0a }, +- { CR19, 0x48 }, { CR20, 0x0c }, { CR21, 0x0c }, +- { CR22, 0x23 }, { CR23, 0x90 }, { CR24, 0x14 }, +- { CR25, 0x40 }, { CR26, 0x10 }, { CR27, 0x19 }, +- { CR28, 0x7f }, { CR29, 0x80 }, { CR30, 0x4b }, +- { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, +- { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, +- { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, +- { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 }, +- { CR43, 0x10 }, { CR44, 0x12 }, { CR46, 0xff }, +- { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b }, +- { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 }, +- { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 }, +- { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff }, +- { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 }, +- { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 }, +- { CR79, 0x68 }, { CR80, 0x64 }, { CR81, 0x64 }, +- { CR82, 0x00 }, { CR83, 0x00 }, { CR84, 0x00 }, +- { CR85, 0x02 }, { CR86, 0x00 }, { CR87, 0x00 }, +- { CR88, 0xff }, { CR89, 0xfc }, { CR90, 0x00 }, +- { CR91, 0x00 }, { CR92, 0x00 }, { CR93, 0x08 }, +- { CR94, 0x00 }, { CR95, 0x00 }, { CR96, 0xff }, +- { CR97, 0xe7 }, { CR98, 0x00 }, { CR99, 0x00 }, +- { CR100, 0x00 }, { CR101, 0xae }, { CR102, 0x02 }, +- { CR103, 0x00 }, { CR104, 0x03 }, { CR105, 0x65 }, +- { CR106, 0x04 }, { CR107, 0x00 }, { CR108, 0x0a }, +- { CR109, 0xaa }, { CR110, 0xaa }, { CR111, 0x25 }, +- { CR112, 0x25 }, { CR113, 0x00 }, { CR119, 0x1e }, +- { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 }, ++ { ZD_CR0, 0x0a }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, ++ { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xa0 }, ++ { ZD_CR10, 0x81 }, { ZD_CR11, 0x00 }, { ZD_CR12, 0x7f }, ++ { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, { ZD_CR15, 0x3d }, ++ { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, { ZD_CR18, 0x0a }, ++ { ZD_CR19, 0x48 }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0c }, ++ { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, { ZD_CR24, 0x14 }, ++ { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, { ZD_CR27, 0x19 }, ++ { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, { ZD_CR30, 0x4b }, ++ { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, ++ { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, ++ { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, ++ { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, ++ { ZD_CR43, 0x10 }, { ZD_CR44, 0x12 }, { ZD_CR46, 0xff }, ++ { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, ++ { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, ++ { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, ++ { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, ++ { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, ++ { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, ++ { ZD_CR79, 0x68 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, ++ { ZD_CR82, 0x00 }, { ZD_CR83, 0x00 }, { ZD_CR84, 0x00 }, ++ { ZD_CR85, 0x02 }, { ZD_CR86, 0x00 }, { ZD_CR87, 0x00 }, ++ { ZD_CR88, 0xff }, { ZD_CR89, 0xfc }, { ZD_CR90, 0x00 }, ++ { ZD_CR91, 0x00 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x08 }, ++ { ZD_CR94, 0x00 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0xff }, ++ { ZD_CR97, 0xe7 }, { ZD_CR98, 0x00 }, { ZD_CR99, 0x00 }, ++ { ZD_CR100, 0x00 }, { ZD_CR101, 0xae }, { ZD_CR102, 0x02 }, ++ { ZD_CR103, 0x00 }, { ZD_CR104, 0x03 }, { ZD_CR105, 0x65 }, ++ { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, { ZD_CR108, 0x0a }, ++ { ZD_CR109, 0xaa }, { ZD_CR110, 0xaa }, { ZD_CR111, 0x25 }, ++ { ZD_CR112, 0x25 }, { ZD_CR113, 0x00 }, { ZD_CR119, 0x1e }, ++ { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, + { }, +- { CR5, 0x00 }, { CR6, 0x00 }, { CR7, 0x00 }, +- { CR8, 0x00 }, { CR9, 0x20 }, { CR12, 0xf0 }, +- { CR20, 0x0e }, { CR21, 0x0e }, { CR27, 0x10 }, +- { CR44, 0x33 }, { CR47, 0x1E }, { CR83, 0x24 }, +- { CR84, 0x04 }, { CR85, 0x00 }, { CR86, 0x0C }, +- { CR87, 0x12 }, { CR88, 0x0C }, { CR89, 0x00 }, +- { CR90, 0x10 }, { CR91, 0x08 }, { CR93, 0x00 }, +- { CR94, 0x01 }, { CR95, 0x00 }, { CR96, 0x50 }, +- { CR97, 0x37 }, { CR98, 0x35 }, { CR101, 0x13 }, +- { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 }, +- { CR105, 0x12 }, { CR109, 0x27 }, { CR110, 0x27 }, +- { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, +- { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, +- { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f }, +- { CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 }, +- { CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C }, +- { CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 }, +- { CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 }, +- { CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c }, +- { CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 }, +- { CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe }, +- { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, +- { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, +- { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, +- { CR170, 0xba }, { CR171, 0xba }, +- /* Note: CR204 must lead the CR203 */ +- { CR204, 0x7d }, ++ { ZD_CR5, 0x00 }, { ZD_CR6, 0x00 }, { ZD_CR7, 0x00 }, ++ { ZD_CR8, 0x00 }, { ZD_CR9, 0x20 }, { ZD_CR12, 0xf0 }, ++ { ZD_CR20, 0x0e }, { ZD_CR21, 0x0e }, { ZD_CR27, 0x10 }, ++ { ZD_CR44, 0x33 }, { ZD_CR47, 0x1E }, { ZD_CR83, 0x24 }, ++ { ZD_CR84, 0x04 }, { ZD_CR85, 0x00 }, { ZD_CR86, 0x0C }, ++ { ZD_CR87, 0x12 }, { ZD_CR88, 0x0C }, { ZD_CR89, 0x00 }, ++ { ZD_CR90, 0x10 }, { ZD_CR91, 0x08 }, { ZD_CR93, 0x00 }, ++ { ZD_CR94, 0x01 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0x50 }, ++ { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, { ZD_CR101, 0x13 }, ++ { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, ++ { ZD_CR105, 0x12 }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, ++ { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, ++ { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, ++ { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR120, 0x4f }, ++ { ZD_CR125, 0xaa }, { ZD_CR127, 0x03 }, { ZD_CR128, 0x14 }, ++ { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, { ZD_CR131, 0x0C }, ++ { ZD_CR136, 0xdf }, { ZD_CR137, 0x40 }, { ZD_CR138, 0xa0 }, ++ { ZD_CR139, 0xb0 }, { ZD_CR140, 0x99 }, { ZD_CR141, 0x82 }, ++ { ZD_CR142, 0x54 }, { ZD_CR143, 0x1c }, { ZD_CR144, 0x6c }, ++ { ZD_CR147, 0x07 }, { ZD_CR148, 0x4c }, { ZD_CR149, 0x50 }, ++ { ZD_CR150, 0x0e }, { ZD_CR151, 0x18 }, { ZD_CR160, 0xfe }, ++ { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, ++ { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, ++ { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, ++ { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, ++ /* Note: ZD_CR204 must lead the ZD_CR203 */ ++ { ZD_CR204, 0x7d }, + { }, +- { CR203, 0x30 }, ++ { ZD_CR203, 0x30 }, + }; + + int r, t; +@@ -697,62 +697,62 @@ + static int zd1211b_hw_reset_phy(struct zd_chip *chip) + { + static const struct zd_ioreq16 ioreqs[] = { +- { CR0, 0x14 }, { CR1, 0x06 }, { CR2, 0x26 }, +- { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xe0 }, +- { CR10, 0x81 }, +- /* power control { { CR11, 1 << 6 }, */ +- { CR11, 0x00 }, +- { CR12, 0xf0 }, { CR13, 0x8c }, { CR14, 0x80 }, +- { CR15, 0x3d }, { CR16, 0x20 }, { CR17, 0x1e }, +- { CR18, 0x0a }, { CR19, 0x48 }, +- { CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ +- { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 }, +- { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 }, +- { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 }, +- { CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ +- { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, +- { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, +- { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, +- { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 }, +- { CR43, 0x10 }, { CR44, 0x33 }, { CR46, 0xff }, +- { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b }, +- { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 }, +- { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 }, +- { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff }, +- { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 }, +- { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 }, +- { CR79, 0xf0 }, { CR80, 0x64 }, { CR81, 0x64 }, +- { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 }, +- { CR85, 0x00 }, { CR86, 0x0c }, { CR87, 0x12 }, +- { CR88, 0x0c }, { CR89, 0x00 }, { CR90, 0x58 }, +- { CR91, 0x04 }, { CR92, 0x00 }, { CR93, 0x00 }, +- { CR94, 0x01 }, +- { CR95, 0x20 }, /* ZD1211B */ +- { CR96, 0x50 }, { CR97, 0x37 }, { CR98, 0x35 }, +- { CR99, 0x00 }, { CR100, 0x01 }, { CR101, 0x13 }, +- { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 }, +- { CR105, 0x12 }, { CR106, 0x04 }, { CR107, 0x00 }, +- { CR108, 0x0a }, { CR109, 0x27 }, { CR110, 0x27 }, +- { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, +- { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, +- { CR117, 0xfc }, { CR118, 0xfa }, { CR119, 0x1e }, +- { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 }, +- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, +- { CR131, 0x0c }, { CR136, 0xdf }, { CR137, 0xa0 }, +- { CR138, 0xa8 }, { CR139, 0xb4 }, { CR140, 0x98 }, +- { CR141, 0x82 }, { CR142, 0x53 }, { CR143, 0x1c }, +- { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x40 }, +- { CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ +- { CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ +- { CR151, 0x18 }, { CR159, 0x70 }, { CR160, 0xfe }, +- { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, +- { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, +- { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, +- { CR170, 0xba }, { CR171, 0xba }, +- /* Note: CR204 must lead the CR203 */ +- { CR204, 0x7d }, ++ { ZD_CR0, 0x14 }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, ++ { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xe0 }, ++ { ZD_CR10, 0x81 }, ++ /* power control { { ZD_CR11, 1 << 6 }, */ ++ { ZD_CR11, 0x00 }, ++ { ZD_CR12, 0xf0 }, { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, ++ { ZD_CR15, 0x3d }, { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, ++ { ZD_CR18, 0x0a }, { ZD_CR19, 0x48 }, ++ { ZD_CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ ++ { ZD_CR21, 0x0e }, { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, ++ { ZD_CR24, 0x14 }, { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, ++ { ZD_CR27, 0x10 }, { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, ++ { ZD_CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ ++ { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, ++ { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, ++ { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, ++ { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, ++ { ZD_CR43, 0x10 }, { ZD_CR44, 0x33 }, { ZD_CR46, 0xff }, ++ { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, ++ { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, ++ { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, ++ { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, ++ { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, ++ { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, ++ { ZD_CR79, 0xf0 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, ++ { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, ++ { ZD_CR85, 0x00 }, { ZD_CR86, 0x0c }, { ZD_CR87, 0x12 }, ++ { ZD_CR88, 0x0c }, { ZD_CR89, 0x00 }, { ZD_CR90, 0x58 }, ++ { ZD_CR91, 0x04 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x00 }, ++ { ZD_CR94, 0x01 }, ++ { ZD_CR95, 0x20 }, /* ZD1211B */ ++ { ZD_CR96, 0x50 }, { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, ++ { ZD_CR99, 0x00 }, { ZD_CR100, 0x01 }, { ZD_CR101, 0x13 }, ++ { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, ++ { ZD_CR105, 0x12 }, { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, ++ { ZD_CR108, 0x0a }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, ++ { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, ++ { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, ++ { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x1e }, ++ { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, ++ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, ++ { ZD_CR131, 0x0c }, { ZD_CR136, 0xdf }, { ZD_CR137, 0xa0 }, ++ { ZD_CR138, 0xa8 }, { ZD_CR139, 0xb4 }, { ZD_CR140, 0x98 }, ++ { ZD_CR141, 0x82 }, { ZD_CR142, 0x53 }, { ZD_CR143, 0x1c }, ++ { ZD_CR144, 0x6c }, { ZD_CR147, 0x07 }, { ZD_CR148, 0x40 }, ++ { ZD_CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ ++ { ZD_CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ ++ { ZD_CR151, 0x18 }, { ZD_CR159, 0x70 }, { ZD_CR160, 0xfe }, ++ { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, ++ { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, ++ { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, ++ { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, ++ /* Note: ZD_CR204 must lead the ZD_CR203 */ ++ { ZD_CR204, 0x7d }, + {}, +- { CR203, 0x30 }, ++ { ZD_CR203, 0x30 }, + }; + + int r, t; +@@ -1200,24 +1200,24 @@ + static int update_pwr_int(struct zd_chip *chip, u8 channel) + { + u8 value = chip->pwr_int_values[channel - 1]; +- return zd_iowrite16_locked(chip, value, CR31); ++ return zd_iowrite16_locked(chip, value, ZD_CR31); + } + + static int update_pwr_cal(struct zd_chip *chip, u8 channel) + { + u8 value = chip->pwr_cal_values[channel-1]; +- return zd_iowrite16_locked(chip, value, CR68); ++ return zd_iowrite16_locked(chip, value, ZD_CR68); + } + + static int update_ofdm_cal(struct zd_chip *chip, u8 channel) + { + struct zd_ioreq16 ioreqs[3]; + +- ioreqs[0].addr = CR67; ++ ioreqs[0].addr = ZD_CR67; + ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1]; +- ioreqs[1].addr = CR66; ++ ioreqs[1].addr = ZD_CR66; + ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1]; +- ioreqs[2].addr = CR65; ++ ioreqs[2].addr = ZD_CR65; + ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1]; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +@@ -1236,9 +1236,9 @@ + return r; + if (zd_chip_is_zd1211b(chip)) { + static const struct zd_ioreq16 ioreqs[] = { +- { CR69, 0x28 }, ++ { ZD_CR69, 0x28 }, + {}, +- { CR69, 0x2a }, ++ { ZD_CR69, 0x2a }, + }; + + r = update_ofdm_cal(chip, channel); +@@ -1269,7 +1269,7 @@ + if (r) + return r; + dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff); +- return zd_iowrite16_locked(chip, value & 0xff, CR47); ++ return zd_iowrite16_locked(chip, value & 0xff, ZD_CR47); + } + + int zd_chip_set_channel(struct zd_chip *chip, u8 channel) +@@ -1505,9 +1505,9 @@ + int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value) + { + const struct zd_ioreq16 ioreqs[] = { +- { CR244, (value >> 16) & 0xff }, +- { CR243, (value >> 8) & 0xff }, +- { CR242, value & 0xff }, ++ { ZD_CR244, (value >> 16) & 0xff }, ++ { ZD_CR243, (value >> 8) & 0xff }, ++ { ZD_CR242, value & 0xff }, + }; + ZD_ASSERT(mutex_is_locked(&chip->mutex)); + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_chip.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_chip.h +--- linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_chip.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_chip.h 2011-05-05 23:29:45.534442457 +0200 +@@ -61,277 +61,288 @@ + #define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset))) + + /* 8-bit hardware registers */ +-#define CR0 CTL_REG(0x0000) +-#define CR1 CTL_REG(0x0004) +-#define CR2 CTL_REG(0x0008) +-#define CR3 CTL_REG(0x000C) ++#define ZD_CR0 CTL_REG(0x0000) ++#define ZD_CR1 CTL_REG(0x0004) ++#define ZD_CR2 CTL_REG(0x0008) ++#define ZD_CR3 CTL_REG(0x000C) + +-#define CR5 CTL_REG(0x0010) ++#define ZD_CR5 CTL_REG(0x0010) + /* bit 5: if set short preamble used + * bit 6: filter band - Japan channel 14 on, else off + */ +-#define CR6 CTL_REG(0x0014) +-#define CR7 CTL_REG(0x0018) +-#define CR8 CTL_REG(0x001C) +- +-#define CR4 CTL_REG(0x0020) +- +-#define CR9 CTL_REG(0x0024) +-/* bit 2: antenna switch (together with CR10) */ +-#define CR10 CTL_REG(0x0028) +-/* bit 1: antenna switch (together with CR9) +- * RF2959 controls with CR11 radion on and off ++#define ZD_CR6 CTL_REG(0x0014) ++#define ZD_CR7 CTL_REG(0x0018) ++#define ZD_CR8 CTL_REG(0x001C) ++ ++#define ZD_CR4 CTL_REG(0x0020) ++ ++#define ZD_CR9 CTL_REG(0x0024) ++/* bit 2: antenna switch (together with ZD_CR10) */ ++#define ZD_CR10 CTL_REG(0x0028) ++/* bit 1: antenna switch (together with ZD_CR9) ++ * RF2959 controls with ZD_CR11 radion on and off + */ +-#define CR11 CTL_REG(0x002C) ++#define ZD_CR11 CTL_REG(0x002C) + /* bit 6: TX power control for OFDM +- * RF2959 controls with CR10 radio on and off ++ * RF2959 controls with ZD_CR10 radio on and off + */ +-#define CR12 CTL_REG(0x0030) +-#define CR13 CTL_REG(0x0034) +-#define CR14 CTL_REG(0x0038) +-#define CR15 CTL_REG(0x003C) +-#define CR16 CTL_REG(0x0040) +-#define CR17 CTL_REG(0x0044) +-#define CR18 CTL_REG(0x0048) +-#define CR19 CTL_REG(0x004C) +-#define CR20 CTL_REG(0x0050) +-#define CR21 CTL_REG(0x0054) +-#define CR22 CTL_REG(0x0058) +-#define CR23 CTL_REG(0x005C) +-#define CR24 CTL_REG(0x0060) /* CCA threshold */ +-#define CR25 CTL_REG(0x0064) +-#define CR26 CTL_REG(0x0068) +-#define CR27 CTL_REG(0x006C) +-#define CR28 CTL_REG(0x0070) +-#define CR29 CTL_REG(0x0074) +-#define CR30 CTL_REG(0x0078) +-#define CR31 CTL_REG(0x007C) /* TX power control for RF in CCK mode */ +-#define CR32 CTL_REG(0x0080) +-#define CR33 CTL_REG(0x0084) +-#define CR34 CTL_REG(0x0088) +-#define CR35 CTL_REG(0x008C) +-#define CR36 CTL_REG(0x0090) +-#define CR37 CTL_REG(0x0094) +-#define CR38 CTL_REG(0x0098) +-#define CR39 CTL_REG(0x009C) +-#define CR40 CTL_REG(0x00A0) +-#define CR41 CTL_REG(0x00A4) +-#define CR42 CTL_REG(0x00A8) +-#define CR43 CTL_REG(0x00AC) +-#define CR44 CTL_REG(0x00B0) +-#define CR45 CTL_REG(0x00B4) +-#define CR46 CTL_REG(0x00B8) +-#define CR47 CTL_REG(0x00BC) /* CCK baseband gain +- * (patch value might be in EEPROM) +- */ +-#define CR48 CTL_REG(0x00C0) +-#define CR49 CTL_REG(0x00C4) +-#define CR50 CTL_REG(0x00C8) +-#define CR51 CTL_REG(0x00CC) /* TX power control for RF in 6-36M modes */ +-#define CR52 CTL_REG(0x00D0) /* TX power control for RF in 48M mode */ +-#define CR53 CTL_REG(0x00D4) /* TX power control for RF in 54M mode */ +-#define CR54 CTL_REG(0x00D8) +-#define CR55 CTL_REG(0x00DC) +-#define CR56 CTL_REG(0x00E0) +-#define CR57 CTL_REG(0x00E4) +-#define CR58 CTL_REG(0x00E8) +-#define CR59 CTL_REG(0x00EC) +-#define CR60 CTL_REG(0x00F0) +-#define CR61 CTL_REG(0x00F4) +-#define CR62 CTL_REG(0x00F8) +-#define CR63 CTL_REG(0x00FC) +-#define CR64 CTL_REG(0x0100) +-#define CR65 CTL_REG(0x0104) /* OFDM 54M calibration */ +-#define CR66 CTL_REG(0x0108) /* OFDM 48M calibration */ +-#define CR67 CTL_REG(0x010C) /* OFDM 36M calibration */ +-#define CR68 CTL_REG(0x0110) /* CCK calibration */ +-#define CR69 CTL_REG(0x0114) +-#define CR70 CTL_REG(0x0118) +-#define CR71 CTL_REG(0x011C) +-#define CR72 CTL_REG(0x0120) +-#define CR73 CTL_REG(0x0124) +-#define CR74 CTL_REG(0x0128) +-#define CR75 CTL_REG(0x012C) +-#define CR76 CTL_REG(0x0130) +-#define CR77 CTL_REG(0x0134) +-#define CR78 CTL_REG(0x0138) +-#define CR79 CTL_REG(0x013C) +-#define CR80 CTL_REG(0x0140) +-#define CR81 CTL_REG(0x0144) +-#define CR82 CTL_REG(0x0148) +-#define CR83 CTL_REG(0x014C) +-#define CR84 CTL_REG(0x0150) +-#define CR85 CTL_REG(0x0154) +-#define CR86 CTL_REG(0x0158) +-#define CR87 CTL_REG(0x015C) +-#define CR88 CTL_REG(0x0160) +-#define CR89 CTL_REG(0x0164) +-#define CR90 CTL_REG(0x0168) +-#define CR91 CTL_REG(0x016C) +-#define CR92 CTL_REG(0x0170) +-#define CR93 CTL_REG(0x0174) +-#define CR94 CTL_REG(0x0178) +-#define CR95 CTL_REG(0x017C) +-#define CR96 CTL_REG(0x0180) +-#define CR97 CTL_REG(0x0184) +-#define CR98 CTL_REG(0x0188) +-#define CR99 CTL_REG(0x018C) +-#define CR100 CTL_REG(0x0190) +-#define CR101 CTL_REG(0x0194) +-#define CR102 CTL_REG(0x0198) +-#define CR103 CTL_REG(0x019C) +-#define CR104 CTL_REG(0x01A0) +-#define CR105 CTL_REG(0x01A4) +-#define CR106 CTL_REG(0x01A8) +-#define CR107 CTL_REG(0x01AC) +-#define CR108 CTL_REG(0x01B0) +-#define CR109 CTL_REG(0x01B4) +-#define CR110 CTL_REG(0x01B8) +-#define CR111 CTL_REG(0x01BC) +-#define CR112 CTL_REG(0x01C0) +-#define CR113 CTL_REG(0x01C4) +-#define CR114 CTL_REG(0x01C8) +-#define CR115 CTL_REG(0x01CC) +-#define CR116 CTL_REG(0x01D0) +-#define CR117 CTL_REG(0x01D4) +-#define CR118 CTL_REG(0x01D8) +-#define CR119 CTL_REG(0x01DC) +-#define CR120 CTL_REG(0x01E0) +-#define CR121 CTL_REG(0x01E4) +-#define CR122 CTL_REG(0x01E8) +-#define CR123 CTL_REG(0x01EC) +-#define CR124 CTL_REG(0x01F0) +-#define CR125 CTL_REG(0x01F4) +-#define CR126 CTL_REG(0x01F8) +-#define CR127 CTL_REG(0x01FC) +-#define CR128 CTL_REG(0x0200) +-#define CR129 CTL_REG(0x0204) +-#define CR130 CTL_REG(0x0208) +-#define CR131 CTL_REG(0x020C) +-#define CR132 CTL_REG(0x0210) +-#define CR133 CTL_REG(0x0214) +-#define CR134 CTL_REG(0x0218) +-#define CR135 CTL_REG(0x021C) +-#define CR136 CTL_REG(0x0220) +-#define CR137 CTL_REG(0x0224) +-#define CR138 CTL_REG(0x0228) +-#define CR139 CTL_REG(0x022C) +-#define CR140 CTL_REG(0x0230) +-#define CR141 CTL_REG(0x0234) +-#define CR142 CTL_REG(0x0238) +-#define CR143 CTL_REG(0x023C) +-#define CR144 CTL_REG(0x0240) +-#define CR145 CTL_REG(0x0244) +-#define CR146 CTL_REG(0x0248) +-#define CR147 CTL_REG(0x024C) +-#define CR148 CTL_REG(0x0250) +-#define CR149 CTL_REG(0x0254) +-#define CR150 CTL_REG(0x0258) +-#define CR151 CTL_REG(0x025C) +-#define CR152 CTL_REG(0x0260) +-#define CR153 CTL_REG(0x0264) +-#define CR154 CTL_REG(0x0268) +-#define CR155 CTL_REG(0x026C) +-#define CR156 CTL_REG(0x0270) +-#define CR157 CTL_REG(0x0274) +-#define CR158 CTL_REG(0x0278) +-#define CR159 CTL_REG(0x027C) +-#define CR160 CTL_REG(0x0280) +-#define CR161 CTL_REG(0x0284) +-#define CR162 CTL_REG(0x0288) +-#define CR163 CTL_REG(0x028C) +-#define CR164 CTL_REG(0x0290) +-#define CR165 CTL_REG(0x0294) +-#define CR166 CTL_REG(0x0298) +-#define CR167 CTL_REG(0x029C) +-#define CR168 CTL_REG(0x02A0) +-#define CR169 CTL_REG(0x02A4) +-#define CR170 CTL_REG(0x02A8) +-#define CR171 CTL_REG(0x02AC) +-#define CR172 CTL_REG(0x02B0) +-#define CR173 CTL_REG(0x02B4) +-#define CR174 CTL_REG(0x02B8) +-#define CR175 CTL_REG(0x02BC) +-#define CR176 CTL_REG(0x02C0) +-#define CR177 CTL_REG(0x02C4) +-#define CR178 CTL_REG(0x02C8) +-#define CR179 CTL_REG(0x02CC) +-#define CR180 CTL_REG(0x02D0) +-#define CR181 CTL_REG(0x02D4) +-#define CR182 CTL_REG(0x02D8) +-#define CR183 CTL_REG(0x02DC) +-#define CR184 CTL_REG(0x02E0) +-#define CR185 CTL_REG(0x02E4) +-#define CR186 CTL_REG(0x02E8) +-#define CR187 CTL_REG(0x02EC) +-#define CR188 CTL_REG(0x02F0) +-#define CR189 CTL_REG(0x02F4) +-#define CR190 CTL_REG(0x02F8) +-#define CR191 CTL_REG(0x02FC) +-#define CR192 CTL_REG(0x0300) +-#define CR193 CTL_REG(0x0304) +-#define CR194 CTL_REG(0x0308) +-#define CR195 CTL_REG(0x030C) +-#define CR196 CTL_REG(0x0310) +-#define CR197 CTL_REG(0x0314) +-#define CR198 CTL_REG(0x0318) +-#define CR199 CTL_REG(0x031C) +-#define CR200 CTL_REG(0x0320) +-#define CR201 CTL_REG(0x0324) +-#define CR202 CTL_REG(0x0328) +-#define CR203 CTL_REG(0x032C) /* I2C bus template value & flash control */ +-#define CR204 CTL_REG(0x0330) +-#define CR205 CTL_REG(0x0334) +-#define CR206 CTL_REG(0x0338) +-#define CR207 CTL_REG(0x033C) +-#define CR208 CTL_REG(0x0340) +-#define CR209 CTL_REG(0x0344) +-#define CR210 CTL_REG(0x0348) +-#define CR211 CTL_REG(0x034C) +-#define CR212 CTL_REG(0x0350) +-#define CR213 CTL_REG(0x0354) +-#define CR214 CTL_REG(0x0358) +-#define CR215 CTL_REG(0x035C) +-#define CR216 CTL_REG(0x0360) +-#define CR217 CTL_REG(0x0364) +-#define CR218 CTL_REG(0x0368) +-#define CR219 CTL_REG(0x036C) +-#define CR220 CTL_REG(0x0370) +-#define CR221 CTL_REG(0x0374) +-#define CR222 CTL_REG(0x0378) +-#define CR223 CTL_REG(0x037C) +-#define CR224 CTL_REG(0x0380) +-#define CR225 CTL_REG(0x0384) +-#define CR226 CTL_REG(0x0388) +-#define CR227 CTL_REG(0x038C) +-#define CR228 CTL_REG(0x0390) +-#define CR229 CTL_REG(0x0394) +-#define CR230 CTL_REG(0x0398) +-#define CR231 CTL_REG(0x039C) +-#define CR232 CTL_REG(0x03A0) +-#define CR233 CTL_REG(0x03A4) +-#define CR234 CTL_REG(0x03A8) +-#define CR235 CTL_REG(0x03AC) +-#define CR236 CTL_REG(0x03B0) +- +-#define CR240 CTL_REG(0x03C0) +-/* bit 7: host-controlled RF register writes +- * CR241-CR245: for hardware controlled writing of RF bits, not needed for +- * USB +- */ +-#define CR241 CTL_REG(0x03C4) +-#define CR242 CTL_REG(0x03C8) +-#define CR243 CTL_REG(0x03CC) +-#define CR244 CTL_REG(0x03D0) +-#define CR245 CTL_REG(0x03D4) +- +-#define CR251 CTL_REG(0x03EC) /* only used for activation and deactivation of +- * Airoha RFs AL2230 and AL7230B +- */ +-#define CR252 CTL_REG(0x03F0) +-#define CR253 CTL_REG(0x03F4) +-#define CR254 CTL_REG(0x03F8) +-#define CR255 CTL_REG(0x03FC) ++#define ZD_CR12 CTL_REG(0x0030) ++#define ZD_CR13 CTL_REG(0x0034) ++#define ZD_CR14 CTL_REG(0x0038) ++#define ZD_CR15 CTL_REG(0x003C) ++#define ZD_CR16 CTL_REG(0x0040) ++#define ZD_CR17 CTL_REG(0x0044) ++#define ZD_CR18 CTL_REG(0x0048) ++#define ZD_CR19 CTL_REG(0x004C) ++#define ZD_CR20 CTL_REG(0x0050) ++#define ZD_CR21 CTL_REG(0x0054) ++#define ZD_CR22 CTL_REG(0x0058) ++#define ZD_CR23 CTL_REG(0x005C) ++#define ZD_CR24 CTL_REG(0x0060) /* CCA threshold */ ++#define ZD_CR25 CTL_REG(0x0064) ++#define ZD_CR26 CTL_REG(0x0068) ++#define ZD_CR27 CTL_REG(0x006C) ++#define ZD_CR28 CTL_REG(0x0070) ++#define ZD_CR29 CTL_REG(0x0074) ++#define ZD_CR30 CTL_REG(0x0078) ++#define ZD_CR31 CTL_REG(0x007C) /* TX power control for RF in ++ * CCK mode ++ */ ++#define ZD_CR32 CTL_REG(0x0080) ++#define ZD_CR33 CTL_REG(0x0084) ++#define ZD_CR34 CTL_REG(0x0088) ++#define ZD_CR35 CTL_REG(0x008C) ++#define ZD_CR36 CTL_REG(0x0090) ++#define ZD_CR37 CTL_REG(0x0094) ++#define ZD_CR38 CTL_REG(0x0098) ++#define ZD_CR39 CTL_REG(0x009C) ++#define ZD_CR40 CTL_REG(0x00A0) ++#define ZD_CR41 CTL_REG(0x00A4) ++#define ZD_CR42 CTL_REG(0x00A8) ++#define ZD_CR43 CTL_REG(0x00AC) ++#define ZD_CR44 CTL_REG(0x00B0) ++#define ZD_CR45 CTL_REG(0x00B4) ++#define ZD_CR46 CTL_REG(0x00B8) ++#define ZD_CR47 CTL_REG(0x00BC) /* CCK baseband gain ++ * (patch value might be in EEPROM) ++ */ ++#define ZD_CR48 CTL_REG(0x00C0) ++#define ZD_CR49 CTL_REG(0x00C4) ++#define ZD_CR50 CTL_REG(0x00C8) ++#define ZD_CR51 CTL_REG(0x00CC) /* TX power control for RF in ++ * 6-36M modes ++ */ ++#define ZD_CR52 CTL_REG(0x00D0) /* TX power control for RF in ++ * 48M mode ++ */ ++#define ZD_CR53 CTL_REG(0x00D4) /* TX power control for RF in ++ * 54M mode ++ */ ++#define ZD_CR54 CTL_REG(0x00D8) ++#define ZD_CR55 CTL_REG(0x00DC) ++#define ZD_CR56 CTL_REG(0x00E0) ++#define ZD_CR57 CTL_REG(0x00E4) ++#define ZD_CR58 CTL_REG(0x00E8) ++#define ZD_CR59 CTL_REG(0x00EC) ++#define ZD_CR60 CTL_REG(0x00F0) ++#define ZD_CR61 CTL_REG(0x00F4) ++#define ZD_CR62 CTL_REG(0x00F8) ++#define ZD_CR63 CTL_REG(0x00FC) ++#define ZD_CR64 CTL_REG(0x0100) ++#define ZD_CR65 CTL_REG(0x0104) /* OFDM 54M calibration */ ++#define ZD_CR66 CTL_REG(0x0108) /* OFDM 48M calibration */ ++#define ZD_CR67 CTL_REG(0x010C) /* OFDM 36M calibration */ ++#define ZD_CR68 CTL_REG(0x0110) /* CCK calibration */ ++#define ZD_CR69 CTL_REG(0x0114) ++#define ZD_CR70 CTL_REG(0x0118) ++#define ZD_CR71 CTL_REG(0x011C) ++#define ZD_CR72 CTL_REG(0x0120) ++#define ZD_CR73 CTL_REG(0x0124) ++#define ZD_CR74 CTL_REG(0x0128) ++#define ZD_CR75 CTL_REG(0x012C) ++#define ZD_CR76 CTL_REG(0x0130) ++#define ZD_CR77 CTL_REG(0x0134) ++#define ZD_CR78 CTL_REG(0x0138) ++#define ZD_CR79 CTL_REG(0x013C) ++#define ZD_CR80 CTL_REG(0x0140) ++#define ZD_CR81 CTL_REG(0x0144) ++#define ZD_CR82 CTL_REG(0x0148) ++#define ZD_CR83 CTL_REG(0x014C) ++#define ZD_CR84 CTL_REG(0x0150) ++#define ZD_CR85 CTL_REG(0x0154) ++#define ZD_CR86 CTL_REG(0x0158) ++#define ZD_CR87 CTL_REG(0x015C) ++#define ZD_CR88 CTL_REG(0x0160) ++#define ZD_CR89 CTL_REG(0x0164) ++#define ZD_CR90 CTL_REG(0x0168) ++#define ZD_CR91 CTL_REG(0x016C) ++#define ZD_CR92 CTL_REG(0x0170) ++#define ZD_CR93 CTL_REG(0x0174) ++#define ZD_CR94 CTL_REG(0x0178) ++#define ZD_CR95 CTL_REG(0x017C) ++#define ZD_CR96 CTL_REG(0x0180) ++#define ZD_CR97 CTL_REG(0x0184) ++#define ZD_CR98 CTL_REG(0x0188) ++#define ZD_CR99 CTL_REG(0x018C) ++#define ZD_CR100 CTL_REG(0x0190) ++#define ZD_CR101 CTL_REG(0x0194) ++#define ZD_CR102 CTL_REG(0x0198) ++#define ZD_CR103 CTL_REG(0x019C) ++#define ZD_CR104 CTL_REG(0x01A0) ++#define ZD_CR105 CTL_REG(0x01A4) ++#define ZD_CR106 CTL_REG(0x01A8) ++#define ZD_CR107 CTL_REG(0x01AC) ++#define ZD_CR108 CTL_REG(0x01B0) ++#define ZD_CR109 CTL_REG(0x01B4) ++#define ZD_CR110 CTL_REG(0x01B8) ++#define ZD_CR111 CTL_REG(0x01BC) ++#define ZD_CR112 CTL_REG(0x01C0) ++#define ZD_CR113 CTL_REG(0x01C4) ++#define ZD_CR114 CTL_REG(0x01C8) ++#define ZD_CR115 CTL_REG(0x01CC) ++#define ZD_CR116 CTL_REG(0x01D0) ++#define ZD_CR117 CTL_REG(0x01D4) ++#define ZD_CR118 CTL_REG(0x01D8) ++#define ZD_CR119 CTL_REG(0x01DC) ++#define ZD_CR120 CTL_REG(0x01E0) ++#define ZD_CR121 CTL_REG(0x01E4) ++#define ZD_CR122 CTL_REG(0x01E8) ++#define ZD_CR123 CTL_REG(0x01EC) ++#define ZD_CR124 CTL_REG(0x01F0) ++#define ZD_CR125 CTL_REG(0x01F4) ++#define ZD_CR126 CTL_REG(0x01F8) ++#define ZD_CR127 CTL_REG(0x01FC) ++#define ZD_CR128 CTL_REG(0x0200) ++#define ZD_CR129 CTL_REG(0x0204) ++#define ZD_CR130 CTL_REG(0x0208) ++#define ZD_CR131 CTL_REG(0x020C) ++#define ZD_CR132 CTL_REG(0x0210) ++#define ZD_CR133 CTL_REG(0x0214) ++#define ZD_CR134 CTL_REG(0x0218) ++#define ZD_CR135 CTL_REG(0x021C) ++#define ZD_CR136 CTL_REG(0x0220) ++#define ZD_CR137 CTL_REG(0x0224) ++#define ZD_CR138 CTL_REG(0x0228) ++#define ZD_CR139 CTL_REG(0x022C) ++#define ZD_CR140 CTL_REG(0x0230) ++#define ZD_CR141 CTL_REG(0x0234) ++#define ZD_CR142 CTL_REG(0x0238) ++#define ZD_CR143 CTL_REG(0x023C) ++#define ZD_CR144 CTL_REG(0x0240) ++#define ZD_CR145 CTL_REG(0x0244) ++#define ZD_CR146 CTL_REG(0x0248) ++#define ZD_CR147 CTL_REG(0x024C) ++#define ZD_CR148 CTL_REG(0x0250) ++#define ZD_CR149 CTL_REG(0x0254) ++#define ZD_CR150 CTL_REG(0x0258) ++#define ZD_CR151 CTL_REG(0x025C) ++#define ZD_CR152 CTL_REG(0x0260) ++#define ZD_CR153 CTL_REG(0x0264) ++#define ZD_CR154 CTL_REG(0x0268) ++#define ZD_CR155 CTL_REG(0x026C) ++#define ZD_CR156 CTL_REG(0x0270) ++#define ZD_CR157 CTL_REG(0x0274) ++#define ZD_CR158 CTL_REG(0x0278) ++#define ZD_CR159 CTL_REG(0x027C) ++#define ZD_CR160 CTL_REG(0x0280) ++#define ZD_CR161 CTL_REG(0x0284) ++#define ZD_CR162 CTL_REG(0x0288) ++#define ZD_CR163 CTL_REG(0x028C) ++#define ZD_CR164 CTL_REG(0x0290) ++#define ZD_CR165 CTL_REG(0x0294) ++#define ZD_CR166 CTL_REG(0x0298) ++#define ZD_CR167 CTL_REG(0x029C) ++#define ZD_CR168 CTL_REG(0x02A0) ++#define ZD_CR169 CTL_REG(0x02A4) ++#define ZD_CR170 CTL_REG(0x02A8) ++#define ZD_CR171 CTL_REG(0x02AC) ++#define ZD_CR172 CTL_REG(0x02B0) ++#define ZD_CR173 CTL_REG(0x02B4) ++#define ZD_CR174 CTL_REG(0x02B8) ++#define ZD_CR175 CTL_REG(0x02BC) ++#define ZD_CR176 CTL_REG(0x02C0) ++#define ZD_CR177 CTL_REG(0x02C4) ++#define ZD_CR178 CTL_REG(0x02C8) ++#define ZD_CR179 CTL_REG(0x02CC) ++#define ZD_CR180 CTL_REG(0x02D0) ++#define ZD_CR181 CTL_REG(0x02D4) ++#define ZD_CR182 CTL_REG(0x02D8) ++#define ZD_CR183 CTL_REG(0x02DC) ++#define ZD_CR184 CTL_REG(0x02E0) ++#define ZD_CR185 CTL_REG(0x02E4) ++#define ZD_CR186 CTL_REG(0x02E8) ++#define ZD_CR187 CTL_REG(0x02EC) ++#define ZD_CR188 CTL_REG(0x02F0) ++#define ZD_CR189 CTL_REG(0x02F4) ++#define ZD_CR190 CTL_REG(0x02F8) ++#define ZD_CR191 CTL_REG(0x02FC) ++#define ZD_CR192 CTL_REG(0x0300) ++#define ZD_CR193 CTL_REG(0x0304) ++#define ZD_CR194 CTL_REG(0x0308) ++#define ZD_CR195 CTL_REG(0x030C) ++#define ZD_CR196 CTL_REG(0x0310) ++#define ZD_CR197 CTL_REG(0x0314) ++#define ZD_CR198 CTL_REG(0x0318) ++#define ZD_CR199 CTL_REG(0x031C) ++#define ZD_CR200 CTL_REG(0x0320) ++#define ZD_CR201 CTL_REG(0x0324) ++#define ZD_CR202 CTL_REG(0x0328) ++#define ZD_CR203 CTL_REG(0x032C) /* I2C bus template value & flash ++ * control ++ */ ++#define ZD_CR204 CTL_REG(0x0330) ++#define ZD_CR205 CTL_REG(0x0334) ++#define ZD_CR206 CTL_REG(0x0338) ++#define ZD_CR207 CTL_REG(0x033C) ++#define ZD_CR208 CTL_REG(0x0340) ++#define ZD_CR209 CTL_REG(0x0344) ++#define ZD_CR210 CTL_REG(0x0348) ++#define ZD_CR211 CTL_REG(0x034C) ++#define ZD_CR212 CTL_REG(0x0350) ++#define ZD_CR213 CTL_REG(0x0354) ++#define ZD_CR214 CTL_REG(0x0358) ++#define ZD_CR215 CTL_REG(0x035C) ++#define ZD_CR216 CTL_REG(0x0360) ++#define ZD_CR217 CTL_REG(0x0364) ++#define ZD_CR218 CTL_REG(0x0368) ++#define ZD_CR219 CTL_REG(0x036C) ++#define ZD_CR220 CTL_REG(0x0370) ++#define ZD_CR221 CTL_REG(0x0374) ++#define ZD_CR222 CTL_REG(0x0378) ++#define ZD_CR223 CTL_REG(0x037C) ++#define ZD_CR224 CTL_REG(0x0380) ++#define ZD_CR225 CTL_REG(0x0384) ++#define ZD_CR226 CTL_REG(0x0388) ++#define ZD_CR227 CTL_REG(0x038C) ++#define ZD_CR228 CTL_REG(0x0390) ++#define ZD_CR229 CTL_REG(0x0394) ++#define ZD_CR230 CTL_REG(0x0398) ++#define ZD_CR231 CTL_REG(0x039C) ++#define ZD_CR232 CTL_REG(0x03A0) ++#define ZD_CR233 CTL_REG(0x03A4) ++#define ZD_CR234 CTL_REG(0x03A8) ++#define ZD_CR235 CTL_REG(0x03AC) ++#define ZD_CR236 CTL_REG(0x03B0) ++ ++#define ZD_CR240 CTL_REG(0x03C0) ++/* bit 7: host-controlled RF register writes ++ * ZD_CR241-ZD_CR245: for hardware controlled writing of RF bits, not needed for ++ * USB ++ */ ++#define ZD_CR241 CTL_REG(0x03C4) ++#define ZD_CR242 CTL_REG(0x03C8) ++#define ZD_CR243 CTL_REG(0x03CC) ++#define ZD_CR244 CTL_REG(0x03D0) ++#define ZD_CR245 CTL_REG(0x03D4) ++ ++#define ZD_CR251 CTL_REG(0x03EC) /* only used for activation and ++ * deactivation of Airoha RFs AL2230 ++ * and AL7230B ++ */ ++#define ZD_CR252 CTL_REG(0x03F0) ++#define ZD_CR253 CTL_REG(0x03F4) ++#define ZD_CR254 CTL_REG(0x03F8) ++#define ZD_CR255 CTL_REG(0x03FC) + + #define CR_MAX_PHY_REG 255 + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_rf_al2230.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_rf_al2230.c +--- linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_rf_al2230.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_rf_al2230.c 2011-05-05 23:29:45.535442469 +0200 +@@ -61,31 +61,31 @@ + }; + + static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = { +- { CR240, 0x57 }, { CR9, 0xe0 }, ++ { ZD_CR240, 0x57 }, { ZD_CR9, 0xe0 }, + }; + + static const struct zd_ioreq16 ioreqs_init_al2230s[] = { +- { CR47, 0x1e }, /* MARK_002 */ +- { CR106, 0x22 }, +- { CR107, 0x2a }, /* MARK_002 */ +- { CR109, 0x13 }, /* MARK_002 */ +- { CR118, 0xf8 }, /* MARK_002 */ +- { CR119, 0x12 }, { CR122, 0xe0 }, +- { CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ +- { CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ +- { CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ ++ { ZD_CR47, 0x1e }, /* MARK_002 */ ++ { ZD_CR106, 0x22 }, ++ { ZD_CR107, 0x2a }, /* MARK_002 */ ++ { ZD_CR109, 0x13 }, /* MARK_002 */ ++ { ZD_CR118, 0xf8 }, /* MARK_002 */ ++ { ZD_CR119, 0x12 }, { ZD_CR122, 0xe0 }, ++ { ZD_CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ ++ { ZD_CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ ++ { ZD_CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ + }; + + static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) + { + int r; + static const struct zd_ioreq16 ioreqs[] = { +- { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, +- { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, +- { CR203, 0x06 }, ++ { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, ++ { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, ++ { ZD_CR203, 0x06 }, + { }, + +- { CR240, 0x80 }, ++ { ZD_CR240, 0x80 }, + }; + + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +@@ -94,12 +94,12 @@ + + /* related to antenna selection? */ + if (chip->new_phy_layout) { +- r = zd_iowrite16_locked(chip, 0xe1, CR9); ++ r = zd_iowrite16_locked(chip, 0xe1, ZD_CR9); + if (r) + return r; + } + +- return zd_iowrite16_locked(chip, 0x06, CR203); ++ return zd_iowrite16_locked(chip, 0x06, ZD_CR203); + } + + static int zd1211_al2230_init_hw(struct zd_rf *rf) +@@ -108,40 +108,40 @@ + struct zd_chip *chip = zd_rf_to_chip(rf); + + static const struct zd_ioreq16 ioreqs_init[] = { +- { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, +- { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, +- { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a }, +- { CR109, 0x09 }, { CR110, 0x27 }, { CR111, 0x2b }, +- { CR112, 0x2b }, { CR119, 0x0a }, { CR10, 0x89 }, ++ { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, ++ { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, ++ { ZD_CR44, 0x33 }, { ZD_CR106, 0x2a }, { ZD_CR107, 0x1a }, ++ { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, { ZD_CR111, 0x2b }, ++ { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, { ZD_CR10, 0x89 }, + /* for newest (3rd cut) AL2300 */ +- { CR17, 0x28 }, +- { CR26, 0x93 }, { CR34, 0x30 }, ++ { ZD_CR17, 0x28 }, ++ { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 }, + /* for newest (3rd cut) AL2300 */ +- { CR35, 0x3e }, +- { CR41, 0x24 }, { CR44, 0x32 }, ++ { ZD_CR35, 0x3e }, ++ { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + /* for newest (3rd cut) AL2300 */ +- { CR46, 0x96 }, +- { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, +- { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, +- { CR92, 0x0a }, { CR99, 0x28 }, { CR100, 0x00 }, +- { CR101, 0x13 }, { CR102, 0x27 }, { CR106, 0x24 }, +- { CR107, 0x2a }, { CR109, 0x09 }, { CR110, 0x13 }, +- { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, +- { CR114, 0x27 }, ++ { ZD_CR46, 0x96 }, ++ { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, ++ { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, ++ { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 }, ++ { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR106, 0x24 }, ++ { ZD_CR107, 0x2a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x13 }, ++ { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, ++ { ZD_CR114, 0x27 }, + /* for newest (3rd cut) AL2300 */ +- { CR115, 0x24 }, +- { CR116, 0x24 }, { CR117, 0xf4 }, { CR118, 0xfc }, +- { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 }, +- { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff }, +- { CR253, 0xff }, ++ { ZD_CR115, 0x24 }, ++ { ZD_CR116, 0x24 }, { ZD_CR117, 0xf4 }, { ZD_CR118, 0xfc }, ++ { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, { ZD_CR121, 0x77 }, ++ { ZD_CR122, 0xe0 }, { ZD_CR137, 0x88 }, { ZD_CR252, 0xff }, ++ { ZD_CR253, 0xff }, + }; + + static const struct zd_ioreq16 ioreqs_pll[] = { + /* shdnb(PLL_ON)=0 */ +- { CR251, 0x2f }, ++ { ZD_CR251, 0x2f }, + /* shdnb(PLL_ON)=1 */ +- { CR251, 0x3f }, +- { CR138, 0x28 }, { CR203, 0x06 }, ++ { ZD_CR251, 0x3f }, ++ { ZD_CR138, 0x28 }, { ZD_CR203, 0x06 }, + }; + + static const u32 rv1[] = { +@@ -161,7 +161,7 @@ + 0x0805b6, + 0x011687, + 0x000688, +- 0x0403b9, /* external control TX power (CR31) */ ++ 0x0403b9, /* external control TX power (ZD_CR31) */ + 0x00dbba, + 0x00099b, + 0x0bdffc, +@@ -221,52 +221,54 @@ + struct zd_chip *chip = zd_rf_to_chip(rf); + + static const struct zd_ioreq16 ioreqs1[] = { +- { CR10, 0x89 }, { CR15, 0x20 }, +- { CR17, 0x2B }, /* for newest(3rd cut) AL2230 */ +- { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, +- { CR28, 0x3e }, { CR29, 0x00 }, +- { CR33, 0x28 }, /* 5621 */ +- { CR34, 0x30 }, +- { CR35, 0x3e }, /* for newest(3rd cut) AL2230 */ +- { CR41, 0x24 }, { CR44, 0x32 }, +- { CR46, 0x99 }, /* for newest(3rd cut) AL2230 */ +- { CR47, 0x1e }, ++ { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 }, ++ { ZD_CR17, 0x2B }, /* for newest(3rd cut) AL2230 */ ++ { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, ++ { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, ++ { ZD_CR33, 0x28 }, /* 5621 */ ++ { ZD_CR34, 0x30 }, ++ { ZD_CR35, 0x3e }, /* for newest(3rd cut) AL2230 */ ++ { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, ++ { ZD_CR46, 0x99 }, /* for newest(3rd cut) AL2230 */ ++ { ZD_CR47, 0x1e }, + + /* ZD1211B 05.06.10 */ +- { CR48, 0x06 }, { CR49, 0xf9 }, { CR51, 0x01 }, +- { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, +- { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, +- { CR69, 0x28 }, +- +- { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, +- { CR87, 0x0a }, { CR89, 0x04 }, +- { CR91, 0x00 }, /* 5621 */ +- { CR92, 0x0a }, +- { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ +- { CR99, 0x00 }, /* 5621 */ +- { CR101, 0x13 }, { CR102, 0x27 }, +- { CR106, 0x24 }, /* for newest(3rd cut) AL2230 */ +- { CR107, 0x2a }, +- { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ +- { CR110, 0x1f }, /* 4804, for 1212 new algorithm */ +- { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, +- { CR114, 0x27 }, +- { CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */ +- { CR116, 0x24 }, +- { CR117, 0xfa }, /* for 1211b */ +- { CR118, 0xfa }, /* for 1211b */ +- { CR119, 0x10 }, +- { CR120, 0x4f }, +- { CR121, 0x6c }, /* for 1211b */ +- { CR122, 0xfc }, /* E0->FC at 4902 */ +- { CR123, 0x57 }, /* 5623 */ +- { CR125, 0xad }, /* 4804, for 1212 new algorithm */ +- { CR126, 0x6c }, /* 5614 */ +- { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ +- { CR137, 0x50 }, /* 5614 */ +- { CR138, 0xa8 }, +- { CR144, 0xac }, /* 5621 */ +- { CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 }, ++ { ZD_CR48, 0x06 }, { ZD_CR49, 0xf9 }, { ZD_CR51, 0x01 }, ++ { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 }, ++ { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 }, ++ { ZD_CR69, 0x28 }, ++ ++ { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, ++ { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, ++ { ZD_CR91, 0x00 }, /* 5621 */ ++ { ZD_CR92, 0x0a }, ++ { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */ ++ { ZD_CR99, 0x00 }, /* 5621 */ ++ { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, ++ { ZD_CR106, 0x24 }, /* for newest(3rd cut) AL2230 */ ++ { ZD_CR107, 0x2a }, ++ { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */ ++ { ZD_CR110, 0x1f }, /* 4804, for 1212 new algorithm */ ++ { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, ++ { ZD_CR114, 0x27 }, ++ { ZD_CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) ++ * AL2230 ++ */ ++ { ZD_CR116, 0x24 }, ++ { ZD_CR117, 0xfa }, /* for 1211b */ ++ { ZD_CR118, 0xfa }, /* for 1211b */ ++ { ZD_CR119, 0x10 }, ++ { ZD_CR120, 0x4f }, ++ { ZD_CR121, 0x6c }, /* for 1211b */ ++ { ZD_CR122, 0xfc }, /* E0->FC at 4902 */ ++ { ZD_CR123, 0x57 }, /* 5623 */ ++ { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */ ++ { ZD_CR126, 0x6c }, /* 5614 */ ++ { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */ ++ { ZD_CR137, 0x50 }, /* 5614 */ ++ { ZD_CR138, 0xa8 }, ++ { ZD_CR144, 0xac }, /* 5621 */ ++ { ZD_CR150, 0x0d }, { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 }, + }; + + static const u32 rv1[] = { +@@ -284,7 +286,7 @@ + 0x6da010, /* Reg6 update for MP versio */ + 0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */ + 0x116000, +- 0x9dc020, /* External control TX power (CR31) */ ++ 0x9dc020, /* External control TX power (ZD_CR31) */ + 0x5ddb00, /* RegA update for MP version */ + 0xd99000, /* RegB update for MP version */ + 0x3ffbd0, /* RegC update for MP version */ +@@ -295,8 +297,8 @@ + }; + + static const struct zd_ioreq16 ioreqs2[] = { +- { CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ +- { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ ++ { ZD_CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ ++ { ZD_CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ + }; + + static const u32 rv3[] = { +@@ -308,7 +310,7 @@ + + static const struct zd_ioreq16 ioreqs3[] = { + /* related to 6M band edge patching, happens unconditionally */ +- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, ++ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + }; + + r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1, +@@ -361,8 +363,8 @@ + const u32 *rv = zd1211_al2230_table[channel-1]; + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { +- { CR138, 0x28 }, +- { CR203, 0x06 }, ++ { ZD_CR138, 0x28 }, ++ { ZD_CR203, 0x06 }, + }; + + r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS); +@@ -393,8 +395,8 @@ + { + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { +- { CR11, 0x00 }, +- { CR251, 0x3f }, ++ { ZD_CR11, 0x00 }, ++ { ZD_CR251, 0x3f }, + }; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +@@ -404,8 +406,8 @@ + { + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { +- { CR11, 0x00 }, +- { CR251, 0x7f }, ++ { ZD_CR11, 0x00 }, ++ { ZD_CR251, 0x7f }, + }; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +@@ -415,8 +417,8 @@ + { + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { +- { CR11, 0x04 }, +- { CR251, 0x2f }, ++ { ZD_CR11, 0x04 }, ++ { ZD_CR251, 0x2f }, + }; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c +--- linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c 2011-05-05 23:29:45.553442685 +0200 +@@ -68,19 +68,19 @@ + }; + + static const struct zd_ioreq16 ioreqs_sw[] = { +- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, +- { CR38, 0x38 }, { CR136, 0xdf }, ++ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, ++ { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, + }; + + static int zd1211b_al7230b_finalize(struct zd_chip *chip) + { + int r; + static const struct zd_ioreq16 ioreqs[] = { +- { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, +- { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, +- { CR203, 0x04 }, ++ { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, ++ { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, ++ { ZD_CR203, 0x04 }, + { }, +- { CR240, 0x80 }, ++ { ZD_CR240, 0x80 }, + }; + + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +@@ -89,12 +89,12 @@ + + if (chip->new_phy_layout) { + /* antenna selection? */ +- r = zd_iowrite16_locked(chip, 0xe5, CR9); ++ r = zd_iowrite16_locked(chip, 0xe5, ZD_CR9); + if (r) + return r; + } + +- return zd_iowrite16_locked(chip, 0x04, CR203); ++ return zd_iowrite16_locked(chip, 0x04, ZD_CR203); + } + + static int zd1211_al7230b_init_hw(struct zd_rf *rf) +@@ -106,66 +106,66 @@ + * specified */ + static const struct zd_ioreq16 ioreqs_1[] = { + /* This one is 7230-specific, and happens before the rest */ +- { CR240, 0x57 }, ++ { ZD_CR240, 0x57 }, + { }, + +- { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, +- { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, +- { CR44, 0x33 }, ++ { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, ++ { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, ++ { ZD_CR44, 0x33 }, + /* This value is different for 7230 (was: 0x2a) */ +- { CR106, 0x22 }, +- { CR107, 0x1a }, { CR109, 0x09 }, { CR110, 0x27 }, +- { CR111, 0x2b }, { CR112, 0x2b }, { CR119, 0x0a }, ++ { ZD_CR106, 0x22 }, ++ { ZD_CR107, 0x1a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, ++ { ZD_CR111, 0x2b }, { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, + /* This happened further down in AL2230, + * and the value changed (was: 0xe0) */ +- { CR122, 0xfc }, +- { CR10, 0x89 }, ++ { ZD_CR122, 0xfc }, ++ { ZD_CR10, 0x89 }, + /* for newest (3rd cut) AL2300 */ +- { CR17, 0x28 }, +- { CR26, 0x93 }, { CR34, 0x30 }, ++ { ZD_CR17, 0x28 }, ++ { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 }, + /* for newest (3rd cut) AL2300 */ +- { CR35, 0x3e }, +- { CR41, 0x24 }, { CR44, 0x32 }, ++ { ZD_CR35, 0x3e }, ++ { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + /* for newest (3rd cut) AL2300 */ +- { CR46, 0x96 }, +- { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, +- { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, +- { CR92, 0x0a }, { CR99, 0x28 }, ++ { ZD_CR46, 0x96 }, ++ { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, ++ { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, ++ { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, + /* This value is different for 7230 (was: 0x00) */ +- { CR100, 0x02 }, +- { CR101, 0x13 }, { CR102, 0x27 }, ++ { ZD_CR100, 0x02 }, ++ { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, + /* This value is different for 7230 (was: 0x24) */ +- { CR106, 0x22 }, ++ { ZD_CR106, 0x22 }, + /* This value is different for 7230 (was: 0x2a) */ +- { CR107, 0x3f }, +- { CR109, 0x09 }, ++ { ZD_CR107, 0x3f }, ++ { ZD_CR109, 0x09 }, + /* This value is different for 7230 (was: 0x13) */ +- { CR110, 0x1f }, +- { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, +- { CR114, 0x27 }, ++ { ZD_CR110, 0x1f }, ++ { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, ++ { ZD_CR114, 0x27 }, + /* for newest (3rd cut) AL2300 */ +- { CR115, 0x24 }, ++ { ZD_CR115, 0x24 }, + /* This value is different for 7230 (was: 0x24) */ +- { CR116, 0x3f }, ++ { ZD_CR116, 0x3f }, + /* This value is different for 7230 (was: 0xf4) */ +- { CR117, 0xfa }, +- { CR118, 0xfc }, { CR119, 0x10 }, { CR120, 0x4f }, +- { CR121, 0x77 }, { CR137, 0x88 }, ++ { ZD_CR117, 0xfa }, ++ { ZD_CR118, 0xfc }, { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, ++ { ZD_CR121, 0x77 }, { ZD_CR137, 0x88 }, + /* This one is 7230-specific */ +- { CR138, 0xa8 }, ++ { ZD_CR138, 0xa8 }, + /* This value is different for 7230 (was: 0xff) */ +- { CR252, 0x34 }, ++ { ZD_CR252, 0x34 }, + /* This value is different for 7230 (was: 0xff) */ +- { CR253, 0x34 }, ++ { ZD_CR253, 0x34 }, + + /* PLL_OFF */ +- { CR251, 0x2f }, ++ { ZD_CR251, 0x2f }, + }; + + static const struct zd_ioreq16 ioreqs_2[] = { +- { CR251, 0x3f }, /* PLL_ON */ +- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, +- { CR38, 0x38 }, { CR136, 0xdf }, ++ { ZD_CR251, 0x3f }, /* PLL_ON */ ++ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, ++ { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, + }; + + r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); +@@ -192,10 +192,10 @@ + if (r) + return r; + +- r = zd_iowrite16_locked(chip, 0x06, CR203); ++ r = zd_iowrite16_locked(chip, 0x06, ZD_CR203); + if (r) + return r; +- r = zd_iowrite16_locked(chip, 0x80, CR240); ++ r = zd_iowrite16_locked(chip, 0x80, ZD_CR240); + if (r) + return r; + +@@ -208,79 +208,79 @@ + struct zd_chip *chip = zd_rf_to_chip(rf); + + static const struct zd_ioreq16 ioreqs_1[] = { +- { CR240, 0x57 }, { CR9, 0x9 }, ++ { ZD_CR240, 0x57 }, { ZD_CR9, 0x9 }, + { }, +- { CR10, 0x8b }, { CR15, 0x20 }, +- { CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ +- { CR20, 0x10 }, /* 4N25->Stone Request */ +- { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, +- { CR28, 0x3e }, { CR29, 0x00 }, +- { CR33, 0x28 }, /* 5613 */ +- { CR34, 0x30 }, +- { CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ +- { CR41, 0x24 }, { CR44, 0x32 }, +- { CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ +- { CR47, 0x1e }, ++ { ZD_CR10, 0x8b }, { ZD_CR15, 0x20 }, ++ { ZD_CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ ++ { ZD_CR20, 0x10 }, /* 4N25->Stone Request */ ++ { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, ++ { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, ++ { ZD_CR33, 0x28 }, /* 5613 */ ++ { ZD_CR34, 0x30 }, ++ { ZD_CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ ++ { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, ++ { ZD_CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ ++ { ZD_CR47, 0x1e }, + + /* ZD1215 5610 */ +- { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 }, +- { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, +- { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, +- { CR69, 0x28 }, +- +- { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, +- { CR87, 0x0A }, { CR89, 0x04 }, +- { CR90, 0x58 }, /* 5112 */ +- { CR91, 0x00 }, /* 5613 */ +- { CR92, 0x0a }, +- { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ +- { CR99, 0x00 }, { CR100, 0x02 }, { CR101, 0x13 }, +- { CR102, 0x27 }, +- { CR106, 0x20 }, /* change to 0x24 for AL7230B */ +- { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ +- { CR112, 0x1f }, ++ { ZD_CR48, 0x00 }, { ZD_CR49, 0x00 }, { ZD_CR51, 0x01 }, ++ { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 }, ++ { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 }, ++ { ZD_CR69, 0x28 }, ++ ++ { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, ++ { ZD_CR87, 0x0A }, { ZD_CR89, 0x04 }, ++ { ZD_CR90, 0x58 }, /* 5112 */ ++ { ZD_CR91, 0x00 }, /* 5613 */ ++ { ZD_CR92, 0x0a }, ++ { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */ ++ { ZD_CR99, 0x00 }, { ZD_CR100, 0x02 }, { ZD_CR101, 0x13 }, ++ { ZD_CR102, 0x27 }, ++ { ZD_CR106, 0x20 }, /* change to 0x24 for AL7230B */ ++ { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */ ++ { ZD_CR112, 0x1f }, + }; + + static const struct zd_ioreq16 ioreqs_new_phy[] = { +- { CR107, 0x28 }, +- { CR110, 0x1f }, /* 5127, 0x13->0x1f */ +- { CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ +- { CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 }, +- { CR121, 0x6c }, /* 5613 */ ++ { ZD_CR107, 0x28 }, ++ { ZD_CR110, 0x1f }, /* 5127, 0x13->0x1f */ ++ { ZD_CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ ++ { ZD_CR116, 0x2a }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x12 }, ++ { ZD_CR121, 0x6c }, /* 5613 */ + }; + + static const struct zd_ioreq16 ioreqs_old_phy[] = { +- { CR107, 0x24 }, +- { CR110, 0x13 }, /* 5127, 0x13->0x1f */ +- { CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ +- { CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 }, +- { CR121, 0x6a }, /* 5613 */ ++ { ZD_CR107, 0x24 }, ++ { ZD_CR110, 0x13 }, /* 5127, 0x13->0x1f */ ++ { ZD_CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ ++ { ZD_CR116, 0x24 }, { ZD_CR118, 0xfc }, { ZD_CR119, 0x11 }, ++ { ZD_CR121, 0x6a }, /* 5613 */ + }; + + static const struct zd_ioreq16 ioreqs_2[] = { +- { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 }, +- { CR117, 0xfa }, { CR120, 0x4f }, +- { CR122, 0xfc }, /* E0->FCh at 4901 */ +- { CR123, 0x57 }, /* 5613 */ +- { CR125, 0xad }, /* 4804, for 1212 new algorithm */ +- { CR126, 0x6c }, /* 5613 */ +- { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ +- { CR130, 0x10 }, +- { CR131, 0x00 }, /* 5112 */ +- { CR137, 0x50 }, /* 5613 */ +- { CR138, 0xa8 }, /* 5112 */ +- { CR144, 0xac }, /* 5613 */ +- { CR148, 0x40 }, /* 5112 */ +- { CR149, 0x40 }, /* 4O07, 50->40 */ +- { CR150, 0x1a }, /* 5112, 0C->1A */ +- { CR252, 0x34 }, { CR253, 0x34 }, +- { CR251, 0x2f }, /* PLL_OFF */ ++ { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x24 }, ++ { ZD_CR117, 0xfa }, { ZD_CR120, 0x4f }, ++ { ZD_CR122, 0xfc }, /* E0->FCh at 4901 */ ++ { ZD_CR123, 0x57 }, /* 5613 */ ++ { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */ ++ { ZD_CR126, 0x6c }, /* 5613 */ ++ { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */ ++ { ZD_CR130, 0x10 }, ++ { ZD_CR131, 0x00 }, /* 5112 */ ++ { ZD_CR137, 0x50 }, /* 5613 */ ++ { ZD_CR138, 0xa8 }, /* 5112 */ ++ { ZD_CR144, 0xac }, /* 5613 */ ++ { ZD_CR148, 0x40 }, /* 5112 */ ++ { ZD_CR149, 0x40 }, /* 4O07, 50->40 */ ++ { ZD_CR150, 0x1a }, /* 5112, 0C->1A */ ++ { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 }, ++ { ZD_CR251, 0x2f }, /* PLL_OFF */ + }; + + static const struct zd_ioreq16 ioreqs_3[] = { +- { CR251, 0x7f }, /* PLL_ON */ +- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, +- { CR38, 0x38 }, { CR136, 0xdf }, ++ { ZD_CR251, 0x7f }, /* PLL_ON */ ++ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, ++ { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, + }; + + r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); +@@ -331,16 +331,16 @@ + + static const struct zd_ioreq16 ioreqs[] = { + /* PLL_ON */ +- { CR251, 0x3f }, +- { CR203, 0x06 }, { CR240, 0x08 }, ++ { ZD_CR251, 0x3f }, ++ { ZD_CR203, 0x06 }, { ZD_CR240, 0x08 }, + }; + +- r = zd_iowrite16_locked(chip, 0x57, CR240); ++ r = zd_iowrite16_locked(chip, 0x57, ZD_CR240); + if (r) + return r; + + /* PLL_OFF */ +- r = zd_iowrite16_locked(chip, 0x2f, CR251); ++ r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251); + if (r) + return r; + +@@ -376,15 +376,15 @@ + const u32 *rv = chan_rv[channel-1]; + struct zd_chip *chip = zd_rf_to_chip(rf); + +- r = zd_iowrite16_locked(chip, 0x57, CR240); ++ r = zd_iowrite16_locked(chip, 0x57, ZD_CR240); + if (r) + return r; +- r = zd_iowrite16_locked(chip, 0xe4, CR9); ++ r = zd_iowrite16_locked(chip, 0xe4, ZD_CR9); + if (r) + return r; + + /* PLL_OFF */ +- r = zd_iowrite16_locked(chip, 0x2f, CR251); ++ r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251); + if (r) + return r; + r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); +@@ -410,7 +410,7 @@ + if (r) + return r; + +- r = zd_iowrite16_locked(chip, 0x7f, CR251); ++ r = zd_iowrite16_locked(chip, 0x7f, ZD_CR251); + if (r) + return r; + +@@ -421,8 +421,8 @@ + { + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { +- { CR11, 0x00 }, +- { CR251, 0x3f }, ++ { ZD_CR11, 0x00 }, ++ { ZD_CR251, 0x3f }, + }; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +@@ -432,8 +432,8 @@ + { + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { +- { CR11, 0x00 }, +- { CR251, 0x7f }, ++ { ZD_CR11, 0x00 }, ++ { ZD_CR251, 0x7f }, + }; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +@@ -443,8 +443,8 @@ + { + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { +- { CR11, 0x04 }, +- { CR251, 0x2f }, ++ { ZD_CR11, 0x04 }, ++ { ZD_CR251, 0x2f }, + }; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +@@ -456,7 +456,7 @@ + { + struct zd_chip *chip = zd_rf_to_chip(rf); + struct zd_ioreq16 ioreqs[] = { +- { CR128, 0x14 }, { CR129, 0x12 }, ++ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, + }; + + /* FIXME: Channel 11 is not the edge for all regulatory domains. */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_rf.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_rf.h +--- linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_rf.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_rf.h 2011-05-05 23:29:45.546442601 +0200 +@@ -55,7 +55,7 @@ + * defaults to 1 (yes) */ + u8 update_channel_int:1; + +- /* whether CR47 should be patched from the EEPROM, if the appropriate ++ /* whether ZD_CR47 should be patched from the EEPROM, if the appropriate + * flag is set in the POD. The vendor driver suggests that this should + * be done for all RF's, but a bug in their code prevents but their + * HW_OverWritePhyRegFromE2P() routine from ever taking effect. */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c +--- linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c 2011-05-05 23:29:45.544442577 +0200 +@@ -152,44 +152,44 @@ + struct zd_chip *chip = zd_rf_to_chip(rf); + + static const struct zd_ioreq16 ioreqs[] = { +- { CR2, 0x1E }, { CR9, 0x20 }, { CR10, 0x89 }, +- { CR11, 0x00 }, { CR15, 0xD0 }, { CR17, 0x68 }, +- { CR19, 0x4a }, { CR20, 0x0c }, { CR21, 0x0E }, +- { CR23, 0x48 }, ++ { ZD_CR2, 0x1E }, { ZD_CR9, 0x20 }, { ZD_CR10, 0x89 }, ++ { ZD_CR11, 0x00 }, { ZD_CR15, 0xD0 }, { ZD_CR17, 0x68 }, ++ { ZD_CR19, 0x4a }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0E }, ++ { ZD_CR23, 0x48 }, + /* normal size for cca threshold */ +- { CR24, 0x14 }, +- /* { CR24, 0x20 }, */ +- { CR26, 0x90 }, { CR27, 0x30 }, { CR29, 0x20 }, +- { CR31, 0xb2 }, { CR32, 0x43 }, { CR33, 0x28 }, +- { CR38, 0x30 }, { CR34, 0x0f }, { CR35, 0xF0 }, +- { CR41, 0x2a }, { CR46, 0x7F }, { CR47, 0x1E }, +- { CR51, 0xc5 }, { CR52, 0xc5 }, { CR53, 0xc5 }, +- { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, +- { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 }, +- { CR85, 0x00 }, { CR86, 0x10 }, { CR87, 0x2A }, +- { CR88, 0x10 }, { CR89, 0x24 }, { CR90, 0x18 }, +- /* { CR91, 0x18 }, */ ++ { ZD_CR24, 0x14 }, ++ /* { ZD_CR24, 0x20 }, */ ++ { ZD_CR26, 0x90 }, { ZD_CR27, 0x30 }, { ZD_CR29, 0x20 }, ++ { ZD_CR31, 0xb2 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x28 }, ++ { ZD_CR38, 0x30 }, { ZD_CR34, 0x0f }, { ZD_CR35, 0xF0 }, ++ { ZD_CR41, 0x2a }, { ZD_CR46, 0x7F }, { ZD_CR47, 0x1E }, ++ { ZD_CR51, 0xc5 }, { ZD_CR52, 0xc5 }, { ZD_CR53, 0xc5 }, ++ { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, ++ { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, ++ { ZD_CR85, 0x00 }, { ZD_CR86, 0x10 }, { ZD_CR87, 0x2A }, ++ { ZD_CR88, 0x10 }, { ZD_CR89, 0x24 }, { ZD_CR90, 0x18 }, ++ /* { ZD_CR91, 0x18 }, */ + /* should solve continuous CTS frame problems */ +- { CR91, 0x00 }, +- { CR92, 0x0a }, { CR93, 0x00 }, { CR94, 0x01 }, +- { CR95, 0x00 }, { CR96, 0x40 }, { CR97, 0x37 }, +- { CR98, 0x05 }, { CR99, 0x28 }, { CR100, 0x00 }, +- { CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 }, +- { CR104, 0x18 }, { CR105, 0x12 }, ++ { ZD_CR91, 0x00 }, ++ { ZD_CR92, 0x0a }, { ZD_CR93, 0x00 }, { ZD_CR94, 0x01 }, ++ { ZD_CR95, 0x00 }, { ZD_CR96, 0x40 }, { ZD_CR97, 0x37 }, ++ { ZD_CR98, 0x05 }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 }, ++ { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, ++ { ZD_CR104, 0x18 }, { ZD_CR105, 0x12 }, + /* normal size */ +- { CR106, 0x1a }, +- /* { CR106, 0x22 }, */ +- { CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 }, +- { CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 }, +- { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 }, +- { CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 }, +- { CR119, 0x16 }, ++ { ZD_CR106, 0x1a }, ++ /* { ZD_CR106, 0x22 }, */ ++ { ZD_CR107, 0x24 }, { ZD_CR108, 0x0a }, { ZD_CR109, 0x13 }, ++ { ZD_CR110, 0x2F }, { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, ++ { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x40 }, ++ { ZD_CR116, 0x40 }, { ZD_CR117, 0xF0 }, { ZD_CR118, 0xF0 }, ++ { ZD_CR119, 0x16 }, + /* no TX continuation */ +- { CR122, 0x00 }, +- /* { CR122, 0xff }, */ +- { CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 }, +- { CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB }, +- { CR170, 0xBB }, ++ { ZD_CR122, 0x00 }, ++ /* { ZD_CR122, 0xff }, */ ++ { ZD_CR127, 0x03 }, { ZD_CR131, 0x08 }, { ZD_CR138, 0x28 }, ++ { ZD_CR148, 0x44 }, { ZD_CR150, 0x10 }, { ZD_CR169, 0xBB }, ++ { ZD_CR170, 0xBB }, + }; + + static const u32 rv[] = { +@@ -210,7 +210,7 @@ + */ + 0x294128, /* internal power */ + /* 0x28252c, */ /* External control TX power */ +- /* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */ ++ /* ZD_CR31_CCK, ZD_CR51_6-36M, ZD_CR52_48M, ZD_CR53_54M */ + 0x2c0000, + 0x300000, + 0x340000, /* REG13(0xD) */ +@@ -245,8 +245,8 @@ + static int rf2959_switch_radio_on(struct zd_rf *rf) + { + static const struct zd_ioreq16 ioreqs[] = { +- { CR10, 0x89 }, +- { CR11, 0x00 }, ++ { ZD_CR10, 0x89 }, ++ { ZD_CR11, 0x00 }, + }; + struct zd_chip *chip = zd_rf_to_chip(rf); + +@@ -256,8 +256,8 @@ + static int rf2959_switch_radio_off(struct zd_rf *rf) + { + static const struct zd_ioreq16 ioreqs[] = { +- { CR10, 0x15 }, +- { CR11, 0x81 }, ++ { ZD_CR10, 0x15 }, ++ { ZD_CR11, 0x81 }, + }; + struct zd_chip *chip = zd_rf_to_chip(rf); + +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c +--- linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c 2011-05-05 23:29:45.552442673 +0200 +@@ -314,42 +314,44 @@ + struct zd_chip *chip = zd_rf_to_chip(rf); + + static const struct zd_ioreq16 ioreqs[] = { +- { CR10, 0x89 }, { CR15, 0x20 }, +- { CR17, 0x28 }, /* 6112 no change */ +- { CR23, 0x38 }, { CR24, 0x20 }, { CR26, 0x93 }, +- { CR27, 0x15 }, { CR28, 0x3e }, { CR29, 0x00 }, +- { CR33, 0x28 }, { CR34, 0x30 }, +- { CR35, 0x43 }, /* 6112 3e->43 */ +- { CR41, 0x24 }, { CR44, 0x32 }, +- { CR46, 0x92 }, /* 6112 96->92 */ +- { CR47, 0x1e }, +- { CR48, 0x04 }, /* 5602 Roger */ +- { CR49, 0xfa }, { CR79, 0x58 }, { CR80, 0x30 }, +- { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, +- { CR91, 0x00 }, { CR92, 0x0a }, { CR98, 0x8d }, +- { CR99, 0x28 }, { CR100, 0x02 }, +- { CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */ +- { CR102, 0x27 }, +- { CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f 6221 1f->1c */ +- { CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */ +- { CR109, 0x13 }, +- { CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */ +- { CR111, 0x13 }, { CR112, 0x1f }, { CR113, 0x27 }, +- { CR114, 0x23 }, /* 6221 27->23 */ +- { CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */ +- { CR116, 0x24 }, /* 6220 1c->24 */ +- { CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */ +- { CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */ +- { CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */ +- { CR120, 0x4f }, +- { CR121, 0x1f }, /* 6220 4f->1f */ +- { CR122, 0xf0 }, { CR123, 0x57 }, { CR125, 0xad }, +- { CR126, 0x6c }, { CR127, 0x03 }, +- { CR128, 0x14 }, /* 6302 12->11 */ +- { CR129, 0x12 }, /* 6301 10->0f */ +- { CR130, 0x10 }, { CR137, 0x50 }, { CR138, 0xa8 }, +- { CR144, 0xac }, { CR146, 0x20 }, { CR252, 0xff }, +- { CR253, 0xff }, ++ { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 }, ++ { ZD_CR17, 0x28 }, /* 6112 no change */ ++ { ZD_CR23, 0x38 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, ++ { ZD_CR27, 0x15 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, ++ { ZD_CR33, 0x28 }, { ZD_CR34, 0x30 }, ++ { ZD_CR35, 0x43 }, /* 6112 3e->43 */ ++ { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, ++ { ZD_CR46, 0x92 }, /* 6112 96->92 */ ++ { ZD_CR47, 0x1e }, ++ { ZD_CR48, 0x04 }, /* 5602 Roger */ ++ { ZD_CR49, 0xfa }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, ++ { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, ++ { ZD_CR91, 0x00 }, { ZD_CR92, 0x0a }, { ZD_CR98, 0x8d }, ++ { ZD_CR99, 0x28 }, { ZD_CR100, 0x02 }, ++ { ZD_CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */ ++ { ZD_CR102, 0x27 }, ++ { ZD_CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f ++ * 6221 1f->1c ++ */ ++ { ZD_CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */ ++ { ZD_CR109, 0x13 }, ++ { ZD_CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */ ++ { ZD_CR111, 0x13 }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, ++ { ZD_CR114, 0x23 }, /* 6221 27->23 */ ++ { ZD_CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */ ++ { ZD_CR116, 0x24 }, /* 6220 1c->24 */ ++ { ZD_CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */ ++ { ZD_CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */ ++ { ZD_CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */ ++ { ZD_CR120, 0x4f }, ++ { ZD_CR121, 0x1f }, /* 6220 4f->1f */ ++ { ZD_CR122, 0xf0 }, { ZD_CR123, 0x57 }, { ZD_CR125, 0xad }, ++ { ZD_CR126, 0x6c }, { ZD_CR127, 0x03 }, ++ { ZD_CR128, 0x14 }, /* 6302 12->11 */ ++ { ZD_CR129, 0x12 }, /* 6301 10->0f */ ++ { ZD_CR130, 0x10 }, { ZD_CR137, 0x50 }, { ZD_CR138, 0xa8 }, ++ { ZD_CR144, 0xac }, { ZD_CR146, 0x20 }, { ZD_CR252, 0xff }, ++ { ZD_CR253, 0xff }, + }; + + static const u32 rv[] = { +@@ -433,7 +435,7 @@ + * the one that produced a lock. */ + UW2453_PRIV(rf)->config = found_config + 1; + +- return zd_iowrite16_locked(chip, 0x06, CR203); ++ return zd_iowrite16_locked(chip, 0x06, ZD_CR203); + } + + static int uw2453_set_channel(struct zd_rf *rf, u8 channel) +@@ -445,8 +447,8 @@ + struct zd_chip *chip = zd_rf_to_chip(rf); + + static const struct zd_ioreq16 ioreqs[] = { +- { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, +- { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, ++ { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, ++ { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, + }; + + r = uw2453_synth_set_channel(chip, channel, autocal); +@@ -474,7 +476,7 @@ + if (r) + return r; + +- return zd_iowrite16_locked(chip, 0x06, CR203); ++ return zd_iowrite16_locked(chip, 0x06, ZD_CR203); + } + + static int uw2453_switch_radio_on(struct zd_rf *rf) +@@ -482,7 +484,7 @@ + int r; + struct zd_chip *chip = zd_rf_to_chip(rf); + struct zd_ioreq16 ioreqs[] = { +- { CR11, 0x00 }, { CR251, 0x3f }, ++ { ZD_CR11, 0x00 }, { ZD_CR251, 0x3f }, + }; + + /* enter RXTX mode */ +@@ -501,7 +503,7 @@ + int r; + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { +- { CR11, 0x04 }, { CR251, 0x2f }, ++ { ZD_CR11, 0x04 }, { ZD_CR251, 0x2f }, + }; + + /* enter IDLE mode */ +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_usb.c linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_usb.c +--- linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_usb.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_usb.c 2011-05-05 23:29:45.552442673 +0200 +@@ -1893,10 +1893,10 @@ + + dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits); + +- r = zd_usb_ioread16(usb, &bit_value_template, CR203); ++ r = zd_usb_ioread16(usb, &bit_value_template, ZD_CR203); + if (r) { + dev_dbg_f(zd_usb_dev(usb), +- "error %d: Couldn't read CR203\n", r); ++ "error %d: Couldn't read ZD_CR203\n", r); + return r; + } + bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); +diff -Naur linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_usb.h linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_usb.h +--- linux-2.6.39-rc6/drivers/net/wireless/zd1211rw/zd_usb.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/net/wireless/zd1211rw/zd_usb.h 2011-05-05 23:29:45.509442155 +0200 +@@ -109,7 +109,7 @@ + __le16 bits; + /* RF2595: 24 */ + __le16 bit_values[0]; +- /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ ++ /* (ZD_CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ + } __packed; + + /* USB interrupt */ +diff -Naur linux-2.6.39-rc6/drivers/ssb/driver_chipcommon.c linux-2.6.39-rc6.rtl8192se/drivers/ssb/driver_chipcommon.c +--- linux-2.6.39-rc6/drivers/ssb/driver_chipcommon.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/ssb/driver_chipcommon.c 2011-05-05 23:29:49.743493311 +0200 +@@ -46,40 +46,66 @@ + if (!ccdev) + return; + bus = ccdev->bus; ++ ++ /* We support SLOW only on 6..9 */ ++ if (ccdev->id.revision >= 10 && mode == SSB_CLKMODE_SLOW) ++ mode = SSB_CLKMODE_DYNAMIC; ++ ++ if (cc->capabilities & SSB_CHIPCO_CAP_PMU) ++ return; /* PMU controls clockmode, separated function needed */ ++ SSB_WARN_ON(ccdev->id.revision >= 20); ++ + /* chipcommon cores prior to rev6 don't support dynamic clock control */ + if (ccdev->id.revision < 6) + return; +- /* chipcommon cores rev10 are a whole new ball game */ ++ ++ /* ChipCommon cores rev10+ need testing */ + if (ccdev->id.revision >= 10) + return; ++ + if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) + return; + + switch (mode) { +- case SSB_CLKMODE_SLOW: ++ case SSB_CLKMODE_SLOW: /* For revs 6..9 only */ + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + break; + case SSB_CLKMODE_FAST: +- ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */ +- tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); +- tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; +- tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; +- chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); ++ if (ccdev->id.revision < 10) { ++ ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */ ++ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); ++ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; ++ tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; ++ chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); ++ } else { ++ chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, ++ (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) | ++ SSB_CHIPCO_SYSCLKCTL_FORCEHT)); ++ /* udelay(150); TODO: not available in early init */ ++ } + break; + case SSB_CLKMODE_DYNAMIC: +- tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); +- tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; +- tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; +- tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; +- if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) +- tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; +- chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); +- +- /* for dynamic control, we have to release our xtal_pu "force on" */ +- if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) +- ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0); ++ if (ccdev->id.revision < 10) { ++ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); ++ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; ++ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; ++ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; ++ if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != ++ SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) ++ tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; ++ chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); ++ ++ /* For dynamic control, we have to release our xtal_pu ++ * "force on" */ ++ if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) ++ ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0); ++ } else { ++ chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, ++ (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) & ++ ~SSB_CHIPCO_SYSCLKCTL_FORCEHT)); ++ } + break; + default: + SSB_WARN_ON(1); +@@ -260,6 +286,12 @@ + if (cc->dev->id.revision >= 11) + cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); + ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status); ++ ++ if (cc->dev->id.revision >= 20) { ++ chipco_write32(cc, SSB_CHIPCO_GPIOPULLUP, 0); ++ chipco_write32(cc, SSB_CHIPCO_GPIOPULLDOWN, 0); ++ } ++ + ssb_pmu_init(cc); + chipco_powercontrol_init(cc); + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); +diff -Naur linux-2.6.39-rc6/drivers/ssb/driver_chipcommon_pmu.c linux-2.6.39-rc6.rtl8192se/drivers/ssb/driver_chipcommon_pmu.c +--- linux-2.6.39-rc6/drivers/ssb/driver_chipcommon_pmu.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/ssb/driver_chipcommon_pmu.c 2011-05-05 23:29:49.742493299 +0200 +@@ -423,6 +423,8 @@ + + switch (bus->chip_id) { + case 0x4312: ++ min_msk = 0xCBB; ++ break; + case 0x4322: + /* We keep the default settings: + * min_msk = 0xCBB +diff -Naur linux-2.6.39-rc6/drivers/ssb/driver_pcicore.c linux-2.6.39-rc6.rtl8192se/drivers/ssb/driver_pcicore.c +--- linux-2.6.39-rc6/drivers/ssb/driver_pcicore.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/ssb/driver_pcicore.c 2011-05-05 23:29:49.767493601 +0200 +@@ -15,6 +15,13 @@ + + #include "ssb_private.h" + ++static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address); ++static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data); ++static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address); ++static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, ++ u8 address, u16 data); ++ ++static void ssb_commit_settings(struct ssb_bus *bus); + + static inline + u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset) +@@ -403,6 +410,107 @@ + } + #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ + ++/************************************************** ++ * Workarounds. ++ **************************************************/ ++ ++static void ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc) ++{ ++ u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0)); ++ if (((tmp & 0xF000) >> 12) != pc->dev->core_index) { ++ tmp &= ~0xF000; ++ tmp |= (pc->dev->core_index << 12); ++ pcicore_write16(pc, SSB_PCICORE_SPROM(0), tmp); ++ } ++} ++ ++static u8 ssb_pcicore_polarity_workaround(struct ssb_pcicore *pc) ++{ ++ return (ssb_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80; ++} ++ ++static void ssb_pcicore_serdes_workaround(struct ssb_pcicore *pc) ++{ ++ const u8 serdes_pll_device = 0x1D; ++ const u8 serdes_rx_device = 0x1F; ++ u16 tmp; ++ ++ ssb_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */, ++ ssb_pcicore_polarity_workaround(pc)); ++ tmp = ssb_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */); ++ if (tmp & 0x4000) ++ ssb_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000); ++} ++ ++static void ssb_pcicore_pci_setup_workarounds(struct ssb_pcicore *pc) ++{ ++ struct ssb_device *pdev = pc->dev; ++ struct ssb_bus *bus = pdev->bus; ++ u32 tmp; ++ ++ tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); ++ tmp |= SSB_PCICORE_SBTOPCI_PREF; ++ tmp |= SSB_PCICORE_SBTOPCI_BURST; ++ pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); ++ ++ if (pdev->id.revision < 5) { ++ tmp = ssb_read32(pdev, SSB_IMCFGLO); ++ tmp &= ~SSB_IMCFGLO_SERTO; ++ tmp |= 2; ++ tmp &= ~SSB_IMCFGLO_REQTO; ++ tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; ++ ssb_write32(pdev, SSB_IMCFGLO, tmp); ++ ssb_commit_settings(bus); ++ } else if (pdev->id.revision >= 11) { ++ tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); ++ tmp |= SSB_PCICORE_SBTOPCI_MRM; ++ pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); ++ } ++} ++ ++static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) ++{ ++ u32 tmp; ++ u8 rev = pc->dev->id.revision; ++ ++ if (rev == 0 || rev == 1) { ++ /* TLP Workaround register. */ ++ tmp = ssb_pcie_read(pc, 0x4); ++ tmp |= 0x8; ++ ssb_pcie_write(pc, 0x4, tmp); ++ } ++ if (rev == 1) { ++ /* DLLP Link Control register. */ ++ tmp = ssb_pcie_read(pc, 0x100); ++ tmp |= 0x40; ++ ssb_pcie_write(pc, 0x100, tmp); ++ } ++ ++ if (rev == 0) { ++ const u8 serdes_rx_device = 0x1F; ++ ++ ssb_pcie_mdio_write(pc, serdes_rx_device, ++ 2 /* Timer */, 0x8128); ++ ssb_pcie_mdio_write(pc, serdes_rx_device, ++ 6 /* CDR */, 0x0100); ++ ssb_pcie_mdio_write(pc, serdes_rx_device, ++ 7 /* CDR BW */, 0x1466); ++ } else if (rev == 3 || rev == 4 || rev == 5) { ++ /* TODO: DLLP Power Management Threshold */ ++ ssb_pcicore_serdes_workaround(pc); ++ /* TODO: ASPM */ ++ } else if (rev == 7) { ++ /* TODO: No PLL down */ ++ } ++ ++ if (rev >= 6) { ++ /* Miscellaneous Configuration Fixup */ ++ tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(5)); ++ if (!(tmp & 0x8000)) ++ pcicore_write16(pc, SSB_PCICORE_SPROM(5), ++ tmp | 0x8000); ++ } ++} + + /************************************************** + * Generic and Clientmode operation code. +@@ -417,14 +525,14 @@ + void ssb_pcicore_init(struct ssb_pcicore *pc) + { + struct ssb_device *dev = pc->dev; +- struct ssb_bus *bus; + + if (!dev) + return; +- bus = dev->bus; + if (!ssb_device_is_enabled(dev)) + ssb_device_enable(dev, 0); + ++ ssb_pcicore_fix_sprom_core_index(pc); ++ + #ifdef CONFIG_SSB_PCICORE_HOSTMODE + pc->hostmode = pcicore_is_in_hostmode(pc); + if (pc->hostmode) +@@ -432,6 +540,11 @@ + #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ + if (!pc->hostmode) + ssb_pcicore_init_clientmode(pc); ++ ++ /* Additional always once-executed workarounds */ ++ ssb_pcicore_serdes_workaround(pc); ++ /* TODO: ASPM */ ++ /* TODO: Clock Request Update */ + } + + static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) +@@ -446,11 +559,75 @@ + pcicore_write32(pc, 0x134, data); + } + ++static void ssb_pcie_mdio_set_phy(struct ssb_pcicore *pc, u8 phy) ++{ ++ const u16 mdio_control = 0x128; ++ const u16 mdio_data = 0x12C; ++ u32 v; ++ int i; ++ ++ v = (1 << 30); /* Start of Transaction */ ++ v |= (1 << 28); /* Write Transaction */ ++ v |= (1 << 17); /* Turnaround */ ++ v |= (0x1F << 18); ++ v |= (phy << 4); ++ pcicore_write32(pc, mdio_data, v); ++ ++ udelay(10); ++ for (i = 0; i < 200; i++) { ++ v = pcicore_read32(pc, mdio_control); ++ if (v & 0x100 /* Trans complete */) ++ break; ++ msleep(1); ++ } ++} ++ ++static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address) ++{ ++ const u16 mdio_control = 0x128; ++ const u16 mdio_data = 0x12C; ++ int max_retries = 10; ++ u16 ret = 0; ++ u32 v; ++ int i; ++ ++ v = 0x80; /* Enable Preamble Sequence */ ++ v |= 0x2; /* MDIO Clock Divisor */ ++ pcicore_write32(pc, mdio_control, v); ++ ++ if (pc->dev->id.revision >= 10) { ++ max_retries = 200; ++ ssb_pcie_mdio_set_phy(pc, device); ++ } ++ ++ v = (1 << 30); /* Start of Transaction */ ++ v |= (1 << 29); /* Read Transaction */ ++ v |= (1 << 17); /* Turnaround */ ++ if (pc->dev->id.revision < 10) ++ v |= (u32)device << 22; ++ v |= (u32)address << 18; ++ pcicore_write32(pc, mdio_data, v); ++ /* Wait for the device to complete the transaction */ ++ udelay(10); ++ for (i = 0; i < max_retries; i++) { ++ v = pcicore_read32(pc, mdio_control); ++ if (v & 0x100 /* Trans complete */) { ++ udelay(10); ++ ret = pcicore_read32(pc, mdio_data); ++ break; ++ } ++ msleep(1); ++ } ++ pcicore_write32(pc, mdio_control, 0); ++ return ret; ++} ++ + static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, + u8 address, u16 data) + { + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; ++ int max_retries = 10; + u32 v; + int i; + +@@ -458,16 +635,22 @@ + v |= 0x2; /* MDIO Clock Divisor */ + pcicore_write32(pc, mdio_control, v); + ++ if (pc->dev->id.revision >= 10) { ++ max_retries = 200; ++ ssb_pcie_mdio_set_phy(pc, device); ++ } ++ + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 28); /* Write Transaction */ + v |= (1 << 17); /* Turnaround */ +- v |= (u32)device << 22; ++ if (pc->dev->id.revision < 10) ++ v |= (u32)device << 22; + v |= (u32)address << 18; + v |= data; + pcicore_write32(pc, mdio_data, v); + /* Wait for the device to complete the transaction */ + udelay(10); +- for (i = 0; i < 10; i++) { ++ for (i = 0; i < max_retries; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) + break; +@@ -550,48 +733,10 @@ + if (pc->setup_done) + goto out; + if (pdev->id.coreid == SSB_DEV_PCI) { +- tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); +- tmp |= SSB_PCICORE_SBTOPCI_PREF; +- tmp |= SSB_PCICORE_SBTOPCI_BURST; +- pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); +- +- if (pdev->id.revision < 5) { +- tmp = ssb_read32(pdev, SSB_IMCFGLO); +- tmp &= ~SSB_IMCFGLO_SERTO; +- tmp |= 2; +- tmp &= ~SSB_IMCFGLO_REQTO; +- tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; +- ssb_write32(pdev, SSB_IMCFGLO, tmp); +- ssb_commit_settings(bus); +- } else if (pdev->id.revision >= 11) { +- tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); +- tmp |= SSB_PCICORE_SBTOPCI_MRM; +- pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); +- } ++ ssb_pcicore_pci_setup_workarounds(pc); + } else { + WARN_ON(pdev->id.coreid != SSB_DEV_PCIE); +- //TODO: Better make defines for all these magic PCIE values. +- if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) { +- /* TLP Workaround register. */ +- tmp = ssb_pcie_read(pc, 0x4); +- tmp |= 0x8; +- ssb_pcie_write(pc, 0x4, tmp); +- } +- if (pdev->id.revision == 0) { +- const u8 serdes_rx_device = 0x1F; +- +- ssb_pcie_mdio_write(pc, serdes_rx_device, +- 2 /* Timer */, 0x8128); +- ssb_pcie_mdio_write(pc, serdes_rx_device, +- 6 /* CDR */, 0x0100); +- ssb_pcie_mdio_write(pc, serdes_rx_device, +- 7 /* CDR BW */, 0x1466); +- } else if (pdev->id.revision == 1) { +- /* DLLP Link Control register. */ +- tmp = ssb_pcie_read(pc, 0x100); +- tmp |= 0x40; +- ssb_pcie_write(pc, 0x100, tmp); +- } ++ ssb_pcicore_pcie_setup_workarounds(pc); + } + pc->setup_done = 1; + out: +diff -Naur linux-2.6.39-rc6/drivers/ssb/main.c linux-2.6.39-rc6.rtl8192se/drivers/ssb/main.c +--- linux-2.6.39-rc6/drivers/ssb/main.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/ssb/main.c 2011-05-05 23:29:49.766493589 +0200 +@@ -1117,23 +1117,22 @@ + { + u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV; + +- /* The REJECT bit changed position in TMSLOW between +- * Backplane revisions. */ ++ /* The REJECT bit seems to be different for Backplane rev 2.3 */ + switch (rev) { + case SSB_IDLOW_SSBREV_22: +- return SSB_TMSLOW_REJECT_22; ++ case SSB_IDLOW_SSBREV_24: ++ case SSB_IDLOW_SSBREV_26: ++ return SSB_TMSLOW_REJECT; + case SSB_IDLOW_SSBREV_23: + return SSB_TMSLOW_REJECT_23; +- case SSB_IDLOW_SSBREV_24: /* TODO - find the proper REJECT bits */ +- case SSB_IDLOW_SSBREV_25: /* same here */ +- case SSB_IDLOW_SSBREV_26: /* same here */ ++ case SSB_IDLOW_SSBREV_25: /* TODO - find the proper REJECT bit */ + case SSB_IDLOW_SSBREV_27: /* same here */ +- return SSB_TMSLOW_REJECT_23; /* this is a guess */ ++ return SSB_TMSLOW_REJECT; /* this is a guess */ + default: + printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev); + WARN_ON(1); + } +- return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23); ++ return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23); + } + + int ssb_device_is_enabled(struct ssb_device *dev) +@@ -1309,20 +1308,20 @@ + + int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl) + { +- struct ssb_chipcommon *cc; + int err; + enum ssb_clkmode mode; + + err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); + if (err) + goto error; +- cc = &bus->chipco; +- mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; +- ssb_chipco_set_clockmode(cc, mode); + + #ifdef CONFIG_SSB_DEBUG + bus->powered_up = 1; + #endif ++ ++ mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; ++ ssb_chipco_set_clockmode(&bus->chipco, mode); ++ + return 0; + error: + ssb_printk(KERN_ERR PFX "Bus powerup failed\n"); +diff -Naur linux-2.6.39-rc6/drivers/ssb/scan.c linux-2.6.39-rc6.rtl8192se/drivers/ssb/scan.c +--- linux-2.6.39-rc6/drivers/ssb/scan.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/drivers/ssb/scan.c 2011-05-05 23:29:49.742493299 +0200 +@@ -307,7 +307,7 @@ + } else { + if (bus->bustype == SSB_BUSTYPE_PCI) { + bus->chip_id = pcidev_to_chipid(bus->host_pci); +- pci_read_config_word(bus->host_pci, PCI_REVISION_ID, ++ pci_read_config_byte(bus->host_pci, PCI_REVISION_ID, + &bus->chip_rev); + bus->chip_package = 0; + } else { +diff -Naur linux-2.6.39-rc6/include/linux/ath9k_platform.h linux-2.6.39-rc6.rtl8192se/include/linux/ath9k_platform.h +--- linux-2.6.39-rc6/include/linux/ath9k_platform.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/linux/ath9k_platform.h 2011-05-05 23:30:06.514695895 +0200 +@@ -23,6 +23,13 @@ + + struct ath9k_platform_data { + u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS]; ++ u8 *macaddr; ++ ++ int led_pin; ++ u32 gpio_mask; ++ u32 gpio_val; ++ ++ bool is_clk_25mhz; + }; + + #endif /* _LINUX_ATH9K_PLATFORM_H */ +diff -Naur linux-2.6.39-rc6/include/linux/ieee80211.h linux-2.6.39-rc6.rtl8192se/include/linux/ieee80211.h +--- linux-2.6.39-rc6/include/linux/ieee80211.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/linux/ieee80211.h 2011-05-05 23:30:10.326741933 +0200 +@@ -884,6 +884,15 @@ + #define IEEE80211_HT_CAP_40MHZ_INTOLERANT 0x4000 + #define IEEE80211_HT_CAP_LSIG_TXOP_PROT 0x8000 + ++/* 802.11n HT extended capabilities masks (for extended_ht_cap_info) */ ++#define IEEE80211_HT_EXT_CAP_PCO 0x0001 ++#define IEEE80211_HT_EXT_CAP_PCO_TIME 0x0006 ++#define IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT 1 ++#define IEEE80211_HT_EXT_CAP_MCS_FB 0x0300 ++#define IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT 8 ++#define IEEE80211_HT_EXT_CAP_HTC_SUP 0x0400 ++#define IEEE80211_HT_EXT_CAP_RD_RESPONDER 0x0800 ++ + /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ + #define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03 + #define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C +diff -Naur linux-2.6.39-rc6/include/linux/nl80211.h linux-2.6.39-rc6.rtl8192se/include/linux/nl80211.h +--- linux-2.6.39-rc6/include/linux/nl80211.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/linux/nl80211.h 2011-05-05 23:30:06.699698129 +0200 +@@ -410,6 +410,16 @@ + * notification. This event is used to indicate that an unprotected + * disassociation frame was dropped when MFP is in use. + * ++ * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a ++ * beacon or probe response from a compatible mesh peer. This is only ++ * sent while no station information (sta_info) exists for the new peer ++ * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set. On ++ * reception of this notification, userspace may decide to create a new ++ * station (@NL80211_CMD_NEW_STATION). To stop this notification from ++ * reoccurring, the userspace authentication daemon may want to create the ++ * new station with the AUTHENTICATED flag unset and maybe change it later ++ * depending on the authentication result. ++ * + * @NL80211_CMD_MAX: highest used command number + * @__NL80211_CMD_AFTER_LAST: internal use + */ +@@ -522,6 +532,8 @@ + NL80211_CMD_UNPROT_DEAUTHENTICATE, + NL80211_CMD_UNPROT_DISASSOCIATE, + ++ NL80211_CMD_NEW_PEER_CANDIDATE, ++ + /* add new commands above here */ + + /* used to define NL80211_CMD_MAX below */ +@@ -545,6 +557,7 @@ + /* source-level API compatibility */ + #define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG + #define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG ++#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE + + /** + * enum nl80211_attrs - nl80211 netlink attributes +@@ -886,6 +899,9 @@ + * changed once the mesh is active. + * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute + * containing attributes from &enum nl80211_meshconf_params. ++ * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver ++ * allows auth frames in a mesh to be passed to userspace for processing via ++ * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag. + * + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -1074,6 +1090,8 @@ + NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, + NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, + ++ NL80211_ATTR_SUPPORT_MESH_AUTH, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +@@ -1168,6 +1186,7 @@ + * with short barker preamble + * @NL80211_STA_FLAG_WME: station is WME/QoS capable + * @NL80211_STA_FLAG_MFP: station uses management frame protection ++ * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated + * @NL80211_STA_FLAG_MAX: highest station flag number currently defined + * @__NL80211_STA_FLAG_AFTER_LAST: internal use + */ +@@ -1177,6 +1196,7 @@ + NL80211_STA_FLAG_SHORT_PREAMBLE, + NL80211_STA_FLAG_WME, + NL80211_STA_FLAG_MFP, ++ NL80211_STA_FLAG_AUTHENTICATED, + + /* keep last */ + __NL80211_STA_FLAG_AFTER_LAST, +@@ -1222,6 +1242,36 @@ + }; + + /** ++ * enum nl80211_sta_bss_param - BSS information collected by STA ++ * ++ * These attribute types are used with %NL80211_STA_INFO_BSS_PARAM ++ * when getting information about the bitrate of a station. ++ * ++ * @__NL80211_STA_BSS_PARAM_INVALID: attribute number 0 is reserved ++ * @NL80211_STA_BSS_PARAM_CTS_PROT: whether CTS protection is enabled (flag) ++ * @NL80211_STA_BSS_PARAM_SHORT_PREAMBLE: whether short preamble is enabled ++ * (flag) ++ * @NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME: whether short slot time is enabled ++ * (flag) ++ * @NL80211_STA_BSS_PARAM_DTIM_PERIOD: DTIM period for beaconing (u8) ++ * @NL80211_STA_BSS_PARAM_BEACON_INTERVAL: Beacon interval (u16) ++ * @NL80211_STA_BSS_PARAM_MAX: highest sta_bss_param number currently defined ++ * @__NL80211_STA_BSS_PARAM_AFTER_LAST: internal use ++ */ ++enum nl80211_sta_bss_param { ++ __NL80211_STA_BSS_PARAM_INVALID, ++ NL80211_STA_BSS_PARAM_CTS_PROT, ++ NL80211_STA_BSS_PARAM_SHORT_PREAMBLE, ++ NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME, ++ NL80211_STA_BSS_PARAM_DTIM_PERIOD, ++ NL80211_STA_BSS_PARAM_BEACON_INTERVAL, ++ ++ /* keep last */ ++ __NL80211_STA_BSS_PARAM_AFTER_LAST, ++ NL80211_STA_BSS_PARAM_MAX = __NL80211_STA_BSS_PARAM_AFTER_LAST - 1 ++}; ++ ++/** + * enum nl80211_sta_info - station information + * + * These attribute types are used with %NL80211_ATTR_STA_INFO +@@ -1233,7 +1283,7 @@ + * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) + * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) + * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute +- * containing info as possible, see &enum nl80211_sta_info_txrate. ++ * containing info as possible, see &enum nl80211_rate_info + * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) + * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this + * station) +@@ -1245,6 +1295,9 @@ + * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station + * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested + * attribute, like NL80211_STA_INFO_TX_BITRATE. ++ * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute ++ * containing info as possible, see &enum nl80211_sta_bss_param ++ * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected + * @__NL80211_STA_INFO_AFTER_LAST: internal + * @NL80211_STA_INFO_MAX: highest possible station info attribute + */ +@@ -1264,6 +1317,8 @@ + NL80211_STA_INFO_TX_FAILED, + NL80211_STA_INFO_SIGNAL_AVG, + NL80211_STA_INFO_RX_BITRATE, ++ NL80211_STA_INFO_BSS_PARAM, ++ NL80211_STA_INFO_CONNECTED_TIME, + + /* keep last */ + __NL80211_STA_INFO_AFTER_LAST, +@@ -1686,9 +1741,12 @@ + * vendor specific path metric or disable it to use the default Airtime + * metric. + * +- * @NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE: A vendor specific information +- * element that vendors will use to identify the path selection methods and +- * metrics in use. ++ * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a ++ * robust security network ie, or a vendor specific information element that ++ * vendors will use to identify the path selection methods and metrics in use. ++ * ++ * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication ++ * daemon will be authenticating mesh candidates. + * + * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number + * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use +@@ -1697,7 +1755,8 @@ + __NL80211_MESH_SETUP_INVALID, + NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL, + NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC, +- NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE, ++ NL80211_MESH_SETUP_IE, ++ NL80211_MESH_SETUP_USERSPACE_AUTH, + + /* keep last */ + __NL80211_MESH_SETUP_ATTR_AFTER_LAST, +diff -Naur linux-2.6.39-rc6/include/linux/rfkill-regulator.h linux-2.6.39-rc6.rtl8192se/include/linux/rfkill-regulator.h +--- linux-2.6.39-rc6/include/linux/rfkill-regulator.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/include/linux/rfkill-regulator.h 2011-05-05 23:30:05.771686923 +0200 +@@ -0,0 +1,48 @@ ++/* ++ * rfkill-regulator.c - Regulator consumer driver for rfkill ++ * ++ * Copyright (C) 2009 Guiming Zhuo ++ * Copyright (C) 2011 Antonio Ospite ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef __LINUX_RFKILL_REGULATOR_H ++#define __LINUX_RFKILL_REGULATOR_H ++ ++/* ++ * Use "vrfkill" as supply id when declaring the regulator consumer: ++ * ++ * static struct regulator_consumer_supply pcap_regulator_V6_consumers [] = { ++ * { .dev_name = "rfkill-regulator.0", .supply = "vrfkill" }, ++ * }; ++ * ++ * If you have several regulator driven rfkill, you can append a numerical id to ++ * .dev_name as done above, and use the same id when declaring the platform ++ * device: ++ * ++ * static struct rfkill_regulator_platform_data ezx_rfkill_bt_data = { ++ * .name = "ezx-bluetooth", ++ * .type = RFKILL_TYPE_BLUETOOTH, ++ * }; ++ * ++ * static struct platform_device a910_rfkill = { ++ * .name = "rfkill-regulator", ++ * .id = 0, ++ * .dev = { ++ * .platform_data = &ezx_rfkill_bt_data, ++ * }, ++ * }; ++ */ ++ ++#include ++ ++struct rfkill_regulator_platform_data { ++ char *name; /* the name for the rfkill switch */ ++ enum rfkill_type type; /* the type as specified in rfkill.h */ ++}; ++ ++#endif /* __LINUX_RFKILL_REGULATOR_H */ +diff -Naur linux-2.6.39-rc6/include/linux/ssb/ssb_driver_chipcommon.h linux-2.6.39-rc6.rtl8192se/include/linux/ssb/ssb_driver_chipcommon.h +--- linux-2.6.39-rc6/include/linux/ssb/ssb_driver_chipcommon.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/linux/ssb/ssb_driver_chipcommon.h 2011-05-05 23:30:10.166740001 +0200 +@@ -123,6 +123,8 @@ + #define SSB_CHIPCO_FLASHDATA 0x0048 + #define SSB_CHIPCO_BCAST_ADDR 0x0050 + #define SSB_CHIPCO_BCAST_DATA 0x0054 ++#define SSB_CHIPCO_GPIOPULLUP 0x0058 /* Rev >= 20 only */ ++#define SSB_CHIPCO_GPIOPULLDOWN 0x005C /* Rev >= 20 only */ + #define SSB_CHIPCO_GPIOIN 0x0060 + #define SSB_CHIPCO_GPIOOUT 0x0064 + #define SSB_CHIPCO_GPIOOUTEN 0x0068 +@@ -131,6 +133,9 @@ + #define SSB_CHIPCO_GPIOIRQ 0x0074 + #define SSB_CHIPCO_WATCHDOG 0x0080 + #define SSB_CHIPCO_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */ ++#define SSB_CHIPCO_GPIOTIMER_OFFTIME 0x0000FFFF ++#define SSB_CHIPCO_GPIOTIMER_OFFTIME_SHIFT 0 ++#define SSB_CHIPCO_GPIOTIMER_ONTIME 0xFFFF0000 + #define SSB_CHIPCO_GPIOTIMER_ONTIME_SHIFT 16 + #define SSB_CHIPCO_GPIOTOUTM 0x008C /* LED powersave (corerev >= 16) */ + #define SSB_CHIPCO_CLOCK_N 0x0090 +@@ -189,8 +194,10 @@ + #define SSB_CHIPCO_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */ + #define SSB_CHIPCO_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */ + #define SSB_CHIPCO_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */ +-#define SSB_CHIPCO_CLKCTLST_HAVEHT 0x00010000 /* HT available */ +-#define SSB_CHIPCO_CLKCTLST_HAVEALP 0x00020000 /* APL available */ ++#define SSB_CHIPCO_CLKCTLST_HAVEALP 0x00010000 /* ALP available */ ++#define SSB_CHIPCO_CLKCTLST_HAVEHT 0x00020000 /* HT available */ ++#define SSB_CHIPCO_CLKCTLST_4328A0_HAVEHT 0x00010000 /* 4328a0 has reversed bits */ ++#define SSB_CHIPCO_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */ + #define SSB_CHIPCO_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */ + #define SSB_CHIPCO_UART0_DATA 0x0300 + #define SSB_CHIPCO_UART0_IMR 0x0304 +diff -Naur linux-2.6.39-rc6/include/linux/ssb/ssb.h linux-2.6.39-rc6.rtl8192se/include/linux/ssb/ssb.h +--- linux-2.6.39-rc6/include/linux/ssb/ssb.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/linux/ssb/ssb.h 2011-05-05 23:30:10.164739976 +0200 +@@ -308,7 +308,7 @@ + + /* ID information about the Chip. */ + u16 chip_id; +- u16 chip_rev; ++ u8 chip_rev; + u16 sprom_offset; + u16 sprom_size; /* number of words in sprom */ + u8 chip_package; +diff -Naur linux-2.6.39-rc6/include/linux/ssb/ssb_regs.h linux-2.6.39-rc6.rtl8192se/include/linux/ssb/ssb_regs.h +--- linux-2.6.39-rc6/include/linux/ssb/ssb_regs.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/linux/ssb/ssb_regs.h 2011-05-05 23:30:10.163739963 +0200 +@@ -97,7 +97,7 @@ + #define SSB_INTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */ + #define SSB_TMSLOW 0x0F98 /* SB Target State Low */ + #define SSB_TMSLOW_RESET 0x00000001 /* Reset */ +-#define SSB_TMSLOW_REJECT_22 0x00000002 /* Reject (Backplane rev 2.2) */ ++#define SSB_TMSLOW_REJECT 0x00000002 /* Reject (Standard Backplane) */ + #define SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */ + #define SSB_TMSLOW_CLOCK 0x00010000 /* Clock Enable */ + #define SSB_TMSLOW_FGC 0x00020000 /* Force Gated Clocks On */ +diff -Naur linux-2.6.39-rc6/include/linux/wl12xx.h linux-2.6.39-rc6.rtl8192se/include/linux/wl12xx.h +--- linux-2.6.39-rc6/include/linux/wl12xx.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/linux/wl12xx.h 2011-05-05 23:30:08.273717139 +0200 +@@ -24,12 +24,26 @@ + #ifndef _LINUX_WL12XX_H + #define _LINUX_WL12XX_H + +-/* The board reference clock values */ ++/* Reference clock values */ + enum { +- WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ +- WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ +- WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ +- WL12XX_REFCLOCK_54 = 3, /* 54 MHz */ ++ WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ ++ WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ ++ WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ ++ WL12XX_REFCLOCK_52 = 3, /* 52 MHz */ ++ WL12XX_REFCLOCK_38_XTAL = 4, /* 38.4 MHz, XTAL */ ++ WL12XX_REFCLOCK_26_XTAL = 5, /* 26 MHz, XTAL */ ++}; ++ ++/* TCXO clock values */ ++enum { ++ WL12XX_TCXOCLOCK_19_2 = 0, /* 19.2MHz */ ++ WL12XX_TCXOCLOCK_26 = 1, /* 26 MHz */ ++ WL12XX_TCXOCLOCK_38_4 = 2, /* 38.4MHz */ ++ WL12XX_TCXOCLOCK_52 = 3, /* 52 MHz */ ++ WL12XX_TCXOCLOCK_16_368 = 4, /* 16.368 MHz */ ++ WL12XX_TCXOCLOCK_32_736 = 5, /* 32.736 MHz */ ++ WL12XX_TCXOCLOCK_16_8 = 6, /* 16.8 MHz */ ++ WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */ + }; + + struct wl12xx_platform_data { +@@ -38,8 +52,13 @@ + int irq; + bool use_eeprom; + int board_ref_clock; ++ int board_tcxo_clock; ++ unsigned long platform_quirks; + }; + ++/* Platform does not support level trigger interrupts */ ++#define WL12XX_PLATFORM_QUIRK_EDGE_IRQ BIT(0) ++ + #ifdef CONFIG_WL12XX_PLATFORM_DATA + + int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); +diff -Naur linux-2.6.39-rc6/include/net/bluetooth/hci_core.h linux-2.6.39-rc6.rtl8192se/include/net/bluetooth/hci_core.h +--- linux-2.6.39-rc6/include/net/bluetooth/hci_core.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/net/bluetooth/hci_core.h 2011-05-05 23:30:11.206752559 +0200 +@@ -82,6 +82,13 @@ + u8 pin_len; + }; + ++struct oob_data { ++ struct list_head list; ++ bdaddr_t bdaddr; ++ u8 hash[16]; ++ u8 randomizer[16]; ++}; ++ + #define NUM_REASSEMBLY 4 + struct hci_dev { + struct list_head list; +@@ -94,7 +101,8 @@ + __u8 bus; + __u8 dev_type; + bdaddr_t bdaddr; +- __u8 dev_name[248]; ++ __u8 dev_name[HCI_MAX_NAME_LENGTH]; ++ __u8 eir[HCI_MAX_EIR_LENGTH]; + __u8 dev_class[3]; + __u8 major_class; + __u8 minor_class; +@@ -118,6 +126,8 @@ + __u16 sniff_min_interval; + __u16 sniff_max_interval; + ++ unsigned int auto_accept_delay; ++ + unsigned long quirks; + + atomic_t cmd_cnt; +@@ -169,6 +179,8 @@ + + struct list_head link_keys; + ++ struct list_head remote_oob_data; ++ + struct hci_dev_stats stat; + + struct sk_buff_head driver_init; +@@ -216,6 +228,7 @@ + __u16 pkt_type; + __u16 link_policy; + __u32 link_mode; ++ __u8 key_type; + __u8 auth_type; + __u8 sec_level; + __u8 pending_sec_level; +@@ -235,6 +248,7 @@ + + struct timer_list disc_timer; + struct timer_list idle_timer; ++ struct timer_list auto_accept_timer; + + struct work_struct work_add; + struct work_struct work_del; +@@ -501,10 +515,17 @@ + + int hci_link_keys_clear(struct hci_dev *hdev); + struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); +-int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, +- u8 *key, u8 type, u8 pin_len); ++int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, ++ bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); + int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); + ++int hci_remote_oob_data_clear(struct hci_dev *hdev); ++struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, ++ bdaddr_t *bdaddr); ++int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, ++ u8 *randomizer); ++int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); ++ + void hci_del_off_timer(struct hci_dev *hdev); + + void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); +@@ -754,19 +775,27 @@ + int mgmt_powered(u16 index, u8 powered); + int mgmt_discoverable(u16 index, u8 discoverable); + int mgmt_connectable(u16 index, u8 connectable); +-int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type); ++int mgmt_new_key(u16 index, struct link_key *key, u8 persistent); + int mgmt_connected(u16 index, bdaddr_t *bdaddr); + int mgmt_disconnected(u16 index, bdaddr_t *bdaddr); + int mgmt_disconnect_failed(u16 index); + int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status); +-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr); ++int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure); + int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); + int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); +-int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value); ++int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value, ++ u8 confirm_hint); + int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); + int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, + u8 status); + int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status); ++int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status); ++int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, ++ u8 status); ++int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, ++ u8 *eir); ++int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name); ++int mgmt_discovering(u16 index, u8 discovering); + + /* HCI info for socket */ + #define hci_pi(sk) ((struct hci_pinfo *) sk) +diff -Naur linux-2.6.39-rc6/include/net/bluetooth/hci.h linux-2.6.39-rc6.rtl8192se/include/net/bluetooth/hci.h +--- linux-2.6.39-rc6/include/net/bluetooth/hci.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/net/bluetooth/hci.h 2011-05-05 23:30:11.204752535 +0200 +@@ -246,6 +246,15 @@ + #define HCI_AT_GENERAL_BONDING 0x04 + #define HCI_AT_GENERAL_BONDING_MITM 0x05 + ++/* Link Key types */ ++#define HCI_LK_COMBINATION 0x00 ++#define HCI_LK_LOCAL_UNIT 0x01 ++#define HCI_LK_REMOTE_UNIT 0x02 ++#define HCI_LK_DEBUG_COMBINATION 0x03 ++#define HCI_LK_UNAUTH_COMBINATION 0x04 ++#define HCI_LK_AUTH_COMBINATION 0x05 ++#define HCI_LK_CHANGED_COMBINATION 0x06 ++ + /* ----- HCI Commands ---- */ + #define HCI_OP_NOP 0x0000 + +@@ -428,6 +437,18 @@ + + #define HCI_OP_USER_CONFIRM_NEG_REPLY 0x042d + ++#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430 ++struct hci_cp_remote_oob_data_reply { ++ bdaddr_t bdaddr; ++ __u8 hash[16]; ++ __u8 randomizer[16]; ++} __packed; ++ ++#define HCI_OP_REMOTE_OOB_DATA_NEG_REPLY 0x0433 ++struct hci_cp_remote_oob_data_neg_reply { ++ bdaddr_t bdaddr; ++} __packed; ++ + #define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434 + struct hci_cp_io_capability_neg_reply { + bdaddr_t bdaddr; +@@ -537,15 +558,17 @@ + __u8 delete_all; + } __packed; + ++#define HCI_MAX_NAME_LENGTH 248 ++ + #define HCI_OP_WRITE_LOCAL_NAME 0x0c13 + struct hci_cp_write_local_name { +- __u8 name[248]; ++ __u8 name[HCI_MAX_NAME_LENGTH]; + } __packed; + + #define HCI_OP_READ_LOCAL_NAME 0x0c14 + struct hci_rp_read_local_name { + __u8 status; +- __u8 name[248]; ++ __u8 name[HCI_MAX_NAME_LENGTH]; + } __packed; + + #define HCI_OP_WRITE_CA_TIMEOUT 0x0c16 +@@ -602,6 +625,14 @@ + + #define HCI_OP_WRITE_INQUIRY_MODE 0x0c45 + ++#define HCI_MAX_EIR_LENGTH 240 ++ ++#define HCI_OP_WRITE_EIR 0x0c52 ++struct hci_cp_write_eir { ++ uint8_t fec; ++ uint8_t data[HCI_MAX_EIR_LENGTH]; ++} __packed; ++ + #define HCI_OP_READ_SSP_MODE 0x0c55 + struct hci_rp_read_ssp_mode { + __u8 status; +@@ -613,6 +644,13 @@ + __u8 mode; + } __packed; + ++#define HCI_OP_READ_LOCAL_OOB_DATA 0x0c57 ++struct hci_rp_read_local_oob_data { ++ __u8 status; ++ __u8 hash[16]; ++ __u8 randomizer[16]; ++} __packed; ++ + #define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58 + + #define HCI_OP_READ_LOCAL_VERSION 0x1001 +@@ -747,7 +785,7 @@ + struct hci_ev_remote_name { + __u8 status; + bdaddr_t bdaddr; +- __u8 name[248]; ++ __u8 name[HCI_MAX_NAME_LENGTH]; + } __packed; + + #define HCI_EV_ENCRYPT_CHANGE 0x08 +@@ -955,6 +993,11 @@ + __le32 passkey; + } __packed; + ++#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35 ++struct hci_ev_remote_oob_data_request { ++ bdaddr_t bdaddr; ++} __packed; ++ + #define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 + struct hci_ev_simple_pair_complete { + __u8 status; +diff -Naur linux-2.6.39-rc6/include/net/bluetooth/l2cap.h linux-2.6.39-rc6.rtl8192se/include/net/bluetooth/l2cap.h +--- linux-2.6.39-rc6/include/net/bluetooth/l2cap.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/net/bluetooth/l2cap.h 2011-05-05 23:30:11.206752559 +0200 +@@ -276,63 +276,17 @@ + #define L2CAP_CONN_PARAM_ACCEPTED 0x0000 + #define L2CAP_CONN_PARAM_REJECTED 0x0001 + +-/* ----- L2CAP connections ----- */ +-struct l2cap_chan_list { +- struct sock *head; +- rwlock_t lock; +- long num; +-}; +- +-struct l2cap_conn { +- struct hci_conn *hcon; +- +- bdaddr_t *dst; +- bdaddr_t *src; +- +- unsigned int mtu; +- +- __u32 feat_mask; +- +- __u8 info_state; +- __u8 info_ident; +- +- struct timer_list info_timer; +- +- spinlock_t lock; +- +- struct sk_buff *rx_skb; +- __u32 rx_len; +- __u8 rx_ident; +- __u8 tx_ident; +- +- __u8 disc_reason; +- +- struct l2cap_chan_list chan_list; +-}; +- +-struct sock_del_list { +- struct sock *sk; +- struct list_head list; +-}; +- +-#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 +-#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04 +-#define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08 +- +-/* ----- L2CAP channel and socket info ----- */ +-#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) +-#define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) +-#define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue) +-#define BUSY_QUEUE(sk) (&l2cap_pi(sk)->busy_queue) +-#define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list) +- ++/* ----- L2CAP channels and connections ----- */ + struct srej_list { + __u8 tx_seq; + struct list_head list; + }; + +-struct l2cap_pinfo { +- struct bt_sock bt; ++struct l2cap_chan { ++ struct sock *sk; ++ ++ struct l2cap_conn *conn; ++ + __le16 psm; + __u16 dcid; + __u16 scid; +@@ -341,17 +295,29 @@ + __u16 omtu; + __u16 flush_to; + __u8 mode; +- __u8 num_conf_req; +- __u8 num_conf_rsp; + +- __u8 fcs; ++ __le16 sport; ++ + __u8 sec_level; + __u8 role_switch; + __u8 force_reliable; + __u8 flushable; + ++ __u8 ident; ++ + __u8 conf_req[64]; + __u8 conf_len; ++ __u8 num_conf_req; ++ __u8 num_conf_rsp; ++ ++ __u8 fcs; ++ ++ __u8 tx_win; ++ __u8 max_tx; ++ __u16 retrans_timeout; ++ __u16 monitor_timeout; ++ __u16 mps; ++ + __u8 conf_state; + __u16 conn_state; + +@@ -369,30 +335,60 @@ + __u16 partial_sdu_len; + struct sk_buff *sdu; + +- __u8 ident; +- +- __u8 tx_win; +- __u8 max_tx; + __u8 remote_tx_win; + __u8 remote_max_tx; +- __u16 retrans_timeout; +- __u16 monitor_timeout; + __u16 remote_mps; +- __u16 mps; +- +- __le16 sport; + + struct timer_list retrans_timer; + struct timer_list monitor_timer; + struct timer_list ack_timer; +- struct sk_buff_head tx_queue; +- struct sk_buff_head srej_queue; +- struct sk_buff_head busy_queue; ++ struct sk_buff *tx_send_head; ++ struct sk_buff_head tx_q; ++ struct sk_buff_head srej_q; ++ struct sk_buff_head busy_q; + struct work_struct busy_work; +- struct srej_list srej_l; +- struct l2cap_conn *conn; +- struct sock *next_c; +- struct sock *prev_c; ++ struct list_head srej_l; ++ ++ struct list_head list; ++}; ++ ++struct l2cap_conn { ++ struct hci_conn *hcon; ++ ++ bdaddr_t *dst; ++ bdaddr_t *src; ++ ++ unsigned int mtu; ++ ++ __u32 feat_mask; ++ ++ __u8 info_state; ++ __u8 info_ident; ++ ++ struct timer_list info_timer; ++ ++ spinlock_t lock; ++ ++ struct sk_buff *rx_skb; ++ __u32 rx_len; ++ __u8 tx_ident; ++ ++ __u8 disc_reason; ++ ++ struct list_head chan_l; ++ rwlock_t chan_lock; ++}; ++ ++#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 ++#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04 ++#define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08 ++ ++/* ----- L2CAP socket info ----- */ ++#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) ++ ++struct l2cap_pinfo { ++ struct bt_sock bt; ++ struct l2cap_chan *chan; + }; + + #define L2CAP_CONF_REQ_SENT 0x01 +@@ -419,24 +415,23 @@ + #define L2CAP_CONN_RNR_SENT 0x0200 + #define L2CAP_CONN_SAR_RETRY 0x0400 + +-#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ ++#define __mod_retrans_timer() mod_timer(&chan->retrans_timer, \ + jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); +-#define __mod_monitor_timer() mod_timer(&l2cap_pi(sk)->monitor_timer, \ ++#define __mod_monitor_timer() mod_timer(&chan->monitor_timer, \ + jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO)); +-#define __mod_ack_timer() mod_timer(&l2cap_pi(sk)->ack_timer, \ ++#define __mod_ack_timer() mod_timer(&chan->ack_timer, \ + jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO)); + +-static inline int l2cap_tx_window_full(struct sock *sk) ++static inline int l2cap_tx_window_full(struct l2cap_chan *ch) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + int sub; + +- sub = (pi->next_tx_seq - pi->expected_ack_seq) % 64; ++ sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64; + + if (sub < 0) + sub += 64; + +- return sub == pi->remote_tx_win; ++ return sub == ch->remote_tx_win; + } + + #define __get_txseq(ctrl) (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1) +@@ -446,24 +441,22 @@ + #define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START) + + extern int disable_ertm; +-extern const struct proto_ops l2cap_sock_ops; + extern struct bt_sock_list l2cap_sk_list; + + int l2cap_init_sockets(void); + void l2cap_cleanup_sockets(void); + +-u8 l2cap_get_ident(struct l2cap_conn *conn); + void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); +-int l2cap_build_conf_req(struct sock *sk, void *data); ++void __l2cap_connect_rsp_defer(struct l2cap_chan *chan); + int __l2cap_wait_ack(struct sock *sk); + +-struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); +-struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len); +-struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen); +-int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len); +-void l2cap_do_send(struct sock *sk, struct sk_buff *skb); +-void l2cap_streaming_send(struct sock *sk); +-int l2cap_ertm_send(struct sock *sk); ++struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); ++struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); ++struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen); ++int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); ++void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb); ++void l2cap_streaming_send(struct l2cap_chan *chan); ++int l2cap_ertm_send(struct l2cap_chan *chan); + + void l2cap_sock_set_timer(struct sock *sk, long timeout); + void l2cap_sock_clear_timer(struct sock *sk); +@@ -472,8 +465,10 @@ + void l2cap_sock_init(struct sock *sk, struct sock *parent); + struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, + int proto, gfp_t prio); +-void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err); +-void l2cap_chan_del(struct sock *sk, int err); +-int l2cap_do_connect(struct sock *sk); ++void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); ++struct l2cap_chan *l2cap_chan_alloc(struct sock *sk); ++void l2cap_chan_del(struct l2cap_chan *chan, int err); ++void l2cap_chan_free(struct l2cap_chan *chan); ++int l2cap_chan_connect(struct l2cap_chan *chan); + + #endif /* __L2CAP_H */ +diff -Naur linux-2.6.39-rc6/include/net/bluetooth/mgmt.h linux-2.6.39-rc6.rtl8192se/include/net/bluetooth/mgmt.h +--- linux-2.6.39-rc6/include/net/bluetooth/mgmt.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/net/bluetooth/mgmt.h 2011-05-05 23:30:11.208752583 +0200 +@@ -41,6 +41,10 @@ + __le16 index[0]; + } __packed; + ++/* Reserve one extra byte for names in management messages so that they ++ * are always guaranteed to be nul-terminated */ ++#define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1) ++ + #define MGMT_OP_READ_INFO 0x0004 + struct mgmt_rp_read_info { + __u8 type; +@@ -55,6 +59,7 @@ + __u16 manufacturer; + __u8 hci_ver; + __u16 hci_rev; ++ __u8 name[MGMT_MAX_NAME_LENGTH]; + } __packed; + + struct mgmt_mode { +@@ -167,6 +172,33 @@ + + #define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x0016 + ++#define MGMT_OP_SET_LOCAL_NAME 0x0017 ++struct mgmt_cp_set_local_name { ++ __u8 name[MGMT_MAX_NAME_LENGTH]; ++} __packed; ++ ++#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0018 ++struct mgmt_rp_read_local_oob_data { ++ __u8 hash[16]; ++ __u8 randomizer[16]; ++} __packed; ++ ++#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0019 ++struct mgmt_cp_add_remote_oob_data { ++ bdaddr_t bdaddr; ++ __u8 hash[16]; ++ __u8 randomizer[16]; ++} __packed; ++ ++#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x001A ++struct mgmt_cp_remove_remote_oob_data { ++ bdaddr_t bdaddr; ++} __packed; ++ ++#define MGMT_OP_START_DISCOVERY 0x001B ++ ++#define MGMT_OP_STOP_DISCOVERY 0x001C ++ + #define MGMT_EV_CMD_COMPLETE 0x0001 + struct mgmt_ev_cmd_complete { + __le16 opcode; +@@ -198,8 +230,8 @@ + + #define MGMT_EV_NEW_KEY 0x000A + struct mgmt_ev_new_key { ++ __u8 store_hint; + struct mgmt_key_info key; +- __u8 old_key_type; + } __packed; + + #define MGMT_EV_CONNECTED 0x000B +@@ -221,11 +253,13 @@ + #define MGMT_EV_PIN_CODE_REQUEST 0x000E + struct mgmt_ev_pin_code_request { + bdaddr_t bdaddr; ++ __u8 secure; + } __packed; + + #define MGMT_EV_USER_CONFIRM_REQUEST 0x000F + struct mgmt_ev_user_confirm_request { + bdaddr_t bdaddr; ++ __u8 confirm_hint; + __le32 value; + } __packed; + +@@ -234,3 +268,24 @@ + bdaddr_t bdaddr; + __u8 status; + } __packed; ++ ++#define MGMT_EV_LOCAL_NAME_CHANGED 0x0011 ++struct mgmt_ev_local_name_changed { ++ __u8 name[MGMT_MAX_NAME_LENGTH]; ++} __packed; ++ ++#define MGMT_EV_DEVICE_FOUND 0x0012 ++struct mgmt_ev_device_found { ++ bdaddr_t bdaddr; ++ __u8 dev_class[3]; ++ __s8 rssi; ++ __u8 eir[HCI_MAX_EIR_LENGTH]; ++} __packed; ++ ++#define MGMT_EV_REMOTE_NAME 0x0013 ++struct mgmt_ev_remote_name { ++ bdaddr_t bdaddr; ++ __u8 name[MGMT_MAX_NAME_LENGTH]; ++} __packed; ++ ++#define MGMT_EV_DISCOVERING 0x0014 +diff -Naur linux-2.6.39-rc6/include/net/cfg80211.h linux-2.6.39-rc6.rtl8192se/include/net/cfg80211.h +--- linux-2.6.39-rc6/include/net/cfg80211.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/net/cfg80211.h 2011-05-05 23:30:11.179752233 +0200 +@@ -422,6 +422,8 @@ + * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled + * @STATION_INFO_SIGNAL_AVG: @signal_avg filled + * @STATION_INFO_RX_BITRATE: @rxrate fields are filled ++ * @STATION_INFO_BSS_PARAM: @bss_param filled ++ * @STATION_INFO_CONNECTED_TIME: @connected_time filled + */ + enum station_info_flags { + STATION_INFO_INACTIVE_TIME = 1<<0, +@@ -439,6 +441,8 @@ + STATION_INFO_RX_DROP_MISC = 1<<12, + STATION_INFO_SIGNAL_AVG = 1<<13, + STATION_INFO_RX_BITRATE = 1<<14, ++ STATION_INFO_BSS_PARAM = 1<<15, ++ STATION_INFO_CONNECTED_TIME = 1<<16 + }; + + /** +@@ -473,11 +477,43 @@ + }; + + /** ++ * enum station_info_rate_flags - bitrate info flags ++ * ++ * Used by the driver to indicate the specific rate transmission ++ * type for 802.11n transmissions. ++ * ++ * @BSS_PARAM_FLAGS_CTS_PROT: whether CTS protection is enabled ++ * @BSS_PARAM_FLAGS_SHORT_PREAMBLE: whether short preamble is enabled ++ * @BSS_PARAM_FLAGS_SHORT_SLOT_TIME: whether short slot time is enabled ++ */ ++enum bss_param_flags { ++ BSS_PARAM_FLAGS_CTS_PROT = 1<<0, ++ BSS_PARAM_FLAGS_SHORT_PREAMBLE = 1<<1, ++ BSS_PARAM_FLAGS_SHORT_SLOT_TIME = 1<<2, ++}; ++ ++/** ++ * struct sta_bss_parameters - BSS parameters for the attached station ++ * ++ * Information about the currently associated BSS ++ * ++ * @flags: bitflag of flags from &enum bss_param_flags ++ * @dtim_period: DTIM period for the BSS ++ * @beacon_interval: beacon interval ++ */ ++struct sta_bss_parameters { ++ u8 flags; ++ u8 dtim_period; ++ u16 beacon_interval; ++}; ++ ++/** + * struct station_info - station information + * + * Station information filled by driver for get_station() and dump_station. + * + * @filled: bitflag of flags from &enum station_info_flags ++ * @connected_time: time(in secs) since a station is last connected + * @inactive_time: time since last station activity (tx/rx) in milliseconds + * @rx_bytes: bytes received from this station + * @tx_bytes: bytes transmitted to this station +@@ -500,6 +536,7 @@ + */ + struct station_info { + u32 filled; ++ u32 connected_time; + u32 inactive_time; + u32 rx_bytes; + u32 tx_bytes; +@@ -515,6 +552,7 @@ + u32 tx_retries; + u32 tx_failed; + u32 rx_dropped_misc; ++ struct sta_bss_parameters bss_param; + + int generation; + }; +@@ -655,8 +693,9 @@ + * @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes + * @path_sel_proto: which path selection protocol to use + * @path_metric: which metric to use +- * @vendor_ie: vendor information elements (optional) +- * @vendor_ie_len: length of vendor information elements ++ * @ie: vendor information elements (optional) ++ * @ie_len: length of vendor information elements ++ * @is_secure: or not + * + * These parameters are fixed when the mesh is created. + */ +@@ -665,8 +704,9 @@ + u8 mesh_id_len; + u8 path_sel_proto; + u8 path_metric; +- const u8 *vendor_ie; +- u8 vendor_ie_len; ++ const u8 *ie; ++ u8 ie_len; ++ bool is_secure; + }; + + /** +@@ -1417,6 +1457,8 @@ + * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN. + * @WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS: The device supports separate + * unicast and multicast TX keys. ++ * @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing ++ * auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH. + */ + enum wiphy_flags { + WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), +@@ -1429,6 +1471,7 @@ + WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), + WIPHY_FLAG_IBSS_RSN = BIT(8), + WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS= BIT(9), ++ WIPHY_FLAG_MESH_AUTH = BIT(10), + }; + + struct mac_address { +@@ -2450,6 +2493,22 @@ + void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp); + + /** ++ * cfg80211_notify_new_candidate - notify cfg80211 of a new mesh peer candidate ++ * ++ * @dev: network device ++ * @macaddr: the MAC address of the new candidate ++ * @ie: information elements advertised by the peer candidate ++ * @ie_len: lenght of the information elements buffer ++ * @gfp: allocation flags ++ * ++ * This function notifies cfg80211 that the mesh peer candidate has been ++ * detected, most likely via a beacon or, less likely, via a probe response. ++ * cfg80211 then sends a notification to userspace. ++ */ ++void cfg80211_notify_new_peer_candidate(struct net_device *dev, ++ const u8 *macaddr, const u8 *ie, u8 ie_len, gfp_t gfp); ++ ++/** + * DOC: RFkill integration + * + * RFkill integration in cfg80211 is almost invisible to drivers, +@@ -2667,6 +2726,15 @@ + struct station_info *sinfo, gfp_t gfp); + + /** ++ * cfg80211_del_sta - notify userspace about deletion of a station ++ * ++ * @dev: the netdev ++ * @mac_addr: the station's address ++ * @gfp: allocation flags ++ */ ++void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); ++ ++/** + * cfg80211_rx_mgmt - notification of received, unprocessed management frame + * @dev: network device + * @freq: Frequency on which the frame was received in MHz +diff -Naur linux-2.6.39-rc6/include/net/mac80211.h linux-2.6.39-rc6.rtl8192se/include/net/mac80211.h +--- linux-2.6.39-rc6/include/net/mac80211.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/include/net/mac80211.h 2011-05-05 23:30:11.138751739 +0200 +@@ -1819,6 +1819,13 @@ + * @set_ringparam: Set tx and rx ring sizes. + * + * @get_ringparam: Get tx and rx ring current and maximum sizes. ++ * ++ * @tx_frames_pending: Check if there is any pending frame in the hardware ++ * queues before entering power save. ++ * ++ * @set_bitrate_mask: Set a mask of rates to be used for rate control selection ++ * when transmitting a frame. Currently only legacy rates are handled. ++ * The callback can sleep. + */ + struct ieee80211_ops { + void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); +@@ -1906,6 +1913,9 @@ + int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx); + void (*get_ringparam)(struct ieee80211_hw *hw, + u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); ++ bool (*tx_frames_pending)(struct ieee80211_hw *hw); ++ int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ++ const struct cfg80211_bitrate_mask *mask); + }; + + /** +@@ -2223,6 +2233,18 @@ + #define IEEE80211_TX_STATUS_HEADROOM 13 + + /** ++ * ieee80211_sta_set_tim - set the TIM bit for a sleeping station ++ * ++ * If a driver buffers frames for a powersave station instead of passing ++ * them back to mac80211 for retransmission, the station needs to be told ++ * to wake up using the TIM bitmap in the beacon. ++ * ++ * This function sets the station's TIM bit - it will be cleared when the ++ * station wakes up. ++ */ ++void ieee80211_sta_set_tim(struct ieee80211_sta *sta); ++ ++/** + * ieee80211_tx_status - transmit status callback + * + * Call this function for all transmitted frames after they have been +@@ -2276,6 +2298,17 @@ + struct sk_buff *skb); + + /** ++ * ieee80211_report_low_ack - report non-responding station ++ * ++ * When operating in AP-mode, call this function to report a non-responding ++ * connected STA. ++ * ++ * @sta: the non-responding connected sta ++ * @num_packets: number of packets sent to @sta without a response ++ */ ++void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets); ++ ++/** + * ieee80211_beacon_get_tim - beacon generation function + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. +diff -Naur linux-2.6.39-rc6/localversion-wireless linux-2.6.39-rc6.rtl8192se/localversion-wireless +--- linux-2.6.39-rc6/localversion-wireless 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/localversion-wireless 2011-05-05 23:30:24.120908487 +0200 +@@ -0,0 +1 @@ ++-wl +diff -Naur linux-2.6.39-rc6/MAINTAINERS linux-2.6.39-rc6.rtl8192se/MAINTAINERS +--- linux-2.6.39-rc6/MAINTAINERS 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/MAINTAINERS 2011-05-05 23:30:02.149643175 +0200 +@@ -1232,13 +1232,6 @@ + S: Supported + F: drivers/net/wireless/ath/ath9k/ + +-ATHEROS AR9170 WIRELESS DRIVER +-M: Christian Lamparter +-L: linux-wireless@vger.kernel.org +-W: http://wireless.kernel.org/en/users/Drivers/ar9170 +-S: Obsolete +-F: drivers/net/wireless/ath/ar9170/ +- + CARL9170 LINUX COMMUNITY WIRELESS DRIVER + M: Christian Lamparter + L: linux-wireless@vger.kernel.org +@@ -3362,6 +3355,12 @@ + F: drivers/net/wimax/i2400m/ + F: include/linux/wimax/i2400m.h + ++INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy) ++M: Stanislaw Gruszka ++L: linux-wireless@vger.kernel.org ++S: Supported ++F: drivers/net/wireless/iwlegacy/ ++ + INTEL WIRELESS WIFI LINK (iwlwifi) + M: Wey-Yi Guy + M: Intel Linux Wireless +diff -Naur linux-2.6.39-rc6/net/bluetooth/bnep/bnep.h linux-2.6.39-rc6.rtl8192se/net/bluetooth/bnep/bnep.h +--- linux-2.6.39-rc6/net/bluetooth/bnep/bnep.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/bnep/bnep.h 2011-05-05 23:30:21.223873511 +0200 +@@ -23,88 +23,88 @@ + #include + #include + +-// Limits +-#define BNEP_MAX_PROTO_FILTERS 5 +-#define BNEP_MAX_MULTICAST_FILTERS 20 +- +-// UUIDs +-#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB +-#define BNEP_UUID16 0x02 +-#define BNEP_UUID32 0x04 +-#define BNEP_UUID128 0x16 +- +-#define BNEP_SVC_PANU 0x1115 +-#define BNEP_SVC_NAP 0x1116 +-#define BNEP_SVC_GN 0x1117 +- +-// Packet types +-#define BNEP_GENERAL 0x00 +-#define BNEP_CONTROL 0x01 +-#define BNEP_COMPRESSED 0x02 +-#define BNEP_COMPRESSED_SRC_ONLY 0x03 +-#define BNEP_COMPRESSED_DST_ONLY 0x04 +- +-// Control types +-#define BNEP_CMD_NOT_UNDERSTOOD 0x00 +-#define BNEP_SETUP_CONN_REQ 0x01 +-#define BNEP_SETUP_CONN_RSP 0x02 +-#define BNEP_FILTER_NET_TYPE_SET 0x03 +-#define BNEP_FILTER_NET_TYPE_RSP 0x04 +-#define BNEP_FILTER_MULTI_ADDR_SET 0x05 +-#define BNEP_FILTER_MULTI_ADDR_RSP 0x06 +- +-// Extension types +-#define BNEP_EXT_CONTROL 0x00 +- +-// Response messages +-#define BNEP_SUCCESS 0x00 +- +-#define BNEP_CONN_INVALID_DST 0x01 +-#define BNEP_CONN_INVALID_SRC 0x02 +-#define BNEP_CONN_INVALID_SVC 0x03 +-#define BNEP_CONN_NOT_ALLOWED 0x04 +- +-#define BNEP_FILTER_UNSUPPORTED_REQ 0x01 +-#define BNEP_FILTER_INVALID_RANGE 0x02 +-#define BNEP_FILTER_INVALID_MCADDR 0x02 +-#define BNEP_FILTER_LIMIT_REACHED 0x03 +-#define BNEP_FILTER_DENIED_SECURITY 0x04 +- +-// L2CAP settings +-#define BNEP_MTU 1691 +-#define BNEP_PSM 0x0f +-#define BNEP_FLUSH_TO 0xffff +-#define BNEP_CONNECT_TO 15 +-#define BNEP_FILTER_TO 15 +- +-// Headers +-#define BNEP_TYPE_MASK 0x7f +-#define BNEP_EXT_HEADER 0x80 ++/* Limits */ ++#define BNEP_MAX_PROTO_FILTERS 5 ++#define BNEP_MAX_MULTICAST_FILTERS 20 ++ ++/* UUIDs */ ++#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB ++#define BNEP_UUID16 0x02 ++#define BNEP_UUID32 0x04 ++#define BNEP_UUID128 0x16 ++ ++#define BNEP_SVC_PANU 0x1115 ++#define BNEP_SVC_NAP 0x1116 ++#define BNEP_SVC_GN 0x1117 ++ ++/* Packet types */ ++#define BNEP_GENERAL 0x00 ++#define BNEP_CONTROL 0x01 ++#define BNEP_COMPRESSED 0x02 ++#define BNEP_COMPRESSED_SRC_ONLY 0x03 ++#define BNEP_COMPRESSED_DST_ONLY 0x04 ++ ++/* Control types */ ++#define BNEP_CMD_NOT_UNDERSTOOD 0x00 ++#define BNEP_SETUP_CONN_REQ 0x01 ++#define BNEP_SETUP_CONN_RSP 0x02 ++#define BNEP_FILTER_NET_TYPE_SET 0x03 ++#define BNEP_FILTER_NET_TYPE_RSP 0x04 ++#define BNEP_FILTER_MULTI_ADDR_SET 0x05 ++#define BNEP_FILTER_MULTI_ADDR_RSP 0x06 ++ ++/* Extension types */ ++#define BNEP_EXT_CONTROL 0x00 ++ ++/* Response messages */ ++#define BNEP_SUCCESS 0x00 ++ ++#define BNEP_CONN_INVALID_DST 0x01 ++#define BNEP_CONN_INVALID_SRC 0x02 ++#define BNEP_CONN_INVALID_SVC 0x03 ++#define BNEP_CONN_NOT_ALLOWED 0x04 ++ ++#define BNEP_FILTER_UNSUPPORTED_REQ 0x01 ++#define BNEP_FILTER_INVALID_RANGE 0x02 ++#define BNEP_FILTER_INVALID_MCADDR 0x02 ++#define BNEP_FILTER_LIMIT_REACHED 0x03 ++#define BNEP_FILTER_DENIED_SECURITY 0x04 ++ ++/* L2CAP settings */ ++#define BNEP_MTU 1691 ++#define BNEP_PSM 0x0f ++#define BNEP_FLUSH_TO 0xffff ++#define BNEP_CONNECT_TO 15 ++#define BNEP_FILTER_TO 15 ++ ++/* Headers */ ++#define BNEP_TYPE_MASK 0x7f ++#define BNEP_EXT_HEADER 0x80 + + struct bnep_setup_conn_req { +- __u8 type; +- __u8 ctrl; +- __u8 uuid_size; +- __u8 service[0]; ++ __u8 type; ++ __u8 ctrl; ++ __u8 uuid_size; ++ __u8 service[0]; + } __packed; + + struct bnep_set_filter_req { +- __u8 type; +- __u8 ctrl; ++ __u8 type; ++ __u8 ctrl; + __be16 len; +- __u8 list[0]; ++ __u8 list[0]; + } __packed; + + struct bnep_control_rsp { +- __u8 type; +- __u8 ctrl; ++ __u8 type; ++ __u8 ctrl; + __be16 resp; + } __packed; + + struct bnep_ext_hdr { +- __u8 type; +- __u8 len; +- __u8 data[0]; ++ __u8 type; ++ __u8 len; ++ __u8 data[0]; + } __packed; + + /* BNEP ioctl defines */ +@@ -114,10 +114,10 @@ + #define BNEPGETCONNINFO _IOR('B', 211, int) + + struct bnep_connadd_req { +- int sock; // Connected socket ++ int sock; /* Connected socket */ + __u32 flags; + __u16 role; +- char device[16]; // Name of the Ethernet device ++ char device[16]; /* Name of the Ethernet device */ + }; + + struct bnep_conndel_req { +@@ -148,14 +148,14 @@ + int bnep_get_connlist(struct bnep_connlist_req *req); + int bnep_get_conninfo(struct bnep_conninfo *ci); + +-// BNEP sessions ++/* BNEP sessions */ + struct bnep_session { + struct list_head list; + + unsigned int role; + unsigned long state; + unsigned long flags; +- atomic_t killed; ++ struct task_struct *task; + + struct ethhdr eh; + struct msghdr msg; +@@ -173,7 +173,7 @@ + + static inline int bnep_mc_hash(__u8 *addr) + { +- return (crc32_be(~0, addr, ETH_ALEN) >> 26); ++ return crc32_be(~0, addr, ETH_ALEN) >> 26; + } + + #endif +diff -Naur linux-2.6.39-rc6/net/bluetooth/bnep/core.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/bnep/core.c +--- linux-2.6.39-rc6/net/bluetooth/bnep/core.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/bnep/core.c 2011-05-05 23:30:21.223873511 +0200 +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -131,7 +132,8 @@ + return -EILSEQ; + + n = get_unaligned_be16(data); +- data++; len -= 2; ++ data++; ++ len -= 2; + + if (len < n) + return -EILSEQ; +@@ -176,7 +178,8 @@ + return -EILSEQ; + + n = get_unaligned_be16(data); +- data += 2; len -= 2; ++ data += 2; ++ len -= 2; + + if (len < n) + return -EILSEQ; +@@ -187,6 +190,8 @@ + n /= (ETH_ALEN * 2); + + if (n > 0) { ++ int i; ++ + s->mc_filter = 0; + + /* Always send broadcast */ +@@ -196,18 +201,22 @@ + for (; n > 0; n--) { + u8 a1[6], *a2; + +- memcpy(a1, data, ETH_ALEN); data += ETH_ALEN; +- a2 = data; data += ETH_ALEN; ++ memcpy(a1, data, ETH_ALEN); ++ data += ETH_ALEN; ++ a2 = data; ++ data += ETH_ALEN; + + BT_DBG("mc filter %s -> %s", + batostr((void *) a1), batostr((void *) a2)); + +- #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); } +- + /* Iterate from a1 to a2 */ + set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter); + while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) { +- INCA(a1); ++ /* Increment a1 */ ++ i = 5; ++ while (i >= 0 && ++a1[i--] == 0) ++ ; ++ + set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter); + } + } +@@ -227,7 +236,8 @@ + u8 cmd = *(u8 *)data; + int err = 0; + +- data++; len--; ++ data++; ++ len--; + + switch (cmd) { + case BNEP_CMD_NOT_UNDERSTOOD: +@@ -302,7 +312,6 @@ + ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */ + ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */ + }; +-#define BNEP_RX_TYPES (sizeof(__bnep_rx_hlen) - 1) + + static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) + { +@@ -312,9 +321,10 @@ + + dev->stats.rx_bytes += skb->len; + +- type = *(u8 *) skb->data; skb_pull(skb, 1); ++ type = *(u8 *) skb->data; ++ skb_pull(skb, 1); + +- if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES) ++ if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) + goto badframe; + + if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { +@@ -367,14 +377,14 @@ + + case BNEP_COMPRESSED_DST_ONLY: + memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), +- ETH_ALEN); ++ ETH_ALEN); + memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, +- ETH_ALEN + 2); ++ ETH_ALEN + 2); + break; + + case BNEP_GENERAL: + memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb), +- ETH_ALEN * 2); ++ ETH_ALEN * 2); + put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2)); + break; + } +@@ -470,15 +480,14 @@ + + BT_DBG(""); + +- daemonize("kbnepd %s", dev->name); + set_user_nice(current, -15); + + init_waitqueue_entry(&wait, current); + add_wait_queue(sk_sleep(sk), &wait); +- while (!atomic_read(&s->killed)) { ++ while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + +- // RX ++ /* RX */ + while ((skb = skb_dequeue(&sk->sk_receive_queue))) { + skb_orphan(skb); + bnep_rx_frame(s, skb); +@@ -487,7 +496,7 @@ + if (sk->sk_state != BT_CONNECTED) + break; + +- // TX ++ /* TX */ + while ((skb = skb_dequeue(&sk->sk_write_queue))) + if (bnep_tx_frame(s, skb)) + break; +@@ -555,8 +564,8 @@ + + /* session struct allocated as private part of net_device */ + dev = alloc_netdev(sizeof(struct bnep_session), +- (*req->device) ? req->device : "bnep%d", +- bnep_net_setup); ++ (*req->device) ? req->device : "bnep%d", ++ bnep_net_setup); + if (!dev) + return -ENOMEM; + +@@ -571,7 +580,7 @@ + s = netdev_priv(dev); + + /* This is rx header therefore addresses are swapped. +- * ie eh.h_dest is our local address. */ ++ * ie. eh.h_dest is our local address. */ + memcpy(s->eh.h_dest, &src, ETH_ALEN); + memcpy(s->eh.h_source, &dst, ETH_ALEN); + memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN); +@@ -597,17 +606,17 @@ + SET_NETDEV_DEVTYPE(dev, &bnep_type); + + err = register_netdev(dev); +- if (err) { ++ if (err) + goto failed; +- } + + __bnep_link_session(s); + +- err = kernel_thread(bnep_session, s, CLONE_KERNEL); +- if (err < 0) { ++ s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name); ++ if (IS_ERR(s->task)) { + /* Session thread start failed, gotta cleanup. */ + unregister_netdev(dev); + __bnep_unlink_session(s); ++ err = PTR_ERR(s->task); + goto failed; + } + +@@ -631,15 +640,9 @@ + down_read(&bnep_session_sem); + + s = __bnep_get_session(req->dst); +- if (s) { +- /* Wakeup user-space which is polling for socket errors. +- * This is temporary hack until we have shutdown in L2CAP */ +- s->sock->sk->sk_err = EUNATCH; +- +- /* Kill session thread */ +- atomic_inc(&s->killed); +- wake_up_interruptible(sk_sleep(s->sock->sk)); +- } else ++ if (s) ++ kthread_stop(s->task); ++ else + err = -ENOENT; + + up_read(&bnep_session_sem); +diff -Naur linux-2.6.39-rc6/net/bluetooth/bnep/sock.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/bnep/sock.c +--- linux-2.6.39-rc6/net/bluetooth/bnep/sock.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/bnep/sock.c 2011-05-05 23:30:21.224873524 +0200 +@@ -39,10 +39,10 @@ + #include + #include + #include ++#include + #include + + #include +-#include + + #include "bnep.h" + +diff -Naur linux-2.6.39-rc6/net/bluetooth/cmtp/capi.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/cmtp/capi.c +--- linux-2.6.39-rc6/net/bluetooth/cmtp/capi.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/cmtp/capi.c 2011-05-05 23:30:21.234873645 +0200 +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -143,7 +144,7 @@ + + skb_queue_tail(&session->transmit, skb); + +- cmtp_schedule(session); ++ wake_up_interruptible(sk_sleep(session->sock->sk)); + } + + static void cmtp_send_interopmsg(struct cmtp_session *session, +@@ -386,8 +387,7 @@ + + capi_ctr_down(ctrl); + +- atomic_inc(&session->terminate); +- cmtp_schedule(session); ++ kthread_stop(session->task); + } + + static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) +diff -Naur linux-2.6.39-rc6/net/bluetooth/cmtp/cmtp.h linux-2.6.39-rc6.rtl8192se/net/bluetooth/cmtp/cmtp.h +--- linux-2.6.39-rc6/net/bluetooth/cmtp/cmtp.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/cmtp/cmtp.h 2011-05-05 23:30:21.235873657 +0200 +@@ -37,7 +37,7 @@ + #define CMTP_LOOPBACK 0 + + struct cmtp_connadd_req { +- int sock; // Connected socket ++ int sock; /* Connected socket */ + __u32 flags; + }; + +@@ -81,7 +81,7 @@ + + char name[BTNAMSIZ]; + +- atomic_t terminate; ++ struct task_struct *task; + + wait_queue_head_t wait; + +@@ -121,13 +121,6 @@ + + void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb); + +-static inline void cmtp_schedule(struct cmtp_session *session) +-{ +- struct sock *sk = session->sock->sk; +- +- wake_up_interruptible(sk_sleep(sk)); +-} +- + /* CMTP init defines */ + int cmtp_init_sockets(void); + void cmtp_cleanup_sockets(void); +diff -Naur linux-2.6.39-rc6/net/bluetooth/cmtp/core.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/cmtp/core.c +--- linux-2.6.39-rc6/net/bluetooth/cmtp/core.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/cmtp/core.c 2011-05-05 23:30:21.234873645 +0200 +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -235,9 +236,12 @@ + + size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len); + +- if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) { +- skb_queue_head(&session->transmit, skb); +- break; ++ if (scb->id < 0) { ++ scb->id = cmtp_alloc_block_id(session); ++ if (scb->id < 0) { ++ skb_queue_head(&session->transmit, skb); ++ break; ++ } + } + + if (size < 256) { +@@ -284,12 +288,11 @@ + + BT_DBG("session %p", session); + +- daemonize("kcmtpd_ctr_%d", session->num); + set_user_nice(current, -15); + + init_waitqueue_entry(&wait, current); + add_wait_queue(sk_sleep(sk), &wait); +- while (!atomic_read(&session->terminate)) { ++ while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + + if (sk->sk_state != BT_CONNECTED) +@@ -343,7 +346,8 @@ + + bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst); + +- session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu); ++ session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu, ++ l2cap_pi(sock->sk)->chan->imtu); + + BT_DBG("mtu %d", session->mtu); + +@@ -367,9 +371,12 @@ + + __cmtp_link_session(session); + +- err = kernel_thread(cmtp_session, session, CLONE_KERNEL); +- if (err < 0) ++ session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d", ++ session->num); ++ if (IS_ERR(session->task)) { ++ err = PTR_ERR(session->task); + goto unlink; ++ } + + if (!(session->flags & (1 << CMTP_LOOPBACK))) { + err = cmtp_attach_device(session); +@@ -406,9 +413,8 @@ + /* Flush the transmit queue */ + skb_queue_purge(&session->transmit); + +- /* Kill session thread */ +- atomic_inc(&session->terminate); +- cmtp_schedule(session); ++ /* Stop session thread */ ++ kthread_stop(session->task); + } else + err = -ENOENT; + +diff -Naur linux-2.6.39-rc6/net/bluetooth/cmtp/sock.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/cmtp/sock.c +--- linux-2.6.39-rc6/net/bluetooth/cmtp/sock.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/cmtp/sock.c 2011-05-05 23:30:21.236873669 +0200 +@@ -34,12 +34,12 @@ + #include + #include + #include ++#include + #include + + #include + + #include +-#include + + #include "cmtp.h" + +diff -Naur linux-2.6.39-rc6/net/bluetooth/hci_conn.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/hci_conn.c +--- linux-2.6.39-rc6/net/bluetooth/hci_conn.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/hci_conn.c 2011-05-05 23:30:21.242873741 +0200 +@@ -269,6 +269,19 @@ + hci_conn_enter_sniff_mode(conn); + } + ++static void hci_conn_auto_accept(unsigned long arg) ++{ ++ struct hci_conn *conn = (void *) arg; ++ struct hci_dev *hdev = conn->hdev; ++ ++ hci_dev_lock(hdev); ++ ++ hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst), ++ &conn->dst); ++ ++ hci_dev_unlock(hdev); ++} ++ + struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) + { + struct hci_conn *conn; +@@ -287,6 +300,7 @@ + conn->auth_type = HCI_AT_GENERAL_BONDING; + conn->io_capability = hdev->io_capability; + conn->remote_auth = 0xff; ++ conn->key_type = 0xff; + + conn->power_save = 1; + conn->disc_timeout = HCI_DISCONN_TIMEOUT; +@@ -311,6 +325,8 @@ + + setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); + setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); ++ setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept, ++ (unsigned long) conn); + + atomic_set(&conn->refcnt, 0); + +@@ -341,6 +357,8 @@ + + del_timer(&conn->disc_timer); + ++ del_timer(&conn->auto_accept_timer); ++ + if (conn->type == ACL_LINK) { + struct hci_conn *sco = conn->link; + if (sco) +@@ -535,32 +553,72 @@ + return 0; + } + ++/* Encrypt the the link */ ++static void hci_conn_encrypt(struct hci_conn *conn) ++{ ++ BT_DBG("conn %p", conn); ++ ++ if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { ++ struct hci_cp_set_conn_encrypt cp; ++ cp.handle = cpu_to_le16(conn->handle); ++ cp.encrypt = 0x01; ++ hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), ++ &cp); ++ } ++} ++ + /* Enable security */ + int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) + { + BT_DBG("conn %p", conn); + ++ /* For sdp we don't need the link key. */ + if (sec_level == BT_SECURITY_SDP) + return 1; + ++ /* For non 2.1 devices and low security level we don't need the link ++ key. */ + if (sec_level == BT_SECURITY_LOW && + (!conn->ssp_mode || !conn->hdev->ssp_mode)) + return 1; + +- if (conn->link_mode & HCI_LM_ENCRYPT) +- return hci_conn_auth(conn, sec_level, auth_type); ++ /* For other security levels we need the link key. */ ++ if (!(conn->link_mode & HCI_LM_AUTH)) ++ goto auth; ++ ++ /* An authenticated combination key has sufficient security for any ++ security level. */ ++ if (conn->key_type == HCI_LK_AUTH_COMBINATION) ++ goto encrypt; ++ ++ /* An unauthenticated combination key has sufficient security for ++ security level 1 and 2. */ ++ if (conn->key_type == HCI_LK_UNAUTH_COMBINATION && ++ (sec_level == BT_SECURITY_MEDIUM || ++ sec_level == BT_SECURITY_LOW)) ++ goto encrypt; ++ ++ /* A combination key has always sufficient security for the security ++ levels 1 or 2. High security level requires the combination key ++ is generated using maximum PIN code length (16). ++ For pre 2.1 units. */ ++ if (conn->key_type == HCI_LK_COMBINATION && ++ (sec_level != BT_SECURITY_HIGH || ++ conn->pin_length == 16)) ++ goto encrypt; + ++auth: + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + return 0; + +- if (hci_conn_auth(conn, sec_level, auth_type)) { +- struct hci_cp_set_conn_encrypt cp; +- cp.handle = cpu_to_le16(conn->handle); +- cp.encrypt = 1; +- hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, +- sizeof(cp), &cp); +- } ++ hci_conn_auth(conn, sec_level, auth_type); ++ return 0; ++ ++encrypt: ++ if (conn->link_mode & HCI_LM_ENCRYPT) ++ return 1; + ++ hci_conn_encrypt(conn); + return 0; + } + EXPORT_SYMBOL(hci_conn_security); +diff -Naur linux-2.6.39-rc6/net/bluetooth/hci_core.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/hci_core.c +--- linux-2.6.39-rc6/net/bluetooth/hci_core.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/hci_core.c 2011-05-05 23:30:21.226873549 +0200 +@@ -56,7 +56,6 @@ + static void hci_cmd_task(unsigned long arg); + static void hci_rx_task(unsigned long arg); + static void hci_tx_task(unsigned long arg); +-static void hci_notify(struct hci_dev *hdev, int event); + + static DEFINE_RWLOCK(hci_task_lock); + +@@ -1021,18 +1020,54 @@ + return NULL; + } + +-int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, +- u8 *val, u8 type, u8 pin_len) ++static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, ++ u8 key_type, u8 old_key_type) ++{ ++ /* Legacy key */ ++ if (key_type < 0x03) ++ return 1; ++ ++ /* Debug keys are insecure so don't store them persistently */ ++ if (key_type == HCI_LK_DEBUG_COMBINATION) ++ return 0; ++ ++ /* Changed combination key and there's no previous one */ ++ if (key_type == HCI_LK_CHANGED_COMBINATION && old_key_type == 0xff) ++ return 0; ++ ++ /* Security mode 3 case */ ++ if (!conn) ++ return 1; ++ ++ /* Neither local nor remote side had no-bonding as requirement */ ++ if (conn->auth_type > 0x01 && conn->remote_auth > 0x01) ++ return 1; ++ ++ /* Local side had dedicated bonding as requirement */ ++ if (conn->auth_type == 0x02 || conn->auth_type == 0x03) ++ return 1; ++ ++ /* Remote side had dedicated bonding as requirement */ ++ if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) ++ return 1; ++ ++ /* If none of the above criteria match, then don't store the key ++ * persistently */ ++ return 0; ++} ++ ++int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, ++ bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) + { + struct link_key *key, *old_key; +- u8 old_key_type; ++ u8 old_key_type, persistent; + + old_key = hci_find_link_key(hdev, bdaddr); + if (old_key) { + old_key_type = old_key->type; + key = old_key; + } else { +- old_key_type = 0xff; ++ old_key_type = conn ? conn->key_type : 0xff; + key = kzalloc(sizeof(*key), GFP_ATOMIC); + if (!key) + return -ENOMEM; +@@ -1041,16 +1076,37 @@ + + BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type); + ++ /* Some buggy controller combinations generate a changed ++ * combination key for legacy pairing even when there's no ++ * previous key */ ++ if (type == HCI_LK_CHANGED_COMBINATION && ++ (!conn || conn->remote_auth == 0xff) && ++ old_key_type == 0xff) { ++ type = HCI_LK_COMBINATION; ++ if (conn) ++ conn->key_type = type; ++ } ++ + bacpy(&key->bdaddr, bdaddr); + memcpy(key->val, val, 16); +- key->type = type; + key->pin_len = pin_len; + +- if (new_key) +- mgmt_new_key(hdev->id, key, old_key_type); +- +- if (type == 0x06) ++ if (type == HCI_LK_CHANGED_COMBINATION) + key->type = old_key_type; ++ else ++ key->type = type; ++ ++ if (!new_key) ++ return 0; ++ ++ persistent = hci_persistent_key(hdev, conn, type, old_key_type); ++ ++ mgmt_new_key(hdev->id, key, persistent); ++ ++ if (!persistent) { ++ list_del(&key->list); ++ kfree(key); ++ } + + return 0; + } +@@ -1082,6 +1138,70 @@ + tasklet_schedule(&hdev->cmd_task); + } + ++struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, ++ bdaddr_t *bdaddr) ++{ ++ struct oob_data *data; ++ ++ list_for_each_entry(data, &hdev->remote_oob_data, list) ++ if (bacmp(bdaddr, &data->bdaddr) == 0) ++ return data; ++ ++ return NULL; ++} ++ ++int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr) ++{ ++ struct oob_data *data; ++ ++ data = hci_find_remote_oob_data(hdev, bdaddr); ++ if (!data) ++ return -ENOENT; ++ ++ BT_DBG("%s removing %s", hdev->name, batostr(bdaddr)); ++ ++ list_del(&data->list); ++ kfree(data); ++ ++ return 0; ++} ++ ++int hci_remote_oob_data_clear(struct hci_dev *hdev) ++{ ++ struct oob_data *data, *n; ++ ++ list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) { ++ list_del(&data->list); ++ kfree(data); ++ } ++ ++ return 0; ++} ++ ++int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, ++ u8 *randomizer) ++{ ++ struct oob_data *data; ++ ++ data = hci_find_remote_oob_data(hdev, bdaddr); ++ ++ if (!data) { ++ data = kmalloc(sizeof(*data), GFP_ATOMIC); ++ if (!data) ++ return -ENOMEM; ++ ++ bacpy(&data->bdaddr, bdaddr); ++ list_add(&data->list, &hdev->remote_oob_data); ++ } ++ ++ memcpy(data->hash, hash, sizeof(data->hash)); ++ memcpy(data->randomizer, randomizer, sizeof(data->randomizer)); ++ ++ BT_DBG("%s for %s", hdev->name, batostr(bdaddr)); ++ ++ return 0; ++} ++ + /* Register HCI device */ + int hci_register_dev(struct hci_dev *hdev) + { +@@ -1146,6 +1266,8 @@ + + INIT_LIST_HEAD(&hdev->link_keys); + ++ INIT_LIST_HEAD(&hdev->remote_oob_data); ++ + INIT_WORK(&hdev->power_on, hci_power_on); + INIT_WORK(&hdev->power_off, hci_power_off); + setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev); +@@ -1225,6 +1347,7 @@ + hci_blacklist_clear(hdev); + hci_uuids_clear(hdev); + hci_link_keys_clear(hdev); ++ hci_remote_oob_data_clear(hdev); + hci_dev_unlock_bh(hdev); + + __hci_dev_put(hdev); +@@ -1274,7 +1397,7 @@ + EXPORT_SYMBOL(hci_recv_frame); + + static int hci_reassembly(struct hci_dev *hdev, int type, void *data, +- int count, __u8 index, gfp_t gfp_mask) ++ int count, __u8 index) + { + int len = 0; + int hlen = 0; +@@ -1304,7 +1427,7 @@ + break; + } + +- skb = bt_skb_alloc(len, gfp_mask); ++ skb = bt_skb_alloc(len, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + +@@ -1390,8 +1513,7 @@ + return -EILSEQ; + + while (count) { +- rem = hci_reassembly(hdev, type, data, count, +- type - 1, GFP_ATOMIC); ++ rem = hci_reassembly(hdev, type, data, count, type - 1); + if (rem < 0) + return rem; + +@@ -1425,8 +1547,8 @@ + } else + type = bt_cb(skb)->pkt_type; + +- rem = hci_reassembly(hdev, type, data, +- count, STREAM_REASSEMBLY, GFP_ATOMIC); ++ rem = hci_reassembly(hdev, type, data, count, ++ STREAM_REASSEMBLY); + if (rem < 0) + return rem; + +diff -Naur linux-2.6.39-rc6/net/bluetooth/hci_event.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/hci_event.c +--- linux-2.6.39-rc6/net/bluetooth/hci_event.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/hci_event.c 2011-05-05 23:30:21.171872885 +0200 +@@ -56,7 +56,9 @@ + if (status) + return; + +- clear_bit(HCI_INQUIRY, &hdev->flags); ++ if (test_bit(HCI_MGMT, &hdev->flags) && ++ test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) ++ mgmt_discovering(hdev->id, 0); + + hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); + +@@ -72,7 +74,9 @@ + if (status) + return; + +- clear_bit(HCI_INQUIRY, &hdev->flags); ++ if (test_bit(HCI_MGMT, &hdev->flags) && ++ test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) ++ mgmt_discovering(hdev->id, 0); + + hci_conn_check_pending(hdev); + } +@@ -195,14 +199,17 @@ + + BT_DBG("%s status 0x%x", hdev->name, status); + +- if (status) +- return; +- + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME); + if (!sent) + return; + +- memcpy(hdev->dev_name, sent, 248); ++ if (test_bit(HCI_MGMT, &hdev->flags)) ++ mgmt_set_local_name_complete(hdev->id, sent, status); ++ ++ if (status) ++ return; ++ ++ memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); + } + + static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) +@@ -214,7 +221,7 @@ + if (rp->status) + return; + +- memcpy(hdev->dev_name, rp->name, 248); ++ memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH); + } + + static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) +@@ -821,16 +828,31 @@ + rp->status); + } + ++static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, ++ struct sk_buff *skb) ++{ ++ struct hci_rp_read_local_oob_data *rp = (void *) skb->data; ++ ++ BT_DBG("%s status 0x%x", hdev->name, rp->status); ++ ++ mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash, ++ rp->randomizer, rp->status); ++} ++ + static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) + { + BT_DBG("%s status 0x%x", hdev->name, status); + + if (status) { + hci_req_complete(hdev, HCI_OP_INQUIRY, status); +- + hci_conn_check_pending(hdev); +- } else +- set_bit(HCI_INQUIRY, &hdev->flags); ++ return; ++ } ++ ++ if (test_bit(HCI_MGMT, &hdev->flags) && ++ !test_and_set_bit(HCI_INQUIRY, ++ &hdev->flags)) ++ mgmt_discovering(hdev->id, 1); + } + + static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) +@@ -999,12 +1021,19 @@ + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); +- if (conn && hci_outgoing_auth_needed(hdev, conn)) { ++ if (!conn) ++ goto unlock; ++ ++ if (!hci_outgoing_auth_needed(hdev, conn)) ++ goto unlock; ++ ++ if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + struct hci_cp_auth_requested cp; + cp.handle = __cpu_to_le16(conn->handle); + hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); + } + ++unlock: + hci_dev_unlock(hdev); + } + +@@ -1194,7 +1223,9 @@ + + BT_DBG("%s status %d", hdev->name, status); + +- clear_bit(HCI_INQUIRY, &hdev->flags); ++ if (test_bit(HCI_MGMT, &hdev->flags) && ++ test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) ++ mgmt_discovering(hdev->id, 0); + + hci_req_complete(hdev, HCI_OP_INQUIRY, status); + +@@ -1214,7 +1245,13 @@ + + hci_dev_lock(hdev); + +- for (; num_rsp; num_rsp--) { ++ if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) { ++ ++ if (test_bit(HCI_MGMT, &hdev->flags)) ++ mgmt_discovering(hdev->id, 1); ++ } ++ ++ for (; num_rsp; num_rsp--, info++) { + bacpy(&data.bdaddr, &info->bdaddr); + data.pscan_rep_mode = info->pscan_rep_mode; + data.pscan_period_mode = info->pscan_period_mode; +@@ -1223,8 +1260,9 @@ + data.clock_offset = info->clock_offset; + data.rssi = 0x00; + data.ssp_mode = 0x00; +- info++; + hci_inquiry_cache_update(hdev, &data); ++ mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0, ++ NULL); + } + + hci_dev_unlock(hdev); +@@ -1428,7 +1466,6 @@ + conn->sec_level = conn->pending_sec_level; + } else { + mgmt_auth_failed(hdev->id, &conn->dst, ev->status); +- conn->sec_level = BT_SECURITY_LOW; + } + + clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); +@@ -1482,13 +1519,23 @@ + + hci_dev_lock(hdev); + ++ if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags)) ++ mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name); ++ + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); +- if (conn && hci_outgoing_auth_needed(hdev, conn)) { ++ if (!conn) ++ goto unlock; ++ ++ if (!hci_outgoing_auth_needed(hdev, conn)) ++ goto unlock; ++ ++ if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + struct hci_cp_auth_requested cp; + cp.handle = __cpu_to_le16(conn->handle); + hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); + } + ++unlock: + hci_dev_unlock(hdev); + } + +@@ -1751,6 +1798,10 @@ + hci_cc_pin_code_neg_reply(hdev, skb); + break; + ++ case HCI_OP_READ_LOCAL_OOB_DATA: ++ hci_cc_read_local_oob_data_reply(hdev, skb); ++ break; ++ + case HCI_OP_LE_READ_BUFFER_SIZE: + hci_cc_le_read_buffer_size(hdev, skb); + break; +@@ -1984,9 +2035,16 @@ + if (!test_bit(HCI_PAIRABLE, &hdev->flags)) + hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, + sizeof(ev->bdaddr), &ev->bdaddr); ++ else if (test_bit(HCI_MGMT, &hdev->flags)) { ++ u8 secure; + +- if (test_bit(HCI_MGMT, &hdev->flags)) +- mgmt_pin_code_request(hdev->id, &ev->bdaddr); ++ if (conn->pending_sec_level == BT_SECURITY_HIGH) ++ secure = 1; ++ else ++ secure = 0; ++ ++ mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure); ++ } + + hci_dev_unlock(hdev); + } +@@ -2015,17 +2073,30 @@ + BT_DBG("%s found key type %u for %s", hdev->name, key->type, + batostr(&ev->bdaddr)); + +- if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && key->type == 0x03) { ++ if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && ++ key->type == HCI_LK_DEBUG_COMBINATION) { + BT_DBG("%s ignoring debug key", hdev->name); + goto not_found; + } + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); ++ if (conn) { ++ if (key->type == HCI_LK_UNAUTH_COMBINATION && ++ conn->auth_type != 0xff && ++ (conn->auth_type & 0x01)) { ++ BT_DBG("%s ignoring unauthenticated key", hdev->name); ++ goto not_found; ++ } ++ ++ if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 && ++ conn->pending_sec_level == BT_SECURITY_HIGH) { ++ BT_DBG("%s ignoring key unauthenticated for high \ ++ security", hdev->name); ++ goto not_found; ++ } + +- if (key->type == 0x04 && conn && conn->auth_type != 0xff && +- (conn->auth_type & 0x01)) { +- BT_DBG("%s ignoring unauthenticated key", hdev->name); +- goto not_found; ++ conn->key_type = key->type; ++ conn->pin_length = key->pin_len; + } + + bacpy(&cp.bdaddr, &ev->bdaddr); +@@ -2057,11 +2128,15 @@ + hci_conn_hold(conn); + conn->disc_timeout = HCI_DISCONN_TIMEOUT; + pin_len = conn->pin_length; ++ ++ if (ev->key_type != HCI_LK_CHANGED_COMBINATION) ++ conn->key_type = ev->key_type; ++ + hci_conn_put(conn); + } + + if (test_bit(HCI_LINK_KEYS, &hdev->flags)) +- hci_add_link_key(hdev, 1, &ev->bdaddr, ev->link_key, ++ hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key, + ev->key_type, pin_len); + + hci_dev_unlock(hdev); +@@ -2136,11 +2211,17 @@ + + hci_dev_lock(hdev); + ++ if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) { ++ ++ if (test_bit(HCI_MGMT, &hdev->flags)) ++ mgmt_discovering(hdev->id, 1); ++ } ++ + if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) { + struct inquiry_info_with_rssi_and_pscan_mode *info; + info = (void *) (skb->data + 1); + +- for (; num_rsp; num_rsp--) { ++ for (; num_rsp; num_rsp--, info++) { + bacpy(&data.bdaddr, &info->bdaddr); + data.pscan_rep_mode = info->pscan_rep_mode; + data.pscan_period_mode = info->pscan_period_mode; +@@ -2149,13 +2230,15 @@ + data.clock_offset = info->clock_offset; + data.rssi = info->rssi; + data.ssp_mode = 0x00; +- info++; + hci_inquiry_cache_update(hdev, &data); ++ mgmt_device_found(hdev->id, &info->bdaddr, ++ info->dev_class, info->rssi, ++ NULL); + } + } else { + struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); + +- for (; num_rsp; num_rsp--) { ++ for (; num_rsp; num_rsp--, info++) { + bacpy(&data.bdaddr, &info->bdaddr); + data.pscan_rep_mode = info->pscan_rep_mode; + data.pscan_period_mode = info->pscan_period_mode; +@@ -2164,8 +2247,10 @@ + data.clock_offset = info->clock_offset; + data.rssi = info->rssi; + data.ssp_mode = 0x00; +- info++; + hci_inquiry_cache_update(hdev, &data); ++ mgmt_device_found(hdev->id, &info->bdaddr, ++ info->dev_class, info->rssi, ++ NULL); + } + } + +@@ -2294,9 +2379,15 @@ + if (!num_rsp) + return; + ++ if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) { ++ ++ if (test_bit(HCI_MGMT, &hdev->flags)) ++ mgmt_discovering(hdev->id, 1); ++ } ++ + hci_dev_lock(hdev); + +- for (; num_rsp; num_rsp--) { ++ for (; num_rsp; num_rsp--, info++) { + bacpy(&data.bdaddr, &info->bdaddr); + data.pscan_rep_mode = info->pscan_rep_mode; + data.pscan_period_mode = info->pscan_period_mode; +@@ -2305,8 +2396,9 @@ + data.clock_offset = info->clock_offset; + data.rssi = info->rssi; + data.ssp_mode = 0x01; +- info++; + hci_inquiry_cache_update(hdev, &data); ++ mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, ++ info->rssi, info->data); + } + + hci_dev_unlock(hdev); +@@ -2326,7 +2418,7 @@ + + /* If remote requests no-bonding follow that lead */ + if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01) +- return 0x00; ++ return conn->remote_auth | (conn->auth_type & 0x01); + + return conn->auth_type; + } +@@ -2355,8 +2447,14 @@ + + bacpy(&cp.bdaddr, &ev->bdaddr); + cp.capability = conn->io_capability; +- cp.oob_data = 0; +- cp.authentication = hci_get_auth_req(conn); ++ conn->auth_type = hci_get_auth_req(conn); ++ cp.authentication = conn->auth_type; ++ ++ if ((conn->out == 0x01 || conn->remote_oob == 0x01) && ++ hci_find_remote_oob_data(hdev, &conn->dst)) ++ cp.oob_data = 0x01; ++ else ++ cp.oob_data = 0x00; + + hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY, + sizeof(cp), &cp); +@@ -2364,7 +2462,7 @@ + struct hci_cp_io_capability_neg_reply cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); +- cp.reason = 0x16; /* Pairing not allowed */ ++ cp.reason = 0x18; /* Pairing not allowed */ + + hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY, + sizeof(cp), &cp); +@@ -2399,14 +2497,67 @@ + struct sk_buff *skb) + { + struct hci_ev_user_confirm_req *ev = (void *) skb->data; ++ int loc_mitm, rem_mitm, confirm_hint = 0; ++ struct hci_conn *conn; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + +- if (test_bit(HCI_MGMT, &hdev->flags)) +- mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey); ++ if (!test_bit(HCI_MGMT, &hdev->flags)) ++ goto unlock; ++ ++ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); ++ if (!conn) ++ goto unlock; ++ ++ loc_mitm = (conn->auth_type & 0x01); ++ rem_mitm = (conn->remote_auth & 0x01); + ++ /* If we require MITM but the remote device can't provide that ++ * (it has NoInputNoOutput) then reject the confirmation ++ * request. The only exception is when we're dedicated bonding ++ * initiators (connect_cfm_cb set) since then we always have the MITM ++ * bit set. */ ++ if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) { ++ BT_DBG("Rejecting request: remote device can't provide MITM"); ++ hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, ++ sizeof(ev->bdaddr), &ev->bdaddr); ++ goto unlock; ++ } ++ ++ /* If no side requires MITM protection; auto-accept */ ++ if ((!loc_mitm || conn->remote_cap == 0x03) && ++ (!rem_mitm || conn->io_capability == 0x03)) { ++ ++ /* If we're not the initiators request authorization to ++ * proceed from user space (mgmt_user_confirm with ++ * confirm_hint set to 1). */ ++ if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { ++ BT_DBG("Confirming auto-accept as acceptor"); ++ confirm_hint = 1; ++ goto confirm; ++ } ++ ++ BT_DBG("Auto-accept of user confirmation with %ums delay", ++ hdev->auto_accept_delay); ++ ++ if (hdev->auto_accept_delay > 0) { ++ int delay = msecs_to_jiffies(hdev->auto_accept_delay); ++ mod_timer(&conn->auto_accept_timer, jiffies + delay); ++ goto unlock; ++ } ++ ++ hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, ++ sizeof(ev->bdaddr), &ev->bdaddr); ++ goto unlock; ++ } ++ ++confirm: ++ mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey, ++ confirm_hint); ++ ++unlock: + hci_dev_unlock(hdev); + } + +@@ -2453,6 +2604,41 @@ + hci_dev_unlock(hdev); + } + ++static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, ++ struct sk_buff *skb) ++{ ++ struct hci_ev_remote_oob_data_request *ev = (void *) skb->data; ++ struct oob_data *data; ++ ++ BT_DBG("%s", hdev->name); ++ ++ hci_dev_lock(hdev); ++ ++ if (!test_bit(HCI_MGMT, &hdev->flags)) ++ goto unlock; ++ ++ data = hci_find_remote_oob_data(hdev, &ev->bdaddr); ++ if (data) { ++ struct hci_cp_remote_oob_data_reply cp; ++ ++ bacpy(&cp.bdaddr, &ev->bdaddr); ++ memcpy(cp.hash, data->hash, sizeof(cp.hash)); ++ memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer)); ++ ++ hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp), ++ &cp); ++ } else { ++ struct hci_cp_remote_oob_data_neg_reply cp; ++ ++ bacpy(&cp.bdaddr, &ev->bdaddr); ++ hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp), ++ &cp); ++ } ++ ++unlock: ++ hci_dev_unlock(hdev); ++} ++ + static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) + { + struct hci_ev_le_conn_complete *ev = (void *) skb->data; +@@ -2655,6 +2841,10 @@ + hci_le_meta_evt(hdev, skb); + break; + ++ case HCI_EV_REMOTE_OOB_DATA_REQUEST: ++ hci_remote_oob_data_request_evt(hdev, skb); ++ break; ++ + default: + BT_DBG("%s event 0x%x", hdev->name, event); + break; +diff -Naur linux-2.6.39-rc6/net/bluetooth/hci_sysfs.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/hci_sysfs.c +--- linux-2.6.39-rc6/net/bluetooth/hci_sysfs.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/hci_sysfs.c 2011-05-05 23:30:21.238873693 +0200 +@@ -216,13 +216,13 @@ + static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) + { + struct hci_dev *hdev = dev_get_drvdata(dev); +- char name[249]; ++ char name[HCI_MAX_NAME_LENGTH + 1]; + int i; + +- for (i = 0; i < 248; i++) ++ for (i = 0; i < HCI_MAX_NAME_LENGTH; i++) + name[i] = hdev->dev_name[i]; + +- name[248] = '\0'; ++ name[HCI_MAX_NAME_LENGTH] = '\0'; + return sprintf(buf, "%s\n", name); + } + +@@ -277,10 +277,12 @@ + static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) + { + struct hci_dev *hdev = dev_get_drvdata(dev); +- unsigned long val; ++ unsigned int val; ++ int rv; + +- if (strict_strtoul(buf, 0, &val) < 0) +- return -EINVAL; ++ rv = kstrtouint(buf, 0, &val); ++ if (rv < 0) ++ return rv; + + if (val != 0 && (val < 500 || val > 3600000)) + return -EINVAL; +@@ -299,15 +301,14 @@ + static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) + { + struct hci_dev *hdev = dev_get_drvdata(dev); +- unsigned long val; +- +- if (strict_strtoul(buf, 0, &val) < 0) +- return -EINVAL; ++ u16 val; ++ int rv; + +- if (val < 0x0002 || val > 0xFFFE || val % 2) +- return -EINVAL; ++ rv = kstrtou16(buf, 0, &val); ++ if (rv < 0) ++ return rv; + +- if (val < hdev->sniff_min_interval) ++ if (val == 0 || val % 2 || val < hdev->sniff_min_interval) + return -EINVAL; + + hdev->sniff_max_interval = val; +@@ -324,15 +325,14 @@ + static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) + { + struct hci_dev *hdev = dev_get_drvdata(dev); +- unsigned long val; ++ u16 val; ++ int rv; + +- if (strict_strtoul(buf, 0, &val) < 0) +- return -EINVAL; +- +- if (val < 0x0002 || val > 0xFFFE || val % 2) +- return -EINVAL; ++ rv = kstrtou16(buf, 0, &val); ++ if (rv < 0) ++ return rv; + +- if (val > hdev->sniff_max_interval) ++ if (val == 0 || val % 2 || val > hdev->sniff_max_interval) + return -EINVAL; + + hdev->sniff_min_interval = val; +@@ -511,6 +511,35 @@ + .release = single_release, + }; + ++static int auto_accept_delay_set(void *data, u64 val) ++{ ++ struct hci_dev *hdev = data; ++ ++ hci_dev_lock_bh(hdev); ++ ++ hdev->auto_accept_delay = val; ++ ++ hci_dev_unlock_bh(hdev); ++ ++ return 0; ++} ++ ++static int auto_accept_delay_get(void *data, u64 *val) ++{ ++ struct hci_dev *hdev = data; ++ ++ hci_dev_lock_bh(hdev); ++ ++ *val = hdev->auto_accept_delay; ++ ++ hci_dev_unlock_bh(hdev); ++ ++ return 0; ++} ++ ++DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get, ++ auto_accept_delay_set, "%llu\n"); ++ + int hci_register_sysfs(struct hci_dev *hdev) + { + struct device *dev = &hdev->dev; +@@ -545,6 +574,8 @@ + + debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); + ++ debugfs_create_file("auto_accept_delay", 0444, hdev->debugfs, hdev, ++ &auto_accept_delay_fops); + return 0; + } + +diff -Naur linux-2.6.39-rc6/net/bluetooth/hidp/core.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/hidp/core.c +--- linux-2.6.39-rc6/net/bluetooth/hidp/core.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/hidp/core.c 2011-05-05 23:30:21.238873693 +0200 +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -55,22 +56,24 @@ + static LIST_HEAD(hidp_session_list); + + static unsigned char hidp_keycode[256] = { +- 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, +- 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, +- 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, +- 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, +- 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, +- 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, +- 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, +- 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, +- 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, +- 122,123, 90, 91, 85, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, +- 150,158,159,128,136,177,178,176,142,152,173,140 ++ 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, ++ 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, ++ 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, ++ 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52, ++ 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88, ++ 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69, ++ 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, ++ 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190, ++ 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135, ++ 136, 113, 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94, ++ 95, 0, 0, 0, 122, 123, 90, 91, 85, 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, ++ 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115, ++ 114, 113, 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140 + }; + + static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; +@@ -461,8 +464,7 @@ + { + struct hidp_session *session = (struct hidp_session *) arg; + +- atomic_inc(&session->terminate); +- hidp_schedule(session); ++ kthread_stop(session->task); + } + + static void hidp_set_timer(struct hidp_session *session) +@@ -533,9 +535,7 @@ + skb_queue_purge(&session->ctrl_transmit); + skb_queue_purge(&session->intr_transmit); + +- /* Kill session thread */ +- atomic_inc(&session->terminate); +- hidp_schedule(session); ++ kthread_stop(session->task); + } + } + +@@ -694,22 +694,10 @@ + struct sock *ctrl_sk = session->ctrl_sock->sk; + struct sock *intr_sk = session->intr_sock->sk; + struct sk_buff *skb; +- int vendor = 0x0000, product = 0x0000; + wait_queue_t ctrl_wait, intr_wait; + + BT_DBG("session %p", session); + +- if (session->input) { +- vendor = session->input->id.vendor; +- product = session->input->id.product; +- } +- +- if (session->hid) { +- vendor = session->hid->vendor; +- product = session->hid->product; +- } +- +- daemonize("khidpd_%04x%04x", vendor, product); + set_user_nice(current, -15); + + init_waitqueue_entry(&ctrl_wait, current); +@@ -718,10 +706,11 @@ + add_wait_queue(sk_sleep(intr_sk), &intr_wait); + session->waiting_for_startup = 0; + wake_up_interruptible(&session->startup_queue); +- while (!atomic_read(&session->terminate)) { ++ while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + +- if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED) ++ if (ctrl_sk->sk_state != BT_CONNECTED || ++ intr_sk->sk_state != BT_CONNECTED) + break; + + while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { +@@ -965,6 +954,7 @@ + int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) + { + struct hidp_session *session, *s; ++ int vendor, product; + int err; + + BT_DBG(""); +@@ -989,8 +979,10 @@ + + bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst); + +- session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu); +- session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu); ++ session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu, ++ l2cap_pi(ctrl_sock->sk)->chan->imtu); ++ session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu, ++ l2cap_pi(intr_sock->sk)->chan->imtu); + + BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu); + +@@ -1026,9 +1018,24 @@ + + hidp_set_timer(session); + +- err = kernel_thread(hidp_session, session, CLONE_KERNEL); +- if (err < 0) ++ if (session->hid) { ++ vendor = session->hid->vendor; ++ product = session->hid->product; ++ } else if (session->input) { ++ vendor = session->input->id.vendor; ++ product = session->input->id.product; ++ } else { ++ vendor = 0x0000; ++ product = 0x0000; ++ } ++ ++ session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x", ++ vendor, product); ++ if (IS_ERR(session->task)) { ++ err = PTR_ERR(session->task); + goto unlink; ++ } ++ + while (session->waiting_for_startup) { + wait_event_interruptible(session->startup_queue, + !session->waiting_for_startup); +@@ -1053,8 +1060,7 @@ + err_add_device: + hid_destroy_device(session->hid); + session->hid = NULL; +- atomic_inc(&session->terminate); +- hidp_schedule(session); ++ kthread_stop(session->task); + + unlink: + hidp_del_timer(session); +@@ -1105,13 +1111,7 @@ + skb_queue_purge(&session->ctrl_transmit); + skb_queue_purge(&session->intr_transmit); + +- /* Wakeup user-space polling for socket errors */ +- session->intr_sock->sk->sk_err = EUNATCH; +- session->ctrl_sock->sk->sk_err = EUNATCH; +- +- /* Kill session thread */ +- atomic_inc(&session->terminate); +- hidp_schedule(session); ++ kthread_stop(session->task); + } + } else + err = -ENOENT; +diff -Naur linux-2.6.39-rc6/net/bluetooth/hidp/hidp.h linux-2.6.39-rc6.rtl8192se/net/bluetooth/hidp/hidp.h +--- linux-2.6.39-rc6/net/bluetooth/hidp/hidp.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/hidp/hidp.h 2011-05-05 23:30:21.239873705 +0200 +@@ -84,8 +84,8 @@ + #define HIDP_WAITING_FOR_SEND_ACK 11 + + struct hidp_connadd_req { +- int ctrl_sock; // Connected control socket +- int intr_sock; // Connteted interrupt socket ++ int ctrl_sock; /* Connected control socket */ ++ int intr_sock; /* Connected interrupt socket */ + __u16 parser; + __u16 rd_size; + __u8 __user *rd_data; +@@ -142,7 +142,7 @@ + uint ctrl_mtu; + uint intr_mtu; + +- atomic_t terminate; ++ struct task_struct *task; + + unsigned char keys[8]; + unsigned char leds; +diff -Naur linux-2.6.39-rc6/net/bluetooth/hidp/sock.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/hidp/sock.c +--- linux-2.6.39-rc6/net/bluetooth/hidp/sock.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/hidp/sock.c 2011-05-05 23:30:21.241873729 +0200 +@@ -85,7 +85,8 @@ + return err; + } + +- if (csock->sk->sk_state != BT_CONNECTED || isock->sk->sk_state != BT_CONNECTED) { ++ if (csock->sk->sk_state != BT_CONNECTED || ++ isock->sk->sk_state != BT_CONNECTED) { + sockfd_put(csock); + sockfd_put(isock); + return -EBADFD; +@@ -140,8 +141,8 @@ + + #ifdef CONFIG_COMPAT + struct compat_hidp_connadd_req { +- int ctrl_sock; // Connected control socket +- int intr_sock; // Connteted interrupt socket ++ int ctrl_sock; /* Connected control socket */ ++ int intr_sock; /* Connected interrupt socket */ + __u16 parser; + __u16 rd_size; + compat_uptr_t rd_data; +diff -Naur linux-2.6.39-rc6/net/bluetooth/l2cap_core.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/l2cap_core.c +--- linux-2.6.39-rc6/net/bluetooth/l2cap_core.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/l2cap_core.c 2011-05-05 23:30:21.196873185 +0200 +@@ -70,160 +70,160 @@ + + static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, + u8 code, u8 ident, u16 dlen, void *data); ++static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); + + static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); + + /* ---- L2CAP channels ---- */ +-static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) ++static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) + { +- struct sock *s; +- for (s = l->head; s; s = l2cap_pi(s)->next_c) { +- if (l2cap_pi(s)->dcid == cid) +- break; ++ struct l2cap_chan *c; ++ ++ list_for_each_entry(c, &conn->chan_l, list) { ++ if (c->dcid == cid) ++ return c; + } +- return s; ++ return NULL; ++ + } + +-static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) ++static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) + { +- struct sock *s; +- for (s = l->head; s; s = l2cap_pi(s)->next_c) { +- if (l2cap_pi(s)->scid == cid) +- break; ++ struct l2cap_chan *c; ++ ++ list_for_each_entry(c, &conn->chan_l, list) { ++ if (c->scid == cid) ++ return c; + } +- return s; ++ return NULL; + } + + /* Find channel with given SCID. + * Returns locked socket */ +-static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) ++static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) + { +- struct sock *s; +- read_lock(&l->lock); +- s = __l2cap_get_chan_by_scid(l, cid); +- if (s) +- bh_lock_sock(s); +- read_unlock(&l->lock); +- return s; ++ struct l2cap_chan *c; ++ ++ read_lock(&conn->chan_lock); ++ c = __l2cap_get_chan_by_scid(conn, cid); ++ if (c) ++ bh_lock_sock(c->sk); ++ read_unlock(&conn->chan_lock); ++ return c; + } + +-static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) ++static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) + { +- struct sock *s; +- for (s = l->head; s; s = l2cap_pi(s)->next_c) { +- if (l2cap_pi(s)->ident == ident) +- break; ++ struct l2cap_chan *c; ++ ++ list_for_each_entry(c, &conn->chan_l, list) { ++ if (c->ident == ident) ++ return c; + } +- return s; ++ return NULL; + } + +-static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) ++static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) + { +- struct sock *s; +- read_lock(&l->lock); +- s = __l2cap_get_chan_by_ident(l, ident); +- if (s) +- bh_lock_sock(s); +- read_unlock(&l->lock); +- return s; ++ struct l2cap_chan *c; ++ ++ read_lock(&conn->chan_lock); ++ c = __l2cap_get_chan_by_ident(conn, ident); ++ if (c) ++ bh_lock_sock(c->sk); ++ read_unlock(&conn->chan_lock); ++ return c; + } + +-static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) ++static u16 l2cap_alloc_cid(struct l2cap_conn *conn) + { + u16 cid = L2CAP_CID_DYN_START; + + for (; cid < L2CAP_CID_DYN_END; cid++) { +- if (!__l2cap_get_chan_by_scid(l, cid)) ++ if (!__l2cap_get_chan_by_scid(conn, cid)) + return cid; + } + + return 0; + } + +-static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) ++struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) + { +- sock_hold(sk); ++ struct l2cap_chan *chan; + +- if (l->head) +- l2cap_pi(l->head)->prev_c = sk; ++ chan = kzalloc(sizeof(*chan), GFP_ATOMIC); ++ if (!chan) ++ return NULL; ++ ++ chan->sk = sk; + +- l2cap_pi(sk)->next_c = l->head; +- l2cap_pi(sk)->prev_c = NULL; +- l->head = sk; ++ return chan; + } + +-static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) ++void l2cap_chan_free(struct l2cap_chan *chan) + { +- struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; +- +- write_lock_bh(&l->lock); +- if (sk == l->head) +- l->head = next; +- +- if (next) +- l2cap_pi(next)->prev_c = prev; +- if (prev) +- l2cap_pi(prev)->next_c = next; +- write_unlock_bh(&l->lock); +- +- __sock_put(sk); ++ kfree(chan); + } + +-static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) ++static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) + { +- struct l2cap_chan_list *l = &conn->chan_list; ++ struct sock *sk = chan->sk; + + BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, +- l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); ++ chan->psm, chan->dcid); + + conn->disc_reason = 0x13; + +- l2cap_pi(sk)->conn = conn; ++ chan->conn = conn; + + if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) { + if (conn->hcon->type == LE_LINK) { + /* LE connection */ +- l2cap_pi(sk)->omtu = L2CAP_LE_DEFAULT_MTU; +- l2cap_pi(sk)->scid = L2CAP_CID_LE_DATA; +- l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA; ++ chan->omtu = L2CAP_LE_DEFAULT_MTU; ++ chan->scid = L2CAP_CID_LE_DATA; ++ chan->dcid = L2CAP_CID_LE_DATA; + } else { + /* Alloc CID for connection-oriented socket */ +- l2cap_pi(sk)->scid = l2cap_alloc_cid(l); +- l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; ++ chan->scid = l2cap_alloc_cid(conn); ++ chan->omtu = L2CAP_DEFAULT_MTU; + } + } else if (sk->sk_type == SOCK_DGRAM) { + /* Connectionless socket */ +- l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS; +- l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS; +- l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; ++ chan->scid = L2CAP_CID_CONN_LESS; ++ chan->dcid = L2CAP_CID_CONN_LESS; ++ chan->omtu = L2CAP_DEFAULT_MTU; + } else { + /* Raw socket can send/recv signalling messages only */ +- l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING; +- l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING; +- l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; ++ chan->scid = L2CAP_CID_SIGNALING; ++ chan->dcid = L2CAP_CID_SIGNALING; ++ chan->omtu = L2CAP_DEFAULT_MTU; + } + +- __l2cap_chan_link(l, sk); ++ sock_hold(sk); + +- if (parent) +- bt_accept_enqueue(parent, sk); ++ list_add(&chan->list, &conn->chan_l); + } + + /* Delete channel. + * Must be called on the locked socket. */ +-void l2cap_chan_del(struct sock *sk, int err) ++void l2cap_chan_del(struct l2cap_chan *chan, int err) + { +- struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct sock *sk = chan->sk; ++ struct l2cap_conn *conn = chan->conn; + struct sock *parent = bt_sk(sk)->parent; + + l2cap_sock_clear_timer(sk); + +- BT_DBG("sk %p, conn %p, err %d", sk, conn, err); ++ BT_DBG("chan %p, conn %p, err %d", chan, conn, err); + + if (conn) { +- /* Unlink from channel list */ +- l2cap_chan_unlink(&conn->chan_list, sk); +- l2cap_pi(sk)->conn = NULL; ++ /* Delete from channel list */ ++ write_lock_bh(&conn->chan_lock); ++ list_del(&chan->list); ++ write_unlock_bh(&conn->chan_lock); ++ __sock_put(sk); ++ ++ chan->conn = NULL; + hci_conn_put(conn->hcon); + } + +@@ -239,29 +239,35 @@ + } else + sk->sk_state_change(sk); + +- skb_queue_purge(TX_QUEUE(sk)); ++ if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE && ++ chan->conf_state & L2CAP_CONF_INPUT_DONE)) ++ return; ++ ++ skb_queue_purge(&chan->tx_q); + +- if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { ++ if (chan->mode == L2CAP_MODE_ERTM) { + struct srej_list *l, *tmp; + +- del_timer(&l2cap_pi(sk)->retrans_timer); +- del_timer(&l2cap_pi(sk)->monitor_timer); +- del_timer(&l2cap_pi(sk)->ack_timer); ++ del_timer(&chan->retrans_timer); ++ del_timer(&chan->monitor_timer); ++ del_timer(&chan->ack_timer); + +- skb_queue_purge(SREJ_QUEUE(sk)); +- skb_queue_purge(BUSY_QUEUE(sk)); ++ skb_queue_purge(&chan->srej_q); ++ skb_queue_purge(&chan->busy_q); + +- list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) { ++ list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { + list_del(&l->list); + kfree(l); + } + } + } + +-static inline u8 l2cap_get_auth_type(struct sock *sk) ++static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) + { ++ struct sock *sk = chan->sk; ++ + if (sk->sk_type == SOCK_RAW) { +- switch (l2cap_pi(sk)->sec_level) { ++ switch (chan->sec_level) { + case BT_SECURITY_HIGH: + return HCI_AT_DEDICATED_BONDING_MITM; + case BT_SECURITY_MEDIUM: +@@ -269,16 +275,16 @@ + default: + return HCI_AT_NO_BONDING; + } +- } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) { +- if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW) +- l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; ++ } else if (chan->psm == cpu_to_le16(0x0001)) { ++ if (chan->sec_level == BT_SECURITY_LOW) ++ chan->sec_level = BT_SECURITY_SDP; + +- if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) ++ if (chan->sec_level == BT_SECURITY_HIGH) + return HCI_AT_NO_BONDING_MITM; + else + return HCI_AT_NO_BONDING; + } else { +- switch (l2cap_pi(sk)->sec_level) { ++ switch (chan->sec_level) { + case BT_SECURITY_HIGH: + return HCI_AT_GENERAL_BONDING_MITM; + case BT_SECURITY_MEDIUM: +@@ -290,15 +296,14 @@ + } + + /* Service level security */ +-static inline int l2cap_check_security(struct sock *sk) ++static inline int l2cap_check_security(struct l2cap_chan *chan) + { +- struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct l2cap_conn *conn = chan->conn; + __u8 auth_type; + +- auth_type = l2cap_get_auth_type(sk); ++ auth_type = l2cap_get_auth_type(chan); + +- return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level, +- auth_type); ++ return hci_conn_security(conn->hcon, chan->sec_level, auth_type); + } + + u8 l2cap_get_ident(struct l2cap_conn *conn) +@@ -341,11 +346,12 @@ + hci_send_acl(conn->hcon, skb, flags); + } + +-static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) ++static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) + { + struct sk_buff *skb; + struct l2cap_hdr *lh; +- struct l2cap_conn *conn = pi->conn; ++ struct l2cap_pinfo *pi = l2cap_pi(chan->sk); ++ struct l2cap_conn *conn = chan->conn; + struct sock *sk = (struct sock *)pi; + int count, hlen = L2CAP_HDR_SIZE + 2; + u8 flags; +@@ -353,22 +359,22 @@ + if (sk->sk_state != BT_CONNECTED) + return; + +- if (pi->fcs == L2CAP_FCS_CRC16) ++ if (chan->fcs == L2CAP_FCS_CRC16) + hlen += 2; + +- BT_DBG("pi %p, control 0x%2.2x", pi, control); ++ BT_DBG("chan %p, control 0x%2.2x", chan, control); + + count = min_t(unsigned int, conn->mtu, hlen); + control |= L2CAP_CTRL_FRAME_TYPE; + +- if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { ++ if (chan->conn_state & L2CAP_CONN_SEND_FBIT) { + control |= L2CAP_CTRL_FINAL; +- pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; ++ chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; + } + +- if (pi->conn_state & L2CAP_CONN_SEND_PBIT) { ++ if (chan->conn_state & L2CAP_CONN_SEND_PBIT) { + control |= L2CAP_CTRL_POLL; +- pi->conn_state &= ~L2CAP_CONN_SEND_PBIT; ++ chan->conn_state &= ~L2CAP_CONN_SEND_PBIT; + } + + skb = bt_skb_alloc(count, GFP_ATOMIC); +@@ -377,10 +383,10 @@ + + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE); +- lh->cid = cpu_to_le16(pi->dcid); ++ lh->cid = cpu_to_le16(chan->dcid); + put_unaligned_le16(control, skb_put(skb, 2)); + +- if (pi->fcs == L2CAP_FCS_CRC16) { ++ if (chan->fcs == L2CAP_FCS_CRC16) { + u16 fcs = crc16(0, (u8 *)lh, count - 2); + put_unaligned_le16(fcs, skb_put(skb, 2)); + } +@@ -390,45 +396,46 @@ + else + flags = ACL_START; + +- hci_send_acl(pi->conn->hcon, skb, flags); ++ hci_send_acl(chan->conn->hcon, skb, flags); + } + +-static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control) ++static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control) + { +- if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { ++ if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { + control |= L2CAP_SUPER_RCV_NOT_READY; +- pi->conn_state |= L2CAP_CONN_RNR_SENT; ++ chan->conn_state |= L2CAP_CONN_RNR_SENT; + } else + control |= L2CAP_SUPER_RCV_READY; + +- control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; ++ control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + +- l2cap_send_sframe(pi, control); ++ l2cap_send_sframe(chan, control); + } + +-static inline int __l2cap_no_conn_pending(struct sock *sk) ++static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) + { +- return !(l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND); ++ return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND); + } + +-static void l2cap_do_start(struct sock *sk) ++static void l2cap_do_start(struct l2cap_chan *chan) + { +- struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct l2cap_conn *conn = chan->conn; + + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { + if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) + return; + +- if (l2cap_check_security(sk) && __l2cap_no_conn_pending(sk)) { ++ if (l2cap_check_security(chan) && ++ __l2cap_no_conn_pending(chan)) { + struct l2cap_conn_req req; +- req.scid = cpu_to_le16(l2cap_pi(sk)->scid); +- req.psm = l2cap_pi(sk)->psm; ++ req.scid = cpu_to_le16(chan->scid); ++ req.psm = chan->psm; + +- l2cap_pi(sk)->ident = l2cap_get_ident(conn); +- l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; ++ chan->ident = l2cap_get_ident(conn); ++ chan->conf_state |= L2CAP_CONF_CONNECT_PEND; + +- l2cap_send_cmd(conn, l2cap_pi(sk)->ident, +- L2CAP_CONN_REQ, sizeof(req), &req); ++ l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, ++ sizeof(req), &req); + } + } else { + struct l2cap_info_req req; +@@ -461,23 +468,24 @@ + } + } + +-void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) ++void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err) + { ++ struct sock *sk; + struct l2cap_disconn_req req; + + if (!conn) + return; + +- skb_queue_purge(TX_QUEUE(sk)); ++ sk = chan->sk; + +- if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { +- del_timer(&l2cap_pi(sk)->retrans_timer); +- del_timer(&l2cap_pi(sk)->monitor_timer); +- del_timer(&l2cap_pi(sk)->ack_timer); ++ if (chan->mode == L2CAP_MODE_ERTM) { ++ del_timer(&chan->retrans_timer); ++ del_timer(&chan->monitor_timer); ++ del_timer(&chan->ack_timer); + } + +- req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); +- req.scid = cpu_to_le16(l2cap_pi(sk)->scid); ++ req.dcid = cpu_to_le16(chan->dcid); ++ req.scid = cpu_to_le16(chan->scid); + l2cap_send_cmd(conn, l2cap_get_ident(conn), + L2CAP_DISCONN_REQ, sizeof(req), &req); + +@@ -488,17 +496,15 @@ + /* ---- L2CAP connections ---- */ + static void l2cap_conn_start(struct l2cap_conn *conn) + { +- struct l2cap_chan_list *l = &conn->chan_list; +- struct sock_del_list del, *tmp1, *tmp2; +- struct sock *sk; ++ struct l2cap_chan *chan, *tmp; + + BT_DBG("conn %p", conn); + +- INIT_LIST_HEAD(&del.list); ++ read_lock(&conn->chan_lock); + +- read_lock(&l->lock); ++ list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { ++ struct sock *sk = chan->sk; + +- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + bh_lock_sock(sk); + + if (sk->sk_type != SOCK_SEQPACKET && +@@ -510,40 +516,41 @@ + if (sk->sk_state == BT_CONNECT) { + struct l2cap_conn_req req; + +- if (!l2cap_check_security(sk) || +- !__l2cap_no_conn_pending(sk)) { ++ if (!l2cap_check_security(chan) || ++ !__l2cap_no_conn_pending(chan)) { + bh_unlock_sock(sk); + continue; + } + +- if (!l2cap_mode_supported(l2cap_pi(sk)->mode, ++ if (!l2cap_mode_supported(chan->mode, + conn->feat_mask) +- && l2cap_pi(sk)->conf_state & ++ && chan->conf_state & + L2CAP_CONF_STATE2_DEVICE) { +- tmp1 = kzalloc(sizeof(struct sock_del_list), +- GFP_ATOMIC); +- tmp1->sk = sk; +- list_add_tail(&tmp1->list, &del.list); ++ /* __l2cap_sock_close() calls list_del(chan) ++ * so release the lock */ ++ read_unlock_bh(&conn->chan_lock); ++ __l2cap_sock_close(sk, ECONNRESET); ++ read_lock_bh(&conn->chan_lock); + bh_unlock_sock(sk); + continue; + } + +- req.scid = cpu_to_le16(l2cap_pi(sk)->scid); +- req.psm = l2cap_pi(sk)->psm; ++ req.scid = cpu_to_le16(chan->scid); ++ req.psm = chan->psm; + +- l2cap_pi(sk)->ident = l2cap_get_ident(conn); +- l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; ++ chan->ident = l2cap_get_ident(conn); ++ chan->conf_state |= L2CAP_CONF_CONNECT_PEND; + +- l2cap_send_cmd(conn, l2cap_pi(sk)->ident, +- L2CAP_CONN_REQ, sizeof(req), &req); ++ l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, ++ sizeof(req), &req); + + } else if (sk->sk_state == BT_CONNECT2) { + struct l2cap_conn_rsp rsp; + char buf[128]; +- rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); +- rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); ++ rsp.scid = cpu_to_le16(chan->dcid); ++ rsp.dcid = cpu_to_le16(chan->scid); + +- if (l2cap_check_security(sk)) { ++ if (l2cap_check_security(chan)) { + if (bt_sk(sk)->defer_setup) { + struct sock *parent = bt_sk(sk)->parent; + rsp.result = cpu_to_le16(L2CAP_CR_PEND); +@@ -560,33 +567,25 @@ + rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); + } + +- l2cap_send_cmd(conn, l2cap_pi(sk)->ident, +- L2CAP_CONN_RSP, sizeof(rsp), &rsp); ++ l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, ++ sizeof(rsp), &rsp); + +- if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT || ++ if (chan->conf_state & L2CAP_CONF_REQ_SENT || + rsp.result != L2CAP_CR_SUCCESS) { + bh_unlock_sock(sk); + continue; + } + +- l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; ++ chan->conf_state |= L2CAP_CONF_REQ_SENT; + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, +- l2cap_build_conf_req(sk, buf), buf); +- l2cap_pi(sk)->num_conf_req++; ++ l2cap_build_conf_req(chan, buf), buf); ++ chan->num_conf_req++; + } + + bh_unlock_sock(sk); + } + +- read_unlock(&l->lock); +- +- list_for_each_entry_safe(tmp1, tmp2, &del.list, list) { +- bh_lock_sock(tmp1->sk); +- __l2cap_sock_close(tmp1->sk, ECONNRESET); +- bh_unlock_sock(tmp1->sk); +- list_del(&tmp1->list); +- kfree(tmp1); +- } ++ read_unlock(&conn->chan_lock); + } + + /* Find socket with cid and source bdaddr. +@@ -594,16 +593,18 @@ + */ + static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) + { +- struct sock *s, *sk = NULL, *sk1 = NULL; ++ struct sock *sk = NULL, *sk1 = NULL; + struct hlist_node *node; + + read_lock(&l2cap_sk_list.lock); + + sk_for_each(sk, node, &l2cap_sk_list.head) { ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; ++ + if (state && sk->sk_state != state) + continue; + +- if (l2cap_pi(sk)->scid == cid) { ++ if (chan->scid == cid) { + /* Exact match. */ + if (!bacmp(&bt_sk(sk)->src, src)) + break; +@@ -613,18 +614,16 @@ + sk1 = sk; + } + } +- s = node ? sk : sk1; +- if (s) +- bh_lock_sock(s); ++ + read_unlock(&l2cap_sk_list.lock); + +- return s; ++ return node ? sk : sk1; + } + + static void l2cap_le_conn_ready(struct l2cap_conn *conn) + { +- struct l2cap_chan_list *list = &conn->chan_list; +- struct sock *parent, *uninitialized_var(sk); ++ struct sock *parent, *sk; ++ struct l2cap_chan *chan; + + BT_DBG(""); + +@@ -634,6 +633,8 @@ + if (!parent) + return; + ++ bh_lock_sock(parent); ++ + /* Check for backlog size */ + if (sk_acceptq_is_full(parent)) { + BT_DBG("backlog full %d", parent->sk_ack_backlog); +@@ -644,22 +645,33 @@ + if (!sk) + goto clean; + +- write_lock_bh(&list->lock); ++ chan = l2cap_chan_alloc(sk); ++ if (!chan) { ++ l2cap_sock_kill(sk); ++ goto clean; ++ } ++ ++ l2cap_pi(sk)->chan = chan; ++ ++ write_lock_bh(&conn->chan_lock); + + hci_conn_hold(conn->hcon); + + l2cap_sock_init(sk, parent); ++ + bacpy(&bt_sk(sk)->src, conn->src); + bacpy(&bt_sk(sk)->dst, conn->dst); + +- __l2cap_chan_add(conn, sk, parent); ++ bt_accept_enqueue(parent, sk); ++ ++ __l2cap_chan_add(conn, chan); + + l2cap_sock_set_timer(sk, sk->sk_sndtimeo); + + sk->sk_state = BT_CONNECTED; + parent->sk_data_ready(parent, 0); + +- write_unlock_bh(&list->lock); ++ write_unlock_bh(&conn->chan_lock); + + clean: + bh_unlock_sock(parent); +@@ -667,17 +679,18 @@ + + static void l2cap_conn_ready(struct l2cap_conn *conn) + { +- struct l2cap_chan_list *l = &conn->chan_list; +- struct sock *sk; ++ struct l2cap_chan *chan; + + BT_DBG("conn %p", conn); + + if (!conn->hcon->out && conn->hcon->type == LE_LINK) + l2cap_le_conn_ready(conn); + +- read_lock(&l->lock); ++ read_lock(&conn->chan_lock); ++ ++ list_for_each_entry(chan, &conn->chan_l, list) { ++ struct sock *sk = chan->sk; + +- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + bh_lock_sock(sk); + + if (conn->hcon->type == LE_LINK) { +@@ -692,30 +705,31 @@ + sk->sk_state = BT_CONNECTED; + sk->sk_state_change(sk); + } else if (sk->sk_state == BT_CONNECT) +- l2cap_do_start(sk); ++ l2cap_do_start(chan); + + bh_unlock_sock(sk); + } + +- read_unlock(&l->lock); ++ read_unlock(&conn->chan_lock); + } + + /* Notify sockets that we cannot guaranty reliability anymore */ + static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) + { +- struct l2cap_chan_list *l = &conn->chan_list; +- struct sock *sk; ++ struct l2cap_chan *chan; + + BT_DBG("conn %p", conn); + +- read_lock(&l->lock); ++ read_lock(&conn->chan_lock); + +- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { +- if (l2cap_pi(sk)->force_reliable) ++ list_for_each_entry(chan, &conn->chan_l, list) { ++ struct sock *sk = chan->sk; ++ ++ if (chan->force_reliable) + sk->sk_err = err; + } + +- read_unlock(&l->lock); ++ read_unlock(&conn->chan_lock); + } + + static void l2cap_info_timeout(unsigned long arg) +@@ -755,7 +769,9 @@ + conn->feat_mask = 0; + + spin_lock_init(&conn->lock); +- rwlock_init(&conn->chan_list.lock); ++ rwlock_init(&conn->chan_lock); ++ ++ INIT_LIST_HEAD(&conn->chan_l); + + if (hcon->type != LE_LINK) + setup_timer(&conn->info_timer, l2cap_info_timeout, +@@ -769,6 +785,7 @@ + static void l2cap_conn_del(struct hci_conn *hcon, int err) + { + struct l2cap_conn *conn = hcon->l2cap_data; ++ struct l2cap_chan *chan, *l; + struct sock *sk; + + if (!conn) +@@ -779,9 +796,10 @@ + kfree_skb(conn->rx_skb); + + /* Kill channels */ +- while ((sk = conn->chan_list.head)) { ++ list_for_each_entry_safe(chan, l, &conn->chan_l, list) { ++ sk = chan->sk; + bh_lock_sock(sk); +- l2cap_chan_del(sk, err); ++ l2cap_chan_del(chan, err); + bh_unlock_sock(sk); + l2cap_sock_kill(sk); + } +@@ -793,12 +811,11 @@ + kfree(conn); + } + +-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) ++static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) + { +- struct l2cap_chan_list *l = &conn->chan_list; +- write_lock_bh(&l->lock); +- __l2cap_chan_add(conn, sk, parent); +- write_unlock_bh(&l->lock); ++ write_lock_bh(&conn->chan_lock); ++ __l2cap_chan_add(conn, chan); ++ write_unlock_bh(&conn->chan_lock); + } + + /* ---- Socket interface ---- */ +@@ -814,10 +831,12 @@ + read_lock(&l2cap_sk_list.lock); + + sk_for_each(sk, node, &l2cap_sk_list.head) { ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; ++ + if (state && sk->sk_state != state) + continue; + +- if (l2cap_pi(sk)->psm == psm) { ++ if (chan->psm == psm) { + /* Exact match. */ + if (!bacmp(&bt_sk(sk)->src, src)) + break; +@@ -833,8 +852,9 @@ + return node ? sk : sk1; + } + +-int l2cap_do_connect(struct sock *sk) ++int l2cap_chan_connect(struct l2cap_chan *chan) + { ++ struct sock *sk = chan->sk; + bdaddr_t *src = &bt_sk(sk)->src; + bdaddr_t *dst = &bt_sk(sk)->dst; + struct l2cap_conn *conn; +@@ -844,7 +864,7 @@ + int err; + + BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), +- l2cap_pi(sk)->psm); ++ chan->psm); + + hdev = hci_get_route(dst, src); + if (!hdev) +@@ -852,14 +872,14 @@ + + hci_dev_lock_bh(hdev); + +- auth_type = l2cap_get_auth_type(sk); ++ auth_type = l2cap_get_auth_type(chan); + +- if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA) ++ if (chan->dcid == L2CAP_CID_LE_DATA) + hcon = hci_connect(hdev, LE_LINK, dst, +- l2cap_pi(sk)->sec_level, auth_type); ++ chan->sec_level, auth_type); + else + hcon = hci_connect(hdev, ACL_LINK, dst, +- l2cap_pi(sk)->sec_level, auth_type); ++ chan->sec_level, auth_type); + + if (IS_ERR(hcon)) { + err = PTR_ERR(hcon); +@@ -876,7 +896,7 @@ + /* Update source addr of the socket */ + bacpy(src, conn->src); + +- l2cap_chan_add(conn, sk, NULL); ++ l2cap_chan_add(conn, chan); + + sk->sk_state = BT_CONNECT; + l2cap_sock_set_timer(sk, sk->sk_sndtimeo); +@@ -885,10 +905,10 @@ + if (sk->sk_type != SOCK_SEQPACKET && + sk->sk_type != SOCK_STREAM) { + l2cap_sock_clear_timer(sk); +- if (l2cap_check_security(sk)) ++ if (l2cap_check_security(chan)) + sk->sk_state = BT_CONNECTED; + } else +- l2cap_do_start(sk); ++ l2cap_do_start(chan); + } + + err = 0; +@@ -901,12 +921,13 @@ + + int __l2cap_wait_ack(struct sock *sk) + { ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + DECLARE_WAITQUEUE(wait, current); + int err = 0; + int timeo = HZ/5; + + add_wait_queue(sk_sleep(sk), &wait); +- while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) { ++ while ((chan->unacked_frames > 0 && chan->conn)) { + set_current_state(TASK_INTERRUPTIBLE); + + if (!timeo) +@@ -932,68 +953,69 @@ + + static void l2cap_monitor_timeout(unsigned long arg) + { +- struct sock *sk = (void *) arg; ++ struct l2cap_chan *chan = (void *) arg; ++ struct sock *sk = chan->sk; + +- BT_DBG("sk %p", sk); ++ BT_DBG("chan %p", chan); + + bh_lock_sock(sk); +- if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) { +- l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED); ++ if (chan->retry_count >= chan->remote_max_tx) { ++ l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); + bh_unlock_sock(sk); + return; + } + +- l2cap_pi(sk)->retry_count++; ++ chan->retry_count++; + __mod_monitor_timer(); + +- l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL); ++ l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); + bh_unlock_sock(sk); + } + + static void l2cap_retrans_timeout(unsigned long arg) + { +- struct sock *sk = (void *) arg; ++ struct l2cap_chan *chan = (void *) arg; ++ struct sock *sk = chan->sk; + +- BT_DBG("sk %p", sk); ++ BT_DBG("chan %p", chan); + + bh_lock_sock(sk); +- l2cap_pi(sk)->retry_count = 1; ++ chan->retry_count = 1; + __mod_monitor_timer(); + +- l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; ++ chan->conn_state |= L2CAP_CONN_WAIT_F; + +- l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL); ++ l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); + bh_unlock_sock(sk); + } + +-static void l2cap_drop_acked_frames(struct sock *sk) ++static void l2cap_drop_acked_frames(struct l2cap_chan *chan) + { + struct sk_buff *skb; + +- while ((skb = skb_peek(TX_QUEUE(sk))) && +- l2cap_pi(sk)->unacked_frames) { +- if (bt_cb(skb)->tx_seq == l2cap_pi(sk)->expected_ack_seq) ++ while ((skb = skb_peek(&chan->tx_q)) && ++ chan->unacked_frames) { ++ if (bt_cb(skb)->tx_seq == chan->expected_ack_seq) + break; + +- skb = skb_dequeue(TX_QUEUE(sk)); ++ skb = skb_dequeue(&chan->tx_q); + kfree_skb(skb); + +- l2cap_pi(sk)->unacked_frames--; ++ chan->unacked_frames--; + } + +- if (!l2cap_pi(sk)->unacked_frames) +- del_timer(&l2cap_pi(sk)->retrans_timer); ++ if (!chan->unacked_frames) ++ del_timer(&chan->retrans_timer); + } + +-void l2cap_do_send(struct sock *sk, struct sk_buff *skb) ++void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); +- struct hci_conn *hcon = pi->conn->hcon; ++ struct hci_conn *hcon = chan->conn->hcon; + u16 flags; + +- BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len); ++ BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len); + +- if (!pi->flushable && lmp_no_flush_capable(hcon->hdev)) ++ if (!chan->flushable && lmp_no_flush_capable(hcon->hdev)) + flags = ACL_START_NO_FLUSH; + else + flags = ACL_START; +@@ -1001,35 +1023,33 @@ + hci_send_acl(hcon, skb, flags); + } + +-void l2cap_streaming_send(struct sock *sk) ++void l2cap_streaming_send(struct l2cap_chan *chan) + { + struct sk_buff *skb; +- struct l2cap_pinfo *pi = l2cap_pi(sk); + u16 control, fcs; + +- while ((skb = skb_dequeue(TX_QUEUE(sk)))) { ++ while ((skb = skb_dequeue(&chan->tx_q))) { + control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE); +- control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; ++ control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; + put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE); + +- if (pi->fcs == L2CAP_FCS_CRC16) { ++ if (chan->fcs == L2CAP_FCS_CRC16) { + fcs = crc16(0, (u8 *)skb->data, skb->len - 2); + put_unaligned_le16(fcs, skb->data + skb->len - 2); + } + +- l2cap_do_send(sk, skb); ++ l2cap_do_send(chan, skb); + +- pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; ++ chan->next_tx_seq = (chan->next_tx_seq + 1) % 64; + } + } + +-static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) ++static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *skb, *tx_skb; + u16 control, fcs; + +- skb = skb_peek(TX_QUEUE(sk)); ++ skb = skb_peek(&chan->tx_q); + if (!skb) + return; + +@@ -1037,14 +1057,14 @@ + if (bt_cb(skb)->tx_seq == tx_seq) + break; + +- if (skb_queue_is_last(TX_QUEUE(sk), skb)) ++ if (skb_queue_is_last(&chan->tx_q, skb)) + return; + +- } while ((skb = skb_queue_next(TX_QUEUE(sk), skb))); ++ } while ((skb = skb_queue_next(&chan->tx_q, skb))); + +- if (pi->remote_max_tx && +- bt_cb(skb)->retries == pi->remote_max_tx) { +- l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); ++ if (chan->remote_max_tx && ++ bt_cb(skb)->retries == chan->remote_max_tx) { ++ l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); + return; + } + +@@ -1053,39 +1073,39 @@ + control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + control &= L2CAP_CTRL_SAR; + +- if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { ++ if (chan->conn_state & L2CAP_CONN_SEND_FBIT) { + control |= L2CAP_CTRL_FINAL; +- pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; ++ chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; + } + +- control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) ++ control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) + | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); + + put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); + +- if (pi->fcs == L2CAP_FCS_CRC16) { ++ if (chan->fcs == L2CAP_FCS_CRC16) { + fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); + put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); + } + +- l2cap_do_send(sk, tx_skb); ++ l2cap_do_send(chan, tx_skb); + } + +-int l2cap_ertm_send(struct sock *sk) ++int l2cap_ertm_send(struct l2cap_chan *chan) + { + struct sk_buff *skb, *tx_skb; +- struct l2cap_pinfo *pi = l2cap_pi(sk); ++ struct sock *sk = chan->sk; + u16 control, fcs; + int nsent = 0; + + if (sk->sk_state != BT_CONNECTED) + return -ENOTCONN; + +- while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) { ++ while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) { + +- if (pi->remote_max_tx && +- bt_cb(skb)->retries == pi->remote_max_tx) { +- l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); ++ if (chan->remote_max_tx && ++ bt_cb(skb)->retries == chan->remote_max_tx) { ++ l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); + break; + } + +@@ -1096,36 +1116,36 @@ + control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + control &= L2CAP_CTRL_SAR; + +- if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { ++ if (chan->conn_state & L2CAP_CONN_SEND_FBIT) { + control |= L2CAP_CTRL_FINAL; +- pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; ++ chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; + } +- control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) +- | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); ++ control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) ++ | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); + put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); + + +- if (pi->fcs == L2CAP_FCS_CRC16) { ++ if (chan->fcs == L2CAP_FCS_CRC16) { + fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2); + put_unaligned_le16(fcs, skb->data + tx_skb->len - 2); + } + +- l2cap_do_send(sk, tx_skb); ++ l2cap_do_send(chan, tx_skb); + + __mod_retrans_timer(); + +- bt_cb(skb)->tx_seq = pi->next_tx_seq; +- pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; ++ bt_cb(skb)->tx_seq = chan->next_tx_seq; ++ chan->next_tx_seq = (chan->next_tx_seq + 1) % 64; + + if (bt_cb(skb)->retries == 1) +- pi->unacked_frames++; ++ chan->unacked_frames++; + +- pi->frames_sent++; ++ chan->frames_sent++; + +- if (skb_queue_is_last(TX_QUEUE(sk), skb)) +- sk->sk_send_head = NULL; ++ if (skb_queue_is_last(&chan->tx_q, skb)) ++ chan->tx_send_head = NULL; + else +- sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb); ++ chan->tx_send_head = skb_queue_next(&chan->tx_q, skb); + + nsent++; + } +@@ -1133,41 +1153,39 @@ + return nsent; + } + +-static int l2cap_retransmit_frames(struct sock *sk) ++static int l2cap_retransmit_frames(struct l2cap_chan *chan) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + int ret; + +- if (!skb_queue_empty(TX_QUEUE(sk))) +- sk->sk_send_head = TX_QUEUE(sk)->next; ++ if (!skb_queue_empty(&chan->tx_q)) ++ chan->tx_send_head = chan->tx_q.next; + +- pi->next_tx_seq = pi->expected_ack_seq; +- ret = l2cap_ertm_send(sk); ++ chan->next_tx_seq = chan->expected_ack_seq; ++ ret = l2cap_ertm_send(chan); + return ret; + } + +-static void l2cap_send_ack(struct l2cap_pinfo *pi) ++static void l2cap_send_ack(struct l2cap_chan *chan) + { +- struct sock *sk = (struct sock *)pi; + u16 control = 0; + +- control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; ++ control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + +- if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { ++ if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { + control |= L2CAP_SUPER_RCV_NOT_READY; +- pi->conn_state |= L2CAP_CONN_RNR_SENT; +- l2cap_send_sframe(pi, control); ++ chan->conn_state |= L2CAP_CONN_RNR_SENT; ++ l2cap_send_sframe(chan, control); + return; + } + +- if (l2cap_ertm_send(sk) > 0) ++ if (l2cap_ertm_send(chan) > 0) + return; + + control |= L2CAP_SUPER_RCV_READY; +- l2cap_send_sframe(pi, control); ++ l2cap_send_sframe(chan, control); + } + +-static void l2cap_send_srejtail(struct sock *sk) ++static void l2cap_send_srejtail(struct l2cap_chan *chan) + { + struct srej_list *tail; + u16 control; +@@ -1175,15 +1193,15 @@ + control = L2CAP_SUPER_SELECT_REJECT; + control |= L2CAP_CTRL_FINAL; + +- tail = list_entry(SREJ_LIST(sk)->prev, struct srej_list, list); ++ tail = list_entry((&chan->srej_l)->prev, struct srej_list, list); + control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + +- l2cap_send_sframe(l2cap_pi(sk), control); ++ l2cap_send_sframe(chan, control); + } + + static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb) + { +- struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; + struct sk_buff **frag; + int err, sent = 0; + +@@ -1213,9 +1231,10 @@ + return sent; + } + +-struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len) ++struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) + { +- struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct sock *sk = chan->sk; ++ struct l2cap_conn *conn = chan->conn; + struct sk_buff *skb; + int err, count, hlen = L2CAP_HDR_SIZE + 2; + struct l2cap_hdr *lh; +@@ -1230,9 +1249,9 @@ + + /* Create L2CAP header */ + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); +- lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); ++ lh->cid = cpu_to_le16(chan->dcid); + lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); +- put_unaligned_le16(l2cap_pi(sk)->psm, skb_put(skb, 2)); ++ put_unaligned_le16(chan->psm, skb_put(skb, 2)); + + err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + if (unlikely(err < 0)) { +@@ -1242,9 +1261,10 @@ + return skb; + } + +-struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len) ++struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) + { +- struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct sock *sk = chan->sk; ++ struct l2cap_conn *conn = chan->conn; + struct sk_buff *skb; + int err, count, hlen = L2CAP_HDR_SIZE; + struct l2cap_hdr *lh; +@@ -1259,7 +1279,7 @@ + + /* Create L2CAP header */ + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); +- lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); ++ lh->cid = cpu_to_le16(chan->dcid); + lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); + + err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); +@@ -1270,9 +1290,10 @@ + return skb; + } + +-struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen) ++struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen) + { +- struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct sock *sk = chan->sk; ++ struct l2cap_conn *conn = chan->conn; + struct sk_buff *skb; + int err, count, hlen = L2CAP_HDR_SIZE + 2; + struct l2cap_hdr *lh; +@@ -1285,7 +1306,7 @@ + if (sdulen) + hlen += 2; + +- if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) ++ if (chan->fcs == L2CAP_FCS_CRC16) + hlen += 2; + + count = min_t(unsigned int, (conn->mtu - hlen), len); +@@ -1296,7 +1317,7 @@ + + /* Create L2CAP header */ + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); +- lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); ++ lh->cid = cpu_to_le16(chan->dcid); + lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); + put_unaligned_le16(control, skb_put(skb, 2)); + if (sdulen) +@@ -1308,16 +1329,15 @@ + return ERR_PTR(err); + } + +- if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) ++ if (chan->fcs == L2CAP_FCS_CRC16) + put_unaligned_le16(0, skb_put(skb, 2)); + + bt_cb(skb)->retries = 0; + return skb; + } + +-int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len) ++int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *skb; + struct sk_buff_head sar_queue; + u16 control; +@@ -1325,26 +1345,26 @@ + + skb_queue_head_init(&sar_queue); + control = L2CAP_SDU_START; +- skb = l2cap_create_iframe_pdu(sk, msg, pi->remote_mps, control, len); ++ skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + __skb_queue_tail(&sar_queue, skb); +- len -= pi->remote_mps; +- size += pi->remote_mps; ++ len -= chan->remote_mps; ++ size += chan->remote_mps; + + while (len > 0) { + size_t buflen; + +- if (len > pi->remote_mps) { ++ if (len > chan->remote_mps) { + control = L2CAP_SDU_CONTINUE; +- buflen = pi->remote_mps; ++ buflen = chan->remote_mps; + } else { + control = L2CAP_SDU_END; + buflen = len; + } + +- skb = l2cap_create_iframe_pdu(sk, msg, buflen, control, 0); ++ skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0); + if (IS_ERR(skb)) { + skb_queue_purge(&sar_queue); + return PTR_ERR(skb); +@@ -1354,9 +1374,9 @@ + len -= buflen; + size += buflen; + } +- skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk)); +- if (sk->sk_send_head == NULL) +- sk->sk_send_head = sar_queue.next; ++ skb_queue_splice_tail(&sar_queue, &chan->tx_q); ++ if (chan->tx_send_head == NULL) ++ chan->tx_send_head = sar_queue.next; + + return size; + } +@@ -1364,10 +1384,11 @@ + static void l2cap_chan_ready(struct sock *sk) + { + struct sock *parent = bt_sk(sk)->parent; ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + + BT_DBG("sk %p, parent %p", sk, parent); + +- l2cap_pi(sk)->conf_state = 0; ++ chan->conf_state = 0; + l2cap_sock_clear_timer(sk); + + if (!parent) { +@@ -1387,14 +1408,14 @@ + /* Copy frame to all raw sockets on that connection */ + static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) + { +- struct l2cap_chan_list *l = &conn->chan_list; + struct sk_buff *nskb; +- struct sock *sk; ++ struct l2cap_chan *chan; + + BT_DBG("conn %p", conn); + +- read_lock(&l->lock); +- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { ++ read_lock(&conn->chan_lock); ++ list_for_each_entry(chan, &conn->chan_l, list) { ++ struct sock *sk = chan->sk; + if (sk->sk_type != SOCK_RAW) + continue; + +@@ -1408,7 +1429,7 @@ + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } +- read_unlock(&l->lock); ++ read_unlock(&conn->chan_lock); + } + + /* ---- L2CAP signalling commands ---- */ +@@ -1540,32 +1561,35 @@ + + static void l2cap_ack_timeout(unsigned long arg) + { +- struct sock *sk = (void *) arg; ++ struct l2cap_chan *chan = (void *) arg; + +- bh_lock_sock(sk); +- l2cap_send_ack(l2cap_pi(sk)); +- bh_unlock_sock(sk); ++ bh_lock_sock(chan->sk); ++ l2cap_send_ack(chan); ++ bh_unlock_sock(chan->sk); + } + +-static inline void l2cap_ertm_init(struct sock *sk) ++static inline void l2cap_ertm_init(struct l2cap_chan *chan) + { +- l2cap_pi(sk)->expected_ack_seq = 0; +- l2cap_pi(sk)->unacked_frames = 0; +- l2cap_pi(sk)->buffer_seq = 0; +- l2cap_pi(sk)->num_acked = 0; +- l2cap_pi(sk)->frames_sent = 0; +- +- setup_timer(&l2cap_pi(sk)->retrans_timer, +- l2cap_retrans_timeout, (unsigned long) sk); +- setup_timer(&l2cap_pi(sk)->monitor_timer, +- l2cap_monitor_timeout, (unsigned long) sk); +- setup_timer(&l2cap_pi(sk)->ack_timer, +- l2cap_ack_timeout, (unsigned long) sk); ++ struct sock *sk = chan->sk; ++ ++ chan->expected_ack_seq = 0; ++ chan->unacked_frames = 0; ++ chan->buffer_seq = 0; ++ chan->num_acked = 0; ++ chan->frames_sent = 0; + +- __skb_queue_head_init(SREJ_QUEUE(sk)); +- __skb_queue_head_init(BUSY_QUEUE(sk)); ++ setup_timer(&chan->retrans_timer, l2cap_retrans_timeout, ++ (unsigned long) chan); ++ setup_timer(&chan->monitor_timer, l2cap_monitor_timeout, ++ (unsigned long) chan); ++ setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan); + +- INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); ++ skb_queue_head_init(&chan->srej_q); ++ skb_queue_head_init(&chan->busy_q); ++ ++ INIT_LIST_HEAD(&chan->srej_l); ++ ++ INIT_WORK(&chan->busy_work, l2cap_busy_work); + + sk->sk_backlog_rcv = l2cap_ertm_data_rcv; + } +@@ -1583,38 +1607,37 @@ + } + } + +-int l2cap_build_conf_req(struct sock *sk, void *data) ++static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_conf_req *req = data; +- struct l2cap_conf_rfc rfc = { .mode = pi->mode }; ++ struct l2cap_conf_rfc rfc = { .mode = chan->mode }; + void *ptr = req->data; + +- BT_DBG("sk %p", sk); ++ BT_DBG("chan %p", chan); + +- if (pi->num_conf_req || pi->num_conf_rsp) ++ if (chan->num_conf_req || chan->num_conf_rsp) + goto done; + +- switch (pi->mode) { ++ switch (chan->mode) { + case L2CAP_MODE_STREAMING: + case L2CAP_MODE_ERTM: +- if (pi->conf_state & L2CAP_CONF_STATE2_DEVICE) ++ if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE) + break; + + /* fall through */ + default: +- pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); ++ chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask); + break; + } + + done: +- if (pi->imtu != L2CAP_DEFAULT_MTU) +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); ++ if (chan->imtu != L2CAP_DEFAULT_MTU) ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu); + +- switch (pi->mode) { ++ switch (chan->mode) { + case L2CAP_MODE_BASIC: +- if (!(pi->conn->feat_mask & L2CAP_FEAT_ERTM) && +- !(pi->conn->feat_mask & L2CAP_FEAT_STREAMING)) ++ if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) && ++ !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING)) + break; + + rfc.mode = L2CAP_MODE_BASIC; +@@ -1630,24 +1653,24 @@ + + case L2CAP_MODE_ERTM: + rfc.mode = L2CAP_MODE_ERTM; +- rfc.txwin_size = pi->tx_win; +- rfc.max_transmit = pi->max_tx; ++ rfc.txwin_size = chan->tx_win; ++ rfc.max_transmit = chan->max_tx; + rfc.retrans_timeout = 0; + rfc.monitor_timeout = 0; + rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); +- if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) +- rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); ++ if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10) ++ rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), + (unsigned long) &rfc); + +- if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) ++ if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) + break; + +- if (pi->fcs == L2CAP_FCS_NONE || +- pi->conf_state & L2CAP_CONF_NO_FCS_RECV) { +- pi->fcs = L2CAP_FCS_NONE; +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); ++ if (chan->fcs == L2CAP_FCS_NONE || ++ chan->conf_state & L2CAP_CONF_NO_FCS_RECV) { ++ chan->fcs = L2CAP_FCS_NONE; ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); + } + break; + +@@ -1658,43 +1681,42 @@ + rfc.retrans_timeout = 0; + rfc.monitor_timeout = 0; + rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); +- if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) +- rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); ++ if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10) ++ rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), + (unsigned long) &rfc); + +- if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) ++ if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) + break; + +- if (pi->fcs == L2CAP_FCS_NONE || +- pi->conf_state & L2CAP_CONF_NO_FCS_RECV) { +- pi->fcs = L2CAP_FCS_NONE; +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); ++ if (chan->fcs == L2CAP_FCS_NONE || ++ chan->conf_state & L2CAP_CONF_NO_FCS_RECV) { ++ chan->fcs = L2CAP_FCS_NONE; ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); + } + break; + } + +- req->dcid = cpu_to_le16(pi->dcid); ++ req->dcid = cpu_to_le16(chan->dcid); + req->flags = cpu_to_le16(0); + + return ptr - data; + } + +-static int l2cap_parse_conf_req(struct sock *sk, void *data) ++static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_conf_rsp *rsp = data; + void *ptr = rsp->data; +- void *req = pi->conf_req; +- int len = pi->conf_len; ++ void *req = chan->conf_req; ++ int len = chan->conf_len; + int type, hint, olen; + unsigned long val; + struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; + u16 mtu = L2CAP_DEFAULT_MTU; + u16 result = L2CAP_CONF_SUCCESS; + +- BT_DBG("sk %p", sk); ++ BT_DBG("chan %p", chan); + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&req, &type, &olen, &val); +@@ -1708,7 +1730,7 @@ + break; + + case L2CAP_CONF_FLUSH_TO: +- pi->flush_to = val; ++ chan->flush_to = val; + break; + + case L2CAP_CONF_QOS: +@@ -1721,7 +1743,7 @@ + + case L2CAP_CONF_FCS: + if (val == L2CAP_FCS_NONE) +- pi->conf_state |= L2CAP_CONF_NO_FCS_RECV; ++ chan->conf_state |= L2CAP_CONF_NO_FCS_RECV; + + break; + +@@ -1735,30 +1757,30 @@ + } + } + +- if (pi->num_conf_rsp || pi->num_conf_req > 1) ++ if (chan->num_conf_rsp || chan->num_conf_req > 1) + goto done; + +- switch (pi->mode) { ++ switch (chan->mode) { + case L2CAP_MODE_STREAMING: + case L2CAP_MODE_ERTM: +- if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) { +- pi->mode = l2cap_select_mode(rfc.mode, +- pi->conn->feat_mask); ++ if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) { ++ chan->mode = l2cap_select_mode(rfc.mode, ++ chan->conn->feat_mask); + break; + } + +- if (pi->mode != rfc.mode) ++ if (chan->mode != rfc.mode) + return -ECONNREFUSED; + + break; + } + + done: +- if (pi->mode != rfc.mode) { ++ if (chan->mode != rfc.mode) { + result = L2CAP_CONF_UNACCEPT; +- rfc.mode = pi->mode; ++ rfc.mode = chan->mode; + +- if (pi->num_conf_rsp == 1) ++ if (chan->num_conf_rsp == 1) + return -ECONNREFUSED; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, +@@ -1773,32 +1795,32 @@ + if (mtu < L2CAP_DEFAULT_MIN_MTU) + result = L2CAP_CONF_UNACCEPT; + else { +- pi->omtu = mtu; +- pi->conf_state |= L2CAP_CONF_MTU_DONE; ++ chan->omtu = mtu; ++ chan->conf_state |= L2CAP_CONF_MTU_DONE; + } +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu); + + switch (rfc.mode) { + case L2CAP_MODE_BASIC: +- pi->fcs = L2CAP_FCS_NONE; +- pi->conf_state |= L2CAP_CONF_MODE_DONE; ++ chan->fcs = L2CAP_FCS_NONE; ++ chan->conf_state |= L2CAP_CONF_MODE_DONE; + break; + + case L2CAP_MODE_ERTM: +- pi->remote_tx_win = rfc.txwin_size; +- pi->remote_max_tx = rfc.max_transmit; ++ chan->remote_tx_win = rfc.txwin_size; ++ chan->remote_max_tx = rfc.max_transmit; + +- if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10) +- rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); ++ if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10) ++ rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); + +- pi->remote_mps = le16_to_cpu(rfc.max_pdu_size); ++ chan->remote_mps = le16_to_cpu(rfc.max_pdu_size); + + rfc.retrans_timeout = + le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO); + rfc.monitor_timeout = + le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO); + +- pi->conf_state |= L2CAP_CONF_MODE_DONE; ++ chan->conf_state |= L2CAP_CONF_MODE_DONE; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); +@@ -1806,12 +1828,12 @@ + break; + + case L2CAP_MODE_STREAMING: +- if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10) +- rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); ++ if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10) ++ rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); + +- pi->remote_mps = le16_to_cpu(rfc.max_pdu_size); ++ chan->remote_mps = le16_to_cpu(rfc.max_pdu_size); + +- pi->conf_state |= L2CAP_CONF_MODE_DONE; ++ chan->conf_state |= L2CAP_CONF_MODE_DONE; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); +@@ -1822,29 +1844,28 @@ + result = L2CAP_CONF_UNACCEPT; + + memset(&rfc, 0, sizeof(rfc)); +- rfc.mode = pi->mode; ++ rfc.mode = chan->mode; + } + + if (result == L2CAP_CONF_SUCCESS) +- pi->conf_state |= L2CAP_CONF_OUTPUT_DONE; ++ chan->conf_state |= L2CAP_CONF_OUTPUT_DONE; + } +- rsp->scid = cpu_to_le16(pi->dcid); ++ rsp->scid = cpu_to_le16(chan->dcid); + rsp->result = cpu_to_le16(result); + rsp->flags = cpu_to_le16(0x0000); + + return ptr - data; + } + +-static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, u16 *result) ++static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, void *data, u16 *result) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_conf_req *req = data; + void *ptr = req->data; + int type, olen; + unsigned long val; + struct l2cap_conf_rfc rfc; + +- BT_DBG("sk %p, rsp %p, len %d, req %p", sk, rsp, len, data); ++ BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data); + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); +@@ -1853,27 +1874,27 @@ + case L2CAP_CONF_MTU: + if (val < L2CAP_DEFAULT_MIN_MTU) { + *result = L2CAP_CONF_UNACCEPT; +- pi->imtu = L2CAP_DEFAULT_MIN_MTU; ++ chan->imtu = L2CAP_DEFAULT_MIN_MTU; + } else +- pi->imtu = val; +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); ++ chan->imtu = val; ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu); + break; + + case L2CAP_CONF_FLUSH_TO: +- pi->flush_to = val; ++ chan->flush_to = val; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, +- 2, pi->flush_to); ++ 2, chan->flush_to); + break; + + case L2CAP_CONF_RFC: + if (olen == sizeof(rfc)) + memcpy(&rfc, (void *)val, olen); + +- if ((pi->conf_state & L2CAP_CONF_STATE2_DEVICE) && +- rfc.mode != pi->mode) ++ if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) && ++ rfc.mode != chan->mode) + return -ECONNREFUSED; + +- pi->fcs = 0; ++ chan->fcs = 0; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); +@@ -1881,53 +1902,74 @@ + } + } + +- if (pi->mode == L2CAP_MODE_BASIC && pi->mode != rfc.mode) ++ if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode) + return -ECONNREFUSED; + +- pi->mode = rfc.mode; ++ chan->mode = rfc.mode; + + if (*result == L2CAP_CONF_SUCCESS) { + switch (rfc.mode) { + case L2CAP_MODE_ERTM: +- pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); +- pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); +- pi->mps = le16_to_cpu(rfc.max_pdu_size); ++ chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); ++ chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); ++ chan->mps = le16_to_cpu(rfc.max_pdu_size); + break; + case L2CAP_MODE_STREAMING: +- pi->mps = le16_to_cpu(rfc.max_pdu_size); ++ chan->mps = le16_to_cpu(rfc.max_pdu_size); + } + } + +- req->dcid = cpu_to_le16(pi->dcid); ++ req->dcid = cpu_to_le16(chan->dcid); + req->flags = cpu_to_le16(0x0000); + + return ptr - data; + } + +-static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 flags) ++static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags) + { + struct l2cap_conf_rsp *rsp = data; + void *ptr = rsp->data; + +- BT_DBG("sk %p", sk); ++ BT_DBG("chan %p", chan); + +- rsp->scid = cpu_to_le16(l2cap_pi(sk)->dcid); ++ rsp->scid = cpu_to_le16(chan->dcid); + rsp->result = cpu_to_le16(result); + rsp->flags = cpu_to_le16(flags); + + return ptr - data; + } + +-static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) ++void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) ++{ ++ struct l2cap_conn_rsp rsp; ++ struct l2cap_conn *conn = chan->conn; ++ u8 buf[128]; ++ ++ rsp.scid = cpu_to_le16(chan->dcid); ++ rsp.dcid = cpu_to_le16(chan->scid); ++ rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); ++ rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); ++ l2cap_send_cmd(conn, chan->ident, ++ L2CAP_CONN_RSP, sizeof(rsp), &rsp); ++ ++ if (chan->conf_state & L2CAP_CONF_REQ_SENT) ++ return; ++ ++ chan->conf_state |= L2CAP_CONF_REQ_SENT; ++ l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, ++ l2cap_build_conf_req(chan, buf), buf); ++ chan->num_conf_req++; ++} ++ ++static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + int type, olen; + unsigned long val; + struct l2cap_conf_rfc rfc; + +- BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len); ++ BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len); + +- if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING)) ++ if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING)) + return; + + while (len >= L2CAP_CONF_OPT_SIZE) { +@@ -1944,12 +1986,12 @@ + done: + switch (rfc.mode) { + case L2CAP_MODE_ERTM: +- pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); +- pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); +- pi->mps = le16_to_cpu(rfc.max_pdu_size); ++ chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); ++ chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); ++ chan->mps = le16_to_cpu(rfc.max_pdu_size); + break; + case L2CAP_MODE_STREAMING: +- pi->mps = le16_to_cpu(rfc.max_pdu_size); ++ chan->mps = le16_to_cpu(rfc.max_pdu_size); + } + } + +@@ -1975,9 +2017,9 @@ + + static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) + { +- struct l2cap_chan_list *list = &conn->chan_list; + struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; + struct l2cap_conn_rsp rsp; ++ struct l2cap_chan *chan = NULL; + struct sock *parent, *sk = NULL; + int result, status = L2CAP_CS_NO_INFO; + +@@ -2015,11 +2057,19 @@ + if (!sk) + goto response; + +- write_lock_bh(&list->lock); ++ chan = l2cap_chan_alloc(sk); ++ if (!chan) { ++ l2cap_sock_kill(sk); ++ goto response; ++ } ++ ++ l2cap_pi(sk)->chan = chan; ++ ++ write_lock_bh(&conn->chan_lock); + + /* Check if we already have channel with that dcid */ +- if (__l2cap_get_chan_by_dcid(list, scid)) { +- write_unlock_bh(&list->lock); ++ if (__l2cap_get_chan_by_dcid(conn, scid)) { ++ write_unlock_bh(&conn->chan_lock); + sock_set_flag(sk, SOCK_ZAPPED); + l2cap_sock_kill(sk); + goto response; +@@ -2030,18 +2080,21 @@ + l2cap_sock_init(sk, parent); + bacpy(&bt_sk(sk)->src, conn->src); + bacpy(&bt_sk(sk)->dst, conn->dst); +- l2cap_pi(sk)->psm = psm; +- l2cap_pi(sk)->dcid = scid; ++ chan->psm = psm; ++ chan->dcid = scid; ++ ++ bt_accept_enqueue(parent, sk); + +- __l2cap_chan_add(conn, sk, parent); +- dcid = l2cap_pi(sk)->scid; ++ __l2cap_chan_add(conn, chan); ++ ++ dcid = chan->scid; + + l2cap_sock_set_timer(sk, sk->sk_sndtimeo); + +- l2cap_pi(sk)->ident = cmd->ident; ++ chan->ident = cmd->ident; + + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { +- if (l2cap_check_security(sk)) { ++ if (l2cap_check_security(chan)) { + if (bt_sk(sk)->defer_setup) { + sk->sk_state = BT_CONNECT2; + result = L2CAP_CR_PEND; +@@ -2063,7 +2116,7 @@ + status = L2CAP_CS_NO_INFO; + } + +- write_unlock_bh(&list->lock); ++ write_unlock_bh(&conn->chan_lock); + + response: + bh_unlock_sock(parent); +@@ -2089,13 +2142,13 @@ + L2CAP_INFO_REQ, sizeof(info), &info); + } + +- if (sk && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) && ++ if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) && + result == L2CAP_CR_SUCCESS) { + u8 buf[128]; +- l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; ++ chan->conf_state |= L2CAP_CONF_REQ_SENT; + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, +- l2cap_build_conf_req(sk, buf), buf); +- l2cap_pi(sk)->num_conf_req++; ++ l2cap_build_conf_req(chan, buf), buf); ++ chan->num_conf_req++; + } + + return 0; +@@ -2105,6 +2158,7 @@ + { + struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; + u16 scid, dcid, result, status; ++ struct l2cap_chan *chan; + struct sock *sk; + u8 req[128]; + +@@ -2116,34 +2170,36 @@ + BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); + + if (scid) { +- sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); +- if (!sk) ++ chan = l2cap_get_chan_by_scid(conn, scid); ++ if (!chan) + return -EFAULT; + } else { +- sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident); +- if (!sk) ++ chan = l2cap_get_chan_by_ident(conn, cmd->ident); ++ if (!chan) + return -EFAULT; + } + ++ sk = chan->sk; ++ + switch (result) { + case L2CAP_CR_SUCCESS: + sk->sk_state = BT_CONFIG; +- l2cap_pi(sk)->ident = 0; +- l2cap_pi(sk)->dcid = dcid; +- l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND; ++ chan->ident = 0; ++ chan->dcid = dcid; ++ chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND; + +- if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) ++ if (chan->conf_state & L2CAP_CONF_REQ_SENT) + break; + +- l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; ++ chan->conf_state |= L2CAP_CONF_REQ_SENT; + + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, +- l2cap_build_conf_req(sk, req), req); +- l2cap_pi(sk)->num_conf_req++; ++ l2cap_build_conf_req(chan, req), req); ++ chan->num_conf_req++; + break; + + case L2CAP_CR_PEND: +- l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; ++ chan->conf_state |= L2CAP_CONF_CONNECT_PEND; + break; + + default: +@@ -2155,7 +2211,7 @@ + break; + } + +- l2cap_chan_del(sk, ECONNREFUSED); ++ l2cap_chan_del(chan, ECONNREFUSED); + break; + } + +@@ -2163,15 +2219,17 @@ + return 0; + } + +-static inline void set_default_fcs(struct l2cap_pinfo *pi) ++static inline void set_default_fcs(struct l2cap_chan *chan) + { ++ struct l2cap_pinfo *pi = l2cap_pi(chan->sk); ++ + /* FCS is enabled only in ERTM or streaming mode, if one or both + * sides request it. + */ +- if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING) +- pi->fcs = L2CAP_FCS_NONE; +- else if (!(pi->conf_state & L2CAP_CONF_NO_FCS_RECV)) +- pi->fcs = L2CAP_FCS_CRC16; ++ if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING) ++ chan->fcs = L2CAP_FCS_NONE; ++ else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV)) ++ chan->fcs = L2CAP_FCS_CRC16; + } + + static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) +@@ -2179,6 +2237,7 @@ + struct l2cap_conf_req *req = (struct l2cap_conf_req *) data; + u16 dcid, flags; + u8 rsp[64]; ++ struct l2cap_chan *chan; + struct sock *sk; + int len; + +@@ -2187,10 +2246,12 @@ + + BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); + +- sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); +- if (!sk) ++ chan = l2cap_get_chan_by_scid(conn, dcid); ++ if (!chan) + return -ENOENT; + ++ sk = chan->sk; ++ + if (sk->sk_state != BT_CONFIG) { + struct l2cap_cmd_rej rej; + +@@ -2202,62 +2263,62 @@ + + /* Reject if config buffer is too small. */ + len = cmd_len - sizeof(*req); +- if (l2cap_pi(sk)->conf_len + len > sizeof(l2cap_pi(sk)->conf_req)) { ++ if (chan->conf_len + len > sizeof(chan->conf_req)) { + l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, +- l2cap_build_conf_rsp(sk, rsp, ++ l2cap_build_conf_rsp(chan, rsp, + L2CAP_CONF_REJECT, flags), rsp); + goto unlock; + } + + /* Store config. */ +- memcpy(l2cap_pi(sk)->conf_req + l2cap_pi(sk)->conf_len, req->data, len); +- l2cap_pi(sk)->conf_len += len; ++ memcpy(chan->conf_req + chan->conf_len, req->data, len); ++ chan->conf_len += len; + + if (flags & 0x0001) { + /* Incomplete config. Send empty response. */ + l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, +- l2cap_build_conf_rsp(sk, rsp, ++ l2cap_build_conf_rsp(chan, rsp, + L2CAP_CONF_SUCCESS, 0x0001), rsp); + goto unlock; + } + + /* Complete config. */ +- len = l2cap_parse_conf_req(sk, rsp); ++ len = l2cap_parse_conf_req(chan, rsp); + if (len < 0) { +- l2cap_send_disconn_req(conn, sk, ECONNRESET); ++ l2cap_send_disconn_req(conn, chan, ECONNRESET); + goto unlock; + } + + l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp); +- l2cap_pi(sk)->num_conf_rsp++; ++ chan->num_conf_rsp++; + + /* Reset config buffer. */ +- l2cap_pi(sk)->conf_len = 0; ++ chan->conf_len = 0; + +- if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE)) ++ if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE)) + goto unlock; + +- if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { +- set_default_fcs(l2cap_pi(sk)); ++ if (chan->conf_state & L2CAP_CONF_INPUT_DONE) { ++ set_default_fcs(chan); + + sk->sk_state = BT_CONNECTED; + +- l2cap_pi(sk)->next_tx_seq = 0; +- l2cap_pi(sk)->expected_tx_seq = 0; +- __skb_queue_head_init(TX_QUEUE(sk)); +- if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) +- l2cap_ertm_init(sk); ++ chan->next_tx_seq = 0; ++ chan->expected_tx_seq = 0; ++ skb_queue_head_init(&chan->tx_q); ++ if (chan->mode == L2CAP_MODE_ERTM) ++ l2cap_ertm_init(chan); + + l2cap_chan_ready(sk); + goto unlock; + } + +- if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { ++ if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) { + u8 buf[64]; +- l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; ++ chan->conf_state |= L2CAP_CONF_REQ_SENT; + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, +- l2cap_build_conf_req(sk, buf), buf); +- l2cap_pi(sk)->num_conf_req++; ++ l2cap_build_conf_req(chan, buf), buf); ++ chan->num_conf_req++; + } + + unlock: +@@ -2269,6 +2330,7 @@ + { + struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; + u16 scid, flags, result; ++ struct l2cap_chan *chan; + struct sock *sk; + int len = cmd->len - sizeof(*rsp); + +@@ -2279,36 +2341,38 @@ + BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", + scid, flags, result); + +- sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); +- if (!sk) ++ chan = l2cap_get_chan_by_scid(conn, scid); ++ if (!chan) + return 0; + ++ sk = chan->sk; ++ + switch (result) { + case L2CAP_CONF_SUCCESS: +- l2cap_conf_rfc_get(sk, rsp->data, len); ++ l2cap_conf_rfc_get(chan, rsp->data, len); + break; + + case L2CAP_CONF_UNACCEPT: +- if (l2cap_pi(sk)->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) { ++ if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) { + char req[64]; + + if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { +- l2cap_send_disconn_req(conn, sk, ECONNRESET); ++ l2cap_send_disconn_req(conn, chan, ECONNRESET); + goto done; + } + + /* throw out any old stored conf requests */ + result = L2CAP_CONF_SUCCESS; +- len = l2cap_parse_conf_rsp(sk, rsp->data, +- len, req, &result); ++ len = l2cap_parse_conf_rsp(chan, rsp->data, len, ++ req, &result); + if (len < 0) { +- l2cap_send_disconn_req(conn, sk, ECONNRESET); ++ l2cap_send_disconn_req(conn, chan, ECONNRESET); + goto done; + } + + l2cap_send_cmd(conn, l2cap_get_ident(conn), + L2CAP_CONF_REQ, len, req); +- l2cap_pi(sk)->num_conf_req++; ++ chan->num_conf_req++; + if (result != L2CAP_CONF_SUCCESS) + goto done; + break; +@@ -2317,24 +2381,24 @@ + default: + sk->sk_err = ECONNRESET; + l2cap_sock_set_timer(sk, HZ * 5); +- l2cap_send_disconn_req(conn, sk, ECONNRESET); ++ l2cap_send_disconn_req(conn, chan, ECONNRESET); + goto done; + } + + if (flags & 0x01) + goto done; + +- l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE; ++ chan->conf_state |= L2CAP_CONF_INPUT_DONE; + +- if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { +- set_default_fcs(l2cap_pi(sk)); ++ if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) { ++ set_default_fcs(chan); + + sk->sk_state = BT_CONNECTED; +- l2cap_pi(sk)->next_tx_seq = 0; +- l2cap_pi(sk)->expected_tx_seq = 0; +- __skb_queue_head_init(TX_QUEUE(sk)); +- if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) +- l2cap_ertm_init(sk); ++ chan->next_tx_seq = 0; ++ chan->expected_tx_seq = 0; ++ skb_queue_head_init(&chan->tx_q); ++ if (chan->mode == L2CAP_MODE_ERTM) ++ l2cap_ertm_init(chan); + + l2cap_chan_ready(sk); + } +@@ -2349,6 +2413,7 @@ + struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data; + struct l2cap_disconn_rsp rsp; + u16 dcid, scid; ++ struct l2cap_chan *chan; + struct sock *sk; + + scid = __le16_to_cpu(req->scid); +@@ -2356,12 +2421,14 @@ + + BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); + +- sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); +- if (!sk) ++ chan = l2cap_get_chan_by_scid(conn, dcid); ++ if (!chan) + return 0; + +- rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); +- rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); ++ sk = chan->sk; ++ ++ rsp.dcid = cpu_to_le16(chan->scid); ++ rsp.scid = cpu_to_le16(chan->dcid); + l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); + + sk->sk_shutdown = SHUTDOWN_MASK; +@@ -2375,7 +2442,7 @@ + return 0; + } + +- l2cap_chan_del(sk, ECONNRESET); ++ l2cap_chan_del(chan, ECONNRESET); + bh_unlock_sock(sk); + + l2cap_sock_kill(sk); +@@ -2386,6 +2453,7 @@ + { + struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data; + u16 dcid, scid; ++ struct l2cap_chan *chan; + struct sock *sk; + + scid = __le16_to_cpu(rsp->scid); +@@ -2393,10 +2461,12 @@ + + BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); + +- sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); +- if (!sk) ++ chan = l2cap_get_chan_by_scid(conn, scid); ++ if (!chan) + return 0; + ++ sk = chan->sk; ++ + /* don't delete l2cap channel if sk is owned by user */ + if (sock_owned_by_user(sk)) { + sk->sk_state = BT_DISCONN; +@@ -2406,7 +2476,7 @@ + return 0; + } + +- l2cap_chan_del(sk, 0); ++ l2cap_chan_del(chan, 0); + bh_unlock_sock(sk); + + l2cap_sock_kill(sk); +@@ -2463,6 +2533,11 @@ + + BT_DBG("type 0x%4.4x result 0x%2.2x", type, result); + ++ /* L2CAP Info req/rsp are unbound to channels, add extra checks */ ++ if (cmd->ident != conn->info_ident || ++ conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) ++ return 0; ++ + del_timer(&conn->info_timer); + + if (result != L2CAP_IR_SUCCESS) { +@@ -2673,7 +2748,8 @@ + + if (err) { + struct l2cap_cmd_rej rej; +- BT_DBG("error %d", err); ++ ++ BT_ERR("Wrong link type (%d)", err); + + /* FIXME: Map err to a valid reason */ + rej.reason = cpu_to_le16(0); +@@ -2687,12 +2763,12 @@ + kfree_skb(skb); + } + +-static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) ++static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb) + { + u16 our_fcs, rcv_fcs; + int hdr_size = L2CAP_HDR_SIZE + 2; + +- if (pi->fcs == L2CAP_FCS_CRC16) { ++ if (chan->fcs == L2CAP_FCS_CRC16) { + skb_trim(skb, skb->len - 2); + rcv_fcs = get_unaligned_le16(skb->data + skb->len); + our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size); +@@ -2703,49 +2779,47 @@ + return 0; + } + +-static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) ++static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + u16 control = 0; + +- pi->frames_sent = 0; ++ chan->frames_sent = 0; + +- control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; ++ control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + +- if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { ++ if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { + control |= L2CAP_SUPER_RCV_NOT_READY; +- l2cap_send_sframe(pi, control); +- pi->conn_state |= L2CAP_CONN_RNR_SENT; ++ l2cap_send_sframe(chan, control); ++ chan->conn_state |= L2CAP_CONN_RNR_SENT; + } + +- if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY) +- l2cap_retransmit_frames(sk); ++ if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY) ++ l2cap_retransmit_frames(chan); + +- l2cap_ertm_send(sk); ++ l2cap_ertm_send(chan); + +- if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) && +- pi->frames_sent == 0) { ++ if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) && ++ chan->frames_sent == 0) { + control |= L2CAP_SUPER_RCV_READY; +- l2cap_send_sframe(pi, control); ++ l2cap_send_sframe(chan, control); + } + } + +-static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) ++static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar) + { + struct sk_buff *next_skb; +- struct l2cap_pinfo *pi = l2cap_pi(sk); + int tx_seq_offset, next_tx_seq_offset; + + bt_cb(skb)->tx_seq = tx_seq; + bt_cb(skb)->sar = sar; + +- next_skb = skb_peek(SREJ_QUEUE(sk)); ++ next_skb = skb_peek(&chan->srej_q); + if (!next_skb) { +- __skb_queue_tail(SREJ_QUEUE(sk), skb); ++ __skb_queue_tail(&chan->srej_q, skb); + return 0; + } + +- tx_seq_offset = (tx_seq - pi->buffer_seq) % 64; ++ tx_seq_offset = (tx_seq - chan->buffer_seq) % 64; + if (tx_seq_offset < 0) + tx_seq_offset += 64; + +@@ -2754,53 +2828,52 @@ + return -EINVAL; + + next_tx_seq_offset = (bt_cb(next_skb)->tx_seq - +- pi->buffer_seq) % 64; ++ chan->buffer_seq) % 64; + if (next_tx_seq_offset < 0) + next_tx_seq_offset += 64; + + if (next_tx_seq_offset > tx_seq_offset) { +- __skb_queue_before(SREJ_QUEUE(sk), next_skb, skb); ++ __skb_queue_before(&chan->srej_q, next_skb, skb); + return 0; + } + +- if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb)) ++ if (skb_queue_is_last(&chan->srej_q, next_skb)) + break; + +- } while ((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb))); ++ } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb))); + +- __skb_queue_tail(SREJ_QUEUE(sk), skb); ++ __skb_queue_tail(&chan->srej_q, skb); + + return 0; + } + +-static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) ++static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *_skb; + int err; + + switch (control & L2CAP_CTRL_SAR) { + case L2CAP_SDU_UNSEGMENTED: +- if (pi->conn_state & L2CAP_CONN_SAR_SDU) ++ if (chan->conn_state & L2CAP_CONN_SAR_SDU) + goto drop; + +- err = sock_queue_rcv_skb(sk, skb); ++ err = sock_queue_rcv_skb(chan->sk, skb); + if (!err) + return err; + + break; + + case L2CAP_SDU_START: +- if (pi->conn_state & L2CAP_CONN_SAR_SDU) ++ if (chan->conn_state & L2CAP_CONN_SAR_SDU) + goto drop; + +- pi->sdu_len = get_unaligned_le16(skb->data); ++ chan->sdu_len = get_unaligned_le16(skb->data); + +- if (pi->sdu_len > pi->imtu) ++ if (chan->sdu_len > chan->imtu) + goto disconnect; + +- pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); +- if (!pi->sdu) ++ chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); ++ if (!chan->sdu) + return -ENOMEM; + + /* pull sdu_len bytes only after alloc, because of Local Busy +@@ -2808,63 +2881,63 @@ + * only once, i.e., when alloc does not fail */ + skb_pull(skb, 2); + +- memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); ++ memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); + +- pi->conn_state |= L2CAP_CONN_SAR_SDU; +- pi->partial_sdu_len = skb->len; ++ chan->conn_state |= L2CAP_CONN_SAR_SDU; ++ chan->partial_sdu_len = skb->len; + break; + + case L2CAP_SDU_CONTINUE: +- if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) ++ if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) + goto disconnect; + +- if (!pi->sdu) ++ if (!chan->sdu) + goto disconnect; + +- pi->partial_sdu_len += skb->len; +- if (pi->partial_sdu_len > pi->sdu_len) ++ chan->partial_sdu_len += skb->len; ++ if (chan->partial_sdu_len > chan->sdu_len) + goto drop; + +- memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); ++ memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); + + break; + + case L2CAP_SDU_END: +- if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) ++ if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) + goto disconnect; + +- if (!pi->sdu) ++ if (!chan->sdu) + goto disconnect; + +- if (!(pi->conn_state & L2CAP_CONN_SAR_RETRY)) { +- pi->partial_sdu_len += skb->len; ++ if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) { ++ chan->partial_sdu_len += skb->len; + +- if (pi->partial_sdu_len > pi->imtu) ++ if (chan->partial_sdu_len > chan->imtu) + goto drop; + +- if (pi->partial_sdu_len != pi->sdu_len) ++ if (chan->partial_sdu_len != chan->sdu_len) + goto drop; + +- memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); ++ memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); + } + +- _skb = skb_clone(pi->sdu, GFP_ATOMIC); ++ _skb = skb_clone(chan->sdu, GFP_ATOMIC); + if (!_skb) { +- pi->conn_state |= L2CAP_CONN_SAR_RETRY; ++ chan->conn_state |= L2CAP_CONN_SAR_RETRY; + return -ENOMEM; + } + +- err = sock_queue_rcv_skb(sk, _skb); ++ err = sock_queue_rcv_skb(chan->sk, _skb); + if (err < 0) { + kfree_skb(_skb); +- pi->conn_state |= L2CAP_CONN_SAR_RETRY; ++ chan->conn_state |= L2CAP_CONN_SAR_RETRY; + return err; + } + +- pi->conn_state &= ~L2CAP_CONN_SAR_RETRY; +- pi->conn_state &= ~L2CAP_CONN_SAR_SDU; ++ chan->conn_state &= ~L2CAP_CONN_SAR_RETRY; ++ chan->conn_state &= ~L2CAP_CONN_SAR_SDU; + +- kfree_skb(pi->sdu); ++ kfree_skb(chan->sdu); + break; + } + +@@ -2872,51 +2945,50 @@ + return 0; + + drop: +- kfree_skb(pi->sdu); +- pi->sdu = NULL; ++ kfree_skb(chan->sdu); ++ chan->sdu = NULL; + + disconnect: +- l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); ++ l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + kfree_skb(skb); + return 0; + } + +-static int l2cap_try_push_rx_skb(struct sock *sk) ++static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *skb; + u16 control; + int err; + +- while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) { ++ while ((skb = skb_dequeue(&chan->busy_q))) { + control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; +- err = l2cap_ertm_reassembly_sdu(sk, skb, control); ++ err = l2cap_ertm_reassembly_sdu(chan, skb, control); + if (err < 0) { +- skb_queue_head(BUSY_QUEUE(sk), skb); ++ skb_queue_head(&chan->busy_q, skb); + return -EBUSY; + } + +- pi->buffer_seq = (pi->buffer_seq + 1) % 64; ++ chan->buffer_seq = (chan->buffer_seq + 1) % 64; + } + +- if (!(pi->conn_state & L2CAP_CONN_RNR_SENT)) ++ if (!(chan->conn_state & L2CAP_CONN_RNR_SENT)) + goto done; + +- control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; ++ control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; +- l2cap_send_sframe(pi, control); +- l2cap_pi(sk)->retry_count = 1; ++ l2cap_send_sframe(chan, control); ++ chan->retry_count = 1; + +- del_timer(&pi->retrans_timer); ++ del_timer(&chan->retrans_timer); + __mod_monitor_timer(); + +- l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; ++ chan->conn_state |= L2CAP_CONN_WAIT_F; + + done: +- pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; +- pi->conn_state &= ~L2CAP_CONN_RNR_SENT; ++ chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; ++ chan->conn_state &= ~L2CAP_CONN_RNR_SENT; + +- BT_DBG("sk %p, Exit local busy", sk); ++ BT_DBG("chan %p, Exit local busy", chan); + + return 0; + } +@@ -2924,21 +2996,21 @@ + static void l2cap_busy_work(struct work_struct *work) + { + DECLARE_WAITQUEUE(wait, current); +- struct l2cap_pinfo *pi = +- container_of(work, struct l2cap_pinfo, busy_work); +- struct sock *sk = (struct sock *)pi; ++ struct l2cap_chan *chan = ++ container_of(work, struct l2cap_chan, busy_work); ++ struct sock *sk = chan->sk; + int n_tries = 0, timeo = HZ/5, err; + struct sk_buff *skb; + + lock_sock(sk); + + add_wait_queue(sk_sleep(sk), &wait); +- while ((skb = skb_peek(BUSY_QUEUE(sk)))) { ++ while ((skb = skb_peek(&chan->busy_q))) { + set_current_state(TASK_INTERRUPTIBLE); + + if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { + err = -EBUSY; +- l2cap_send_disconn_req(pi->conn, sk, EBUSY); ++ l2cap_send_disconn_req(chan->conn, chan, EBUSY); + break; + } + +@@ -2958,7 +3030,7 @@ + if (err) + break; + +- if (l2cap_try_push_rx_skb(sk) == 0) ++ if (l2cap_try_push_rx_skb(chan) == 0) + break; + } + +@@ -2968,48 +3040,46 @@ + release_sock(sk); + } + +-static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) ++static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + int sctrl, err; + +- if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { ++ if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { + bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; +- __skb_queue_tail(BUSY_QUEUE(sk), skb); +- return l2cap_try_push_rx_skb(sk); ++ __skb_queue_tail(&chan->busy_q, skb); ++ return l2cap_try_push_rx_skb(chan); + + + } + +- err = l2cap_ertm_reassembly_sdu(sk, skb, control); ++ err = l2cap_ertm_reassembly_sdu(chan, skb, control); + if (err >= 0) { +- pi->buffer_seq = (pi->buffer_seq + 1) % 64; ++ chan->buffer_seq = (chan->buffer_seq + 1) % 64; + return err; + } + + /* Busy Condition */ +- BT_DBG("sk %p, Enter local busy", sk); ++ BT_DBG("chan %p, Enter local busy", chan); + +- pi->conn_state |= L2CAP_CONN_LOCAL_BUSY; ++ chan->conn_state |= L2CAP_CONN_LOCAL_BUSY; + bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; +- __skb_queue_tail(BUSY_QUEUE(sk), skb); ++ __skb_queue_tail(&chan->busy_q, skb); + +- sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; ++ sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + sctrl |= L2CAP_SUPER_RCV_NOT_READY; +- l2cap_send_sframe(pi, sctrl); ++ l2cap_send_sframe(chan, sctrl); + +- pi->conn_state |= L2CAP_CONN_RNR_SENT; ++ chan->conn_state |= L2CAP_CONN_RNR_SENT; + +- del_timer(&pi->ack_timer); ++ del_timer(&chan->ack_timer); + +- queue_work(_busy_wq, &pi->busy_work); ++ queue_work(_busy_wq, &chan->busy_work); + + return err; + } + +-static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) ++static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *_skb; + int err = -EINVAL; + +@@ -3020,80 +3090,80 @@ + + switch (control & L2CAP_CTRL_SAR) { + case L2CAP_SDU_UNSEGMENTED: +- if (pi->conn_state & L2CAP_CONN_SAR_SDU) { +- kfree_skb(pi->sdu); ++ if (chan->conn_state & L2CAP_CONN_SAR_SDU) { ++ kfree_skb(chan->sdu); + break; + } + +- err = sock_queue_rcv_skb(sk, skb); ++ err = sock_queue_rcv_skb(chan->sk, skb); + if (!err) + return 0; + + break; + + case L2CAP_SDU_START: +- if (pi->conn_state & L2CAP_CONN_SAR_SDU) { +- kfree_skb(pi->sdu); ++ if (chan->conn_state & L2CAP_CONN_SAR_SDU) { ++ kfree_skb(chan->sdu); + break; + } + +- pi->sdu_len = get_unaligned_le16(skb->data); ++ chan->sdu_len = get_unaligned_le16(skb->data); + skb_pull(skb, 2); + +- if (pi->sdu_len > pi->imtu) { ++ if (chan->sdu_len > chan->imtu) { + err = -EMSGSIZE; + break; + } + +- pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); +- if (!pi->sdu) { ++ chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); ++ if (!chan->sdu) { + err = -ENOMEM; + break; + } + +- memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); ++ memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); + +- pi->conn_state |= L2CAP_CONN_SAR_SDU; +- pi->partial_sdu_len = skb->len; ++ chan->conn_state |= L2CAP_CONN_SAR_SDU; ++ chan->partial_sdu_len = skb->len; + err = 0; + break; + + case L2CAP_SDU_CONTINUE: +- if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) ++ if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) + break; + +- memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); ++ memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); + +- pi->partial_sdu_len += skb->len; +- if (pi->partial_sdu_len > pi->sdu_len) +- kfree_skb(pi->sdu); ++ chan->partial_sdu_len += skb->len; ++ if (chan->partial_sdu_len > chan->sdu_len) ++ kfree_skb(chan->sdu); + else + err = 0; + + break; + + case L2CAP_SDU_END: +- if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) ++ if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) + break; + +- memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); ++ memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); + +- pi->conn_state &= ~L2CAP_CONN_SAR_SDU; +- pi->partial_sdu_len += skb->len; ++ chan->conn_state &= ~L2CAP_CONN_SAR_SDU; ++ chan->partial_sdu_len += skb->len; + +- if (pi->partial_sdu_len > pi->imtu) ++ if (chan->partial_sdu_len > chan->imtu) + goto drop; + +- if (pi->partial_sdu_len == pi->sdu_len) { +- _skb = skb_clone(pi->sdu, GFP_ATOMIC); +- err = sock_queue_rcv_skb(sk, _skb); ++ if (chan->partial_sdu_len == chan->sdu_len) { ++ _skb = skb_clone(chan->sdu, GFP_ATOMIC); ++ err = sock_queue_rcv_skb(chan->sk, _skb); + if (err < 0) + kfree_skb(_skb); + } + err = 0; + + drop: +- kfree_skb(pi->sdu); ++ kfree_skb(chan->sdu); + break; + } + +@@ -3101,31 +3171,30 @@ + return err; + } + +-static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq) ++static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) + { + struct sk_buff *skb; + u16 control; + +- while ((skb = skb_peek(SREJ_QUEUE(sk)))) { ++ while ((skb = skb_peek(&chan->srej_q))) { + if (bt_cb(skb)->tx_seq != tx_seq) + break; + +- skb = skb_dequeue(SREJ_QUEUE(sk)); ++ skb = skb_dequeue(&chan->srej_q); + control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; +- l2cap_ertm_reassembly_sdu(sk, skb, control); +- l2cap_pi(sk)->buffer_seq_srej = +- (l2cap_pi(sk)->buffer_seq_srej + 1) % 64; ++ l2cap_ertm_reassembly_sdu(chan, skb, control); ++ chan->buffer_seq_srej = ++ (chan->buffer_seq_srej + 1) % 64; + tx_seq = (tx_seq + 1) % 64; + } + } + +-static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq) ++static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + struct srej_list *l, *tmp; + u16 control; + +- list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) { ++ list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { + if (l->tx_seq == tx_seq) { + list_del(&l->list); + kfree(l); +@@ -3133,107 +3202,105 @@ + } + control = L2CAP_SUPER_SELECT_REJECT; + control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; +- l2cap_send_sframe(pi, control); ++ l2cap_send_sframe(chan, control); + list_del(&l->list); +- list_add_tail(&l->list, SREJ_LIST(sk)); ++ list_add_tail(&l->list, &chan->srej_l); + } + } + +-static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) ++static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + struct srej_list *new; + u16 control; + +- while (tx_seq != pi->expected_tx_seq) { ++ while (tx_seq != chan->expected_tx_seq) { + control = L2CAP_SUPER_SELECT_REJECT; +- control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; +- l2cap_send_sframe(pi, control); ++ control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; ++ l2cap_send_sframe(chan, control); + + new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); +- new->tx_seq = pi->expected_tx_seq; +- pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; +- list_add_tail(&new->list, SREJ_LIST(sk)); ++ new->tx_seq = chan->expected_tx_seq; ++ chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; ++ list_add_tail(&new->list, &chan->srej_l); + } +- pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; ++ chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; + } + +-static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) ++static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + u8 tx_seq = __get_txseq(rx_control); + u8 req_seq = __get_reqseq(rx_control); + u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; + int tx_seq_offset, expected_tx_seq_offset; +- int num_to_ack = (pi->tx_win/6) + 1; ++ int num_to_ack = (chan->tx_win/6) + 1; + int err = 0; + +- BT_DBG("sk %p len %d tx_seq %d rx_control 0x%4.4x", sk, skb->len, tx_seq, +- rx_control); ++ BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len, ++ tx_seq, rx_control); + + if (L2CAP_CTRL_FINAL & rx_control && +- l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) { +- del_timer(&pi->monitor_timer); +- if (pi->unacked_frames > 0) ++ chan->conn_state & L2CAP_CONN_WAIT_F) { ++ del_timer(&chan->monitor_timer); ++ if (chan->unacked_frames > 0) + __mod_retrans_timer(); +- pi->conn_state &= ~L2CAP_CONN_WAIT_F; ++ chan->conn_state &= ~L2CAP_CONN_WAIT_F; + } + +- pi->expected_ack_seq = req_seq; +- l2cap_drop_acked_frames(sk); ++ chan->expected_ack_seq = req_seq; ++ l2cap_drop_acked_frames(chan); + +- if (tx_seq == pi->expected_tx_seq) ++ if (tx_seq == chan->expected_tx_seq) + goto expected; + +- tx_seq_offset = (tx_seq - pi->buffer_seq) % 64; ++ tx_seq_offset = (tx_seq - chan->buffer_seq) % 64; + if (tx_seq_offset < 0) + tx_seq_offset += 64; + + /* invalid tx_seq */ +- if (tx_seq_offset >= pi->tx_win) { +- l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); ++ if (tx_seq_offset >= chan->tx_win) { ++ l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + goto drop; + } + +- if (pi->conn_state == L2CAP_CONN_LOCAL_BUSY) ++ if (chan->conn_state == L2CAP_CONN_LOCAL_BUSY) + goto drop; + +- if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { ++ if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { + struct srej_list *first; + +- first = list_first_entry(SREJ_LIST(sk), ++ first = list_first_entry(&chan->srej_l, + struct srej_list, list); + if (tx_seq == first->tx_seq) { +- l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); +- l2cap_check_srej_gap(sk, tx_seq); ++ l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); ++ l2cap_check_srej_gap(chan, tx_seq); + + list_del(&first->list); + kfree(first); + +- if (list_empty(SREJ_LIST(sk))) { +- pi->buffer_seq = pi->buffer_seq_srej; +- pi->conn_state &= ~L2CAP_CONN_SREJ_SENT; +- l2cap_send_ack(pi); +- BT_DBG("sk %p, Exit SREJ_SENT", sk); ++ if (list_empty(&chan->srej_l)) { ++ chan->buffer_seq = chan->buffer_seq_srej; ++ chan->conn_state &= ~L2CAP_CONN_SREJ_SENT; ++ l2cap_send_ack(chan); ++ BT_DBG("chan %p, Exit SREJ_SENT", chan); + } + } else { + struct srej_list *l; + + /* duplicated tx_seq */ +- if (l2cap_add_to_srej_queue(sk, skb, tx_seq, sar) < 0) ++ if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0) + goto drop; + +- list_for_each_entry(l, SREJ_LIST(sk), list) { ++ list_for_each_entry(l, &chan->srej_l, list) { + if (l->tx_seq == tx_seq) { +- l2cap_resend_srejframe(sk, tx_seq); ++ l2cap_resend_srejframe(chan, tx_seq); + return 0; + } + } +- l2cap_send_srejframe(sk, tx_seq); ++ l2cap_send_srejframe(chan, tx_seq); + } + } else { + expected_tx_seq_offset = +- (pi->expected_tx_seq - pi->buffer_seq) % 64; ++ (chan->expected_tx_seq - chan->buffer_seq) % 64; + if (expected_tx_seq_offset < 0) + expected_tx_seq_offset += 64; + +@@ -3241,51 +3308,51 @@ + if (tx_seq_offset < expected_tx_seq_offset) + goto drop; + +- pi->conn_state |= L2CAP_CONN_SREJ_SENT; ++ chan->conn_state |= L2CAP_CONN_SREJ_SENT; + +- BT_DBG("sk %p, Enter SREJ", sk); ++ BT_DBG("chan %p, Enter SREJ", chan); + +- INIT_LIST_HEAD(SREJ_LIST(sk)); +- pi->buffer_seq_srej = pi->buffer_seq; ++ INIT_LIST_HEAD(&chan->srej_l); ++ chan->buffer_seq_srej = chan->buffer_seq; + +- __skb_queue_head_init(SREJ_QUEUE(sk)); +- __skb_queue_head_init(BUSY_QUEUE(sk)); +- l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); ++ __skb_queue_head_init(&chan->srej_q); ++ __skb_queue_head_init(&chan->busy_q); ++ l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); + +- pi->conn_state |= L2CAP_CONN_SEND_PBIT; ++ chan->conn_state |= L2CAP_CONN_SEND_PBIT; + +- l2cap_send_srejframe(sk, tx_seq); ++ l2cap_send_srejframe(chan, tx_seq); + +- del_timer(&pi->ack_timer); ++ del_timer(&chan->ack_timer); + } + return 0; + + expected: +- pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; ++ chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; + +- if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { ++ if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { + bt_cb(skb)->tx_seq = tx_seq; + bt_cb(skb)->sar = sar; +- __skb_queue_tail(SREJ_QUEUE(sk), skb); ++ __skb_queue_tail(&chan->srej_q, skb); + return 0; + } + +- err = l2cap_push_rx_skb(sk, skb, rx_control); ++ err = l2cap_push_rx_skb(chan, skb, rx_control); + if (err < 0) + return 0; + + if (rx_control & L2CAP_CTRL_FINAL) { +- if (pi->conn_state & L2CAP_CONN_REJ_ACT) +- pi->conn_state &= ~L2CAP_CONN_REJ_ACT; ++ if (chan->conn_state & L2CAP_CONN_REJ_ACT) ++ chan->conn_state &= ~L2CAP_CONN_REJ_ACT; + else +- l2cap_retransmit_frames(sk); ++ l2cap_retransmit_frames(chan); + } + + __mod_ack_timer(); + +- pi->num_acked = (pi->num_acked + 1) % num_to_ack; +- if (pi->num_acked == num_to_ack - 1) +- l2cap_send_ack(pi); ++ chan->num_acked = (chan->num_acked + 1) % num_to_ack; ++ if (chan->num_acked == num_to_ack - 1) ++ l2cap_send_ack(chan); + + return 0; + +@@ -3294,165 +3361,160 @@ + return 0; + } + +-static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) ++static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); +- +- BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control), ++ BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control), + rx_control); + +- pi->expected_ack_seq = __get_reqseq(rx_control); +- l2cap_drop_acked_frames(sk); ++ chan->expected_ack_seq = __get_reqseq(rx_control); ++ l2cap_drop_acked_frames(chan); + + if (rx_control & L2CAP_CTRL_POLL) { +- pi->conn_state |= L2CAP_CONN_SEND_FBIT; +- if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { +- if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && +- (pi->unacked_frames > 0)) ++ chan->conn_state |= L2CAP_CONN_SEND_FBIT; ++ if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { ++ if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && ++ (chan->unacked_frames > 0)) + __mod_retrans_timer(); + +- pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; +- l2cap_send_srejtail(sk); ++ chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; ++ l2cap_send_srejtail(chan); + } else { +- l2cap_send_i_or_rr_or_rnr(sk); ++ l2cap_send_i_or_rr_or_rnr(chan); + } + + } else if (rx_control & L2CAP_CTRL_FINAL) { +- pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; ++ chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + +- if (pi->conn_state & L2CAP_CONN_REJ_ACT) +- pi->conn_state &= ~L2CAP_CONN_REJ_ACT; ++ if (chan->conn_state & L2CAP_CONN_REJ_ACT) ++ chan->conn_state &= ~L2CAP_CONN_REJ_ACT; + else +- l2cap_retransmit_frames(sk); ++ l2cap_retransmit_frames(chan); + + } else { +- if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && +- (pi->unacked_frames > 0)) ++ if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && ++ (chan->unacked_frames > 0)) + __mod_retrans_timer(); + +- pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; +- if (pi->conn_state & L2CAP_CONN_SREJ_SENT) +- l2cap_send_ack(pi); ++ chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; ++ if (chan->conn_state & L2CAP_CONN_SREJ_SENT) ++ l2cap_send_ack(chan); + else +- l2cap_ertm_send(sk); ++ l2cap_ertm_send(chan); + } + } + +-static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control) ++static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + u8 tx_seq = __get_reqseq(rx_control); + +- BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control); ++ BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); + +- pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; ++ chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + +- pi->expected_ack_seq = tx_seq; +- l2cap_drop_acked_frames(sk); ++ chan->expected_ack_seq = tx_seq; ++ l2cap_drop_acked_frames(chan); + + if (rx_control & L2CAP_CTRL_FINAL) { +- if (pi->conn_state & L2CAP_CONN_REJ_ACT) +- pi->conn_state &= ~L2CAP_CONN_REJ_ACT; ++ if (chan->conn_state & L2CAP_CONN_REJ_ACT) ++ chan->conn_state &= ~L2CAP_CONN_REJ_ACT; + else +- l2cap_retransmit_frames(sk); ++ l2cap_retransmit_frames(chan); + } else { +- l2cap_retransmit_frames(sk); ++ l2cap_retransmit_frames(chan); + +- if (pi->conn_state & L2CAP_CONN_WAIT_F) +- pi->conn_state |= L2CAP_CONN_REJ_ACT; ++ if (chan->conn_state & L2CAP_CONN_WAIT_F) ++ chan->conn_state |= L2CAP_CONN_REJ_ACT; + } + } +-static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control) ++static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + u8 tx_seq = __get_reqseq(rx_control); + +- BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control); ++ BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); + +- pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; ++ chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + + if (rx_control & L2CAP_CTRL_POLL) { +- pi->expected_ack_seq = tx_seq; +- l2cap_drop_acked_frames(sk); ++ chan->expected_ack_seq = tx_seq; ++ l2cap_drop_acked_frames(chan); + +- pi->conn_state |= L2CAP_CONN_SEND_FBIT; +- l2cap_retransmit_one_frame(sk, tx_seq); ++ chan->conn_state |= L2CAP_CONN_SEND_FBIT; ++ l2cap_retransmit_one_frame(chan, tx_seq); + +- l2cap_ertm_send(sk); ++ l2cap_ertm_send(chan); + +- if (pi->conn_state & L2CAP_CONN_WAIT_F) { +- pi->srej_save_reqseq = tx_seq; +- pi->conn_state |= L2CAP_CONN_SREJ_ACT; ++ if (chan->conn_state & L2CAP_CONN_WAIT_F) { ++ chan->srej_save_reqseq = tx_seq; ++ chan->conn_state |= L2CAP_CONN_SREJ_ACT; + } + } else if (rx_control & L2CAP_CTRL_FINAL) { +- if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) && +- pi->srej_save_reqseq == tx_seq) +- pi->conn_state &= ~L2CAP_CONN_SREJ_ACT; ++ if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) && ++ chan->srej_save_reqseq == tx_seq) ++ chan->conn_state &= ~L2CAP_CONN_SREJ_ACT; + else +- l2cap_retransmit_one_frame(sk, tx_seq); ++ l2cap_retransmit_one_frame(chan, tx_seq); + } else { +- l2cap_retransmit_one_frame(sk, tx_seq); +- if (pi->conn_state & L2CAP_CONN_WAIT_F) { +- pi->srej_save_reqseq = tx_seq; +- pi->conn_state |= L2CAP_CONN_SREJ_ACT; ++ l2cap_retransmit_one_frame(chan, tx_seq); ++ if (chan->conn_state & L2CAP_CONN_WAIT_F) { ++ chan->srej_save_reqseq = tx_seq; ++ chan->conn_state |= L2CAP_CONN_SREJ_ACT; + } + } + } + +-static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control) ++static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); + u8 tx_seq = __get_reqseq(rx_control); + +- BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control); ++ BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); + +- pi->conn_state |= L2CAP_CONN_REMOTE_BUSY; +- pi->expected_ack_seq = tx_seq; +- l2cap_drop_acked_frames(sk); ++ chan->conn_state |= L2CAP_CONN_REMOTE_BUSY; ++ chan->expected_ack_seq = tx_seq; ++ l2cap_drop_acked_frames(chan); + + if (rx_control & L2CAP_CTRL_POLL) +- pi->conn_state |= L2CAP_CONN_SEND_FBIT; ++ chan->conn_state |= L2CAP_CONN_SEND_FBIT; + +- if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) { +- del_timer(&pi->retrans_timer); ++ if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) { ++ del_timer(&chan->retrans_timer); + if (rx_control & L2CAP_CTRL_POLL) +- l2cap_send_rr_or_rnr(pi, L2CAP_CTRL_FINAL); ++ l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL); + return; + } + + if (rx_control & L2CAP_CTRL_POLL) +- l2cap_send_srejtail(sk); ++ l2cap_send_srejtail(chan); + else +- l2cap_send_sframe(pi, L2CAP_SUPER_RCV_READY); ++ l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY); + } + +-static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) ++static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) + { +- BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); ++ BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len); + + if (L2CAP_CTRL_FINAL & rx_control && +- l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) { +- del_timer(&l2cap_pi(sk)->monitor_timer); +- if (l2cap_pi(sk)->unacked_frames > 0) ++ chan->conn_state & L2CAP_CONN_WAIT_F) { ++ del_timer(&chan->monitor_timer); ++ if (chan->unacked_frames > 0) + __mod_retrans_timer(); +- l2cap_pi(sk)->conn_state &= ~L2CAP_CONN_WAIT_F; ++ chan->conn_state &= ~L2CAP_CONN_WAIT_F; + } + + switch (rx_control & L2CAP_CTRL_SUPERVISE) { + case L2CAP_SUPER_RCV_READY: +- l2cap_data_channel_rrframe(sk, rx_control); ++ l2cap_data_channel_rrframe(chan, rx_control); + break; + + case L2CAP_SUPER_REJECT: +- l2cap_data_channel_rejframe(sk, rx_control); ++ l2cap_data_channel_rejframe(chan, rx_control); + break; + + case L2CAP_SUPER_SELECT_REJECT: +- l2cap_data_channel_srejframe(sk, rx_control); ++ l2cap_data_channel_srejframe(chan, rx_control); + break; + + case L2CAP_SUPER_RCV_NOT_READY: +- l2cap_data_channel_rnrframe(sk, rx_control); ++ l2cap_data_channel_rnrframe(chan, rx_control); + break; + } + +@@ -3462,7 +3524,7 @@ + + static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) + { +- struct l2cap_pinfo *pi = l2cap_pi(sk); ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + u16 control; + u8 req_seq; + int len, next_tx_seq_offset, req_seq_offset; +@@ -3476,51 +3538,51 @@ + * Receiver will miss it and start proper recovery + * procedures and ask retransmission. + */ +- if (l2cap_check_fcs(pi, skb)) ++ if (l2cap_check_fcs(chan, skb)) + goto drop; + + if (__is_sar_start(control) && __is_iframe(control)) + len -= 2; + +- if (pi->fcs == L2CAP_FCS_CRC16) ++ if (chan->fcs == L2CAP_FCS_CRC16) + len -= 2; + +- if (len > pi->mps) { +- l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); ++ if (len > chan->mps) { ++ l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + goto drop; + } + + req_seq = __get_reqseq(control); +- req_seq_offset = (req_seq - pi->expected_ack_seq) % 64; ++ req_seq_offset = (req_seq - chan->expected_ack_seq) % 64; + if (req_seq_offset < 0) + req_seq_offset += 64; + + next_tx_seq_offset = +- (pi->next_tx_seq - pi->expected_ack_seq) % 64; ++ (chan->next_tx_seq - chan->expected_ack_seq) % 64; + if (next_tx_seq_offset < 0) + next_tx_seq_offset += 64; + + /* check for invalid req-seq */ + if (req_seq_offset > next_tx_seq_offset) { +- l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); ++ l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + goto drop; + } + + if (__is_iframe(control)) { + if (len < 0) { +- l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); ++ l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + goto drop; + } + +- l2cap_data_channel_iframe(sk, control, skb); ++ l2cap_data_channel_iframe(chan, control, skb); + } else { + if (len != 0) { + BT_ERR("%d", len); +- l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); ++ l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + goto drop; + } + +- l2cap_data_channel_sframe(sk, control, skb); ++ l2cap_data_channel_sframe(chan, control, skb); + } + + return 0; +@@ -3532,33 +3594,35 @@ + + static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) + { ++ struct l2cap_chan *chan; + struct sock *sk; + struct l2cap_pinfo *pi; + u16 control; + u8 tx_seq; + int len; + +- sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); +- if (!sk) { ++ chan = l2cap_get_chan_by_scid(conn, cid); ++ if (!chan) { + BT_DBG("unknown cid 0x%4.4x", cid); + goto drop; + } + ++ sk = chan->sk; + pi = l2cap_pi(sk); + +- BT_DBG("sk %p, len %d", sk, skb->len); ++ BT_DBG("chan %p, len %d", chan, skb->len); + + if (sk->sk_state != BT_CONNECTED) + goto drop; + +- switch (pi->mode) { ++ switch (chan->mode) { + case L2CAP_MODE_BASIC: + /* If socket recv buffers overflows we drop data here + * which is *bad* because L2CAP has to be reliable. + * But we don't have any other choice. L2CAP doesn't + * provide flow control mechanism. */ + +- if (pi->imtu < skb->len) ++ if (chan->imtu < skb->len) + goto drop; + + if (!sock_queue_rcv_skb(sk, skb)) +@@ -3580,31 +3644,31 @@ + skb_pull(skb, 2); + len = skb->len; + +- if (l2cap_check_fcs(pi, skb)) ++ if (l2cap_check_fcs(chan, skb)) + goto drop; + + if (__is_sar_start(control)) + len -= 2; + +- if (pi->fcs == L2CAP_FCS_CRC16) ++ if (chan->fcs == L2CAP_FCS_CRC16) + len -= 2; + +- if (len > pi->mps || len < 0 || __is_sframe(control)) ++ if (len > chan->mps || len < 0 || __is_sframe(control)) + goto drop; + + tx_seq = __get_txseq(control); + +- if (pi->expected_tx_seq == tx_seq) +- pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; ++ if (chan->expected_tx_seq == tx_seq) ++ chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; + else +- pi->expected_tx_seq = (tx_seq + 1) % 64; ++ chan->expected_tx_seq = (tx_seq + 1) % 64; + +- l2cap_streaming_reassembly_sdu(sk, skb, control); ++ l2cap_streaming_reassembly_sdu(chan, skb, control); + + goto done; + + default: +- BT_DBG("sk %p: bad mode 0x%2.2x", sk, pi->mode); ++ BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode); + break; + } + +@@ -3633,7 +3697,37 @@ + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) + goto drop; + +- if (l2cap_pi(sk)->imtu < skb->len) ++ if (l2cap_pi(sk)->chan->imtu < skb->len) ++ goto drop; ++ ++ if (!sock_queue_rcv_skb(sk, skb)) ++ goto done; ++ ++drop: ++ kfree_skb(skb); ++ ++done: ++ if (sk) ++ bh_unlock_sock(sk); ++ return 0; ++} ++ ++static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) ++{ ++ struct sock *sk; ++ ++ sk = l2cap_get_sock_by_scid(0, cid, conn->src); ++ if (!sk) ++ goto drop; ++ ++ bh_lock_sock(sk); ++ ++ BT_DBG("sk %p, len %d", sk, skb->len); ++ ++ if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) ++ goto drop; ++ ++ if (l2cap_pi(sk)->chan->imtu < skb->len) + goto drop; + + if (!sock_queue_rcv_skb(sk, skb)) +@@ -3677,6 +3771,10 @@ + l2cap_conless_channel(conn, psm, skb); + break; + ++ case L2CAP_CID_LE_DATA: ++ l2cap_att_channel(conn, cid, skb); ++ break; ++ + default: + l2cap_data_channel(conn, cid, skb); + break; +@@ -3699,17 +3797,19 @@ + /* Find listening sockets and check their link_mode */ + read_lock(&l2cap_sk_list.lock); + sk_for_each(sk, node, &l2cap_sk_list.head) { ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; ++ + if (sk->sk_state != BT_LISTEN) + continue; + + if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { + lm1 |= HCI_LM_ACCEPT; +- if (l2cap_pi(sk)->role_switch) ++ if (chan->role_switch) + lm1 |= HCI_LM_MASTER; + exact++; + } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { + lm2 |= HCI_LM_ACCEPT; +- if (l2cap_pi(sk)->role_switch) ++ if (chan->role_switch) + lm2 |= HCI_LM_MASTER; + } + } +@@ -3761,49 +3861,50 @@ + return 0; + } + +-static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt) ++static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) + { ++ struct sock *sk = chan->sk; ++ + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) + return; + + if (encrypt == 0x00) { +- if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) { ++ if (chan->sec_level == BT_SECURITY_MEDIUM) { + l2cap_sock_clear_timer(sk); + l2cap_sock_set_timer(sk, HZ * 5); +- } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) ++ } else if (chan->sec_level == BT_SECURITY_HIGH) + __l2cap_sock_close(sk, ECONNREFUSED); + } else { +- if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) ++ if (chan->sec_level == BT_SECURITY_MEDIUM) + l2cap_sock_clear_timer(sk); + } + } + + static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) + { +- struct l2cap_chan_list *l; + struct l2cap_conn *conn = hcon->l2cap_data; +- struct sock *sk; ++ struct l2cap_chan *chan; + + if (!conn) + return 0; + +- l = &conn->chan_list; +- + BT_DBG("conn %p", conn); + +- read_lock(&l->lock); ++ read_lock(&conn->chan_lock); ++ ++ list_for_each_entry(chan, &conn->chan_l, list) { ++ struct sock *sk = chan->sk; + +- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + bh_lock_sock(sk); + +- if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) { ++ if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) { + bh_unlock_sock(sk); + continue; + } + + if (!status && (sk->sk_state == BT_CONNECTED || + sk->sk_state == BT_CONFIG)) { +- l2cap_check_encryption(sk, encrypt); ++ l2cap_check_encryption(chan, encrypt); + bh_unlock_sock(sk); + continue; + } +@@ -3811,13 +3912,13 @@ + if (sk->sk_state == BT_CONNECT) { + if (!status) { + struct l2cap_conn_req req; +- req.scid = cpu_to_le16(l2cap_pi(sk)->scid); +- req.psm = l2cap_pi(sk)->psm; ++ req.scid = cpu_to_le16(chan->scid); ++ req.psm = chan->psm; + +- l2cap_pi(sk)->ident = l2cap_get_ident(conn); +- l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; ++ chan->ident = l2cap_get_ident(conn); ++ chan->conf_state |= L2CAP_CONF_CONNECT_PEND; + +- l2cap_send_cmd(conn, l2cap_pi(sk)->ident, ++ l2cap_send_cmd(conn, chan->ident, + L2CAP_CONN_REQ, sizeof(req), &req); + } else { + l2cap_sock_clear_timer(sk); +@@ -3836,18 +3937,18 @@ + result = L2CAP_CR_SEC_BLOCK; + } + +- rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); +- rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); ++ rsp.scid = cpu_to_le16(chan->dcid); ++ rsp.dcid = cpu_to_le16(chan->scid); + rsp.result = cpu_to_le16(result); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); +- l2cap_send_cmd(conn, l2cap_pi(sk)->ident, +- L2CAP_CONN_RSP, sizeof(rsp), &rsp); ++ l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, ++ sizeof(rsp), &rsp); + } + + bh_unlock_sock(sk); + } + +- read_unlock(&l->lock); ++ read_unlock(&conn->chan_lock); + + return 0; + } +@@ -3866,7 +3967,7 @@ + + if (!(flags & ACL_CONT)) { + struct l2cap_hdr *hdr; +- struct sock *sk; ++ struct l2cap_chan *chan; + u16 cid; + int len; + +@@ -3904,18 +4005,21 @@ + goto drop; + } + +- sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); ++ chan = l2cap_get_chan_by_scid(conn, cid); + +- if (sk && l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) { +- BT_ERR("Frame exceeding recv MTU (len %d, MTU %d)", +- len, l2cap_pi(sk)->imtu); +- bh_unlock_sock(sk); +- l2cap_conn_unreliable(conn, ECOMM); +- goto drop; +- } ++ if (chan && chan->sk) { ++ struct sock *sk = chan->sk; + +- if (sk) ++ if (chan->imtu < len - L2CAP_HDR_SIZE) { ++ BT_ERR("Frame exceeding recv MTU (len %d, " ++ "MTU %d)", len, ++ chan->imtu); ++ bh_unlock_sock(sk); ++ l2cap_conn_unreliable(conn, ECOMM); ++ goto drop; ++ } + bh_unlock_sock(sk); ++ } + + /* Allocate skb for the complete frame (with header) */ + conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC); +@@ -3969,14 +4073,15 @@ + + sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_pinfo *pi = l2cap_pi(sk); ++ struct l2cap_chan *chan = pi->chan; + + seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n", + batostr(&bt_sk(sk)->src), + batostr(&bt_sk(sk)->dst), +- sk->sk_state, __le16_to_cpu(pi->psm), +- pi->scid, pi->dcid, +- pi->imtu, pi->omtu, pi->sec_level, +- pi->mode); ++ sk->sk_state, __le16_to_cpu(chan->psm), ++ chan->scid, chan->dcid, ++ chan->imtu, chan->omtu, chan->sec_level, ++ chan->mode); + } + + read_unlock_bh(&l2cap_sk_list.lock); +diff -Naur linux-2.6.39-rc6/net/bluetooth/l2cap_sock.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/l2cap_sock.c +--- linux-2.6.39-rc6/net/bluetooth/l2cap_sock.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/l2cap_sock.c 2011-05-05 23:30:21.227873561 +0200 +@@ -30,6 +30,8 @@ + #include + #include + ++static const struct proto_ops l2cap_sock_ops; ++ + /* ---- L2CAP timers ---- */ + static void l2cap_sock_timeout(unsigned long arg) + { +@@ -51,7 +53,7 @@ + if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) + reason = ECONNREFUSED; + else if (sk->sk_state == BT_CONNECT && +- l2cap_pi(sk)->sec_level != BT_SECURITY_SDP) ++ l2cap_pi(sk)->chan->sec_level != BT_SECURITY_SDP) + reason = ECONNREFUSED; + else + reason = ETIMEDOUT; +@@ -80,9 +82,13 @@ + { + struct sock *sk; + struct hlist_node *node; +- sk_for_each(sk, node, &l2cap_sk_list.head) +- if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src)) ++ sk_for_each(sk, node, &l2cap_sk_list.head) { ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; ++ ++ if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src)) + goto found; ++ } ++ + sk = NULL; + found: + return sk; +@@ -91,6 +97,7 @@ + static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) + { + struct sock *sk = sock->sk; ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct sockaddr_l2 la; + int len, err = 0; + +@@ -136,17 +143,17 @@ + } else { + /* Save source address */ + bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); +- l2cap_pi(sk)->psm = la.l2_psm; +- l2cap_pi(sk)->sport = la.l2_psm; ++ chan->psm = la.l2_psm; ++ chan->sport = la.l2_psm; + sk->sk_state = BT_BOUND; + + if (__le16_to_cpu(la.l2_psm) == 0x0001 || + __le16_to_cpu(la.l2_psm) == 0x0003) +- l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; ++ chan->sec_level = BT_SECURITY_SDP; + } + + if (la.l2_cid) +- l2cap_pi(sk)->scid = la.l2_cid; ++ chan->scid = la.l2_cid; + + write_unlock_bh(&l2cap_sk_list.lock); + +@@ -158,6 +165,7 @@ + static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) + { + struct sock *sk = sock->sk; ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct sockaddr_l2 la; + int len, err = 0; + +@@ -182,7 +190,7 @@ + goto done; + } + +- switch (l2cap_pi(sk)->mode) { ++ switch (chan->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_ERTM: +@@ -226,10 +234,10 @@ + + /* Set destination address and psm */ + bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); +- l2cap_pi(sk)->psm = la.l2_psm; +- l2cap_pi(sk)->dcid = la.l2_cid; ++ chan->psm = la.l2_psm; ++ chan->dcid = la.l2_cid; + +- err = l2cap_do_connect(sk); ++ err = l2cap_chan_connect(l2cap_pi(sk)->chan); + if (err) + goto done; + +@@ -244,6 +252,7 @@ + static int l2cap_sock_listen(struct socket *sock, int backlog) + { + struct sock *sk = sock->sk; ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + int err = 0; + + BT_DBG("sk %p backlog %d", sk, backlog); +@@ -256,7 +265,7 @@ + goto done; + } + +- switch (l2cap_pi(sk)->mode) { ++ switch (chan->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_ERTM: +@@ -269,7 +278,7 @@ + goto done; + } + +- if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->dcid) { ++ if (!chan->psm && !chan->scid) { + bdaddr_t *src = &bt_sk(sk)->src; + u16 psm; + +@@ -279,8 +288,8 @@ + + for (psm = 0x1001; psm < 0x1100; psm += 2) + if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { +- l2cap_pi(sk)->psm = cpu_to_le16(psm); +- l2cap_pi(sk)->sport = cpu_to_le16(psm); ++ chan->psm = cpu_to_le16(psm); ++ chan->sport = cpu_to_le16(psm); + err = 0; + break; + } +@@ -360,6 +369,7 @@ + { + struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; + struct sock *sk = sock->sk; ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + + BT_DBG("sock %p, sk %p", sock, sk); + +@@ -367,13 +377,13 @@ + *len = sizeof(struct sockaddr_l2); + + if (peer) { +- la->l2_psm = l2cap_pi(sk)->psm; ++ la->l2_psm = chan->psm; + bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst); +- la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid); ++ la->l2_cid = cpu_to_le16(chan->dcid); + } else { +- la->l2_psm = l2cap_pi(sk)->sport; ++ la->l2_psm = chan->sport; + bacpy(&la->l2_bdaddr, &bt_sk(sk)->src); +- la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid); ++ la->l2_cid = cpu_to_le16(chan->scid); + } + + return 0; +@@ -382,6 +392,7 @@ + static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen) + { + struct sock *sk = sock->sk; ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct l2cap_options opts; + struct l2cap_conninfo cinfo; + int len, err = 0; +@@ -397,13 +408,13 @@ + switch (optname) { + case L2CAP_OPTIONS: + memset(&opts, 0, sizeof(opts)); +- opts.imtu = l2cap_pi(sk)->imtu; +- opts.omtu = l2cap_pi(sk)->omtu; +- opts.flush_to = l2cap_pi(sk)->flush_to; +- opts.mode = l2cap_pi(sk)->mode; +- opts.fcs = l2cap_pi(sk)->fcs; +- opts.max_tx = l2cap_pi(sk)->max_tx; +- opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; ++ opts.imtu = chan->imtu; ++ opts.omtu = chan->omtu; ++ opts.flush_to = chan->flush_to; ++ opts.mode = chan->mode; ++ opts.fcs = chan->fcs; ++ opts.max_tx = chan->max_tx; ++ opts.txwin_size = (__u16)chan->tx_win; + + len = min_t(unsigned int, len, sizeof(opts)); + if (copy_to_user(optval, (char *) &opts, len)) +@@ -412,7 +423,7 @@ + break; + + case L2CAP_LM: +- switch (l2cap_pi(sk)->sec_level) { ++ switch (chan->sec_level) { + case BT_SECURITY_LOW: + opt = L2CAP_LM_AUTH; + break; +@@ -428,10 +439,10 @@ + break; + } + +- if (l2cap_pi(sk)->role_switch) ++ if (chan->role_switch) + opt |= L2CAP_LM_MASTER; + +- if (l2cap_pi(sk)->force_reliable) ++ if (chan->force_reliable) + opt |= L2CAP_LM_RELIABLE; + + if (put_user(opt, (u32 __user *) optval)) +@@ -446,8 +457,8 @@ + break; + } + +- cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle; +- memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3); ++ cinfo.hci_handle = chan->conn->hcon->handle; ++ memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3); + + len = min_t(unsigned int, len, sizeof(cinfo)); + if (copy_to_user(optval, (char *) &cinfo, len)) +@@ -467,6 +478,7 @@ + static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) + { + struct sock *sk = sock->sk; ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct bt_security sec; + int len, err = 0; + +@@ -491,7 +503,7 @@ + break; + } + +- sec.level = l2cap_pi(sk)->sec_level; ++ sec.level = chan->sec_level; + + len = min_t(unsigned int, len, sizeof(sec)); + if (copy_to_user(optval, (char *) &sec, len)) +@@ -511,7 +523,7 @@ + break; + + case BT_FLUSHABLE: +- if (put_user(l2cap_pi(sk)->flushable, (u32 __user *) optval)) ++ if (put_user(chan->flushable, (u32 __user *) optval)) + err = -EFAULT; + + break; +@@ -528,6 +540,7 @@ + static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) + { + struct sock *sk = sock->sk; ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct l2cap_options opts; + int len, err = 0; + u32 opt; +@@ -543,13 +556,13 @@ + break; + } + +- opts.imtu = l2cap_pi(sk)->imtu; +- opts.omtu = l2cap_pi(sk)->omtu; +- opts.flush_to = l2cap_pi(sk)->flush_to; +- opts.mode = l2cap_pi(sk)->mode; +- opts.fcs = l2cap_pi(sk)->fcs; +- opts.max_tx = l2cap_pi(sk)->max_tx; +- opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; ++ opts.imtu = chan->imtu; ++ opts.omtu = chan->omtu; ++ opts.flush_to = chan->flush_to; ++ opts.mode = chan->mode; ++ opts.fcs = chan->fcs; ++ opts.max_tx = chan->max_tx; ++ opts.txwin_size = (__u16)chan->tx_win; + + len = min_t(unsigned int, sizeof(opts), optlen); + if (copy_from_user((char *) &opts, optval, len)) { +@@ -562,10 +575,10 @@ + break; + } + +- l2cap_pi(sk)->mode = opts.mode; +- switch (l2cap_pi(sk)->mode) { ++ chan->mode = opts.mode; ++ switch (chan->mode) { + case L2CAP_MODE_BASIC: +- l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; ++ chan->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; + break; + case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: +@@ -577,11 +590,11 @@ + break; + } + +- l2cap_pi(sk)->imtu = opts.imtu; +- l2cap_pi(sk)->omtu = opts.omtu; +- l2cap_pi(sk)->fcs = opts.fcs; +- l2cap_pi(sk)->max_tx = opts.max_tx; +- l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size; ++ chan->imtu = opts.imtu; ++ chan->omtu = opts.omtu; ++ chan->fcs = opts.fcs; ++ chan->max_tx = opts.max_tx; ++ chan->tx_win = (__u8)opts.txwin_size; + break; + + case L2CAP_LM: +@@ -591,14 +604,14 @@ + } + + if (opt & L2CAP_LM_AUTH) +- l2cap_pi(sk)->sec_level = BT_SECURITY_LOW; ++ chan->sec_level = BT_SECURITY_LOW; + if (opt & L2CAP_LM_ENCRYPT) +- l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM; ++ chan->sec_level = BT_SECURITY_MEDIUM; + if (opt & L2CAP_LM_SECURE) +- l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH; ++ chan->sec_level = BT_SECURITY_HIGH; + +- l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER); +- l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE); ++ chan->role_switch = (opt & L2CAP_LM_MASTER); ++ chan->force_reliable = (opt & L2CAP_LM_RELIABLE); + break; + + default: +@@ -613,6 +626,7 @@ + static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) + { + struct sock *sk = sock->sk; ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct bt_security sec; + int len, err = 0; + u32 opt; +@@ -649,7 +663,7 @@ + break; + } + +- l2cap_pi(sk)->sec_level = sec.level; ++ chan->sec_level = sec.level; + break; + + case BT_DEFER_SETUP: +@@ -678,7 +692,7 @@ + } + + if (opt == BT_FLUSHABLE_OFF) { +- struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct l2cap_conn *conn = chan->conn; + /* proceed further only when we have l2cap_conn and + No Flush support in the LM */ + if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) { +@@ -687,7 +701,7 @@ + } + } + +- l2cap_pi(sk)->flushable = opt; ++ chan->flushable = opt; + break; + + default: +@@ -702,7 +716,7 @@ + static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) + { + struct sock *sk = sock->sk; +- struct l2cap_pinfo *pi = l2cap_pi(sk); ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct sk_buff *skb; + u16 control; + int err; +@@ -725,74 +739,77 @@ + + /* Connectionless channel */ + if (sk->sk_type == SOCK_DGRAM) { +- skb = l2cap_create_connless_pdu(sk, msg, len); ++ skb = l2cap_create_connless_pdu(chan, msg, len); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + } else { +- l2cap_do_send(sk, skb); ++ l2cap_do_send(chan, skb); + err = len; + } + goto done; + } + +- switch (pi->mode) { ++ switch (chan->mode) { + case L2CAP_MODE_BASIC: + /* Check outgoing MTU */ +- if (len > pi->omtu) { ++ if (len > chan->omtu) { + err = -EMSGSIZE; + goto done; + } + + /* Create a basic PDU */ +- skb = l2cap_create_basic_pdu(sk, msg, len); ++ skb = l2cap_create_basic_pdu(chan, msg, len); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + goto done; + } + +- l2cap_do_send(sk, skb); ++ l2cap_do_send(chan, skb); + err = len; + break; + + case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: + /* Entire SDU fits into one PDU */ +- if (len <= pi->remote_mps) { ++ if (len <= chan->remote_mps) { + control = L2CAP_SDU_UNSEGMENTED; +- skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0); ++ skb = l2cap_create_iframe_pdu(chan, msg, len, control, ++ 0); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + goto done; + } +- __skb_queue_tail(TX_QUEUE(sk), skb); ++ __skb_queue_tail(&chan->tx_q, skb); + +- if (sk->sk_send_head == NULL) +- sk->sk_send_head = skb; ++ if (chan->tx_send_head == NULL) ++ chan->tx_send_head = skb; + + } else { + /* Segment SDU into multiples PDUs */ +- err = l2cap_sar_segment_sdu(sk, msg, len); ++ err = l2cap_sar_segment_sdu(chan, msg, len); + if (err < 0) + goto done; + } + +- if (pi->mode == L2CAP_MODE_STREAMING) { +- l2cap_streaming_send(sk); +- } else { +- if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && +- (pi->conn_state & L2CAP_CONN_WAIT_F)) { +- err = len; +- break; +- } +- err = l2cap_ertm_send(sk); ++ if (chan->mode == L2CAP_MODE_STREAMING) { ++ l2cap_streaming_send(chan); ++ err = len; ++ break; ++ } ++ ++ if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && ++ (chan->conn_state & L2CAP_CONN_WAIT_F)) { ++ err = len; ++ break; + } ++ err = l2cap_ertm_send(chan); + + if (err >= 0) + err = len; + break; + + default: +- BT_DBG("bad state %1.1x", pi->mode); ++ BT_DBG("bad state %1.1x", chan->mode); + err = -EBADFD; + } + +@@ -808,29 +825,9 @@ + lock_sock(sk); + + if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { +- struct l2cap_conn_rsp rsp; +- struct l2cap_conn *conn = l2cap_pi(sk)->conn; +- u8 buf[128]; +- + sk->sk_state = BT_CONFIG; + +- rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); +- rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); +- rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); +- rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); +- l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident, +- L2CAP_CONN_RSP, sizeof(rsp), &rsp); +- +- if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) { +- release_sock(sk); +- return 0; +- } +- +- l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; +- l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, +- l2cap_build_conf_req(sk, buf), buf); +- l2cap_pi(sk)->num_conf_req++; +- ++ __l2cap_connect_rsp_defer(l2cap_pi(sk)->chan); + release_sock(sk); + return 0; + } +@@ -854,6 +851,8 @@ + BT_DBG("sk %p state %d", sk, sk->sk_state); + + /* Kill poor orphan */ ++ ++ l2cap_chan_free(l2cap_pi(sk)->chan); + bt_sock_unlink(&l2cap_sk_list, sk); + sock_set_flag(sk, SOCK_DEAD); + sock_put(sk); +@@ -885,7 +884,8 @@ + + void __l2cap_sock_close(struct sock *sk, int reason) + { +- struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; ++ struct l2cap_conn *conn = chan->conn; + + BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); + +@@ -900,9 +900,9 @@ + sk->sk_type == SOCK_STREAM) && + conn->hcon->type == ACL_LINK) { + l2cap_sock_set_timer(sk, sk->sk_sndtimeo); +- l2cap_send_disconn_req(conn, sk, reason); ++ l2cap_send_disconn_req(conn, chan, reason); + } else +- l2cap_chan_del(sk, reason); ++ l2cap_chan_del(chan, reason); + break; + + case BT_CONNECT2: +@@ -917,20 +917,20 @@ + else + result = L2CAP_CR_BAD_PSM; + +- rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); +- rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); ++ rsp.scid = cpu_to_le16(chan->dcid); ++ rsp.dcid = cpu_to_le16(chan->scid); + rsp.result = cpu_to_le16(result); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); +- l2cap_send_cmd(conn, l2cap_pi(sk)->ident, +- L2CAP_CONN_RSP, sizeof(rsp), &rsp); ++ l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, ++ sizeof(rsp), &rsp); + } + +- l2cap_chan_del(sk, reason); ++ l2cap_chan_del(chan, reason); + break; + + case BT_CONNECT: + case BT_DISCONN: +- l2cap_chan_del(sk, reason); ++ l2cap_chan_del(chan, reason); + break; + + default: +@@ -942,6 +942,7 @@ + static int l2cap_sock_shutdown(struct socket *sock, int how) + { + struct sock *sk = sock->sk; ++ struct l2cap_chan *chan = l2cap_pi(sk)->chan; + int err = 0; + + BT_DBG("sock %p, sk %p", sock, sk); +@@ -951,7 +952,7 @@ + + lock_sock(sk); + if (!sk->sk_shutdown) { +- if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) ++ if (chan->mode == L2CAP_MODE_ERTM) + err = __l2cap_wait_ack(sk); + + sk->sk_shutdown = SHUTDOWN_MASK; +@@ -998,49 +999,47 @@ + void l2cap_sock_init(struct sock *sk, struct sock *parent) + { + struct l2cap_pinfo *pi = l2cap_pi(sk); ++ struct l2cap_chan *chan = pi->chan; + + BT_DBG("sk %p", sk); + + if (parent) { ++ struct l2cap_chan *pchan = l2cap_pi(parent)->chan; ++ + sk->sk_type = parent->sk_type; + bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; + +- pi->imtu = l2cap_pi(parent)->imtu; +- pi->omtu = l2cap_pi(parent)->omtu; +- pi->conf_state = l2cap_pi(parent)->conf_state; +- pi->mode = l2cap_pi(parent)->mode; +- pi->fcs = l2cap_pi(parent)->fcs; +- pi->max_tx = l2cap_pi(parent)->max_tx; +- pi->tx_win = l2cap_pi(parent)->tx_win; +- pi->sec_level = l2cap_pi(parent)->sec_level; +- pi->role_switch = l2cap_pi(parent)->role_switch; +- pi->force_reliable = l2cap_pi(parent)->force_reliable; +- pi->flushable = l2cap_pi(parent)->flushable; ++ chan->imtu = pchan->imtu; ++ chan->omtu = pchan->omtu; ++ chan->conf_state = pchan->conf_state; ++ chan->mode = pchan->mode; ++ chan->fcs = pchan->fcs; ++ chan->max_tx = pchan->max_tx; ++ chan->tx_win = pchan->tx_win; ++ chan->sec_level = pchan->sec_level; ++ chan->role_switch = pchan->role_switch; ++ chan->force_reliable = pchan->force_reliable; ++ chan->flushable = pchan->flushable; + } else { +- pi->imtu = L2CAP_DEFAULT_MTU; +- pi->omtu = 0; ++ chan->imtu = L2CAP_DEFAULT_MTU; ++ chan->omtu = 0; + if (!disable_ertm && sk->sk_type == SOCK_STREAM) { +- pi->mode = L2CAP_MODE_ERTM; +- pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; ++ chan->mode = L2CAP_MODE_ERTM; ++ chan->conf_state |= L2CAP_CONF_STATE2_DEVICE; + } else { +- pi->mode = L2CAP_MODE_BASIC; ++ chan->mode = L2CAP_MODE_BASIC; + } +- pi->max_tx = L2CAP_DEFAULT_MAX_TX; +- pi->fcs = L2CAP_FCS_CRC16; +- pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; +- pi->sec_level = BT_SECURITY_LOW; +- pi->role_switch = 0; +- pi->force_reliable = 0; +- pi->flushable = BT_FLUSHABLE_OFF; ++ chan->max_tx = L2CAP_DEFAULT_MAX_TX; ++ chan->fcs = L2CAP_FCS_CRC16; ++ chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; ++ chan->sec_level = BT_SECURITY_LOW; ++ chan->role_switch = 0; ++ chan->force_reliable = 0; ++ chan->flushable = BT_FLUSHABLE_OFF; + } + + /* Default config options */ +- pi->conf_len = 0; +- pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; +- skb_queue_head_init(TX_QUEUE(sk)); +- skb_queue_head_init(SREJ_QUEUE(sk)); +- skb_queue_head_init(BUSY_QUEUE(sk)); +- INIT_LIST_HEAD(SREJ_LIST(sk)); ++ chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; + } + + static struct proto l2cap_proto = { +@@ -1078,6 +1077,7 @@ + int kern) + { + struct sock *sk; ++ struct l2cap_chan *chan; + + BT_DBG("sock %p", sock); + +@@ -1096,11 +1096,19 @@ + if (!sk) + return -ENOMEM; + ++ chan = l2cap_chan_alloc(sk); ++ if (!chan) { ++ l2cap_sock_kill(sk); ++ return -ENOMEM; ++ } ++ ++ l2cap_pi(sk)->chan = chan; ++ + l2cap_sock_init(sk, NULL); + return 0; + } + +-const struct proto_ops l2cap_sock_ops = { ++static const struct proto_ops l2cap_sock_ops = { + .family = PF_BLUETOOTH, + .owner = THIS_MODULE, + .release = l2cap_sock_release, +diff -Naur linux-2.6.39-rc6/net/bluetooth/mgmt.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/mgmt.c +--- linux-2.6.39-rc6/net/bluetooth/mgmt.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/mgmt.c 2011-05-05 23:30:21.166872823 +0200 +@@ -36,7 +36,7 @@ + struct list_head list; + __u16 opcode; + int index; +- void *cmd; ++ void *param; + struct sock *sk; + void *user_data; + }; +@@ -179,10 +179,12 @@ + + hci_del_off_timer(hdev); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + set_bit(HCI_MGMT, &hdev->flags); + ++ memset(&rp, 0, sizeof(rp)); ++ + rp.type = hdev->dev_type; + + rp.powered = test_bit(HCI_UP, &hdev->flags); +@@ -204,7 +206,9 @@ + rp.hci_ver = hdev->hci_ver; + put_unaligned_le16(hdev->hci_rev, &rp.hci_rev); + +- hci_dev_unlock_bh(hdev); ++ memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); ++ ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp)); +@@ -213,7 +217,7 @@ + static void mgmt_pending_free(struct pending_cmd *cmd) + { + sock_put(cmd->sk); +- kfree(cmd->cmd); ++ kfree(cmd->param); + kfree(cmd); + } + +@@ -229,13 +233,14 @@ + cmd->opcode = opcode; + cmd->index = index; + +- cmd->cmd = kmalloc(len, GFP_ATOMIC); +- if (!cmd->cmd) { ++ cmd->param = kmalloc(len, GFP_ATOMIC); ++ if (!cmd->param) { + kfree(cmd); + return NULL; + } + +- memcpy(cmd->cmd, data, len); ++ if (data) ++ memcpy(cmd->param, data, len); + + cmd->sk = sk; + sock_hold(sk); +@@ -311,7 +316,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + up = test_bit(HCI_UP, &hdev->flags); + if ((cp->val && up) || (!cp->val && !up)) { +@@ -338,7 +343,7 @@ + err = 0; + + failed: +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + return err; + } +@@ -363,7 +368,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN); +@@ -398,7 +403,7 @@ + mgmt_pending_remove(cmd); + + failed: +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +@@ -424,7 +429,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN); +@@ -458,7 +463,7 @@ + mgmt_pending_remove(cmd); + + failed: +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +@@ -517,7 +522,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + if (cp->val) + set_bit(HCI_PAIRABLE, &hdev->flags); +@@ -533,12 +538,156 @@ + err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk); + + failed: +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; + } + ++#define EIR_FLAGS 0x01 /* flags */ ++#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ ++#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ ++#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ ++#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ ++#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ ++#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ ++#define EIR_NAME_SHORT 0x08 /* shortened local name */ ++#define EIR_NAME_COMPLETE 0x09 /* complete local name */ ++#define EIR_TX_POWER 0x0A /* transmit power level */ ++#define EIR_DEVICE_ID 0x10 /* device ID */ ++ ++#define PNP_INFO_SVCLASS_ID 0x1200 ++ ++static u8 bluetooth_base_uuid[] = { ++ 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, ++ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++}; ++ ++static u16 get_uuid16(u8 *uuid128) ++{ ++ u32 val; ++ int i; ++ ++ for (i = 0; i < 12; i++) { ++ if (bluetooth_base_uuid[i] != uuid128[i]) ++ return 0; ++ } ++ ++ memcpy(&val, &uuid128[12], 4); ++ ++ val = le32_to_cpu(val); ++ if (val > 0xffff) ++ return 0; ++ ++ return (u16) val; ++} ++ ++static void create_eir(struct hci_dev *hdev, u8 *data) ++{ ++ u8 *ptr = data; ++ u16 eir_len = 0; ++ u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)]; ++ int i, truncated = 0; ++ struct list_head *p; ++ size_t name_len; ++ ++ name_len = strlen(hdev->dev_name); ++ ++ if (name_len > 0) { ++ /* EIR Data type */ ++ if (name_len > 48) { ++ name_len = 48; ++ ptr[1] = EIR_NAME_SHORT; ++ } else ++ ptr[1] = EIR_NAME_COMPLETE; ++ ++ /* EIR Data length */ ++ ptr[0] = name_len + 1; ++ ++ memcpy(ptr + 2, hdev->dev_name, name_len); ++ ++ eir_len += (name_len + 2); ++ ptr += (name_len + 2); ++ } ++ ++ memset(uuid16_list, 0, sizeof(uuid16_list)); ++ ++ /* Group all UUID16 types */ ++ list_for_each(p, &hdev->uuids) { ++ struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list); ++ u16 uuid16; ++ ++ uuid16 = get_uuid16(uuid->uuid); ++ if (uuid16 == 0) ++ return; ++ ++ if (uuid16 < 0x1100) ++ continue; ++ ++ if (uuid16 == PNP_INFO_SVCLASS_ID) ++ continue; ++ ++ /* Stop if not enough space to put next UUID */ ++ if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { ++ truncated = 1; ++ break; ++ } ++ ++ /* Check for duplicates */ ++ for (i = 0; uuid16_list[i] != 0; i++) ++ if (uuid16_list[i] == uuid16) ++ break; ++ ++ if (uuid16_list[i] == 0) { ++ uuid16_list[i] = uuid16; ++ eir_len += sizeof(u16); ++ } ++ } ++ ++ if (uuid16_list[0] != 0) { ++ u8 *length = ptr; ++ ++ /* EIR Data type */ ++ ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; ++ ++ ptr += 2; ++ eir_len += 2; ++ ++ for (i = 0; uuid16_list[i] != 0; i++) { ++ *ptr++ = (uuid16_list[i] & 0x00ff); ++ *ptr++ = (uuid16_list[i] & 0xff00) >> 8; ++ } ++ ++ /* EIR Data length */ ++ *length = (i * sizeof(u16)) + 1; ++ } ++} ++ ++static int update_eir(struct hci_dev *hdev) ++{ ++ struct hci_cp_write_eir cp; ++ ++ if (!(hdev->features[6] & LMP_EXT_INQ)) ++ return 0; ++ ++ if (hdev->ssp_mode == 0) ++ return 0; ++ ++ if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) ++ return 0; ++ ++ memset(&cp, 0, sizeof(cp)); ++ ++ create_eir(hdev, cp.data); ++ ++ if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) ++ return 0; ++ ++ memcpy(hdev->eir, cp.data, sizeof(cp.data)); ++ ++ return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); ++} ++ + static u8 get_service_classes(struct hci_dev *hdev) + { + struct list_head *p; +@@ -590,7 +739,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); + if (!uuid) { +@@ -607,10 +756,14 @@ + if (err < 0) + goto failed; + ++ err = update_eir(hdev); ++ if (err < 0) ++ goto failed; ++ + err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); + + failed: +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +@@ -635,7 +788,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { + err = hci_uuids_clear(hdev); +@@ -663,10 +816,14 @@ + if (err < 0) + goto unlock; + ++ err = update_eir(hdev); ++ if (err < 0) ++ goto unlock; ++ + err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); + + unlock: +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +@@ -690,7 +847,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + hdev->major_class = cp->major; + hdev->minor_class = cp->minor; +@@ -700,7 +857,7 @@ + if (err == 0) + err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); + +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +@@ -722,7 +879,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + BT_DBG("hci%u enable %d", index, cp->enable); + +@@ -732,13 +889,15 @@ + } else { + clear_bit(HCI_SERVICE_CACHE, &hdev->flags); + err = update_class(hdev); ++ if (err == 0) ++ err = update_eir(hdev); + } + + if (err == 0) + err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL, + 0); + +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +@@ -772,7 +931,7 @@ + BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, + key_count); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + hci_link_keys_clear(hdev); + +@@ -786,11 +945,11 @@ + for (i = 0; i < key_count; i++) { + struct mgmt_key_info *key = &cp->keys[i]; + +- hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type, ++ hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, + key->pin_len); + } + +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return 0; +@@ -812,7 +971,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + err = hci_remove_link_key(hdev, &cp->bdaddr); + if (err < 0) { +@@ -835,7 +994,7 @@ + } + + unlock: +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +@@ -861,7 +1020,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN); +@@ -893,7 +1052,7 @@ + mgmt_pending_remove(cmd); + + failed: +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +@@ -914,7 +1073,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + count = 0; + list_for_each(p, &hdev->conn_hash.list) { +@@ -945,7 +1104,7 @@ + + unlock: + kfree(rp); +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + return err; + } +@@ -970,7 +1129,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN); +@@ -992,7 +1151,7 @@ + mgmt_pending_remove(cmd); + + failed: +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +@@ -1019,7 +1178,7 @@ + return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, + ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, +@@ -1040,7 +1199,7 @@ + mgmt_pending_remove(cmd); + + failed: +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +@@ -1063,14 +1222,14 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + hdev->io_capability = cp->io_capability; + + BT_DBG("%s IO capability set to 0x%02x", hdev->name, + hdev->io_capability); + +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); +@@ -1156,7 +1315,7 @@ + if (!hdev) + return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + if (cp->io_cap == 0x03) { + sec_level = BT_SECURITY_MEDIUM; +@@ -1198,7 +1357,7 @@ + err = 0; + + unlock: +- hci_dev_unlock_bh(hdev); ++ hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +@@ -1230,7 +1389,7 @@ + if (!hdev) + return cmd_status(sk, index, mgmt_op, ENODEV); + +- hci_dev_lock_bh(hdev); ++ hci_dev_lock(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, mgmt_op, ENETDOWN); +@@ -1248,6 +1407,231 @@ + mgmt_pending_remove(cmd); + + failed: ++ hci_dev_unlock(hdev); ++ hci_dev_put(hdev); ++ ++ return err; ++} ++ ++static int set_local_name(struct sock *sk, u16 index, unsigned char *data, ++ u16 len) ++{ ++ struct mgmt_cp_set_local_name *mgmt_cp = (void *) data; ++ struct hci_cp_write_local_name hci_cp; ++ struct hci_dev *hdev; ++ struct pending_cmd *cmd; ++ int err; ++ ++ BT_DBG(""); ++ ++ if (len != sizeof(*mgmt_cp)) ++ return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL); ++ ++ hdev = hci_dev_get(index); ++ if (!hdev) ++ return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV); ++ ++ hci_dev_lock(hdev); ++ ++ cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len); ++ if (!cmd) { ++ err = -ENOMEM; ++ goto failed; ++ } ++ ++ memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name)); ++ err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp), ++ &hci_cp); ++ if (err < 0) ++ mgmt_pending_remove(cmd); ++ ++failed: ++ hci_dev_unlock(hdev); ++ hci_dev_put(hdev); ++ ++ return err; ++} ++ ++static int read_local_oob_data(struct sock *sk, u16 index) ++{ ++ struct hci_dev *hdev; ++ struct pending_cmd *cmd; ++ int err; ++ ++ BT_DBG("hci%u", index); ++ ++ hdev = hci_dev_get(index); ++ if (!hdev) ++ return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, ++ ENODEV); ++ ++ hci_dev_lock(hdev); ++ ++ if (!test_bit(HCI_UP, &hdev->flags)) { ++ err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, ++ ENETDOWN); ++ goto unlock; ++ } ++ ++ if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { ++ err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, ++ EOPNOTSUPP); ++ goto unlock; ++ } ++ ++ if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) { ++ err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY); ++ goto unlock; ++ } ++ ++ cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0); ++ if (!cmd) { ++ err = -ENOMEM; ++ goto unlock; ++ } ++ ++ err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); ++ if (err < 0) ++ mgmt_pending_remove(cmd); ++ ++unlock: ++ hci_dev_unlock(hdev); ++ hci_dev_put(hdev); ++ ++ return err; ++} ++ ++static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, ++ u16 len) ++{ ++ struct hci_dev *hdev; ++ struct mgmt_cp_add_remote_oob_data *cp = (void *) data; ++ int err; ++ ++ BT_DBG("hci%u ", index); ++ ++ if (len != sizeof(*cp)) ++ return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, ++ EINVAL); ++ ++ hdev = hci_dev_get(index); ++ if (!hdev) ++ return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, ++ ENODEV); ++ ++ hci_dev_lock(hdev); ++ ++ err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, ++ cp->randomizer); ++ if (err < 0) ++ err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err); ++ else ++ err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, ++ 0); ++ ++ hci_dev_unlock(hdev); ++ hci_dev_put(hdev); ++ ++ return err; ++} ++ ++static int remove_remote_oob_data(struct sock *sk, u16 index, ++ unsigned char *data, u16 len) ++{ ++ struct hci_dev *hdev; ++ struct mgmt_cp_remove_remote_oob_data *cp = (void *) data; ++ int err; ++ ++ BT_DBG("hci%u ", index); ++ ++ if (len != sizeof(*cp)) ++ return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, ++ EINVAL); ++ ++ hdev = hci_dev_get(index); ++ if (!hdev) ++ return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, ++ ENODEV); ++ ++ hci_dev_lock(hdev); ++ ++ err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); ++ if (err < 0) ++ err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, ++ -err); ++ else ++ err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, ++ NULL, 0); ++ ++ hci_dev_unlock(hdev); ++ hci_dev_put(hdev); ++ ++ return err; ++} ++ ++static int start_discovery(struct sock *sk, u16 index) ++{ ++ u8 lap[3] = { 0x33, 0x8b, 0x9e }; ++ struct hci_cp_inquiry cp; ++ struct pending_cmd *cmd; ++ struct hci_dev *hdev; ++ int err; ++ ++ BT_DBG("hci%u", index); ++ ++ hdev = hci_dev_get(index); ++ if (!hdev) ++ return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV); ++ ++ hci_dev_lock_bh(hdev); ++ ++ cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0); ++ if (!cmd) { ++ err = -ENOMEM; ++ goto failed; ++ } ++ ++ memset(&cp, 0, sizeof(cp)); ++ memcpy(&cp.lap, lap, 3); ++ cp.length = 0x08; ++ cp.num_rsp = 0x00; ++ ++ err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp); ++ if (err < 0) ++ mgmt_pending_remove(cmd); ++ ++failed: ++ hci_dev_unlock_bh(hdev); ++ hci_dev_put(hdev); ++ ++ return err; ++} ++ ++static int stop_discovery(struct sock *sk, u16 index) ++{ ++ struct hci_dev *hdev; ++ struct pending_cmd *cmd; ++ int err; ++ ++ BT_DBG("hci%u", index); ++ ++ hdev = hci_dev_get(index); ++ if (!hdev) ++ return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV); ++ ++ hci_dev_lock_bh(hdev); ++ ++ cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0); ++ if (!cmd) { ++ err = -ENOMEM; ++ goto failed; ++ } ++ ++ err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); ++ if (err < 0) ++ mgmt_pending_remove(cmd); ++ ++failed: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + +@@ -1266,7 +1650,7 @@ + if (msglen < sizeof(*hdr)) + return -EINVAL; + +- buf = kmalloc(msglen, GFP_ATOMIC); ++ buf = kmalloc(msglen, GFP_KERNEL); + if (!buf) + return -ENOMEM; + +@@ -1349,6 +1733,25 @@ + case MGMT_OP_USER_CONFIRM_NEG_REPLY: + err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0); + break; ++ case MGMT_OP_SET_LOCAL_NAME: ++ err = set_local_name(sk, index, buf + sizeof(*hdr), len); ++ break; ++ case MGMT_OP_READ_LOCAL_OOB_DATA: ++ err = read_local_oob_data(sk, index); ++ break; ++ case MGMT_OP_ADD_REMOTE_OOB_DATA: ++ err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len); ++ break; ++ case MGMT_OP_REMOVE_REMOTE_OOB_DATA: ++ err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr), ++ len); ++ break; ++ case MGMT_OP_START_DISCOVERY: ++ err = start_discovery(sk, index); ++ break; ++ case MGMT_OP_STOP_DISCOVERY: ++ err = stop_discovery(sk, index); ++ break; + default: + BT_DBG("Unknown op %u", opcode); + err = cmd_status(sk, index, opcode, 0x01); +@@ -1382,7 +1785,7 @@ + + static void mode_rsp(struct pending_cmd *cmd, void *data) + { +- struct mgmt_mode *cp = cmd->cmd; ++ struct mgmt_mode *cp = cmd->param; + struct cmd_lookup *match = data; + + if (cp->val != match->val) +@@ -1455,17 +1858,17 @@ + return ret; + } + +-int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type) ++int mgmt_new_key(u16 index, struct link_key *key, u8 persistent) + { + struct mgmt_ev_new_key ev; + + memset(&ev, 0, sizeof(ev)); + ++ ev.store_hint = persistent; + bacpy(&ev.key.bdaddr, &key->bdaddr); + ev.key.type = key->type; + memcpy(ev.key.val, key->val, 16); + ev.key.pin_len = key->pin_len; +- ev.old_key_type = old_key_type; + + return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL); + } +@@ -1481,7 +1884,7 @@ + + static void disconnect_rsp(struct pending_cmd *cmd, void *data) + { +- struct mgmt_cp_disconnect *cp = cmd->cmd; ++ struct mgmt_cp_disconnect *cp = cmd->param; + struct sock **sk = data; + struct mgmt_rp_disconnect rp; + +@@ -1539,11 +1942,12 @@ + return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL); + } + +-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr) ++int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure) + { + struct mgmt_ev_pin_code_request ev; + + bacpy(&ev.bdaddr, bdaddr); ++ ev.secure = secure; + + return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev), + NULL); +@@ -1591,13 +1995,15 @@ + return err; + } + +-int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value) ++int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value, ++ u8 confirm_hint) + { + struct mgmt_ev_user_confirm_request ev; + + BT_DBG("hci%u", index); + + bacpy(&ev.bdaddr, bdaddr); ++ ev.confirm_hint = confirm_hint; + put_unaligned_le32(value, &ev.value); + + return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev), +@@ -1645,3 +2051,110 @@ + + return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL); + } ++ ++int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status) ++{ ++ struct pending_cmd *cmd; ++ struct hci_dev *hdev; ++ struct mgmt_cp_set_local_name ev; ++ int err; ++ ++ memset(&ev, 0, sizeof(ev)); ++ memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); ++ ++ cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index); ++ if (!cmd) ++ goto send_event; ++ ++ if (status) { ++ err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO); ++ goto failed; ++ } ++ ++ hdev = hci_dev_get(index); ++ if (hdev) { ++ hci_dev_lock_bh(hdev); ++ update_eir(hdev); ++ hci_dev_unlock_bh(hdev); ++ hci_dev_put(hdev); ++ } ++ ++ err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev, ++ sizeof(ev)); ++ if (err < 0) ++ goto failed; ++ ++send_event: ++ err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev), ++ cmd ? cmd->sk : NULL); ++ ++failed: ++ if (cmd) ++ mgmt_pending_remove(cmd); ++ return err; ++} ++ ++int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, ++ u8 status) ++{ ++ struct pending_cmd *cmd; ++ int err; ++ ++ BT_DBG("hci%u status %u", index, status); ++ ++ cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index); ++ if (!cmd) ++ return -ENOENT; ++ ++ if (status) { ++ err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, ++ EIO); ++ } else { ++ struct mgmt_rp_read_local_oob_data rp; ++ ++ memcpy(rp.hash, hash, sizeof(rp.hash)); ++ memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer)); ++ ++ err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, ++ &rp, sizeof(rp)); ++ } ++ ++ mgmt_pending_remove(cmd); ++ ++ return err; ++} ++ ++int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, ++ u8 *eir) ++{ ++ struct mgmt_ev_device_found ev; ++ ++ memset(&ev, 0, sizeof(ev)); ++ ++ bacpy(&ev.bdaddr, bdaddr); ++ memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); ++ ev.rssi = rssi; ++ ++ if (eir) ++ memcpy(ev.eir, eir, sizeof(ev.eir)); ++ ++ return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL); ++} ++ ++int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name) ++{ ++ struct mgmt_ev_remote_name ev; ++ ++ memset(&ev, 0, sizeof(ev)); ++ ++ bacpy(&ev.bdaddr, bdaddr); ++ memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); ++ ++ return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL); ++} ++ ++int mgmt_discovering(u16 index, u8 discovering) ++{ ++ return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering, ++ sizeof(discovering), NULL); ++} +diff -Naur linux-2.6.39-rc6/net/bluetooth/rfcomm/core.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/rfcomm/core.c +--- linux-2.6.39-rc6/net/bluetooth/rfcomm/core.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/rfcomm/core.c 2011-05-05 23:30:21.187873077 +0200 +@@ -232,6 +232,8 @@ + static inline int rfcomm_check_security(struct rfcomm_dlc *d) + { + struct sock *sk = d->session->sock->sk; ++ struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; ++ + __u8 auth_type; + + switch (d->sec_level) { +@@ -246,8 +248,7 @@ + break; + } + +- return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level, +- auth_type); ++ return hci_conn_security(conn->hcon, d->sec_level, auth_type); + } + + static void rfcomm_session_timeout(unsigned long arg) +@@ -710,10 +711,10 @@ + /* Set L2CAP options */ + sk = sock->sk; + lock_sock(sk); +- l2cap_pi(sk)->imtu = l2cap_mtu; +- l2cap_pi(sk)->sec_level = sec_level; ++ l2cap_pi(sk)->chan->imtu = l2cap_mtu; ++ l2cap_pi(sk)->chan->sec_level = sec_level; + if (l2cap_ertm) +- l2cap_pi(sk)->mode = L2CAP_MODE_ERTM; ++ l2cap_pi(sk)->chan->mode = L2CAP_MODE_ERTM; + release_sock(sk); + + s = rfcomm_session_add(sock, BT_BOUND); +@@ -1241,6 +1242,7 @@ + void rfcomm_dlc_accept(struct rfcomm_dlc *d) + { + struct sock *sk = d->session->sock->sk; ++ struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; + + BT_DBG("dlc %p", d); + +@@ -1254,7 +1256,7 @@ + rfcomm_dlc_unlock(d); + + if (d->role_switch) +- hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00); ++ hci_conn_switch_role(conn->hcon, 0x00); + + rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); + } +@@ -1890,7 +1892,8 @@ + + /* We should adjust MTU on incoming sessions. + * L2CAP MTU minus UIH header and FCS. */ +- s->mtu = min(l2cap_pi(nsock->sk)->omtu, l2cap_pi(nsock->sk)->imtu) - 5; ++ s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu, ++ l2cap_pi(nsock->sk)->chan->imtu) - 5; + + rfcomm_schedule(); + } else +@@ -1909,7 +1912,7 @@ + + /* We can adjust MTU on outgoing sessions. + * L2CAP MTU minus UIH header and FCS. */ +- s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5; ++ s->mtu = min(l2cap_pi(sk)->chan->omtu, l2cap_pi(sk)->chan->imtu) - 5; + + rfcomm_send_sabm(s, 0); + break; +@@ -1992,7 +1995,7 @@ + /* Set L2CAP options */ + sk = sock->sk; + lock_sock(sk); +- l2cap_pi(sk)->imtu = l2cap_mtu; ++ l2cap_pi(sk)->chan->imtu = l2cap_mtu; + release_sock(sk); + + /* Start listening on the socket */ +diff -Naur linux-2.6.39-rc6/net/bluetooth/rfcomm/sock.c linux-2.6.39-rc6.rtl8192se/net/bluetooth/rfcomm/sock.c +--- linux-2.6.39-rc6/net/bluetooth/rfcomm/sock.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/bluetooth/rfcomm/sock.c 2011-05-05 23:30:21.188873089 +0200 +@@ -743,6 +743,7 @@ + struct sock *sk = sock->sk; + struct sock *l2cap_sk; + struct rfcomm_conninfo cinfo; ++ struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; + int len, err = 0; + u32 opt; + +@@ -787,8 +788,8 @@ + + l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk; + +- cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle; +- memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3); ++ cinfo.hci_handle = conn->hcon->handle; ++ memcpy(cinfo.dev_class, conn->hcon->dev_class, 3); + + len = min_t(unsigned int, len, sizeof(cinfo)); + if (copy_to_user(optval, (char *) &cinfo, len)) +diff -Naur linux-2.6.39-rc6/net/mac80211/aes_ccm.c linux-2.6.39-rc6.rtl8192se/net/mac80211/aes_ccm.c +--- linux-2.6.39-rc6/net/mac80211/aes_ccm.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/aes_ccm.c 2011-05-05 23:30:21.815880659 +0200 +@@ -54,13 +54,12 @@ + u8 *cdata, u8 *mic) + { + int i, j, last_len, num_blocks; +- u8 *pos, *cpos, *b, *s_0, *e, *b_0, *aad; ++ u8 *pos, *cpos, *b, *s_0, *e, *b_0; + + b = scratch; + s_0 = scratch + AES_BLOCK_LEN; + e = scratch + 2 * AES_BLOCK_LEN; + b_0 = scratch + 3 * AES_BLOCK_LEN; +- aad = scratch + 4 * AES_BLOCK_LEN; + + num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); + last_len = data_len % AES_BLOCK_LEN; +@@ -94,13 +93,12 @@ + u8 *cdata, size_t data_len, u8 *mic, u8 *data) + { + int i, j, last_len, num_blocks; +- u8 *pos, *cpos, *b, *s_0, *a, *b_0, *aad; ++ u8 *pos, *cpos, *b, *s_0, *a, *b_0; + + b = scratch; + s_0 = scratch + AES_BLOCK_LEN; + a = scratch + 2 * AES_BLOCK_LEN; + b_0 = scratch + 3 * AES_BLOCK_LEN; +- aad = scratch + 4 * AES_BLOCK_LEN; + + num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); + last_len = data_len % AES_BLOCK_LEN; +diff -Naur linux-2.6.39-rc6/net/mac80211/cfg.c linux-2.6.39-rc6.rtl8192se/net/mac80211/cfg.c +--- linux-2.6.39-rc6/net/mac80211/cfg.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/cfg.c 2011-05-05 23:30:21.771880129 +0200 +@@ -330,6 +330,7 @@ + static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) + { + struct ieee80211_sub_if_data *sdata = sta->sdata; ++ struct timespec uptime; + + sinfo->generation = sdata->local->sta_generation; + +@@ -342,7 +343,12 @@ + STATION_INFO_TX_FAILED | + STATION_INFO_TX_BITRATE | + STATION_INFO_RX_BITRATE | +- STATION_INFO_RX_DROP_MISC; ++ STATION_INFO_RX_DROP_MISC | ++ STATION_INFO_BSS_PARAM | ++ STATION_INFO_CONNECTED_TIME; ++ ++ do_posix_clock_monotonic_gettime(&uptime); ++ sinfo->connected_time = uptime.tv_sec - sta->last_connected; + + sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); + sinfo->rx_bytes = sta->rx_bytes; +@@ -389,6 +395,16 @@ + sinfo->plink_state = sta->plink_state; + #endif + } ++ ++ sinfo->bss_param.flags = 0; ++ if (sdata->vif.bss_conf.use_cts_prot) ++ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; ++ if (sdata->vif.bss_conf.use_short_preamble) ++ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; ++ if (sdata->vif.bss_conf.use_short_slot) ++ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; ++ sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; ++ sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; + } + + +@@ -675,6 +691,12 @@ + if (set & BIT(NL80211_STA_FLAG_MFP)) + sta->flags |= WLAN_STA_MFP; + } ++ ++ if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) { ++ sta->flags &= ~WLAN_STA_AUTH; ++ if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) ++ sta->flags |= WLAN_STA_AUTH; ++ } + spin_unlock_irqrestore(&sta->flaglock, flags); + + /* +@@ -1023,26 +1045,26 @@ + u8 *new_ie; + const u8 *old_ie; + +- /* first allocate the new vendor information element */ ++ /* allocate information elements */ + new_ie = NULL; +- old_ie = ifmsh->vendor_ie; ++ old_ie = ifmsh->ie; + +- ifmsh->vendor_ie_len = setup->vendor_ie_len; +- if (setup->vendor_ie_len) { +- new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len, ++ if (setup->ie_len) { ++ new_ie = kmemdup(setup->ie, setup->ie_len, + GFP_KERNEL); + if (!new_ie) + return -ENOMEM; + } ++ ifmsh->ie_len = setup->ie_len; ++ ifmsh->ie = new_ie; ++ kfree(old_ie); + + /* now copy the rest of the setup parameters */ + ifmsh->mesh_id_len = setup->mesh_id_len; + memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); + ifmsh->mesh_pp_id = setup->path_sel_proto; + ifmsh->mesh_pm_id = setup->path_metric; +- ifmsh->vendor_ie = new_ie; +- +- kfree(old_ie); ++ ifmsh->is_secure = setup->is_secure; + + return 0; + } +@@ -1611,16 +1633,13 @@ + { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); +- int i; +- +- /* +- * This _could_ be supported by providing a hook for +- * drivers for this function, but at this point it +- * doesn't seem worth bothering. +- */ +- if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) +- return -EOPNOTSUPP; ++ int i, ret; + ++ if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) { ++ ret = drv_set_bitrate_mask(local, sdata, mask); ++ if (ret) ++ return ret; ++ } + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + sdata->rc_rateidx_mask[i] = mask->control[i].legacy; +diff -Naur linux-2.6.39-rc6/net/mac80211/debugfs.c linux-2.6.39-rc6.rtl8192se/net/mac80211/debugfs.c +--- linux-2.6.39-rc6/net/mac80211/debugfs.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/debugfs.c 2011-05-05 23:30:21.822880743 +0200 +@@ -37,7 +37,7 @@ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); + } + +-#define DEBUGFS_READONLY_FILE(name, fmt, value...) \ ++#define DEBUGFS_READONLY_FILE_FN(name, fmt, value...) \ + static ssize_t name## _read(struct file *file, char __user *userbuf, \ + size_t count, loff_t *ppos) \ + { \ +@@ -45,14 +45,19 @@ + \ + return mac80211_format_buffer(userbuf, count, ppos, \ + fmt "\n", ##value); \ +-} \ +- \ ++} ++ ++#define DEBUGFS_READONLY_FILE_OPS(name) \ + static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .open = mac80211_open_file_generic, \ + .llseek = generic_file_llseek, \ + }; + ++#define DEBUGFS_READONLY_FILE(name, fmt, value...) \ ++ DEBUGFS_READONLY_FILE_FN(name, fmt, value) \ ++ DEBUGFS_READONLY_FILE_OPS(name) ++ + #define DEBUGFS_ADD(name) \ + debugfs_create_file(#name, 0400, phyd, local, &name## _ops); + +@@ -291,11 +296,70 @@ + return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); + } + +-static const struct file_operations channel_type_ops = { +- .read = channel_type_read, +- .open = mac80211_open_file_generic, +- .llseek = default_llseek, +-}; ++static ssize_t hwflags_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ieee80211_local *local = file->private_data; ++ int mxln = 500; ++ ssize_t rv; ++ char *buf = kzalloc(mxln, GFP_KERNEL); ++ int sf = 0; /* how many written so far */ ++ ++ sf += snprintf(buf, mxln - sf, "0x%x\n", local->hw.flags); ++ if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) ++ sf += snprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n"); ++ if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) ++ sf += snprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n"); ++ if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) ++ sf += snprintf(buf + sf, mxln - sf, ++ "HOST_BCAST_PS_BUFFERING\n"); ++ if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE) ++ sf += snprintf(buf + sf, mxln - sf, ++ "2GHZ_SHORT_SLOT_INCAPABLE\n"); ++ if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE) ++ sf += snprintf(buf + sf, mxln - sf, ++ "2GHZ_SHORT_PREAMBLE_INCAPABLE\n"); ++ if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) ++ sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n"); ++ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ++ sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n"); ++ if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) ++ sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_PERIOD\n"); ++ if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT) ++ sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n"); ++ if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) ++ sf += snprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n"); ++ if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ++ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n"); ++ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) ++ sf += snprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n"); ++ if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) ++ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); ++ if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) ++ sf += snprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); ++ if (local->hw.flags & IEEE80211_HW_BEACON_FILTER) ++ sf += snprintf(buf + sf, mxln - sf, "BEACON_FILTER\n"); ++ if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) ++ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n"); ++ if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) ++ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_SMPS\n"); ++ if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) ++ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n"); ++ if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) ++ sf += snprintf(buf + sf, mxln - sf, "REPORTS_TX_ACK_STATUS\n"); ++ if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) ++ sf += snprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n"); ++ if (local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) ++ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_CQM_RSSI\n"); ++ if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK) ++ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n"); ++ if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) ++ sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); ++ ++ rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++ kfree(buf); ++ return rv; ++} + + static ssize_t queues_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +@@ -315,11 +379,9 @@ + return simple_read_from_buffer(user_buf, count, ppos, buf, res); + } + +-static const struct file_operations queues_ops = { +- .read = queues_read, +- .open = mac80211_open_file_generic, +- .llseek = default_llseek, +-}; ++DEBUGFS_READONLY_FILE_OPS(hwflags); ++DEBUGFS_READONLY_FILE_OPS(channel_type); ++DEBUGFS_READONLY_FILE_OPS(queues); + + /* statistics stuff */ + +@@ -395,6 +457,7 @@ + DEBUGFS_ADD(uapsd_queues); + DEBUGFS_ADD(uapsd_max_sp_len); + DEBUGFS_ADD(channel_type); ++ DEBUGFS_ADD(hwflags); + DEBUGFS_ADD(user_power); + DEBUGFS_ADD(power); + +diff -Naur linux-2.6.39-rc6/net/mac80211/debugfs_sta.c linux-2.6.39-rc6.rtl8192se/net/mac80211/debugfs_sta.c +--- linux-2.6.39-rc6/net/mac80211/debugfs_sta.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/debugfs_sta.c 2011-05-05 23:30:21.820880719 +0200 +@@ -92,6 +92,31 @@ + } + STA_OPS(inactive_ms); + ++ ++static ssize_t sta_connected_time_read(struct file *file, char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct sta_info *sta = file->private_data; ++ struct timespec uptime; ++ struct tm result; ++ long connected_time_secs; ++ char buf[100]; ++ int res; ++ do_posix_clock_monotonic_gettime(&uptime); ++ connected_time_secs = uptime.tv_sec - sta->last_connected; ++ time_to_tm(connected_time_secs, 0, &result); ++ result.tm_year -= 70; ++ result.tm_mday -= 1; ++ res = scnprintf(buf, sizeof(buf), ++ "years - %ld\nmonths - %d\ndays - %d\nclock - %d:%d:%d\n\n", ++ result.tm_year, result.tm_mon, result.tm_mday, ++ result.tm_hour, result.tm_min, result.tm_sec); ++ return simple_read_from_buffer(userbuf, count, ppos, buf, res); ++} ++STA_OPS(connected_time); ++ ++ ++ + static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) + { +@@ -324,6 +349,7 @@ + DEBUGFS_ADD(flags); + DEBUGFS_ADD(num_ps_buf_frames); + DEBUGFS_ADD(inactive_ms); ++ DEBUGFS_ADD(connected_time); + DEBUGFS_ADD(last_seq_ctrl); + DEBUGFS_ADD(agg_status); + DEBUGFS_ADD(dev); +diff -Naur linux-2.6.39-rc6/net/mac80211/driver-ops.h linux-2.6.39-rc6.rtl8192se/net/mac80211/driver-ops.h +--- linux-2.6.39-rc6/net/mac80211/driver-ops.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/driver-ops.h 2011-05-05 23:30:21.807880563 +0200 +@@ -552,4 +552,35 @@ + trace_drv_return_void(local); + } + ++static inline bool drv_tx_frames_pending(struct ieee80211_local *local) ++{ ++ bool ret = false; ++ ++ might_sleep(); ++ ++ trace_drv_tx_frames_pending(local); ++ if (local->ops->tx_frames_pending) ++ ret = local->ops->tx_frames_pending(&local->hw); ++ trace_drv_return_bool(local, ret); ++ ++ return ret; ++} ++ ++static inline int drv_set_bitrate_mask(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ const struct cfg80211_bitrate_mask *mask) ++{ ++ int ret = -EOPNOTSUPP; ++ ++ might_sleep(); ++ ++ trace_drv_set_bitrate_mask(local, sdata, mask); ++ if (local->ops->set_bitrate_mask) ++ ret = local->ops->set_bitrate_mask(&local->hw, ++ &sdata->vif, mask); ++ trace_drv_return_int(local, ret); ++ ++ return ret; ++} ++ + #endif /* __MAC80211_DRIVER_OPS */ +diff -Naur linux-2.6.39-rc6/net/mac80211/driver-trace.h linux-2.6.39-rc6.rtl8192se/net/mac80211/driver-trace.h +--- linux-2.6.39-rc6/net/mac80211/driver-trace.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/driver-trace.h 2011-05-05 23:30:21.828880817 +0200 +@@ -74,6 +74,21 @@ + TP_printk(LOCAL_PR_FMT " - %d", LOCAL_PR_ARG, __entry->ret) + ); + ++TRACE_EVENT(drv_return_bool, ++ TP_PROTO(struct ieee80211_local *local, bool ret), ++ TP_ARGS(local, ret), ++ TP_STRUCT__entry( ++ LOCAL_ENTRY ++ __field(bool, ret) ++ ), ++ TP_fast_assign( ++ LOCAL_ASSIGN; ++ __entry->ret = ret; ++ ), ++ TP_printk(LOCAL_PR_FMT " - %s", LOCAL_PR_ARG, (__entry->ret) ? ++ "true" : "false") ++); ++ + TRACE_EVENT(drv_return_u64, + TP_PROTO(struct ieee80211_local *local, u64 ret), + TP_ARGS(local, ret), +@@ -964,11 +979,43 @@ + ) + ); + ++DEFINE_EVENT(local_only_evt, drv_tx_frames_pending, ++ TP_PROTO(struct ieee80211_local *local), ++ TP_ARGS(local) ++); ++ + DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait, + TP_PROTO(struct ieee80211_local *local), + TP_ARGS(local) + ); + ++TRACE_EVENT(drv_set_bitrate_mask, ++ TP_PROTO(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ const struct cfg80211_bitrate_mask *mask), ++ ++ TP_ARGS(local, sdata, mask), ++ ++ TP_STRUCT__entry( ++ LOCAL_ENTRY ++ VIF_ENTRY ++ __field(u32, legacy_2g) ++ __field(u32, legacy_5g) ++ ), ++ ++ TP_fast_assign( ++ LOCAL_ASSIGN; ++ VIF_ASSIGN; ++ __entry->legacy_2g = mask->control[IEEE80211_BAND_2GHZ].legacy; ++ __entry->legacy_5g = mask->control[IEEE80211_BAND_5GHZ].legacy; ++ ), ++ ++ TP_printk( ++ LOCAL_PR_FMT VIF_PR_FMT " 2G Mask:0x%x 5G Mask:0x%x", ++ LOCAL_PR_ARG, VIF_PR_ARG, __entry->legacy_2g, __entry->legacy_5g ++ ) ++); ++ + /* + * Tracing for API calls that drivers call. + */ +diff -Naur linux-2.6.39-rc6/net/mac80211/ibss.c linux-2.6.39-rc6.rtl8192se/net/mac80211/ibss.c +--- linux-2.6.39-rc6/net/mac80211/ibss.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/ibss.c 2011-05-05 23:30:21.826880793 +0200 +@@ -40,7 +40,7 @@ + struct ieee80211_mgmt *mgmt, + size_t len) + { +- u16 auth_alg, auth_transaction, status_code; ++ u16 auth_alg, auth_transaction; + + lockdep_assert_held(&sdata->u.ibss.mtx); + +@@ -49,7 +49,6 @@ + + auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); + auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); +- status_code = le16_to_cpu(mgmt->u.auth.status_code); + + /* + * IEEE 802.11 standard does not require authentication in IBSS +@@ -527,8 +526,6 @@ + static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) + { + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; +- struct ieee80211_local *local = sdata->local; +- struct ieee80211_supported_band *sband; + u8 bssid[ETH_ALEN]; + u16 capability; + int i; +@@ -551,8 +548,6 @@ + printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", + sdata->name, bssid); + +- sband = local->hw.wiphy->bands[ifibss->channel->band]; +- + capability = WLAN_CAPABILITY_IBSS; + + if (ifibss->privacy) +@@ -661,7 +656,6 @@ + static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, + struct sk_buff *req) + { +- struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(req); + struct ieee80211_mgmt *mgmt = (void *)req->data; + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; + struct ieee80211_local *local = sdata->local; +@@ -685,7 +679,7 @@ + mgmt->bssid, tx_last_beacon); + #endif /* CONFIG_MAC80211_IBSS_DEBUG */ + +- if (!tx_last_beacon && !(rx_status->rx_flags & IEEE80211_RX_RA_MATCH)) ++ if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da)) + return; + + if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 && +diff -Naur linux-2.6.39-rc6/net/mac80211/ieee80211_i.h linux-2.6.39-rc6.rtl8192se/net/mac80211/ieee80211_i.h +--- linux-2.6.39-rc6/net/mac80211/ieee80211_i.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/ieee80211_i.h 2011-05-05 23:30:21.817880683 +0200 +@@ -488,8 +488,9 @@ + struct mesh_config mshcfg; + u32 mesh_seqnum; + bool accepting_plinks; +- const u8 *vendor_ie; +- u8 vendor_ie_len; ++ const u8 *ie; ++ u8 ie_len; ++ bool is_secure; + }; + + #ifdef CONFIG_MAC80211_MESH +@@ -765,6 +766,9 @@ + + int tx_headroom; /* required headroom for hardware/radiotap */ + ++ /* count for keys needing tailroom space allocation */ ++ int crypto_tx_tailroom_needed_cnt; ++ + /* Tasklet and skb queue to process calls from IRQ mode. All frames + * added to skb_queue will be processed, but frames in + * skb_queue_unreliable may be dropped if the total length of these +@@ -809,8 +813,8 @@ + + struct rate_control_ref *rate_ctrl; + +- struct crypto_blkcipher *wep_tx_tfm; +- struct crypto_blkcipher *wep_rx_tfm; ++ struct crypto_cipher *wep_tx_tfm; ++ struct crypto_cipher *wep_rx_tfm; + u32 wep_iv; + + /* see iface.c */ +diff -Naur linux-2.6.39-rc6/net/mac80211/Kconfig linux-2.6.39-rc6.rtl8192se/net/mac80211/Kconfig +--- linux-2.6.39-rc6/net/mac80211/Kconfig 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/Kconfig 2011-05-05 23:30:21.830880841 +0200 +@@ -2,7 +2,6 @@ + tristate "Generic IEEE 802.11 Networking Stack (mac80211)" + depends on CFG80211 + select CRYPTO +- select CRYPTO_ECB + select CRYPTO_ARC4 + select CRYPTO_AES + select CRC32 +diff -Naur linux-2.6.39-rc6/net/mac80211/key.c linux-2.6.39-rc6.rtl8192se/net/mac80211/key.c +--- linux-2.6.39-rc6/net/mac80211/key.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/key.c 2011-05-05 23:30:21.819880707 +0200 +@@ -101,6 +101,10 @@ + + if (!ret) { + key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; ++ ++ if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) ++ key->local->crypto_tx_tailroom_needed_cnt--; ++ + return 0; + } + +@@ -156,6 +160,9 @@ + key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); + + key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; ++ ++ if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) ++ key->local->crypto_tx_tailroom_needed_cnt++; + } + + void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) +@@ -388,8 +395,10 @@ + ieee80211_aes_key_free(key->u.ccmp.tfm); + if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) + ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); +- if (key->local) ++ if (key->local) { + ieee80211_debugfs_key_remove(key); ++ key->local->crypto_tx_tailroom_needed_cnt--; ++ } + + kfree(key); + } +@@ -451,6 +460,8 @@ + + ieee80211_debugfs_key_add(key); + ++ key->local->crypto_tx_tailroom_needed_cnt++; ++ + ret = ieee80211_key_enable_hw_accel(key); + + mutex_unlock(&sdata->local->key_mtx); +@@ -492,8 +503,12 @@ + + mutex_lock(&sdata->local->key_mtx); + +- list_for_each_entry(key, &sdata->key_list, list) ++ sdata->local->crypto_tx_tailroom_needed_cnt = 0; ++ ++ list_for_each_entry(key, &sdata->key_list, list) { ++ sdata->local->crypto_tx_tailroom_needed_cnt++; + ieee80211_key_enable_hw_accel(key); ++ } + + mutex_unlock(&sdata->local->key_mtx); + } +diff -Naur linux-2.6.39-rc6/net/mac80211/main.c linux-2.6.39-rc6.rtl8192se/net/mac80211/main.c +--- linux-2.6.39-rc6/net/mac80211/main.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/main.c 2011-05-05 23:30:21.825880780 +0200 +@@ -33,12 +33,6 @@ + #include "cfg.h" + #include "debugfs.h" + +- +-static bool ieee80211_disable_40mhz_24ghz; +-module_param(ieee80211_disable_40mhz_24ghz, bool, 0644); +-MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz, +- "Disable 40MHz support in the 2.4GHz band"); +- + static struct lock_class_key ieee80211_rx_skb_queue_class; + + void ieee80211_configure_filter(struct ieee80211_local *local) +@@ -545,7 +539,9 @@ + }, + [NL80211_IFTYPE_MESH_POINT] = { + .tx = 0xffff, +- .rx = BIT(IEEE80211_STYPE_ACTION >> 4), ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4), + }, + }; + +@@ -726,18 +722,6 @@ + } + channels += sband->n_channels; + +- /* +- * Since ieee80211_disable_40mhz_24ghz is global, we can +- * modify the sband's ht data even if the driver uses a +- * global structure for that. +- */ +- if (ieee80211_disable_40mhz_24ghz && +- band == IEEE80211_BAND_2GHZ && +- sband->ht_cap.ht_supported) { +- sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; +- sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; +- } +- + if (max_bitrates < sband->n_bitrates) + max_bitrates = sband->n_bitrates; + supp_ht = supp_ht || sband->ht_cap.ht_supported; +@@ -760,6 +744,11 @@ + local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); + #endif + ++ /* if the underlying driver supports mesh, mac80211 will (at least) ++ * provide routing of mesh authentication frames to userspace */ ++ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) ++ local->hw.wiphy->flags |= WIPHY_FLAG_MESH_AUTH; ++ + /* mac80211 supports control port protocol changing */ + local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; + +@@ -879,10 +868,6 @@ + + local->dynamic_ps_forced_timeout = -1; + +- result = sta_info_start(local); +- if (result < 0) +- goto fail_sta_info; +- + result = ieee80211_wep_init(local); + if (result < 0) + wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", +@@ -945,7 +930,6 @@ + rtnl_unlock(); + ieee80211_wep_free(local); + sta_info_stop(local); +- fail_sta_info: + destroy_workqueue(local->workqueue); + fail_workqueue: + wiphy_unregister(local->hw.wiphy); +diff -Naur linux-2.6.39-rc6/net/mac80211/mesh.c linux-2.6.39-rc6.rtl8192se/net/mac80211/mesh.c +--- linux-2.6.39-rc6/net/mac80211/mesh.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/mesh.c 2011-05-05 23:30:21.806880551 +0200 +@@ -279,9 +279,9 @@ + MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; + *pos++ = 0x00; + +- if (sdata->u.mesh.vendor_ie) { +- int len = sdata->u.mesh.vendor_ie_len; +- const u8 *data = sdata->u.mesh.vendor_ie; ++ if (sdata->u.mesh.ie) { ++ int len = sdata->u.mesh.ie_len; ++ const u8 *data = sdata->u.mesh.ie; + if (skb_tailroom(skb) > len) + memcpy(skb_put(skb, len), data, len); + } +@@ -573,6 +573,10 @@ + ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, + &elems); + ++ /* ignore beacons from secure mesh peers if our security is off */ ++ if (elems.rsn_len && !sdata->u.mesh.is_secure) ++ return; ++ + if (elems.ds_params && elems.ds_params_len == 1) + freq = ieee80211_channel_to_frequency(elems.ds_params[0], band); + else +@@ -586,9 +590,7 @@ + if (elems.mesh_id && elems.mesh_config && + mesh_matches_local(&elems, sdata)) { + supp_rates = ieee80211_sta_get_rates(local, &elems, band); +- +- mesh_neighbour_update(mgmt->sa, supp_rates, sdata, +- mesh_peer_accepts_plinks(&elems)); ++ mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems); + } + } + +@@ -611,12 +613,9 @@ + struct sk_buff *skb) + { + struct ieee80211_rx_status *rx_status; +- struct ieee80211_if_mesh *ifmsh; + struct ieee80211_mgmt *mgmt; + u16 stype; + +- ifmsh = &sdata->u.mesh; +- + rx_status = IEEE80211_SKB_RXCB(skb); + mgmt = (struct ieee80211_mgmt *) skb->data; + stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; +diff -Naur linux-2.6.39-rc6/net/mac80211/mesh.h linux-2.6.39-rc6.rtl8192se/net/mac80211/mesh.h +--- linux-2.6.39-rc6/net/mac80211/mesh.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/mesh.h 2011-05-05 23:30:21.832880865 +0200 +@@ -226,7 +226,8 @@ + int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); + /* Mesh plinks */ + void mesh_neighbour_update(u8 *hw_addr, u32 rates, +- struct ieee80211_sub_if_data *sdata, bool add); ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee802_11_elems *ie); + bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); + void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); + void mesh_plink_broken(struct sta_info *sta); +diff -Naur linux-2.6.39-rc6/net/mac80211/mesh_hwmp.c linux-2.6.39-rc6.rtl8192se/net/mac80211/mesh_hwmp.c +--- linux-2.6.39-rc6/net/mac80211/mesh_hwmp.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/mesh_hwmp.c 2011-05-05 23:30:21.782880261 +0200 +@@ -633,7 +633,6 @@ + struct mesh_path *mpath; + u8 ttl; + u8 *ta, *target_addr; +- u8 target_flags; + u32 target_sn; + u16 target_rcode; + +@@ -644,7 +643,6 @@ + return; + } + ttl--; +- target_flags = PERR_IE_TARGET_FLAGS(perr_elem); + target_addr = PERR_IE_TARGET_ADDR(perr_elem); + target_sn = PERR_IE_TARGET_SN(perr_elem); + target_rcode = PERR_IE_TARGET_RCODE(perr_elem); +@@ -675,12 +673,10 @@ + { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + struct mesh_path *mpath; +- u8 *ta; + u8 ttl, flags, hopcount; + u8 *orig_addr; + u32 orig_sn, metric; + +- ta = mgmt->sa; + ttl = rann->rann_ttl; + if (ttl <= 1) { + ifmsh->mshstats.dropped_frames_ttl++; +diff -Naur linux-2.6.39-rc6/net/mac80211/mesh_pathtbl.c linux-2.6.39-rc6.rtl8192se/net/mac80211/mesh_pathtbl.c +--- linux-2.6.39-rc6/net/mac80211/mesh_pathtbl.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/mesh_pathtbl.c 2011-05-05 23:30:21.833880877 +0200 +@@ -65,42 +65,37 @@ + __mesh_table_free(tbl); + } + +-static struct mesh_table *mesh_table_grow(struct mesh_table *tbl) ++static int mesh_table_grow(struct mesh_table *oldtbl, ++ struct mesh_table *newtbl) + { +- struct mesh_table *newtbl; + struct hlist_head *oldhash; + struct hlist_node *p, *q; + int i; + +- if (atomic_read(&tbl->entries) +- < tbl->mean_chain_len * (tbl->hash_mask + 1)) +- goto endgrow; ++ if (atomic_read(&oldtbl->entries) ++ < oldtbl->mean_chain_len * (oldtbl->hash_mask + 1)) ++ return -EAGAIN; + +- newtbl = mesh_table_alloc(tbl->size_order + 1); +- if (!newtbl) +- goto endgrow; + +- newtbl->free_node = tbl->free_node; +- newtbl->mean_chain_len = tbl->mean_chain_len; +- newtbl->copy_node = tbl->copy_node; +- atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); ++ newtbl->free_node = oldtbl->free_node; ++ newtbl->mean_chain_len = oldtbl->mean_chain_len; ++ newtbl->copy_node = oldtbl->copy_node; ++ atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries)); + +- oldhash = tbl->hash_buckets; +- for (i = 0; i <= tbl->hash_mask; i++) ++ oldhash = oldtbl->hash_buckets; ++ for (i = 0; i <= oldtbl->hash_mask; i++) + hlist_for_each(p, &oldhash[i]) +- if (tbl->copy_node(p, newtbl) < 0) ++ if (oldtbl->copy_node(p, newtbl) < 0) + goto errcopy; + +- return newtbl; ++ return 0; + + errcopy: + for (i = 0; i <= newtbl->hash_mask; i++) { + hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) +- tbl->free_node(p, 0); ++ oldtbl->free_node(p, 0); + } +- __mesh_table_free(newtbl); +-endgrow: +- return NULL; ++ return -ENOMEM; + } + + +@@ -334,10 +329,13 @@ + { + struct mesh_table *oldtbl, *newtbl; + ++ newtbl = mesh_table_alloc(mesh_paths->size_order + 1); ++ if (!newtbl) ++ return; + write_lock(&pathtbl_resize_lock); + oldtbl = mesh_paths; +- newtbl = mesh_table_grow(mesh_paths); +- if (!newtbl) { ++ if (mesh_table_grow(mesh_paths, newtbl) < 0) { ++ __mesh_table_free(newtbl); + write_unlock(&pathtbl_resize_lock); + return; + } +@@ -352,10 +350,13 @@ + { + struct mesh_table *oldtbl, *newtbl; + ++ newtbl = mesh_table_alloc(mpp_paths->size_order + 1); ++ if (!newtbl) ++ return; + write_lock(&pathtbl_resize_lock); + oldtbl = mpp_paths; +- newtbl = mesh_table_grow(mpp_paths); +- if (!newtbl) { ++ if (mesh_table_grow(mpp_paths, newtbl) < 0) { ++ __mesh_table_free(newtbl); + write_unlock(&pathtbl_resize_lock); + return; + } +diff -Naur linux-2.6.39-rc6/net/mac80211/mesh_plink.c linux-2.6.39-rc6.rtl8192se/net/mac80211/mesh_plink.c +--- linux-2.6.39-rc6/net/mac80211/mesh_plink.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/mesh_plink.c 2011-05-05 23:30:21.808880575 +0200 +@@ -105,7 +105,7 @@ + if (!sta) + return NULL; + +- sta->flags = WLAN_STA_AUTHORIZED; ++ sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH; + sta->sta.supp_rates[local->hw.conf.channel->band] = rates; + rate_control_rate_init(sta); + +@@ -161,7 +161,7 @@ + __le16 reason) { + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 + +- sdata->u.mesh.vendor_ie_len); ++ sdata->u.mesh.ie_len); + struct ieee80211_mgmt *mgmt; + bool include_plid = false; + static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; +@@ -237,8 +237,9 @@ + return 0; + } + +-void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data *sdata, +- bool peer_accepting_plinks) ++void mesh_neighbour_update(u8 *hw_addr, u32 rates, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee802_11_elems *elems) + { + struct ieee80211_local *local = sdata->local; + struct sta_info *sta; +@@ -248,8 +249,14 @@ + sta = sta_info_get(sdata, hw_addr); + if (!sta) { + rcu_read_unlock(); +- +- sta = mesh_plink_alloc(sdata, hw_addr, rates); ++ /* Userspace handles peer allocation when security is enabled ++ * */ ++ if (sdata->u.mesh.is_secure) ++ cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, ++ elems->ie_start, elems->total_len, ++ GFP_KERNEL); ++ else ++ sta = mesh_plink_alloc(sdata, hw_addr, rates); + if (!sta) + return; + if (sta_info_insert_rcu(sta)) { +@@ -260,7 +267,8 @@ + + sta->last_rx = jiffies; + sta->sta.supp_rates[local->hw.conf.channel->band] = rates; +- if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN && ++ if (mesh_peer_accepts_plinks(elems) && ++ sta->plink_state == PLINK_LISTEN && + sdata->u.mesh.accepting_plinks && + sdata->u.mesh.mshcfg.auto_open_plinks) + mesh_plink_open(sta); +@@ -372,6 +380,9 @@ + __le16 llid; + struct ieee80211_sub_if_data *sdata = sta->sdata; + ++ if (!test_sta_flags(sta, WLAN_STA_AUTH)) ++ return -EPERM; ++ + spin_lock_bh(&sta->lock); + get_random_bytes(&llid, 2); + sta->llid = llid; +@@ -449,6 +460,10 @@ + mpl_dbg("Mesh plink: missing necessary peer link ie\n"); + return; + } ++ if (elems.rsn_len && !sdata->u.mesh.is_secure) { ++ mpl_dbg("Mesh plink: can't establish link with secure peer\n"); ++ return; ++ } + + ftype = mgmt->u.action.u.plink_action.action_code; + ie_len = elems.peer_link_len; +@@ -480,6 +495,12 @@ + return; + } + ++ if (sta && !test_sta_flags(sta, WLAN_STA_AUTH)) { ++ mpl_dbg("Mesh plink: Action frame from non-authed peer\n"); ++ rcu_read_unlock(); ++ return; ++ } ++ + if (sta && sta->plink_state == PLINK_BLOCKED) { + rcu_read_unlock(); + return; +diff -Naur linux-2.6.39-rc6/net/mac80211/mlme.c linux-2.6.39-rc6.rtl8192se/net/mac80211/mlme.c +--- linux-2.6.39-rc6/net/mac80211/mlme.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/mlme.c 2011-05-05 23:30:21.781880249 +0200 +@@ -90,20 +90,11 @@ + /* no action required */ + RX_MGMT_NONE, + +- /* caller must call cfg80211_send_rx_auth() */ +- RX_MGMT_CFG80211_AUTH, +- +- /* caller must call cfg80211_send_rx_assoc() */ +- RX_MGMT_CFG80211_ASSOC, +- + /* caller must call cfg80211_send_deauth() */ + RX_MGMT_CFG80211_DEAUTH, + + /* caller must call cfg80211_send_disassoc() */ + RX_MGMT_CFG80211_DISASSOC, +- +- /* caller must tell cfg80211 about internal error */ +- RX_MGMT_CFG80211_ASSOC_ERROR, + }; + + /* utils */ +@@ -770,15 +761,16 @@ + if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && + (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { + netif_tx_stop_all_queues(sdata->dev); +- /* +- * Flush all the frames queued in the driver before +- * going to power save +- */ +- drv_flush(local, false); +- ieee80211_send_nullfunc(local, sdata, 1); + +- /* Flush once again to get the tx status of nullfunc frame */ +- drv_flush(local, false); ++ if (drv_tx_frames_pending(local)) ++ mod_timer(&local->dynamic_ps_timer, jiffies + ++ msecs_to_jiffies( ++ local->hw.conf.dynamic_ps_timeout)); ++ else { ++ ieee80211_send_nullfunc(local, sdata, 1); ++ /* Flush to get the tx status of nullfunc frame */ ++ drv_flush(local, false); ++ } + } + + if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && +diff -Naur linux-2.6.39-rc6/net/mac80211/pm.c linux-2.6.39-rc6.rtl8192se/net/mac80211/pm.c +--- linux-2.6.39-rc6/net/mac80211/pm.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/pm.c 2011-05-05 23:30:21.822880743 +0200 +@@ -14,12 +14,23 @@ + + ieee80211_scan_cancel(local); + ++ if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { ++ mutex_lock(&local->sta_mtx); ++ list_for_each_entry(sta, &local->sta_list, list) { ++ set_sta_flags(sta, WLAN_STA_BLOCK_BA); ++ ieee80211_sta_tear_down_BA_sessions(sta, true); ++ } ++ mutex_unlock(&local->sta_mtx); ++ } ++ + ieee80211_stop_queues_by_reason(hw, + IEEE80211_QUEUE_STOP_REASON_SUSPEND); + + /* flush out all packets */ + synchronize_net(); + ++ drv_flush(local, false); ++ + local->quiescing = true; + /* make quiescing visible to timers everywhere */ + mb(); +@@ -43,11 +54,6 @@ + /* tear down aggregation sessions and remove STAs */ + mutex_lock(&local->sta_mtx); + list_for_each_entry(sta, &local->sta_list, list) { +- if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { +- set_sta_flags(sta, WLAN_STA_BLOCK_BA); +- ieee80211_sta_tear_down_BA_sessions(sta, true); +- } +- + if (sta->uploaded) { + sdata = sta->sdata; + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) +diff -Naur linux-2.6.39-rc6/net/mac80211/rx.c linux-2.6.39-rc6.rtl8192se/net/mac80211/rx.c +--- linux-2.6.39-rc6/net/mac80211/rx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/rx.c 2011-05-05 23:30:21.814880647 +0200 +@@ -143,7 +143,8 @@ + if (status->flag & RX_FLAG_HT) { + /* + * MCS information is a separate field in radiotap, +- * added below. ++ * added below. The byte here is needed as padding ++ * for the channel though, so initialise it to 0. + */ + *pos = 0; + } else { +@@ -502,7 +503,8 @@ + + if (ieee80211_is_probe_req(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control) || +- ieee80211_is_beacon(hdr->frame_control)) ++ ieee80211_is_beacon(hdr->frame_control) || ++ ieee80211_is_auth(hdr->frame_control)) + return RX_CONTINUE; + + return RX_DROP_MONITOR; +@@ -650,7 +652,7 @@ + set_release_timer: + + mod_timer(&tid_agg_rx->reorder_timer, +- tid_agg_rx->reorder_time[j] + ++ tid_agg_rx->reorder_time[j] + 1 + + HT_RX_REORDER_BUF_TIMEOUT); + } else { + del_timer(&tid_agg_rx->reorder_timer); +@@ -707,6 +709,8 @@ + /* + * If the current MPDU is in the right order and nothing else + * is stored we can process it directly, no need to buffer it. ++ * If it is first but there's something stored, we may be able ++ * to release frames after this one. + */ + if (mpdu_seq_num == tid_agg_rx->head_seq_num && + tid_agg_rx->stored_mpdu_num == 0) { +@@ -1583,7 +1587,7 @@ + } + + static int +-__ieee80211_data_to_8023(struct ieee80211_rx_data *rx) ++__ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control) + { + struct ieee80211_sub_if_data *sdata = rx->sdata; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; +@@ -1591,6 +1595,7 @@ + struct ethhdr *ehdr; + int ret; + ++ *port_control = false; + if (ieee80211_has_a4(hdr->frame_control) && + sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta) + return -1; +@@ -1609,11 +1614,13 @@ + return -1; + + ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type); +- if (ret < 0 || !check_port_control) ++ if (ret < 0) + return ret; + + ehdr = (struct ethhdr *) rx->skb->data; +- if (ehdr->h_proto != rx->sdata->control_port_protocol) ++ if (ehdr->h_proto == rx->sdata->control_port_protocol) ++ *port_control = true; ++ else if (check_port_control) + return -1; + + return 0; +@@ -1914,6 +1921,7 @@ + struct net_device *dev = sdata->dev; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; + __le16 fc = hdr->frame_control; ++ bool port_control; + int err; + + if (unlikely(!ieee80211_is_data(hdr->frame_control))) +@@ -1930,13 +1938,21 @@ + sdata->vif.type == NL80211_IFTYPE_AP) + return RX_DROP_MONITOR; + +- err = __ieee80211_data_to_8023(rx); ++ err = __ieee80211_data_to_8023(rx, &port_control); + if (unlikely(err)) + return RX_DROP_UNUSABLE; + + if (!ieee80211_frame_allowed(rx, fc)) + return RX_DROP_MONITOR; + ++ if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && ++ unlikely(port_control) && sdata->bss) { ++ sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, ++ u.ap); ++ dev = sdata->dev; ++ rx->sdata = sdata; ++ } ++ + rx->skb->dev = dev; + + dev->stats.rx_packets++; +@@ -2352,47 +2368,6 @@ + return RX_QUEUED; + } + +-static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, +- struct ieee80211_rx_data *rx) +-{ +- int keyidx; +- unsigned int hdrlen; +- +- hdrlen = ieee80211_hdrlen(hdr->frame_control); +- if (rx->skb->len >= hdrlen + 4) +- keyidx = rx->skb->data[hdrlen + 3] >> 6; +- else +- keyidx = -1; +- +- if (!rx->sta) { +- /* +- * Some hardware seem to generate incorrect Michael MIC +- * reports; ignore them to avoid triggering countermeasures. +- */ +- return; +- } +- +- if (!ieee80211_has_protected(hdr->frame_control)) +- return; +- +- if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) { +- /* +- * APs with pairwise keys should never receive Michael MIC +- * errors for non-zero keyidx because these are reserved for +- * group keys and only the AP is sending real multicast +- * frames in the BSS. +- */ +- return; +- } +- +- if (!ieee80211_is_data(hdr->frame_control) && +- !ieee80211_is_auth(hdr->frame_control)) +- return; +- +- mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL, +- GFP_ATOMIC); +-} +- + /* TODO: use IEEE80211_RX_FRAGMENTED */ + static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, + struct ieee80211_rate *rate) +@@ -2736,12 +2711,6 @@ + if (!prepares) + return false; + +- if (status->flag & RX_FLAG_MMIC_ERROR) { +- if (status->rx_flags & IEEE80211_RX_RA_MATCH) +- ieee80211_rx_michael_mic_report(hdr, rx); +- return false; +- } +- + if (!consume) { + skb = skb_copy(skb, GFP_ATOMIC); + if (!skb) { +diff -Naur linux-2.6.39-rc6/net/mac80211/sta_info.c linux-2.6.39-rc6.rtl8192se/net/mac80211/sta_info.c +--- linux-2.6.39-rc6/net/mac80211/sta_info.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/sta_info.c 2011-05-05 23:30:21.772880141 +0200 +@@ -228,6 +228,7 @@ + { + struct ieee80211_local *local = sdata->local; + struct sta_info *sta; ++ struct timespec uptime; + int i; + + sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); +@@ -245,6 +246,8 @@ + sta->sdata = sdata; + sta->last_rx = jiffies; + ++ do_posix_clock_monotonic_gettime(&uptime); ++ sta->last_connected = uptime.tv_sec; + ewma_init(&sta->avg_signal, 1024, 8); + + if (sta_prepare_rate_control(local, sta, gfp)) { +@@ -584,7 +587,6 @@ + { + unsigned long flags; + struct sk_buff *skb; +- struct ieee80211_sub_if_data *sdata; + + if (skb_queue_empty(&sta->ps_tx_buf)) + return false; +@@ -601,7 +603,6 @@ + if (!skb) + break; + +- sdata = sta->sdata; + local->total_ps_buffered--; + #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n", +@@ -609,7 +610,8 @@ + #endif + dev_kfree_skb(skb); + +- if (skb_queue_empty(&sta->ps_tx_buf)) ++ if (skb_queue_empty(&sta->ps_tx_buf) && ++ !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF)) + sta_info_clear_tim_bit(sta); + } + +@@ -698,6 +700,8 @@ + #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + cancel_work_sync(&sta->drv_unblock_wk); + ++ cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); ++ + rate_control_remove_sta_debugfs(sta); + ieee80211_sta_debugfs_remove(sta); + +@@ -766,9 +770,8 @@ + if (!timer_needed) + return; + +- local->sta_cleanup.expires = +- round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); +- add_timer(&local->sta_cleanup); ++ mod_timer(&local->sta_cleanup, ++ round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL)); + } + + void sta_info_init(struct ieee80211_local *local) +@@ -781,14 +784,6 @@ + + setup_timer(&local->sta_cleanup, sta_info_cleanup, + (unsigned long)local); +- local->sta_cleanup.expires = +- round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); +-} +- +-int sta_info_start(struct ieee80211_local *local) +-{ +- add_timer(&local->sta_cleanup); +- return 0; + } + + void sta_info_stop(struct ieee80211_local *local) +@@ -900,6 +895,7 @@ + struct ieee80211_local *local = sdata->local; + int sent, buffered; + ++ clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); + if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) + drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); + +@@ -992,3 +988,12 @@ + ieee80211_queue_work(hw, &sta->drv_unblock_wk); + } + EXPORT_SYMBOL(ieee80211_sta_block_awake); ++ ++void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta) ++{ ++ struct sta_info *sta = container_of(pubsta, struct sta_info, sta); ++ ++ set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); ++ sta_info_set_tim_bit(sta); ++} ++EXPORT_SYMBOL(ieee80211_sta_set_tim); +diff -Naur linux-2.6.39-rc6/net/mac80211/sta_info.h linux-2.6.39-rc6.rtl8192se/net/mac80211/sta_info.h +--- linux-2.6.39-rc6/net/mac80211/sta_info.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/sta_info.h 2011-05-05 23:30:21.786880309 +0200 +@@ -43,6 +43,8 @@ + * be in the queues + * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping + * station in power-save mode, reply when the driver unblocks. ++ * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal ++ * buffers. Automatically cleared on station wake-up. + */ + enum ieee80211_sta_info_flags { + WLAN_STA_AUTH = 1<<0, +@@ -58,6 +60,7 @@ + WLAN_STA_BLOCK_BA = 1<<11, + WLAN_STA_PS_DRIVER = 1<<12, + WLAN_STA_PSPOLL = 1<<13, ++ WLAN_STA_PS_DRIVER_BUF = 1<<14, + }; + + #define STA_TID_NUM 16 +@@ -226,6 +229,7 @@ + * @rx_bytes: Number of bytes received from this STA + * @wep_weak_iv_count: number of weak WEP IVs received from this station + * @last_rx: time (in jiffies) when last frame was received from this STA ++ * @last_connected: time (in seconds) when a station got connected + * @num_duplicates: number of duplicate frames received from this STA + * @rx_fragments: number of received MPDUs + * @rx_dropped: number of dropped MPDUs from this STA +@@ -295,6 +299,7 @@ + unsigned long rx_packets, rx_bytes; + unsigned long wep_weak_iv_count; + unsigned long last_rx; ++ long last_connected; + unsigned long num_duplicates; + unsigned long rx_fragments; + unsigned long rx_dropped; +@@ -497,7 +502,6 @@ + void sta_info_clear_tim_bit(struct sta_info *sta); + + void sta_info_init(struct ieee80211_local *local); +-int sta_info_start(struct ieee80211_local *local); + void sta_info_stop(struct ieee80211_local *local); + int sta_info_flush(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata); +diff -Naur linux-2.6.39-rc6/net/mac80211/status.c linux-2.6.39-rc6.rtl8192se/net/mac80211/status.c +--- linux-2.6.39-rc6/net/mac80211/status.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/status.c 2011-05-05 23:30:21.809880587 +0200 +@@ -189,16 +189,19 @@ + bool acked; + + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { +- /* the HW cannot have attempted that rate */ +- if (i >= hw->max_report_rates) { ++ if (info->status.rates[i].idx < 0) { ++ break; ++ } else if (i >= hw->max_report_rates) { ++ /* the HW cannot have attempted that rate */ + info->status.rates[i].idx = -1; + info->status.rates[i].count = 0; +- } else if (info->status.rates[i].idx >= 0) { +- rates_idx = i; ++ break; + } + + retry_count += info->status.rates[i].count; + } ++ rates_idx = i - 1; ++ + if (retry_count < 0) + retry_count = 0; + +@@ -443,3 +446,11 @@ + dev_kfree_skb(skb); + } + EXPORT_SYMBOL(ieee80211_tx_status); ++ ++void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets) ++{ ++ struct sta_info *sta = container_of(pubsta, struct sta_info, sta); ++ cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr, ++ num_packets, GFP_ATOMIC); ++} ++EXPORT_SYMBOL(ieee80211_report_low_ack); +diff -Naur linux-2.6.39-rc6/net/mac80211/tkip.c linux-2.6.39-rc6.rtl8192se/net/mac80211/tkip.c +--- linux-2.6.39-rc6/net/mac80211/tkip.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/tkip.c 2011-05-05 23:30:21.820880719 +0200 +@@ -202,7 +202,7 @@ + * @payload_len is the length of payload (_not_ including IV/ICV length). + * @ta is the transmitter addresses. + */ +-int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, ++int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, + struct ieee80211_key *key, + u8 *pos, size_t payload_len, u8 *ta) + { +@@ -223,7 +223,7 @@ + * beginning of the buffer containing IEEE 802.11 header payload, i.e., + * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the + * length of payload, including IV, Ext. IV, MIC, ICV. */ +-int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, ++int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, + struct ieee80211_key *key, + u8 *payload, size_t payload_len, u8 *ta, + u8 *ra, int only_iv, int queue, +diff -Naur linux-2.6.39-rc6/net/mac80211/tkip.h linux-2.6.39-rc6.rtl8192se/net/mac80211/tkip.h +--- linux-2.6.39-rc6/net/mac80211/tkip.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/tkip.h 2011-05-05 23:30:21.809880587 +0200 +@@ -15,7 +15,7 @@ + + u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16); + +-int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, ++int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, + struct ieee80211_key *key, + u8 *pos, size_t payload_len, u8 *ta); + enum { +@@ -24,7 +24,7 @@ + TKIP_DECRYPT_INVALID_KEYIDX = -2, + TKIP_DECRYPT_REPLAY = -3, + }; +-int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, ++int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, + struct ieee80211_key *key, + u8 *payload, size_t payload_len, u8 *ta, + u8 *ra, int only_iv, int queue, +diff -Naur linux-2.6.39-rc6/net/mac80211/tx.c linux-2.6.39-rc6.rtl8192se/net/mac80211/tx.c +--- linux-2.6.39-rc6/net/mac80211/tx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/tx.c 2011-05-05 23:30:21.758879971 +0200 +@@ -1036,14 +1036,11 @@ + struct ieee80211_radiotap_iterator iterator; + struct ieee80211_radiotap_header *rthdr = + (struct ieee80211_radiotap_header *) skb->data; +- struct ieee80211_supported_band *sband; + bool hw_frag; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, + NULL); + +- sband = tx->local->hw.wiphy->bands[tx->channel->band]; +- + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + tx->flags &= ~IEEE80211_TX_FRAGMENTED; + +@@ -1442,11 +1439,8 @@ + struct ieee80211_tx_data tx; + ieee80211_tx_result res_prepare; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +- u16 queue; + bool result = true; + +- queue = skb_get_queue_mapping(skb); +- + if (unlikely(skb->len < 10)) { + dev_kfree_skb(skb); + return true; +@@ -1482,12 +1476,7 @@ + { + int tail_need = 0; + +- /* +- * This could be optimised, devices that do full hardware +- * crypto (including TKIP MMIC) need no tailroom... But we +- * have no drivers for such devices currently. +- */ +- if (may_encrypt) { ++ if (may_encrypt && local->crypto_tx_tailroom_needed_cnt) { + tail_need = IEEE80211_ENCRYPT_TAILROOM; + tail_need -= skb_tailroom(skb); + tail_need = max_t(int, tail_need, 0); +@@ -2262,7 +2251,7 @@ + + /* headroom, head length, tail length and maximum TIM length */ + skb = dev_alloc_skb(local->tx_headroom + 400 + +- sdata->u.mesh.vendor_ie_len); ++ sdata->u.mesh.ie_len); + if (!skb) + goto out; + +@@ -2485,7 +2474,6 @@ + { + struct ieee80211_local *local = hw_to_local(hw); + struct sk_buff *skb = NULL; +- struct sta_info *sta; + struct ieee80211_tx_data tx; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_ap *bss = NULL; +@@ -2527,7 +2515,6 @@ + + info = IEEE80211_SKB_CB(skb); + +- sta = tx.sta; + tx.flags |= IEEE80211_TX_PS_BUFFERED; + tx.channel = local->hw.conf.channel; + info->band = tx.channel->band; +diff -Naur linux-2.6.39-rc6/net/mac80211/util.c linux-2.6.39-rc6.rtl8192se/net/mac80211/util.c +--- linux-2.6.39-rc6/net/mac80211/util.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/util.c 2011-05-05 23:30:21.786880309 +0200 +@@ -1290,7 +1290,7 @@ + } + } + +- add_timer(&local->sta_cleanup); ++ mod_timer(&local->sta_cleanup, jiffies + 1); + + mutex_lock(&local->sta_mtx); + list_for_each_entry(sta, &local->sta_list, list) +diff -Naur linux-2.6.39-rc6/net/mac80211/wep.c linux-2.6.39-rc6.rtl8192se/net/mac80211/wep.c +--- linux-2.6.39-rc6/net/mac80211/wep.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/wep.c 2011-05-05 23:30:21.733879669 +0200 +@@ -30,17 +30,15 @@ + /* start WEP IV from a random value */ + get_random_bytes(&local->wep_iv, WEP_IV_LEN); + +- local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, +- CRYPTO_ALG_ASYNC); ++ local->wep_tx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(local->wep_tx_tfm)) { + local->wep_rx_tfm = ERR_PTR(-EINVAL); + return PTR_ERR(local->wep_tx_tfm); + } + +- local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, +- CRYPTO_ALG_ASYNC); ++ local->wep_rx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(local->wep_rx_tfm)) { +- crypto_free_blkcipher(local->wep_tx_tfm); ++ crypto_free_cipher(local->wep_tx_tfm); + local->wep_tx_tfm = ERR_PTR(-EINVAL); + return PTR_ERR(local->wep_rx_tfm); + } +@@ -51,9 +49,9 @@ + void ieee80211_wep_free(struct ieee80211_local *local) + { + if (!IS_ERR(local->wep_tx_tfm)) +- crypto_free_blkcipher(local->wep_tx_tfm); ++ crypto_free_cipher(local->wep_tx_tfm); + if (!IS_ERR(local->wep_rx_tfm)) +- crypto_free_blkcipher(local->wep_rx_tfm); ++ crypto_free_cipher(local->wep_rx_tfm); + } + + static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen) +@@ -127,12 +125,11 @@ + /* Perform WEP encryption using given key. data buffer must have tailroom + * for 4-byte ICV. data_len must not include this ICV. Note: this function + * does _not_ add IV. data = RC4(data | CRC32(data)) */ +-int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, ++int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key, + size_t klen, u8 *data, size_t data_len) + { +- struct blkcipher_desc desc = { .tfm = tfm }; +- struct scatterlist sg; + __le32 icv; ++ int i; + + if (IS_ERR(tfm)) + return -1; +@@ -140,9 +137,9 @@ + icv = cpu_to_le32(~crc32_le(~0, data, data_len)); + put_unaligned(icv, (__le32 *)(data + data_len)); + +- crypto_blkcipher_setkey(tfm, rc4key, klen); +- sg_init_one(&sg, data, data_len + WEP_ICV_LEN); +- crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length); ++ crypto_cipher_setkey(tfm, rc4key, klen); ++ for (i = 0; i < data_len + WEP_ICV_LEN; i++) ++ crypto_cipher_encrypt_one(tfm, data + i, data + i); + + return 0; + } +@@ -186,19 +183,18 @@ + /* Perform WEP decryption using given key. data buffer includes encrypted + * payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV. + * Return 0 on success and -1 on ICV mismatch. */ +-int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, ++int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key, + size_t klen, u8 *data, size_t data_len) + { +- struct blkcipher_desc desc = { .tfm = tfm }; +- struct scatterlist sg; + __le32 crc; ++ int i; + + if (IS_ERR(tfm)) + return -1; + +- crypto_blkcipher_setkey(tfm, rc4key, klen); +- sg_init_one(&sg, data, data_len + WEP_ICV_LEN); +- crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length); ++ crypto_cipher_setkey(tfm, rc4key, klen); ++ for (i = 0; i < data_len + WEP_ICV_LEN; i++) ++ crypto_cipher_decrypt_one(tfm, data + i, data + i); + + crc = cpu_to_le32(~crc32_le(~0, data, data_len)); + if (memcmp(&crc, data + data_len, WEP_ICV_LEN) != 0) +diff -Naur linux-2.6.39-rc6/net/mac80211/wep.h linux-2.6.39-rc6.rtl8192se/net/mac80211/wep.h +--- linux-2.6.39-rc6/net/mac80211/wep.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/wep.h 2011-05-05 23:30:21.818880695 +0200 +@@ -18,12 +18,12 @@ + + int ieee80211_wep_init(struct ieee80211_local *local); + void ieee80211_wep_free(struct ieee80211_local *local); +-int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, ++int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key, + size_t klen, u8 *data, size_t data_len); + int ieee80211_wep_encrypt(struct ieee80211_local *local, + struct sk_buff *skb, + const u8 *key, int keylen, int keyidx); +-int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, ++int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key, + size_t klen, u8 *data, size_t data_len); + bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); + +diff -Naur linux-2.6.39-rc6/net/mac80211/work.c linux-2.6.39-rc6.rtl8192se/net/mac80211/work.c +--- linux-2.6.39-rc6/net/mac80211/work.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/work.c 2011-05-05 23:30:21.806880551 +0200 +@@ -198,9 +198,8 @@ + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u8 *pos, qos_info; +- const u8 *ies; + size_t offset = 0, noffset; +- int i, len, count, rates_len, supp_rates_len; ++ int i, count, rates_len, supp_rates_len; + u16 capab; + struct ieee80211_supported_band *sband; + u32 rates = 0; +@@ -285,7 +284,7 @@ + } + + /* SSID */ +- ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); ++ pos = skb_put(skb, 2 + wk->assoc.ssid_len); + *pos++ = WLAN_EID_SSID; + *pos++ = wk->assoc.ssid_len; + memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); +@@ -295,7 +294,6 @@ + if (supp_rates_len > 8) + supp_rates_len = 8; + +- len = sband->n_bitrates; + pos = skb_put(skb, supp_rates_len + 2); + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = supp_rates_len; +diff -Naur linux-2.6.39-rc6/net/mac80211/wpa.c linux-2.6.39-rc6.rtl8192se/net/mac80211/wpa.c +--- linux-2.6.39-rc6/net/mac80211/wpa.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/mac80211/wpa.c 2011-05-05 23:30:21.808880575 +0200 +@@ -87,42 +87,76 @@ + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + +- /* No way to verify the MIC if the hardware stripped it */ +- if (status->flag & RX_FLAG_MMIC_STRIPPED) ++ /* ++ * it makes no sense to check for MIC errors on anything other ++ * than data frames. ++ */ ++ if (!ieee80211_is_data_present(hdr->frame_control)) ++ return RX_CONTINUE; ++ ++ /* ++ * No way to verify the MIC if the hardware stripped it or ++ * the IV with the key index. In this case we have solely rely ++ * on the driver to set RX_FLAG_MMIC_ERROR in the event of a ++ * MIC failure report. ++ */ ++ if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) { ++ if (status->flag & RX_FLAG_MMIC_ERROR) ++ goto mic_fail; ++ ++ if (!(status->flag & RX_FLAG_IV_STRIPPED)) ++ goto update_iv; ++ + return RX_CONTINUE; ++ } + ++ /* ++ * Some hardware seems to generate Michael MIC failure reports; even ++ * though, the frame was not encrypted with TKIP and therefore has no ++ * MIC. Ignore the flag them to avoid triggering countermeasures. ++ */ + if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || +- !ieee80211_has_protected(hdr->frame_control) || +- !ieee80211_is_data_present(hdr->frame_control)) ++ !(status->flag & RX_FLAG_DECRYPTED)) + return RX_CONTINUE; + ++ if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) { ++ /* ++ * APs with pairwise keys should never receive Michael MIC ++ * errors for non-zero keyidx because these are reserved for ++ * group keys and only the AP is sending real multicast ++ * frames in the BSS. ( ++ */ ++ return RX_DROP_UNUSABLE; ++ } ++ ++ if (status->flag & RX_FLAG_MMIC_ERROR) ++ goto mic_fail; ++ + hdrlen = ieee80211_hdrlen(hdr->frame_control); + if (skb->len < hdrlen + MICHAEL_MIC_LEN) + return RX_DROP_UNUSABLE; + + data = skb->data + hdrlen; + data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; +- + key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; + michael_mic(key, hdr, data, data_len, mic); +- if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) { +- if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) +- return RX_DROP_UNUSABLE; +- +- mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, +- (void *) skb->data, NULL, +- GFP_ATOMIC); +- return RX_DROP_UNUSABLE; +- } ++ if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) ++ goto mic_fail; + + /* remove Michael MIC from payload */ + skb_trim(skb, skb->len - MICHAEL_MIC_LEN); + ++update_iv: + /* update IV in key information to be able to detect replays */ + rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32; + rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16; + + return RX_CONTINUE; ++ ++mic_fail: ++ mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, ++ (void *) skb->data, NULL, GFP_ATOMIC); ++ return RX_DROP_UNUSABLE; + } + + +diff -Naur linux-2.6.39-rc6/net/rfkill/Kconfig linux-2.6.39-rc6.rtl8192se/net/rfkill/Kconfig +--- linux-2.6.39-rc6/net/rfkill/Kconfig 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/rfkill/Kconfig 2011-05-05 23:30:19.015846853 +0200 +@@ -22,3 +22,14 @@ + depends on RFKILL + depends on INPUT = y || RFKILL = INPUT + default y if !EXPERT ++ ++config RFKILL_REGULATOR ++ tristate "Generic rfkill regulator driver" ++ depends on RFKILL || !RFKILL ++ depends on REGULATOR ++ help ++ This options enable controlling radio transmitters connected to ++ voltage regulator using the regulator framework. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called rfkill-regulator. +diff -Naur linux-2.6.39-rc6/net/rfkill/Makefile linux-2.6.39-rc6.rtl8192se/net/rfkill/Makefile +--- linux-2.6.39-rc6/net/rfkill/Makefile 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/rfkill/Makefile 2011-05-05 23:30:19.005846733 +0200 +@@ -5,3 +5,4 @@ + rfkill-y += core.o + rfkill-$(CONFIG_RFKILL_INPUT) += input.o + obj-$(CONFIG_RFKILL) += rfkill.o ++obj-$(CONFIG_RFKILL_REGULATOR) += rfkill-regulator.o +diff -Naur linux-2.6.39-rc6/net/rfkill/rfkill-regulator.c linux-2.6.39-rc6.rtl8192se/net/rfkill/rfkill-regulator.c +--- linux-2.6.39-rc6/net/rfkill/rfkill-regulator.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.rtl8192se/net/rfkill/rfkill-regulator.c 2011-05-05 23:30:19.005846733 +0200 +@@ -0,0 +1,164 @@ ++/* ++ * rfkill-regulator.c - Regulator consumer driver for rfkill ++ * ++ * Copyright (C) 2009 Guiming Zhuo ++ * Copyright (C) 2011 Antonio Ospite ++ * ++ * Implementation inspired by leds-regulator driver. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct rfkill_regulator_data { ++ struct rfkill *rf_kill; ++ bool reg_enabled; ++ ++ struct regulator *vcc; ++}; ++ ++static int rfkill_regulator_set_block(void *data, bool blocked) ++{ ++ struct rfkill_regulator_data *rfkill_data = data; ++ ++ pr_debug("%s: blocked: %d\n", __func__, blocked); ++ ++ if (blocked) { ++ if (rfkill_data->reg_enabled) { ++ regulator_disable(rfkill_data->vcc); ++ rfkill_data->reg_enabled = 0; ++ } ++ } else { ++ if (!rfkill_data->reg_enabled) { ++ regulator_enable(rfkill_data->vcc); ++ rfkill_data->reg_enabled = 1; ++ } ++ } ++ ++ pr_debug("%s: regulator_is_enabled after set_block: %d\n", __func__, ++ regulator_is_enabled(rfkill_data->vcc)); ++ ++ return 0; ++} ++ ++struct rfkill_ops rfkill_regulator_ops = { ++ .set_block = rfkill_regulator_set_block, ++}; ++ ++static int __devinit rfkill_regulator_probe(struct platform_device *pdev) ++{ ++ struct rfkill_regulator_platform_data *pdata = pdev->dev.platform_data; ++ struct rfkill_regulator_data *rfkill_data; ++ struct regulator *vcc; ++ struct rfkill *rf_kill; ++ int ret = 0; ++ ++ if (pdata == NULL) { ++ dev_err(&pdev->dev, "no platform data\n"); ++ return -ENODEV; ++ } ++ ++ if (pdata->name == NULL || pdata->type == 0) { ++ dev_err(&pdev->dev, "invalid name or type in platform data\n"); ++ return -EINVAL; ++ } ++ ++ vcc = regulator_get_exclusive(&pdev->dev, "vrfkill"); ++ if (IS_ERR(vcc)) { ++ dev_err(&pdev->dev, "Cannot get vcc for %s\n", pdata->name); ++ ret = PTR_ERR(vcc); ++ goto out; ++ } ++ ++ rfkill_data = kzalloc(sizeof(*rfkill_data), GFP_KERNEL); ++ if (rfkill_data == NULL) { ++ ret = -ENOMEM; ++ goto err_data_alloc; ++ } ++ ++ rf_kill = rfkill_alloc(pdata->name, &pdev->dev, ++ pdata->type, ++ &rfkill_regulator_ops, rfkill_data); ++ if (rf_kill == NULL) { ++ dev_err(&pdev->dev, "Cannot alloc rfkill device\n"); ++ ret = -ENOMEM; ++ goto err_rfkill_alloc; ++ } ++ ++ if (regulator_is_enabled(vcc)) { ++ dev_dbg(&pdev->dev, "Regulator already enabled\n"); ++ rfkill_data->reg_enabled = 1; ++ } ++ rfkill_data->vcc = vcc; ++ rfkill_data->rf_kill = rf_kill; ++ ++ ret = rfkill_register(rf_kill); ++ if (ret) { ++ dev_err(&pdev->dev, "Cannot register rfkill device\n"); ++ goto err_rfkill_register; ++ } ++ ++ platform_set_drvdata(pdev, rfkill_data); ++ dev_info(&pdev->dev, "%s initialized\n", pdata->name); ++ ++ return 0; ++ ++err_rfkill_register: ++ rfkill_destroy(rf_kill); ++err_rfkill_alloc: ++ kfree(rfkill_data); ++err_data_alloc: ++ regulator_put(vcc); ++out: ++ return ret; ++} ++ ++static int __devexit rfkill_regulator_remove(struct platform_device *pdev) ++{ ++ struct rfkill_regulator_data *rfkill_data = platform_get_drvdata(pdev); ++ struct rfkill *rf_kill = rfkill_data->rf_kill; ++ ++ rfkill_unregister(rf_kill); ++ rfkill_destroy(rf_kill); ++ regulator_put(rfkill_data->vcc); ++ kfree(rfkill_data); ++ ++ return 0; ++} ++ ++static struct platform_driver rfkill_regulator_driver = { ++ .probe = rfkill_regulator_probe, ++ .remove = __devexit_p(rfkill_regulator_remove), ++ .driver = { ++ .name = "rfkill-regulator", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init rfkill_regulator_init(void) ++{ ++ return platform_driver_register(&rfkill_regulator_driver); ++} ++module_init(rfkill_regulator_init); ++ ++static void __exit rfkill_regulator_exit(void) ++{ ++ platform_driver_unregister(&rfkill_regulator_driver); ++} ++module_exit(rfkill_regulator_exit); ++ ++MODULE_AUTHOR("Guiming Zhuo "); ++MODULE_AUTHOR("Antonio Ospite "); ++MODULE_DESCRIPTION("Regulator consumer driver for rfkill"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:rfkill-regulator"); +diff -Naur linux-2.6.39-rc6/net/wireless/core.c linux-2.6.39-rc6.rtl8192se/net/wireless/core.c +--- linux-2.6.39-rc6/net/wireless/core.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/wireless/core.c 2011-05-05 23:30:21.708879367 +0200 +@@ -46,6 +46,11 @@ + /* for the cleanup, scan and event works */ + struct workqueue_struct *cfg80211_wq; + ++static bool cfg80211_disable_40mhz_24ghz; ++module_param(cfg80211_disable_40mhz_24ghz, bool, 0644); ++MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, ++ "Disable 40MHz support in the 2.4GHz band"); ++ + /* requires cfg80211_mutex to be held! */ + struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) + { +@@ -451,6 +456,18 @@ + return -EINVAL; + + /* ++ * Since cfg80211_disable_40mhz_24ghz is global, we can ++ * modify the sband's ht data even if the driver uses a ++ * global structure for that. ++ */ ++ if (cfg80211_disable_40mhz_24ghz && ++ band == IEEE80211_BAND_2GHZ && ++ sband->ht_cap.ht_supported) { ++ sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; ++ sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; ++ } ++ ++ /* + * Since we use a u32 for rate bitmaps in + * ieee80211_get_response_rate, we cannot + * have more than 32 legacy rates. +diff -Naur linux-2.6.39-rc6/net/wireless/mesh.c linux-2.6.39-rc6.rtl8192se/net/wireless/mesh.c +--- linux-2.6.39-rc6/net/wireless/mesh.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/wireless/mesh.c 2011-05-05 23:30:21.706879343 +0200 +@@ -1,5 +1,6 @@ + #include + #include ++#include "nl80211.h" + #include "core.h" + + /* Default values, timeouts in ms */ +@@ -53,8 +54,9 @@ + const struct mesh_setup default_mesh_setup = { + .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, + .path_metric = IEEE80211_PATH_METRIC_AIRTIME, +- .vendor_ie = NULL, +- .vendor_ie_len = 0, ++ .ie = NULL, ++ .ie_len = 0, ++ .is_secure = false, + }; + + int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, +@@ -72,6 +74,10 @@ + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; + ++ if (!(rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && ++ setup->is_secure) ++ return -EOPNOTSUPP; ++ + if (wdev->mesh_id_len) + return -EALREADY; + +@@ -105,6 +111,19 @@ + return err; + } + ++void cfg80211_notify_new_peer_candidate(struct net_device *dev, ++ const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp) ++{ ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ ++ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT)) ++ return; ++ ++ nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev, ++ macaddr, ie, ie_len, gfp); ++} ++EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate); ++ + static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, + struct net_device *dev) + { +diff -Naur linux-2.6.39-rc6/net/wireless/mlme.c linux-2.6.39-rc6.rtl8192se/net/wireless/mlme.c +--- linux-2.6.39-rc6/net/wireless/mlme.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/wireless/mlme.c 2011-05-05 23:30:21.696879223 +0200 +@@ -770,6 +770,15 @@ + } + EXPORT_SYMBOL(cfg80211_new_sta); + ++void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) ++{ ++ struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; ++ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); ++ ++ nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp); ++} ++EXPORT_SYMBOL(cfg80211_del_sta); ++ + struct cfg80211_mgmt_registration { + struct list_head list; + +diff -Naur linux-2.6.39-rc6/net/wireless/nl80211.c linux-2.6.39-rc6.rtl8192se/net/wireless/nl80211.c +--- linux-2.6.39-rc6/net/wireless/nl80211.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/wireless/nl80211.c 2011-05-05 23:30:21.700879271 +0200 +@@ -124,6 +124,7 @@ + [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 }, + + [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, ++ [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG }, + + [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, + .len = NL80211_HT_CAPABILITY_LEN }, +@@ -594,6 +595,8 @@ + + if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) + NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); ++ if (dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) ++ NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH); + + NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, + sizeof(u32) * dev->wiphy.n_cipher_suites, +@@ -1922,6 +1925,7 @@ + [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, + [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, + [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG }, ++ [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG }, + }; + + static int parse_station_flags(struct genl_info *info, +@@ -2002,7 +2006,7 @@ + const u8 *mac_addr, struct station_info *sinfo) + { + void *hdr; +- struct nlattr *sinfoattr; ++ struct nlattr *sinfoattr, *bss_param; + + hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); + if (!hdr) +@@ -2016,6 +2020,9 @@ + sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); + if (!sinfoattr) + goto nla_put_failure; ++ if (sinfo->filled & STATION_INFO_CONNECTED_TIME) ++ NLA_PUT_U32(msg, NL80211_STA_INFO_CONNECTED_TIME, ++ sinfo->connected_time); + if (sinfo->filled & STATION_INFO_INACTIVE_TIME) + NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, + sinfo->inactive_time); +@@ -2062,6 +2069,25 @@ + if (sinfo->filled & STATION_INFO_TX_FAILED) + NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, + sinfo->tx_failed); ++ if (sinfo->filled & STATION_INFO_BSS_PARAM) { ++ bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); ++ if (!bss_param) ++ goto nla_put_failure; ++ ++ if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) ++ NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_CTS_PROT); ++ if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) ++ NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE); ++ if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) ++ NLA_PUT_FLAG(msg, ++ NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME); ++ NLA_PUT_U8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD, ++ sinfo->bss_param.dtim_period); ++ NLA_PUT_U16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL, ++ sinfo->bss_param.beacon_interval); ++ ++ nla_nest_end(msg, bss_param); ++ } + nla_nest_end(msg, sinfoattr); + + return genlmsg_end(msg, hdr); +@@ -2262,7 +2288,9 @@ + err = -EINVAL; + if (params.supported_rates) + err = -EINVAL; +- if (params.sta_flags_mask) ++ if (params.sta_flags_mask & ++ ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | ++ BIT(NL80211_STA_FLAG_AUTHORIZED))) + err = -EINVAL; + break; + default: +@@ -2324,11 +2352,16 @@ + params.ht_capa = + nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); + ++ if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) ++ params.plink_action = ++ nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); ++ + if (parse_station_flags(info, ¶ms)) + return -EINVAL; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && ++ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EINVAL; + +@@ -2804,7 +2837,8 @@ + nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = { + [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, + [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, +- [NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE] = { .type = NLA_BINARY, ++ [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, ++ [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + }; + +@@ -2906,14 +2940,16 @@ + IEEE80211_PATH_METRIC_VENDOR : + IEEE80211_PATH_METRIC_AIRTIME; + +- if (tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]) { ++ ++ if (tb[NL80211_MESH_SETUP_IE]) { + struct nlattr *ieattr = +- tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]; ++ tb[NL80211_MESH_SETUP_IE]; + if (!is_valid_ie_attr(ieattr)) + return -EINVAL; +- setup->vendor_ie = nla_data(ieattr); +- setup->vendor_ie_len = nla_len(ieattr); ++ setup->ie = nla_data(ieattr); ++ setup->ie_len = nla_len(ieattr); + } ++ setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]); + + return 0; + } +@@ -5785,6 +5821,44 @@ + nlmsg_free(msg); + } + ++void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, ++ struct net_device *netdev, ++ const u8 *macaddr, const u8* ie, u8 ie_len, ++ gfp_t gfp) ++{ ++ struct sk_buff *msg; ++ void *hdr; ++ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); ++ if (!msg) ++ return; ++ ++ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE); ++ if (!hdr) { ++ nlmsg_free(msg); ++ return; ++ } ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr); ++ if (ie_len && ie) ++ NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie); ++ ++ if (genlmsg_end(msg, hdr) < 0) { ++ nlmsg_free(msg); ++ return; ++ } ++ ++ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, ++ nl80211_mlme_mcgrp.id, gfp); ++ return; ++ ++ nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ nlmsg_free(msg); ++} ++ + void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr, + enum nl80211_key_type key_type, int key_id, +@@ -5966,6 +6040,40 @@ + nl80211_mlme_mcgrp.id, gfp); + } + ++void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, ++ struct net_device *dev, const u8 *mac_addr, ++ gfp_t gfp) ++{ ++ struct sk_buff *msg; ++ void *hdr; ++ ++ msg = nlmsg_new(NLMSG_GOODSIZE, gfp); ++ if (!msg) ++ return; ++ ++ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_STATION); ++ if (!hdr) { ++ nlmsg_free(msg); ++ return; ++ } ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); ++ ++ if (genlmsg_end(msg, hdr) < 0) { ++ nlmsg_free(msg); ++ return; ++ } ++ ++ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, ++ nl80211_mlme_mcgrp.id, gfp); ++ return; ++ ++ nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ nlmsg_free(msg); ++} ++ + int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u32 nlpid, + int freq, const u8 *buf, size_t len, gfp_t gfp) +diff -Naur linux-2.6.39-rc6/net/wireless/nl80211.h linux-2.6.39-rc6.rtl8192se/net/wireless/nl80211.h +--- linux-2.6.39-rc6/net/wireless/nl80211.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/wireless/nl80211.h 2011-05-05 23:30:21.713879427 +0200 +@@ -50,6 +50,10 @@ + struct net_device *netdev, u16 reason, + const u8 *ie, size_t ie_len, bool from_ap); + ++void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, ++ struct net_device *netdev, ++ const u8 *macaddr, const u8* ie, u8 ie_len, ++ gfp_t gfp); + void + nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr, +@@ -79,6 +83,9 @@ + void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + struct station_info *sinfo, gfp_t gfp); ++void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, ++ struct net_device *dev, const u8 *mac_addr, ++ gfp_t gfp); + + int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u32 nlpid, int freq, +diff -Naur linux-2.6.39-rc6/net/wireless/reg.c linux-2.6.39-rc6.rtl8192se/net/wireless/reg.c +--- linux-2.6.39-rc6/net/wireless/reg.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.rtl8192se/net/wireless/reg.c 2011-05-05 23:30:21.710879391 +0200 +@@ -106,6 +106,9 @@ + static void reg_todo(struct work_struct *work); + static DECLARE_WORK(reg_work, reg_todo); + ++static void reg_timeout_work(struct work_struct *work); ++static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); ++ + /* We keep a static world regulatory domain in case of the absence of CRDA */ + static const struct ieee80211_regdomain world_regdom = { + .n_reg_rules = 5, +@@ -1330,6 +1333,9 @@ + need_more_processing = true; + spin_unlock(®_requests_lock); + ++ if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) ++ cancel_delayed_work_sync(®_timeout); ++ + if (need_more_processing) + schedule_work(®_work); + } +@@ -1440,8 +1446,18 @@ + r = __regulatory_hint(wiphy, reg_request); + /* This is required so that the orig_* parameters are saved */ + if (r == -EALREADY && wiphy && +- wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) ++ wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { + wiphy_update_regulatory(wiphy, initiator); ++ return; ++ } ++ ++ /* ++ * We only time out user hints, given that they should be the only ++ * source of bogus requests. ++ */ ++ if (r != -EALREADY && ++ reg_request->initiator == NL80211_REGDOM_SET_BY_USER) ++ schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); + } + + /* +@@ -1744,6 +1760,8 @@ + { + char alpha2[2]; + struct reg_beacon *reg_beacon, *btmp; ++ struct regulatory_request *reg_request, *tmp; ++ LIST_HEAD(tmp_reg_req_list); + + mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); +@@ -1751,6 +1769,25 @@ + reset_regdomains(); + restore_alpha2(alpha2, reset_user); + ++ /* ++ * If there's any pending requests we simply ++ * stash them to a temporary pending queue and ++ * add then after we've restored regulatory ++ * settings. ++ */ ++ spin_lock(®_requests_lock); ++ if (!list_empty(®_requests_list)) { ++ list_for_each_entry_safe(reg_request, tmp, ++ ®_requests_list, list) { ++ if (reg_request->initiator != ++ NL80211_REGDOM_SET_BY_USER) ++ continue; ++ list_del(®_request->list); ++ list_add_tail(®_request->list, &tmp_reg_req_list); ++ } ++ } ++ spin_unlock(®_requests_lock); ++ + /* Clear beacon hints */ + spin_lock_bh(®_pending_beacons_lock); + if (!list_empty(®_pending_beacons)) { +@@ -1785,8 +1822,31 @@ + */ + if (is_an_alpha2(alpha2)) + regulatory_hint_user(user_alpha2); +-} + ++ if (list_empty(&tmp_reg_req_list)) ++ return; ++ ++ mutex_lock(&cfg80211_mutex); ++ mutex_lock(®_mutex); ++ ++ spin_lock(®_requests_lock); ++ list_for_each_entry_safe(reg_request, tmp, &tmp_reg_req_list, list) { ++ REG_DBG_PRINT("Adding request for country %c%c back " ++ "into the queue\n", ++ reg_request->alpha2[0], ++ reg_request->alpha2[1]); ++ list_del(®_request->list); ++ list_add_tail(®_request->list, ®_requests_list); ++ } ++ spin_unlock(®_requests_lock); ++ ++ mutex_unlock(®_mutex); ++ mutex_unlock(&cfg80211_mutex); ++ ++ REG_DBG_PRINT("Kicking the queue\n"); ++ ++ schedule_work(®_work); ++} + + void regulatory_hint_disconnect(void) + { +@@ -2125,6 +2185,13 @@ + mutex_unlock(®_mutex); + } + ++static void reg_timeout_work(struct work_struct *work) ++{ ++ REG_DBG_PRINT("Timeout while waiting for CRDA to reply, " ++ "restoring regulatory settings"); ++ restore_regulatory_settings(true); ++} ++ + int __init regulatory_init(void) + { + int err = 0; +@@ -2178,6 +2245,7 @@ + struct reg_beacon *reg_beacon, *btmp; + + cancel_work_sync(®_work); ++ cancel_delayed_work_sync(®_timeout); + + mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); diff --git a/projects/ATV/linux/linux.i386.conf b/projects/ATV/linux/linux.i386.conf index 216470d793..34a2ebce94 100644 --- a/projects/ATV/linux/linux.i386.conf +++ b/projects/ATV/linux/linux.i386.conf @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux/i386 2.6.39-rc5-git4 Kernel Configuration +# Linux/i386 2.6.39-rc6 Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -964,10 +964,10 @@ CONFIG_ATH5K_PCI=y CONFIG_ATH9K_HW=m CONFIG_ATH9K_COMMON=m CONFIG_ATH9K=m +CONFIG_ATH9K_PCI=y +# CONFIG_ATH9K_AHB is not set CONFIG_ATH9K_RATE_CONTROL=y CONFIG_ATH9K_HTC=m -CONFIG_AR9170_USB=m -CONFIG_AR9170_LEDS=y # CONFIG_CARL9170 is not set # CONFIG_B43 is not set # CONFIG_B43LEGACY is not set @@ -997,12 +997,12 @@ CONFIG_RT2800USB=m CONFIG_RT2800_LIB=m CONFIG_RT2X00_LIB_USB=m CONFIG_RT2X00_LIB=m -CONFIG_RT2X00_LIB_HT=y CONFIG_RT2X00_LIB_FIRMWARE=y CONFIG_RT2X00_LIB_CRYPTO=y CONFIG_RT2X00_LIB_LEDS=y # CONFIG_RT2X00_DEBUG is not set # CONFIG_RTL8192CE is not set +# CONFIG_RTL8192SE is not set CONFIG_RTL8192CU=m CONFIG_RTLWIFI=m CONFIG_RTL8192C_COMMON=m @@ -1010,6 +1010,7 @@ CONFIG_RTL8192C_COMMON=m # CONFIG_WL12XX_MENU is not set CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_MWIFIEX is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers diff --git a/projects/ATV/options b/projects/ATV/options index 4f7d65ad4e..6d8d97d5fc 100644 --- a/projects/ATV/options +++ b/projects/ATV/options @@ -121,9 +121,8 @@ # additional drivers to install: # bcm_sta: Broadcom STA WLAN Driver -# rtl8192se: Realtek RTL8192SE WLAN driver # Space separated list is supported, -# e.g. ADDITIONAL_DRIVERS="rtl8192se" +# e.g. ADDITIONAL_DRIVERS="bcm_sta" ADDITIONAL_DRIVERS="bcm_sta" # build with network support (yes / no) diff --git a/projects/Generic/linux/linux.i386.conf b/projects/Generic/linux/linux.i386.conf index 2129f916bc..2cf2b93e6c 100644 --- a/projects/Generic/linux/linux.i386.conf +++ b/projects/Generic/linux/linux.i386.conf @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux/i386 2.6.39-rc5-git4 Kernel Configuration +# Linux/i386 2.6.39-rc6 Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -1070,10 +1070,10 @@ CONFIG_ATH5K_PCI=y CONFIG_ATH9K_HW=m CONFIG_ATH9K_COMMON=m CONFIG_ATH9K=m +CONFIG_ATH9K_PCI=y +# CONFIG_ATH9K_AHB is not set CONFIG_ATH9K_RATE_CONTROL=y CONFIG_ATH9K_HTC=m -CONFIG_AR9170_USB=m -CONFIG_AR9170_LEDS=y # CONFIG_CARL9170 is not set CONFIG_B43=m CONFIG_B43_PCI_AUTOSELECT=y @@ -1149,12 +1149,12 @@ CONFIG_RT2800_LIB=m CONFIG_RT2X00_LIB_PCI=m CONFIG_RT2X00_LIB_USB=m CONFIG_RT2X00_LIB=m -CONFIG_RT2X00_LIB_HT=y CONFIG_RT2X00_LIB_FIRMWARE=y CONFIG_RT2X00_LIB_CRYPTO=y CONFIG_RT2X00_LIB_LEDS=y # CONFIG_RT2X00_DEBUG is not set CONFIG_RTL8192CE=m +CONFIG_RTL8192SE=m CONFIG_RTL8192CU=m CONFIG_RTLWIFI=m CONFIG_RTL8192C_COMMON=m @@ -1162,6 +1162,7 @@ CONFIG_RTL8192C_COMMON=m # CONFIG_WL12XX_MENU is not set CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_MWIFIEX is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers diff --git a/projects/Generic/options b/projects/Generic/options index 0feb0b39ee..f1edc83c92 100644 --- a/projects/Generic/options +++ b/projects/Generic/options @@ -121,10 +121,9 @@ # additional drivers to install: # bcm_sta: Broadcom STA WLAN Driver -# rtl8192se: Realtek RTL8192SE WLAN driver # Space separated list is supported, -# e.g. ADDITIONAL_DRIVERS="rtl8192se" - ADDITIONAL_DRIVERS="rtl8192se" +# e.g. ADDITIONAL_DRIVERS="bcm_sta" + ADDITIONAL_DRIVERS="" # build with network support (yes / no) NETWORK="yes" diff --git a/projects/ION/linux/linux.i386.conf b/projects/ION/linux/linux.i386.conf index 08706af8da..36d78afea0 100644 --- a/projects/ION/linux/linux.i386.conf +++ b/projects/ION/linux/linux.i386.conf @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux/i386 2.6.39-rc5-git4 Kernel Configuration +# Linux/i386 2.6.39-rc6 Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -1025,10 +1025,10 @@ CONFIG_ATH5K_PCI=y CONFIG_ATH9K_HW=m CONFIG_ATH9K_COMMON=m CONFIG_ATH9K=m +CONFIG_ATH9K_PCI=y +# CONFIG_ATH9K_AHB is not set CONFIG_ATH9K_RATE_CONTROL=y CONFIG_ATH9K_HTC=m -CONFIG_AR9170_USB=m -CONFIG_AR9170_LEDS=y # CONFIG_CARL9170 is not set # CONFIG_B43 is not set # CONFIG_B43LEGACY is not set @@ -1063,12 +1063,12 @@ CONFIG_RT2800_LIB=m CONFIG_RT2X00_LIB_PCI=m CONFIG_RT2X00_LIB_USB=m CONFIG_RT2X00_LIB=m -CONFIG_RT2X00_LIB_HT=y CONFIG_RT2X00_LIB_FIRMWARE=y CONFIG_RT2X00_LIB_CRYPTO=y CONFIG_RT2X00_LIB_LEDS=y # CONFIG_RT2X00_DEBUG is not set # CONFIG_RTL8192CE is not set +CONFIG_RTL8192SE=m CONFIG_RTL8192CU=m CONFIG_RTLWIFI=m CONFIG_RTL8192C_COMMON=m @@ -1076,6 +1076,7 @@ CONFIG_RTL8192C_COMMON=m # CONFIG_WL12XX_MENU is not set CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_MWIFIEX is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers diff --git a/projects/ION/linux/linux.x86_64.conf b/projects/ION/linux/linux.x86_64.conf index 0349264129..0d2fc7324c 100644 --- a/projects/ION/linux/linux.x86_64.conf +++ b/projects/ION/linux/linux.x86_64.conf @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux/x86_64 2.6.39-rc5-git4 Kernel Configuration +# Linux/x86_64 2.6.39-rc6 Kernel Configuration # CONFIG_64BIT=y # CONFIG_X86_32 is not set @@ -974,10 +974,10 @@ CONFIG_ATH5K_PCI=y CONFIG_ATH9K_HW=m CONFIG_ATH9K_COMMON=m CONFIG_ATH9K=m +CONFIG_ATH9K_PCI=y +# CONFIG_ATH9K_AHB is not set CONFIG_ATH9K_RATE_CONTROL=y CONFIG_ATH9K_HTC=m -CONFIG_AR9170_USB=m -CONFIG_AR9170_LEDS=y # CONFIG_CARL9170 is not set # CONFIG_B43 is not set # CONFIG_B43LEGACY is not set @@ -1012,12 +1012,12 @@ CONFIG_RT2800_LIB=m CONFIG_RT2X00_LIB_PCI=m CONFIG_RT2X00_LIB_USB=m CONFIG_RT2X00_LIB=m -CONFIG_RT2X00_LIB_HT=y CONFIG_RT2X00_LIB_FIRMWARE=y CONFIG_RT2X00_LIB_CRYPTO=y CONFIG_RT2X00_LIB_LEDS=y # CONFIG_RT2X00_DEBUG is not set # CONFIG_RTL8192CE is not set +CONFIG_RTL8192SE=m CONFIG_RTL8192CU=m CONFIG_RTLWIFI=m CONFIG_RTL8192C_COMMON=m @@ -1025,6 +1025,7 @@ CONFIG_RTL8192C_COMMON=m # CONFIG_WL12XX_MENU is not set CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_MWIFIEX is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers diff --git a/projects/ION/options b/projects/ION/options index 2fa3cac2b6..f9e023deec 100644 --- a/projects/ION/options +++ b/projects/ION/options @@ -121,10 +121,9 @@ # additional drivers to install: # bcm_sta: Broadcom STA WLAN Driver -# rtl8192se: Realtek RTL8192SE WLAN driver # Space separated list is supported, -# e.g. ADDITIONAL_DRIVERS="rtl8192se" - ADDITIONAL_DRIVERS="rtl8192se" +# e.g. ADDITIONAL_DRIVERS="bcm_sta" + ADDITIONAL_DRIVERS="" # build with network support (yes / no) NETWORK="yes" diff --git a/projects/Intel/linux/linux.i386.conf b/projects/Intel/linux/linux.i386.conf index a1629c4fa0..d80a00aa88 100644 --- a/projects/Intel/linux/linux.i386.conf +++ b/projects/Intel/linux/linux.i386.conf @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux/i386 2.6.39-rc5-git4 Kernel Configuration +# Linux/i386 2.6.39-rc6 Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -989,10 +989,10 @@ CONFIG_ATH5K_PCI=y CONFIG_ATH9K_HW=m CONFIG_ATH9K_COMMON=m CONFIG_ATH9K=m +CONFIG_ATH9K_PCI=y +# CONFIG_ATH9K_AHB is not set CONFIG_ATH9K_RATE_CONTROL=y CONFIG_ATH9K_HTC=m -CONFIG_AR9170_USB=m -CONFIG_AR9170_LEDS=y # CONFIG_CARL9170 is not set # CONFIG_B43 is not set # CONFIG_B43LEGACY is not set @@ -1039,12 +1039,12 @@ CONFIG_RT2800_LIB=m CONFIG_RT2X00_LIB_PCI=m CONFIG_RT2X00_LIB_USB=m CONFIG_RT2X00_LIB=m -CONFIG_RT2X00_LIB_HT=y CONFIG_RT2X00_LIB_FIRMWARE=y CONFIG_RT2X00_LIB_CRYPTO=y CONFIG_RT2X00_LIB_LEDS=y # CONFIG_RT2X00_DEBUG is not set # CONFIG_RTL8192CE is not set +CONFIG_RTL8192SE=m CONFIG_RTL8192CU=m CONFIG_RTLWIFI=m CONFIG_RTL8192C_COMMON=m @@ -1052,6 +1052,7 @@ CONFIG_RTL8192C_COMMON=m # CONFIG_WL12XX_MENU is not set CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_MWIFIEX is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers diff --git a/projects/Intel/linux/linux.x86_64.conf b/projects/Intel/linux/linux.x86_64.conf index fa9a93a15f..afcfde08fd 100644 --- a/projects/Intel/linux/linux.x86_64.conf +++ b/projects/Intel/linux/linux.x86_64.conf @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux/x86_64 2.6.39-rc5-git4 Kernel Configuration +# Linux/x86_64 2.6.39-rc6 Kernel Configuration # CONFIG_64BIT=y # CONFIG_X86_32 is not set @@ -939,10 +939,10 @@ CONFIG_ATH5K_PCI=y CONFIG_ATH9K_HW=m CONFIG_ATH9K_COMMON=m CONFIG_ATH9K=m +CONFIG_ATH9K_PCI=y +# CONFIG_ATH9K_AHB is not set CONFIG_ATH9K_RATE_CONTROL=y CONFIG_ATH9K_HTC=m -CONFIG_AR9170_USB=m -CONFIG_AR9170_LEDS=y # CONFIG_CARL9170 is not set # CONFIG_B43 is not set # CONFIG_B43LEGACY is not set @@ -989,12 +989,12 @@ CONFIG_RT2800_LIB=m CONFIG_RT2X00_LIB_PCI=m CONFIG_RT2X00_LIB_USB=m CONFIG_RT2X00_LIB=m -CONFIG_RT2X00_LIB_HT=y CONFIG_RT2X00_LIB_FIRMWARE=y CONFIG_RT2X00_LIB_CRYPTO=y CONFIG_RT2X00_LIB_LEDS=y # CONFIG_RT2X00_DEBUG is not set # CONFIG_RTL8192CE is not set +CONFIG_RTL8192SE=m CONFIG_RTL8192CU=m CONFIG_RTLWIFI=m CONFIG_RTL8192C_COMMON=m @@ -1002,6 +1002,7 @@ CONFIG_RTL8192C_COMMON=m # CONFIG_WL12XX_MENU is not set CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_MWIFIEX is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers diff --git a/projects/Intel/options b/projects/Intel/options index 4d8971b7c5..b62e1b32ba 100644 --- a/projects/Intel/options +++ b/projects/Intel/options @@ -121,10 +121,9 @@ # additional drivers to install: # bcm_sta: Broadcom STA WLAN Driver -# rtl8192se: Realtek RTL8192SE WLAN driver # Space separated list is supported, -# e.g. ADDITIONAL_DRIVERS="rtl8192se" - ADDITIONAL_DRIVERS="rtl8192se" +# e.g. ADDITIONAL_DRIVERS="bcm_sta" + ADDITIONAL_DRIVERS="" # build with network support (yes / no) NETWORK="yes" From 45704d0f41b90b57bb0182cba86e9f315006db09 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sat, 7 May 2011 02:02:40 +0200 Subject: [PATCH 17/31] wpa_supplicant: build agains openssl Signed-off-by: Stephan Raue --- packages/network/wpa_supplicant/build | 4 ++-- packages/network/wpa_supplicant/meta | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/network/wpa_supplicant/build b/packages/network/wpa_supplicant/build index 0606b143ca..c804a252f2 100755 --- a/packages/network/wpa_supplicant/build +++ b/packages/network/wpa_supplicant/build @@ -26,8 +26,8 @@ cd $PKG_BUILD/$1 cp $ROOT/$PKG_DIR/config/makefile.config .config -echo "CONFIG_TLS=gnutls" >> .config -echo "CONFIG_GNUTLS_EXTRA=y" >> .config +# echo "CONFIG_TLS=gnutls" >> .config +# echo "CONFIG_GNUTLS_EXTRA=y" >> .config [ "$DEBUG" = "no" ] && echo "CONFIG_NO_STDOUT_DEBUG=y" >> .config make diff --git a/packages/network/wpa_supplicant/meta b/packages/network/wpa_supplicant/meta index 9e3aad83d3..e7b1850e80 100644 --- a/packages/network/wpa_supplicant/meta +++ b/packages/network/wpa_supplicant/meta @@ -25,8 +25,8 @@ PKG_ARCH="any" PKG_LICENSE="GPL" PKG_SITE="http://hostap.epitest.fi/wpa_supplicant/" PKG_URL="http://hostap.epitest.fi/releases/$PKG_NAME-$PKG_VERSION.tar.gz" -PKG_DEPENDS="dbus libnl gnutls" -PKG_BUILD_DEPENDS="toolchain dbus libnl gnutls" +PKG_DEPENDS="dbus libnl openssl" +PKG_BUILD_DEPENDS="toolchain dbus libnl openssl" PKG_PRIORITY="optional" PKG_SECTION="network" PKG_SHORTDESC="wpa_supplicant: An IEEE 802.11i supplicant implementation" From 1e80376aedeba2bf86801115f54bb33ff78a07ac Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sat, 7 May 2011 02:03:09 +0200 Subject: [PATCH 18/31] openssh: install /etc/moduli too Signed-off-by: Stephan Raue --- packages/network/openssh/install | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/network/openssh/install b/packages/network/openssh/install index ab23340cb3..136e1df10a 100755 --- a/packages/network/openssh/install +++ b/packages/network/openssh/install @@ -27,6 +27,7 @@ add_group sshd 74 mkdir -p $INSTALL/etc cp $PKG_DIR/config/* $INSTALL/etc + cp $PKG_BUILD/moduli $INSTALL/etc mkdir -p $INSTALL/usr/bin cp $PKG_BUILD/scp $INSTALL/usr/bin/ From c2f81e742846e4070808766ac62084a2e54d0667 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sat, 7 May 2011 22:07:47 +0200 Subject: [PATCH 19/31] .gitignore: update .gitignore Signed-off-by: Stephan Raue --- .gitignore | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 0e55a33021..db0a5ca9c1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,17 @@ # build directorys -build.*/ -.fakeroot.* +/build.*/ +/.fakeroot.* # automatically downloaded source files -sources/ -.stamps/ +/sources/ +/.stamps/ # prebuild target binarys to provide -target/ +/target/ # scripts for getting and packing source packages -tools/mkpkg/* -!tools/mkpkg/mkpkg_* +/tools/mkpkg/* +!/tools/mkpkg/mkpkg_* # private working directory -.work/ +/.work/ From 3207d810bd5b211fc8541f9e68c18b7297d2b580 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sat, 7 May 2011 22:08:23 +0200 Subject: [PATCH 20/31] speedcontrol: add missing sources Signed-off-by: Stephan Raue --- .../speedcontrol/sources/speedcontrol.c | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 packages/sysutils/speedcontrol/sources/speedcontrol.c diff --git a/packages/sysutils/speedcontrol/sources/speedcontrol.c b/packages/sysutils/speedcontrol/sources/speedcontrol.c new file mode 100644 index 0000000000..871d5eb514 --- /dev/null +++ b/packages/sysutils/speedcontrol/sources/speedcontrol.c @@ -0,0 +1,136 @@ +/* + * SpeedControl - use SET STREAMING command to set the speed of DVD-drives + * + * + * Copyright (c) 2004 Thomas Fritzsche + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +void dump_sense(unsigned char *cdb, struct request_sense *sense) +{ + int i; + + printf("Command failed: "); + + for (i=0; i<12; i++) + printf("%02x ", cdb[i]); + + if (sense) { + printf(" - sense: %02x.%02x.%02x\n", sense->sense_key, sense->asc, + sense->ascq); + } else { + printf(", no sense\n"); + } +} + +int main(int argc, char *argv[]) +{ + char *device = "/dev/cdrom"; + int c,fd; + int speed = 0; + unsigned long rw_size; + + unsigned char buffer[28]; + + struct cdrom_generic_command cgc; + struct request_sense sense; + extern char * optarg; + + while((c=getopt(argc,argv,"x:"))!=EOF) { + switch(c) { + case 'x': speed = atoi(optarg); break; + default: + printf("Usage: speedcontrol [-x speed] [device]"); + return -1; + } + } + + if (argc > optind) device = argv[optind]; + + fd = open(device, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + printf("Can't open device %s\n", device); + return -1; + } + + + memset(&cgc, 0, sizeof(cgc)); + memset(&sense, 0, sizeof(sense)); + memset(&buffer, 0, sizeof(buffer)); + + /* SET STREAMING command */ + cgc.cmd[0] = 0xb6; + /* 28 byte parameter list length */ + cgc.cmd[10] = 28; + + cgc.sense = &sense; + cgc.buffer = buffer; + cgc.buflen = sizeof(buffer); + cgc.data_direction = CGC_DATA_WRITE; + cgc.quiet = 1; + + if(speed == 0) { +/* set Restore Drive Defaults */ + buffer[0] = 4; + } + + buffer[8] = 0xff; + buffer[9] = 0xff; + buffer[10] = 0xff; + buffer[11] = 0xff; + + rw_size = 177 * speed; + +/* read size */ + buffer[12] = (rw_size >> 24) & 0xff; + buffer[13] = (rw_size >> 16) & 0xff; + buffer[14] = (rw_size >> 8) & 0xff; + buffer[15] = rw_size & 0xff; + +/* read time 1 sec. */ + buffer[18] = 0x03; + buffer[19] = 0xE8; + +/* write size */ + buffer[20] = (rw_size >> 24) & 0xff; + buffer[21] = (rw_size >> 16) & 0xff; + buffer[22] = (rw_size >> 8) & 0xff; + buffer[23] = rw_size & 0xff; + +/* write time 1 sec. */ + buffer[26] = 0x03; + buffer[27] = 0xE8; + + if (ioctl(fd, CDROM_SEND_PACKET, &cgc) != 0) + if (ioctl(fd, CDROM_SELECT_SPEED, speed) != 0) { + dump_sense(cgc.cmd, cgc.sense); + printf("ERROR.\n"); + return -1; + } + printf("OK...\n"); + return 0; +} + From 4aa13f1ff483c3ae210b7bbfabd18b3b9f610963 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 8 May 2011 03:25:04 +0200 Subject: [PATCH 21/31] libgcrypt: add patch so sed will not replace parts of paths Signed-off-by: Stephan Raue --- ....6-01-dont_replace_parts_of_path-0.1.patch | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 packages/security/libgcrypt/patches/libgcrypt-1.4.6-01-dont_replace_parts_of_path-0.1.patch diff --git a/packages/security/libgcrypt/patches/libgcrypt-1.4.6-01-dont_replace_parts_of_path-0.1.patch b/packages/security/libgcrypt/patches/libgcrypt-1.4.6-01-dont_replace_parts_of_path-0.1.patch new file mode 100644 index 0000000000..db465f2f41 --- /dev/null +++ b/packages/security/libgcrypt/patches/libgcrypt-1.4.6-01-dont_replace_parts_of_path-0.1.patch @@ -0,0 +1,24 @@ +diff -Naur libgcrypt-1.4.6/cipher/Makefile.am libgcrypt-1.4.6.patch/cipher/Makefile.am +--- libgcrypt-1.4.6/cipher/Makefile.am 2009-12-11 16:31:38.000000000 +0100 ++++ libgcrypt-1.4.6.patch/cipher/Makefile.am 2011-05-08 03:21:56.463021968 +0200 +@@ -68,7 +68,7 @@ + camellia.c camellia.h camellia-glue.c + + if ENABLE_O_FLAG_MUNGING +-o_flag_munging = sed -e 's/-O[2-9s]*/-O1/g' ++o_flag_munging = sed -e 's/-O[2-9s]/-O1/g' + else + o_flag_munging = cat + endif +diff -Naur libgcrypt-1.4.6/cipher/Makefile.in libgcrypt-1.4.6.patch/cipher/Makefile.in +--- libgcrypt-1.4.6/cipher/Makefile.in 2010-07-13 17:42:20.000000000 +0200 ++++ libgcrypt-1.4.6.patch/cipher/Makefile.in 2011-05-08 03:22:12.059208971 +0200 +@@ -274,7 +274,7 @@ + camellia.c camellia.h camellia-glue.c + + @ENABLE_O_FLAG_MUNGING_FALSE@o_flag_munging = cat +-@ENABLE_O_FLAG_MUNGING_TRUE@o_flag_munging = sed -e 's/-O[2-9s]*/-O1/g' ++@ENABLE_O_FLAG_MUNGING_TRUE@o_flag_munging = sed -e 's/-O[2-9s]/-O1/g' + all: all-am + + .SUFFIXES: From 64c452aa8c541d570eefa9d1eb858b4fec40d2ce Mon Sep 17 00:00:00 2001 From: root Date: Sun, 8 May 2011 01:51:00 -0600 Subject: [PATCH 22/31] adding diskdev_cmds tweaking urls to be http instead ftp adding crosscompile patch for glew installing sftp subsystem --- licenses/APSL.txt | 339 ++ packages/audio/alsa-lib/meta | 2 +- packages/audio/alsa-utils/meta | 2 +- packages/databases/mysql/meta | 4 +- .../mysql-5.1.57-010_crosscompiling.patch | 128 + .../patches/glew-1.6.0-crosscompile.patch | 18 + packages/graphics/glew/patches/test.patch | 20 + packages/network/openssh/install | 3 + packages/sysutils/diskdev_cmds/build | 27 + packages/sysutils/diskdev_cmds/install | 32 + packages/sysutils/diskdev_cmds/meta | 36 + .../patches/diskdev_cmds-332.14-main.patch | 2713 +++++++++++++++++ .../diskdev_cmds-332.14-respect-cflags.patch | 9 + 13 files changed, 3329 insertions(+), 4 deletions(-) create mode 100644 licenses/APSL.txt create mode 100644 packages/databases/mysql/patches/mysql-5.1.57-010_crosscompiling.patch create mode 100644 packages/graphics/glew/patches/glew-1.6.0-crosscompile.patch create mode 100644 packages/graphics/glew/patches/test.patch create mode 100755 packages/sysutils/diskdev_cmds/build create mode 100755 packages/sysutils/diskdev_cmds/install create mode 100644 packages/sysutils/diskdev_cmds/meta create mode 100644 packages/sysutils/diskdev_cmds/patches/diskdev_cmds-332.14-main.patch create mode 100644 packages/sysutils/diskdev_cmds/patches/diskdev_cmds-332.14-respect-cflags.patch diff --git a/licenses/APSL.txt b/licenses/APSL.txt new file mode 100644 index 0000000000..c0400ae765 --- /dev/null +++ b/licenses/APSL.txt @@ -0,0 +1,339 @@ +PPLE PUBLIC SOURCE LICENSE +Version 2.0 - August 6, 2003 + +Please read this License carefully before downloading this software. By +downloading or using this software, you are agreeing to be bound by the terms +of this License. If you do not or cannot agree to the terms of this License, +please do not download or use the software. + +Apple Note: In January 2007, Apple changed its corporate name from "Apple +Computer, Inc." to "Apple Inc." This change has been reflected below and +copyright years updated, but no other changes have been made to the APSL 2.0. + +1. General; Definitions. This License applies to any program or other +work which Apple Inc. ("Apple") makes publicly available and which contains a +notice placed by Apple identifying such program or work as "Original Code" and +stating that it is subject to the terms of this Apple Public Source License +version 2.0 ("License"). As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is the +grantor of rights, (i) claims of patents that are now or hereafter acquired, +owned by or assigned to Apple and (ii) that cover subject matter contained in +the Original Code, but only to the extent necessary to use, reproduce and/or +distribute the Original Code without infringement; and (b) in the case where +You are the grantor of rights, (i) claims of patents that are now or hereafter +acquired, owned by or assigned to You and (ii) that cover subject matter in +Your Modifications, taken alone or in combination with Original Code. + +1.2 "Contributor" means any person or entity that creates or contributes +to the creation of Modifications. + +1.3 "Covered Code" means the Original Code, Modifications, the +combination of Original Code and any Modifications, and/or any respective +portions thereof. + +1.4 "Externally Deploy" means: (a) to sublicense, distribute or otherwise +make Covered Code available, directly or indirectly, to anyone other than You; +and/or (b) to use Covered Code, alone or as part of a Larger Work, in any way +to provide a service, including but not limited to delivery of content, +through electronic communication with a client other than You. + +1.5 "Larger Work" means a work which combines Covered Code or portions +thereof with code not governed by the terms of this License. + +1.6 "Modifications" mean any addition to, deletion from, and/or change to, +the substance and/or structure of the Original Code, any previous +Modifications, the combination of Original Code and any previous +Modifications, and/or any respective portions thereof. When code is released +as a series of files, a Modification is: (a) any addition to or deletion from +the contents of a file containing Covered Code; and/or (b) any new file or +other representation of computer program statements that contains any part of +Covered Code. + +1.7 "Original Code" means (a) the Source Code of a program or other work +as originally made available by Apple under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Apple under this License, and that has been expressly identified by Apple as +such in the header file(s) of such work; and (b) the object code compiled from +such Source Code and originally made available by Apple under this License + +1.8 "Source Code" means the human readable form of a program or other work +that is suitable for making modifications to it, including all modules it +contains, plus any associated interface definition files, scripts used to +control compilation and installation of an executable (object code). + +1.9 "You" or "Your" means an individual or a legal entity exercising +rights under this License. For legal entities, "You" or "Your" includes any +entity which controls, is controlled by, or is under common control with, You, +where "control" means (a) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or otherwise, or +(b) ownership of fifty percent (50%) or more of the outstanding shares or +beneficial ownership of such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and +conditions of this License, Apple hereby grants You, effective on the date You +accept this License and download the Original Code, a world-wide, +royalty-free, non-exclusive license, to the extent of Apple's Applicable +Patent Rights and copyrights covering the Original Code, to do the following: + +2.1 Unmodified Code. You may use, reproduce, display, perform, internally +distribute within Your organization, and Externally Deploy verbatim, +unmodified copies of the Original Code, for commercial or non-commercial +purposes, provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the +copyright and other proprietary notices and disclaimers of Apple as they +appear in the Original Code, and keep intact all notices in the Original Code +that refer to this License; and + +(b) You must include a copy of this License with every copy of Source Code +of Covered Code and documentation You distribute or Externally Deploy, and You +may not offer or impose any terms on such Source Code that alter or restrict +this License or the recipients' rights hereunder, except as permitted under +Section 6. + +2.2 Modified Code. You may modify Covered Code and use, reproduce, +display, perform, internally distribute within Your organization, and +Externally Deploy Your Modifications and Covered Code, for commercial or +non-commercial purposes, provided that in each instance You also meet all of +these conditions: + +(a) You must satisfy all the conditions of Section 2.1 with respect to the +Source Code of the Covered Code; + +(b) You must duplicate, to the extent it does not already exist, the +notice in Exhibit A in each file of the Source Code of all Your Modifications, +and cause the modified files to carry prominent notices stating that You +changed the files and the date of any change; and + +(c) If You Externally Deploy Your Modifications, You must make Source Code +of all Your Externally Deployed Modifications either available to those to +whom You have Externally Deployed Your Modifications, or publicly available. +Source Code of Your Externally Deployed Modifications must be released under +the terms set forth in this License, including the license grants set forth in +Section 3 below, for as long as you Externally Deploy the Covered Code or +twelve (12) months from the date of initial External Deployment, whichever is +longer. You should preferably distribute the Source Code of Your Externally +Deployed Modifications electronically (e.g. download from a web site). + +2.3 Distribution of Executable Versions. In addition, if You Externally +Deploy Covered Code (Original Code and/or Modifications) in object code, +executable form only, You must include a prominent notice, in the code itself +as well as in related documentation, stating that Source Code of the Covered +Code is available under the terms of this License with information on how and +where to obtain such Source Code. + +2.4 Third Party Rights. You expressly acknowledge and agree that although +Apple and each Contributor grants the licenses to their respective portions of +the Covered Code set forth herein, no assurances are provided by Apple or any +Contributor that the Covered Code does not infringe the patent or other +intellectual property rights of any other entity. Apple and each Contributor +disclaim any liability to You for claims brought by any other entity based on +infringement of intellectual property rights or otherwise. As a condition to +exercising the rights and licenses granted hereunder, You hereby assume sole +responsibility to secure any other intellectual property rights needed, if +any. For example, if a third party patent license is required to allow You to +distribute the Covered Code, it is Your responsibility to acquire that license +before distributing the Covered Code. + +3. Your Grants. In consideration of, and as a condition to, the licenses +granted to You under this License, You hereby grant to any person or entity +receiving or distributing Covered Code under this License a non-exclusive, +royalty-free, perpetual, irrevocable license, under Your Applicable Patent +Rights and other intellectual property rights (other than patent) owned or +controlled by You, to use, reproduce, display, perform, modify, sublicense, +distribute and Externally Deploy Your Modifications of the same scope and +extent as Apple's licenses under Sections 2.1 and 2.2 above. + +4. Larger Works. You may create a Larger Work by combining Covered Code +with other code not governed by the terms of this License and distribute the +Larger Work as a single product. In each such instance, You must make sure +the requirements of this License are fulfilled for the Covered Code or any +portion thereof. + +5. Limitations on Patent License. Except as expressly stated in Section +2, no other patent rights, express or implied, are granted by Apple herein. +Modifications and/or Larger Works may require additional patent licenses from +Apple which Apple may grant in its sole discretion. + +6. Additional Terms. You may choose to offer, and to charge a fee for, +warranty, support, indemnity or liability obligations and/or other rights +consistent with the scope of the license granted herein ("Additional Terms") +to one or more recipients of Covered Code. However, You may do so only on Your +own behalf and as Your sole responsibility, and not on behalf of Apple or any +Contributor. You must obtain the recipient's agreement that any such +Additional Terms are offered by You alone, and You hereby agree to indemnify, +defend and hold Apple and every Contributor harmless for any liability +incurred by or claims asserted against Apple or such Contributor by reason of +any such Additional Terms. + +7. Versions of the License. Apple may publish revised and/or new +versions of this License from time to time. Each version will be given a +distinguishing version number. Once Original Code has been published under a +particular version of this License, You may continue to use it under the terms +of that version. You may also choose to use such Original Code under the terms +of any subsequent version of this License published by Apple. No one other +than Apple has the right to modify the terms applicable to Covered Code +created under this License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in +part pre-release, untested, or not fully tested works. The Covered Code may +contain errors that could cause failures or loss of data, and may be +incomplete or contain inaccuracies. You expressly acknowledge and agree that +use of the Covered Code, or any portion thereof, is at Your sole and entire +risk. THE COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR +SUPPORT OF ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED +TO AS "APPLE" FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS +EXPRESSLY DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF +MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, +OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR +ENJOYMENT OF THE COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED +CODE WILL MEET YOUR REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL +BE UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE +CORRECTED. NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You +acknowledge that the Covered Code is not intended for use in the operation of +nuclear facilities, aircraft navigation, communication systems, or air traffic +control machines in which case the failure of the Covered Code could lead to +death, personal injury, or severe physical or environmental damage. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO +EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE +OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, +WHETHER UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), +PRODUCTS LIABILITY OR OTHERWISE, EVEN IF APPLE OR SUCH CONTRIBUTOR HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF +ESSENTIAL PURPOSE OF ANY REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE +LIMITATION OF LIABILITY OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS +LIMITATION MAY NOT APPLY TO YOU. In no event shall Apple's total liability to +You for all damages (other than as may be required by applicable law) under +this License exceed the amount of fifty dollars ($50.00). + +10. Trademarks. This License does not grant any rights to use the +trademarks or trade names "Apple", "Mac", "Mac OS", "QuickTime", "QuickTime +Streaming Server" or any other trademarks, service marks, logos or trade names +belonging to Apple (collectively "Apple Marks") or to any trademark, service +mark, logo or trade name belonging to any Contributor. You agree not to use +any Apple Marks in or as part of the name of products derived from the +Original Code or to endorse or promote products derived from the Original Code +other than as expressly permitted by and in strict compliance at all times +with Apple's third party trademark usage guidelines which are posted at +http://www.apple.com/legal/guidelinesfor3rdparties.html. + +11. Ownership. Subject to the licenses granted under this License, each +Contributor retains all rights, title and interest in and to any Modifications +made by such Contributor. Apple retains all rights, title and interest in and +to the Original Code and any Modifications made by or on behalf of Apple +("Apple Modifications"), and such Apple Modifications will not be +automatically subject to this License. Apple may, at its sole discretion, +choose to license such Apple Modifications under this License, or on different +terms from those contained in this License or may choose not to license them +at all. + +12. Termination. + +12.1 Termination. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Apple if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of +becoming aware of such breach; +(b) immediately in the event of the circumstances described in Section +13.5(b); or +(c) automatically without notice from Apple if You, at any time during the +term of this License, commence an action for patent infringement against +Apple; provided that Apple did not first commence an action for patent +infringement against You in that instance. + +12.2 Effect of Termination. Upon termination, You agree to immediately +stop any further use, reproduction, modification, sublicensing and +distribution of the Covered Code. All sublicenses to the Covered Code which +have been properly granted prior to termination shall survive any termination +of this License. Provisions which, by their nature, should remain in effect +beyond the termination of this License shall survive, including but not +limited to Sections 3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable +to any other for compensation, indemnity or damages of any sort solely as a +result of terminating this License in accordance with its terms, and +termination of this License will be without prejudice to any other right or +remedy of any party. + +13. Miscellaneous. + +13.1 Government End Users. The Covered Code is a "commercial item" as +defined in FAR 2.101. Government software and technical data rights in the +Covered Code include only those rights customarily provided to the public as +defined in this License. This customary commercial license in technical data +and software is provided in accordance with FAR 12.211 (Technical Data) and +12.212 (Computer Software) and, for Department of Defense purchases, DFAR +252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3 (Rights in +Commercial Computer Software or Computer Software Documentation). +Accordingly, all U.S. Government End Users acquire Covered Code with only +those rights set forth herein. + +13.2 Relationship of Parties. This License will not be construed as +creating an agency, partnership, joint venture or any other form of legal +association between or among You, Apple or any Contributor, and You will not +represent to the contrary, whether expressly, by implication, appearance or +otherwise. + +13.3 Independent Development. Nothing in this License will impair Apple's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions +as, or otherwise compete with, Modifications, Larger Works, technology or +products that You may develop, produce, market or distribute. + +13.4 Waiver; Construction. Failure by Apple or any Contributor to enforce +any provision of this License will not be deemed a waiver of future +enforcement of that or any other provision. Any law or regulation which +provides that the language of a contract shall be construed against the +drafter will not apply to this License. + +13.5 Severability. (a) If for any reason a court of competent jurisdiction +finds any provision of this License, or portion thereof, to be unenforceable, +that provision of the License will be enforced to the maximum extent +permissible so as to effect the economic benefits and intent of the parties, +and the remainder of this License will continue in full force and effect. (b) +Notwithstanding the foregoing, if applicable law prohibits or restricts You +from fully and/or specifically complying with Sections 2 and/or 3 or prevents +the enforceability of either of those Sections, this License will immediately +terminate and You must immediately discontinue any use of the Covered Code and +destroy all copies of it that are in your possession or control. + +13.6 Dispute Resolution. Any litigation or other dispute resolution +between You and Apple relating to this License shall take place in the +Northern District of California, and You and Apple hereby consent to the +personal jurisdiction of, and venue in, the state and federal courts within +that District with respect to this License. The application of the United +Nations Convention on Contracts for the International Sale of Goods is +expressly excluded. + +13.7 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +California, except that body of California law concerning conflicts of law. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this +License and all related documents be drafted in English. Les parties ont +exigé que le présent contrat et tous les documents connexes soient rédigés +en anglais. + +EXHIBIT A. + +"Portions Copyright (c) 1999-2007 Apple Inc. All Rights Reserved. + +This file contains Original Code and/or Modifications of Original Code as +defined in and that are subject to the Apple Public Source License Version 2.0 +(the 'License'). You may not use this file except in compliance with the +License. Please obtain a copy of the License at +http://www.opensource.apple.com/apsl/ and read it before using this file. + +The Original Code and all software distributed under the License are +distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS +OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the +specific language governing rights and limitations under the License." diff --git a/packages/audio/alsa-lib/meta b/packages/audio/alsa-lib/meta index e97f0bbba3..64c4264c3e 100644 --- a/packages/audio/alsa-lib/meta +++ b/packages/audio/alsa-lib/meta @@ -24,7 +24,7 @@ PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" PKG_SITE="http://www.alsa-project.org/" -PKG_URL="ftp://ftp.alsa-project.org/pub/lib/$PKG_NAME-$PKG_VERSION.tar.bz2" +PKG_URL="http://dl.ambiweb.de/mirrors/ftp.alsa-project.org/lib/$PKG_NAME-$PKG_VERSION.tar.bz2" PKG_DEPENDS="" PKG_BUILD_DEPENDS="toolchain" PKG_PRIORITY="optional" diff --git a/packages/audio/alsa-utils/meta b/packages/audio/alsa-utils/meta index 421f1ba063..b81c1f125b 100644 --- a/packages/audio/alsa-utils/meta +++ b/packages/audio/alsa-utils/meta @@ -24,7 +24,7 @@ PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" PKG_SITE="http://www.alsa-project.org/" -PKG_URL="ftp://ftp.alsa-project.org/pub/utils/$PKG_NAME-$PKG_VERSION.tar.bz2" +PKG_URL="http://dl.ambiweb.de/mirrors/ftp.alsa-project.org/utils/$PKG_NAME-$PKG_VERSION.tar.bz2" PKG_DEPENDS="alsa-lib" PKG_BUILD_DEPENDS="toolchain alsa-lib" PKG_PRIORITY="optional" diff --git a/packages/databases/mysql/meta b/packages/databases/mysql/meta index c104f63144..b7668d27b9 100644 --- a/packages/databases/mysql/meta +++ b/packages/databases/mysql/meta @@ -19,12 +19,12 @@ ################################################################################ PKG_NAME="mysql" -PKG_VERSION="5.1.55" +PKG_VERSION="5.1.57" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="LGPL" PKG_SITE="http://www.mysql.com" -PKG_URL="ftp://mirror.switch.ch/mirror/$PKG_NAME/Downloads/MySQL-5.1/$PKG_NAME-$PKG_VERSION.tar.gz" +PKG_URL="http://ftp.gwdg.de/pub/misc/$PKG_NAME/Downloads/MySQL-5.1/$PKG_NAME-$PKG_VERSION.tar.gz" PKG_DEPENDS="zlib ncurses" PKG_BUILD_DEPENDS="toolchain zlib ncurses mysql-hosttools" PKG_PRIORITY="optional" diff --git a/packages/databases/mysql/patches/mysql-5.1.57-010_crosscompiling.patch b/packages/databases/mysql/patches/mysql-5.1.57-010_crosscompiling.patch new file mode 100644 index 0000000000..b6c3e068a1 --- /dev/null +++ b/packages/databases/mysql/patches/mysql-5.1.57-010_crosscompiling.patch @@ -0,0 +1,128 @@ +diff -Naur mysql-5.1.38/dbug/Makefile.am mysql-5.1.38.patch/dbug/Makefile.am +--- mysql-5.1.38/dbug/Makefile.am 2009-08-21 14:09:22.000000000 +0200 ++++ mysql-5.1.38.patch/dbug/Makefile.am 2009-09-10 02:57:59.000000000 +0200 +@@ -44,19 +44,19 @@ + -groff -mm user.r > $@ + + output1.r: factorial +- ./factorial 1 2 3 4 5 | cat > $@ ++ mysql-factorial 1 2 3 4 5 | cat > $@ + + output2.r: factorial +- ./factorial -\#t:o 2 3 | cat >$@ ++ mysql-factorial -\#t:o 2 3 | cat >$@ + + output3.r: factorial +- ./factorial -\#d:t:o 3 | cat >$@ ++ mysql-factorial -\#d:t:o 3 | cat >$@ + + output4.r: factorial +- ./factorial -\#d,result:o 4 | cat >$@ ++ mysql-factorial -\#d,result:o 4 | cat >$@ + + output5.r: factorial +- ./factorial -\#d:f,factorial:F:L:o 3 | cat >$@ ++ mysql-factorial -\#d:f,factorial:F:L:o 3 | cat >$@ + .c.r: + @RM@ -f $@ + @SED@ -e 's!\\!\\\\!g' $< > $@ +diff -Naur mysql-5.1.38/dbug/Makefile.in mysql-5.1.38.patch/dbug/Makefile.in +--- mysql-5.1.38/dbug/Makefile.in 2009-08-21 14:17:15.000000000 +0200 ++++ mysql-5.1.38.patch/dbug/Makefile.in 2009-09-10 02:58:14.000000000 +0200 +@@ -746,19 +746,19 @@ + -groff -mm user.r > $@ + + output1.r: factorial +- ./factorial 1 2 3 4 5 | cat > $@ ++ mysql-factorial 1 2 3 4 5 | cat > $@ + + output2.r: factorial +- ./factorial -\#t:o 2 3 | cat >$@ ++ mysql-factorial -\#t:o 2 3 | cat >$@ + + output3.r: factorial +- ./factorial -\#d:t:o 3 | cat >$@ ++ mysql-factorial -\#d:t:o 3 | cat >$@ + + output4.r: factorial +- ./factorial -\#d,result:o 4 | cat >$@ ++ mysql-factorial -\#d,result:o 4 | cat >$@ + + output5.r: factorial +- ./factorial -\#d:f,factorial:F:L:o 3 | cat >$@ ++ mysql-factorial -\#d:f,factorial:F:L:o 3 | cat >$@ + .c.r: + @RM@ -f $@ + @SED@ -e 's!\\!\\\\!g' $< > $@ +diff -Naur mysql-5.1.38/extra/Makefile.am mysql-5.1.38.patch/extra/Makefile.am +--- mysql-5.1.38/extra/Makefile.am 2009-08-21 14:09:23.000000000 +0200 ++++ mysql-5.1.38.patch/extra/Makefile.am 2009-09-10 02:53:50.000000000 +0200 +@@ -32,7 +32,7 @@ + $(top_builddir)/include/mysqld_error.h: comp_err.c \ + $(top_srcdir)/sql/share/errmsg.txt + $(MAKE) $(AM_MAKEFLAGS) comp_err$(EXEEXT) +- $(top_builddir)/extra/comp_err$(EXEEXT) \ ++ mysql-comp_err$(EXEEXT) \ + --charset=$(top_srcdir)/sql/share/charsets \ + --out-dir=$(top_builddir)/sql/share/ \ + --header_file=$(top_builddir)/include/mysqld_error.h \ +diff -Naur mysql-5.1.38/extra/Makefile.in mysql-5.1.38.patch/extra/Makefile.in +--- mysql-5.1.38/extra/Makefile.in 2009-08-21 14:17:16.000000000 +0200 ++++ mysql-5.1.38.patch/extra/Makefile.in 2009-09-10 02:53:16.000000000 +0200 +@@ -936,7 +936,7 @@ + $(top_builddir)/include/mysqld_error.h: comp_err.c \ + $(top_srcdir)/sql/share/errmsg.txt + $(MAKE) $(AM_MAKEFLAGS) comp_err$(EXEEXT) +- $(top_builddir)/extra/comp_err$(EXEEXT) \ ++ mysql-comp_err$(EXEEXT) \ + --charset=$(top_srcdir)/sql/share/charsets \ + --out-dir=$(top_builddir)/sql/share/ \ + --header_file=$(top_builddir)/include/mysqld_error.h \ +diff -Naur mysql-5.1.38/scripts/Makefile.am mysql-5.1.38.patch/scripts/Makefile.am +--- mysql-5.1.38/scripts/Makefile.am 2009-08-21 14:11:26.000000000 +0200 ++++ mysql-5.1.38.patch/scripts/Makefile.am 2009-09-10 02:57:01.000000000 +0200 +@@ -121,7 +121,7 @@ + mysql_fix_privilege_tables_sql.c: comp_sql.c mysql_fix_privilege_tables.sql + $(MAKE) $(AM_MAKEFLAGS) comp_sql$(EXEEXT) + sleep 2 +- $(top_builddir)/scripts/comp_sql$(EXEEXT) \ ++ mysql-comp_sql$(EXEEXT) \ + mysql_fix_privilege_tables \ + $(top_srcdir)/scripts/mysql_fix_privilege_tables.sql $@ + +diff -Naur mysql-5.1.38/scripts/Makefile.in mysql-5.1.38.patch/scripts/Makefile.in +--- mysql-5.1.38/scripts/Makefile.in 2009-08-21 14:17:23.000000000 +0200 ++++ mysql-5.1.38.patch/scripts/Makefile.in 2009-09-10 02:57:11.000000000 +0200 +@@ -802,7 +802,7 @@ + mysql_fix_privilege_tables_sql.c: comp_sql.c mysql_fix_privilege_tables.sql + $(MAKE) $(AM_MAKEFLAGS) comp_sql$(EXEEXT) + sleep 2 +- $(top_builddir)/scripts/comp_sql$(EXEEXT) \ ++ mysql-comp_sql$(EXEEXT) \ + mysql_fix_privilege_tables \ + $(top_srcdir)/scripts/mysql_fix_privilege_tables.sql $@ + +diff -Naur mysql-5.1.38/sql/Makefile.am mysql-5.1.38.patch/sql/Makefile.am +--- mysql-5.1.38/sql/Makefile.am 2009-08-21 14:12:24.000000000 +0200 ++++ mysql-5.1.38.patch/sql/Makefile.am 2009-09-10 02:55:09.000000000 +0200 +@@ -174,7 +174,7 @@ + # this avoid the rebuild of the built files in a source dist + lex_hash.h: gen_lex_hash.cc lex.h + $(MAKE) $(AM_MAKEFLAGS) gen_lex_hash$(EXEEXT) +- ./gen_lex_hash$(EXEEXT) > $@-t ++ mysql-gen_lex_hash$(EXEEXT) > $@-t + $(MV) $@-t $@ + + # For testing of udf_example.so +diff -Naur mysql-5.1.38/sql/Makefile.in mysql-5.1.38.patch/sql/Makefile.in +--- mysql-5.1.38/sql/Makefile.in 2009-08-21 14:17:25.000000000 +0200 ++++ mysql-5.1.38.patch/sql/Makefile.in 2009-09-10 02:55:22.000000000 +0200 +@@ -1302,7 +1302,7 @@ + # this avoid the rebuild of the built files in a source dist + lex_hash.h: gen_lex_hash.cc lex.h + $(MAKE) $(AM_MAKEFLAGS) gen_lex_hash$(EXEEXT) +- ./gen_lex_hash$(EXEEXT) > $@-t ++ mysql-gen_lex_hash$(EXEEXT) > $@-t + $(MV) $@-t $@ + + # We might have some stuff not built in this build, but that we want to install diff --git a/packages/graphics/glew/patches/glew-1.6.0-crosscompile.patch b/packages/graphics/glew/patches/glew-1.6.0-crosscompile.patch new file mode 100644 index 0000000000..622db8f4cb --- /dev/null +++ b/packages/graphics/glew/patches/glew-1.6.0-crosscompile.patch @@ -0,0 +1,18 @@ +--- glew-1.6.0/config/Makefile.linux.orig 2011-05-07 12:17:35.143944898 -0600 ++++ glew-1.6.0/config/Makefile.linux 2011-05-07 12:17:59.207718777 -0600 +@@ -1,15 +1,7 @@ + NAME = $(GLEW_NAME) +-CC = cc +-LD = cc + PICFLAG = -fPIC + M_ARCH ?= $(shell uname -m) +-ifeq (x86_64,${M_ARCH}) +-LDFLAGS.EXTRA = -L/usr/X11R6/lib64 +-LIBDIR = $(GLEW_DEST)/lib64 +-else +-LDFLAGS.EXTRA = -L/usr/X11R6/lib + LIBDIR = $(GLEW_DEST)/lib +-endif + LDFLAGS.GL = -lXmu -lXi -lGLU -lGL -lXext -lX11 + LDFLAGS.STATIC = -Wl,-Bstatic + LDFLAGS.DYNAMIC = -Wl,-Bdynamic diff --git a/packages/graphics/glew/patches/test.patch b/packages/graphics/glew/patches/test.patch new file mode 100644 index 0000000000..a064d19f42 --- /dev/null +++ b/packages/graphics/glew/patches/test.patch @@ -0,0 +1,20 @@ +--- glew-1.6.0/config/Makefile.linux.orig 2011-05-07 12:08:25.427908940 -0600 ++++ glew-1.6.0/config/Makefile.linux 2011-05-07 12:08:50.345126195 -0600 +@@ -1,15 +1,9 @@ + NAME = $(GLEW_NAME) +-CC = cc +-LD = cc ++CC = $(CC) ++LD = $(CC) + PICFLAG = -fPIC + M_ARCH ?= $(shell uname -m) +-ifeq (x86_64,${M_ARCH}) +-LDFLAGS.EXTRA = -L/usr/X11R6/lib64 +-LIBDIR = $(GLEW_DEST)/lib64 +-else +-LDFLAGS.EXTRA = -L/usr/X11R6/lib + LIBDIR = $(GLEW_DEST)/lib +-endif + LDFLAGS.GL = -lXmu -lXi -lGLU -lGL -lXext -lX11 + LDFLAGS.STATIC = -Wl,-Bstatic + LDFLAGS.DYNAMIC = -Wl,-Bdynamic diff --git a/packages/network/openssh/install b/packages/network/openssh/install index 136e1df10a..31437bb4c9 100755 --- a/packages/network/openssh/install +++ b/packages/network/openssh/install @@ -38,3 +38,6 @@ mkdir -p $INSTALL/usr/bin mkdir -p $INSTALL/usr/sbin cp $PKG_BUILD/sshd $INSTALL/usr/sbin/ + +mkdir -p $INSTALL/usr/libexec + cp $PKG_BUILD/sftp-server $INSTALL/usr/libexec diff --git a/packages/sysutils/diskdev_cmds/build b/packages/sysutils/diskdev_cmds/build new file mode 100755 index 0000000000..014322f721 --- /dev/null +++ b/packages/sysutils/diskdev_cmds/build @@ -0,0 +1,27 @@ +#!/bin/sh + +################################################################################ +# This file is part of OpenELEC - http://www.openelec.tv +# Copyright (C) 2009-2011 Stephan Raue (stephan@openelec.tv) +# +# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +################################################################################ + +. config/options $1 + +cd $PKG_BUILD + +make -f Makefile.lnx CC=$CC diff --git a/packages/sysutils/diskdev_cmds/install b/packages/sysutils/diskdev_cmds/install new file mode 100755 index 0000000000..e21a54406d --- /dev/null +++ b/packages/sysutils/diskdev_cmds/install @@ -0,0 +1,32 @@ +#!/bin/sh + +################################################################################ +# This file is part of OpenELEC - http://www.openelec.tv +# Copyright (C) 2009-2011 Stephan Raue (stephan@openelec.tv) +# +# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +################################################################################ + +. config/options $1 + +mkdir -p $INSTALL/usr/sbin + cp $PKG_BUILD/fsck_hfs.tproj/fsck_hfs $INSTALL/usr/sbin + ln -sf fsck_hfs $INSTALL/usr/sbin/fsck.hfs + ln -sf fsck_hfs $INSTALL/usr/sbin/fsck.hfsplus + + cp $PKG_BUILD/newfs_hfs.tproj/newfs_hfs $INSTALL/usr/sbin + ln -sf newfs_hfs $INSTALL/usr/sbin/mkfs.hfs + ln -sf newfs_hfs $INSTALL/usr/sbin/mkfs.hfsplus diff --git a/packages/sysutils/diskdev_cmds/meta b/packages/sysutils/diskdev_cmds/meta new file mode 100644 index 0000000000..18d4e8e28f --- /dev/null +++ b/packages/sysutils/diskdev_cmds/meta @@ -0,0 +1,36 @@ +################################################################################ +# This file is part of OpenELEC - http://www.openelec.tv +# Copyright (C) 2009-2011 Stephan Raue (stephan@openelec.tv) +# +# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +################################################################################ + +PKG_NAME="diskdev_cmds" +PKG_VERSION="332.14" +PKG_REV="1" +PKG_ARCH="any" +PKG_LICENSE="APSL" +PKG_SITE="http://src.gnu-darwin.org/DarwinSourceArchive/expanded/diskdev_cmds/" +PKG_URL="http://src.gnu-darwin.org/DarwinSourceArchive/apsl/$PKG_NAME-$PKG_VERSION.tar.gz" +PKG_DEPENDS="" +PKG_BUILD_DEPENDS="toolchain" +PKG_PRIORITY="optional" +PKG_SECTION="system" +PKG_SHORTDESC="diskdev_cmds: hfs filesystem utilities" +PKG_LONGDESC="The fsck and mkfs utliities for hfs and hfsplus filesystems." +PKG_IS_ADDON="no" + +PKG_AUTORECONF="no" diff --git a/packages/sysutils/diskdev_cmds/patches/diskdev_cmds-332.14-main.patch b/packages/sysutils/diskdev_cmds/patches/diskdev_cmds-332.14-main.patch new file mode 100644 index 0000000000..8e64851021 --- /dev/null +++ b/packages/sysutils/diskdev_cmds/patches/diskdev_cmds-332.14-main.patch @@ -0,0 +1,2713 @@ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/cache.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/cache.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/cache.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/cache.c 2008-07-01 22:30:11.000000000 +0200 +@@ -26,7 +26,11 @@ + #include + #include + #include ++#if LINUX ++#include "missing.h" ++#else + #include ++#endif /* __LINUX__ */ + #include + #include + #include +Files diskdev_cmds-332.14/fsck_hfs.tproj/cache.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/cache.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BlockCache.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BlockCache.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BlockCache.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BlockCache.c 2008-07-01 22:30:11.000000000 +0200 +@@ -20,6 +20,9 @@ + * @APPLE_LICENSE_HEADER_END@ + */ + ++#if LINUX ++#include "missing.h" ++#endif + #include "SRuntime.h" + #include "Scavenger.h" + #include "../cache.h" +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BlockCache.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BlockCache.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BTreeAllocate.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BTreeAllocate.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BTree.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BTree.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BTree.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BTree.c 2008-07-01 22:30:11.000000000 +0200 +@@ -1705,7 +1705,9 @@ + UInt16 version, + BTreeInfoRec *info ) + { ++#if !LINUX + #pragma unused (version) ++#endif + + BTreeControlBlockPtr btreePtr; + +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BTreeMiscOps.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BTreeMiscOps.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BTreeNodeOps.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BTreeNodeOps.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BTree.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BTree.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BTreeScanner.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BTreeScanner.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BTreeTreeOps.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BTreeTreeOps.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BTreeTreeOps.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BTreeTreeOps.c 2008-07-01 22:30:11.000000000 +0200 +@@ -223,7 +223,7 @@ + // + if (curNodeNum == 0) + { +-// Panic("\pSearchTree: curNodeNum is zero!"); ++ Panic("SearchTree: curNodeNum is zero!"); + err = fsBTInvalidNodeErr; + goto ErrorExit; + } +@@ -433,7 +433,7 @@ + M_ExitOnError (err); + + if ( DEBUG_BUILD && updateParent && newRoot ) +- DebugStr("\p InsertLevel: New root from primary key, update from secondary key..."); ++ DebugStr("InsertLevel: New root from primary key, update from secondary key..."); + } + + //////////////////////// Update Parent(s) /////////////////////////////// +@@ -448,7 +448,7 @@ + + secondaryKey = nil; + +- PanicIf ( (level == btreePtr->treeDepth), "\p InsertLevel: unfinished insert!?"); ++ PanicIf ( (level == btreePtr->treeDepth), "InsertLevel: unfinished insert!?"); + + ++level; + +@@ -456,7 +456,7 @@ + index = treePathTable [level].index; + parentNodeNum = treePathTable [level].node; + +- PanicIf ( parentNodeNum == 0, "\p InsertLevel: parent node is zero!?"); ++ PanicIf ( parentNodeNum == 0, "InsertLevel: parent node is zero!?"); + + err = GetNode (btreePtr, parentNodeNum, &parentNode); // released as target node in next level up + M_ExitOnError (err); +@@ -470,7 +470,7 @@ + { + //¥¥Êdebug: check if ptr == targetNodeNum + GetRecordByIndex (btreePtr, parentNode.buffer, index, &keyPtr, &recPtr, &recSize); +- PanicIf( (*(UInt32 *) recPtr) != targetNodeNum, "\p InsertLevel: parent ptr doesn't match target node!"); ++ PanicIf( (*(UInt32 *) recPtr) != targetNodeNum, "InsertLevel: parent ptr doesn't match target node!"); + + // need to delete and re-insert this parent key/ptr + // we delete it here and it gets re-inserted in the +@@ -532,7 +532,7 @@ + (void) ReleaseNode (btreePtr, targetNode); + (void) ReleaseNode (btreePtr, &siblingNode); + +- Panic ("\p InsertLevel: an error occured!"); ++ Panic ("InsertLevel: an error occured!"); + + return err; + +@@ -566,7 +566,7 @@ + + *rootSplit = false; + +- PanicIf ( targetNode->buffer == siblingNode->buffer, "\p InsertNode: targetNode == siblingNode, huh?"); ++ PanicIf ( targetNode->buffer == siblingNode->buffer, "InsertNode: targetNode == siblingNode, huh?"); + + leftNodeNum = ((NodeDescPtr) targetNode->buffer)->bLink; + rightNodeNum = ((NodeDescPtr) targetNode->buffer)->fLink; +@@ -606,7 +606,7 @@ + + if ( leftNodeNum > 0 ) + { +- PanicIf ( siblingNode->buffer != nil, "\p InsertNode: siblingNode already aquired!"); ++ PanicIf ( siblingNode->buffer != nil, "InsertNode: siblingNode already aquired!"); + + if ( siblingNode->buffer == nil ) + { +@@ -614,7 +614,7 @@ + M_ExitOnError (err); + } + +- PanicIf ( ((NodeDescPtr) siblingNode->buffer)->fLink != nodeNum, "\p InsertNode, RotateLeft: invalid sibling link!" ); ++ PanicIf ( ((NodeDescPtr) siblingNode->buffer)->fLink != nodeNum, "InsertNode, RotateLeft: invalid sibling link!" ); + + if ( !key->skipRotate ) // are rotates allowed? + { +@@ -703,7 +703,7 @@ + + targetNodeNum = treePathTable[level].node; + targetNodePtr = targetNode->buffer; +- PanicIf (targetNodePtr == nil, "\pDeleteTree: targetNode has nil buffer!"); ++ PanicIf (targetNodePtr == nil, "DeleteTree: targetNode has nil buffer!"); + + DeleteRecord (btreePtr, targetNodePtr, index); + +@@ -797,7 +797,7 @@ + + //¥¥Êdebug: check if ptr == targetNodeNum + GetRecordByIndex (btreePtr, parentNode.buffer, index, &keyPtr, &recPtr, &recSize); +- PanicIf( (*(UInt32 *) recPtr) != targetNodeNum, "\p DeleteTree: parent ptr doesn't match targetNodeNum!!"); ++ PanicIf( (*(UInt32 *) recPtr) != targetNodeNum, " DeleteTree: parent ptr doesn't match targetNodeNum!!"); + + // need to delete and re-insert this parent key/ptr + DeleteRecord (btreePtr, parentNode.buffer, index); +@@ -1018,7 +1018,7 @@ + keyPtr, keyLength, recPtr, recSize); + if ( !didItFit ) + { +- Panic ("\pRotateLeft: InsertKeyRecord (left) returned false!"); ++ Panic ("RotateLeft: InsertKeyRecord (left) returned false!"); + err = fsBTBadRotateErr; + goto ErrorExit; + } +@@ -1031,7 +1031,7 @@ + didItFit = RotateRecordLeft (btreePtr, leftNode, rightNode); + if ( !didItFit ) + { +- Panic ("\pRotateLeft: RotateRecordLeft returned false!"); ++ Panic ("RotateLeft: RotateRecordLeft returned false!"); + err = fsBTBadRotateErr; + goto ErrorExit; + } +@@ -1048,7 +1048,7 @@ + keyPtr, keyLength, recPtr, recSize); + if ( !didItFit ) + { +- Panic ("\pRotateLeft: InsertKeyRecord (right) returned false!"); ++ Panic ("RotateLeft: InsertKeyRecord (right) returned false!"); + err = fsBTBadRotateErr; + goto ErrorExit; + } +@@ -1117,7 +1117,7 @@ + right = rightNode->buffer; + left = leftNode->buffer; + +- PanicIf ( right->bLink != 0 && left == 0, "\p SplitLeft: left sibling missing!?" ); ++ PanicIf ( right->bLink != 0 && left == 0, " SplitLeft: left sibling missing!?" ); + + //¥¥ type should be kLeafNode or kIndexNode + +@@ -1240,8 +1240,8 @@ + Boolean didItFit; + UInt16 keyLength; + +- PanicIf (leftNode == nil, "\pAddNewRootNode: leftNode == nil"); +- PanicIf (rightNode == nil, "\pAddNewRootNode: rightNode == nil"); ++ PanicIf (leftNode == nil, "AddNewRootNode: leftNode == nil"); ++ PanicIf (rightNode == nil, "AddNewRootNode: rightNode == nil"); + + + /////////////////////// Initialize New Root Node //////////////////////////// +@@ -1264,7 +1264,7 @@ + didItFit = InsertKeyRecord ( btreePtr, rootNode.buffer, 0, keyPtr, keyLength, + (UInt8 *) &rightNode->bLink, 4 ); + +- PanicIf ( !didItFit, "\pAddNewRootNode:InsertKeyRecord failed for left index record"); ++ PanicIf ( !didItFit, "AddNewRootNode:InsertKeyRecord failed for left index record"); + + + //////////////////// Insert Right Node Index Record ///////////////////////// +@@ -1275,7 +1275,7 @@ + didItFit = InsertKeyRecord ( btreePtr, rootNode.buffer, 1, keyPtr, keyLength, + (UInt8 *) &leftNode->fLink, 4 ); + +- PanicIf ( !didItFit, "\pAddNewRootNode:InsertKeyRecord failed for right index record"); ++ PanicIf ( !didItFit, "AddNewRootNode:InsertKeyRecord failed for right index record"); + + + #if DEBUG_TREEOPS +@@ -1355,7 +1355,7 @@ + } + rightPtr = rightNodePtr->buffer; + +- PanicIf ( leftPtr->fLink != 0 && rightPtr == 0, "\p SplitRight: right sibling missing!?" ); ++ PanicIf ( leftPtr->fLink != 0 && rightPtr == 0, "SplitRight: right sibling missing!?" ); + + //¥¥ type should be kLeafNode or kIndexNode + +@@ -1557,7 +1557,7 @@ + keyPtr, keyLength, recPtr, recSize); + if ( !didItFit ) + { +- Panic ("\pRotateRight: InsertKeyRecord (left) returned false!"); ++ Panic ("RotateRight: InsertKeyRecord (left) returned false!"); + err = fsBTBadRotateErr; + goto ErrorExit; + } +@@ -1572,7 +1572,7 @@ + didItFit = RotateRecordRight( btreePtr, leftNodePtr, rightNodePtr ); + if ( !didItFit ) + { +- Panic ("\pRotateRight: RotateRecordRight returned false!"); ++ Panic ("RotateRight: RotateRecordRight returned false!"); + err = fsBTBadRotateErr; + goto ErrorExit; + } +@@ -1583,7 +1583,7 @@ + keyPtr, keyLength, recPtr, recSize); + if ( !didItFit ) + { +- Panic ("\pRotateRight: InsertKeyRecord (left) returned false!"); ++ Panic ("RotateRight: InsertKeyRecord (left) returned false!"); + err = fsBTBadRotateErr; + goto ErrorExit; + } +@@ -1607,7 +1607,7 @@ + keyPtr, keyLength, recPtr, recSize); + if ( !didItFit ) + { +- Panic ("\pRotateRight: InsertKeyRecord (right) returned false!"); ++ Panic ("RotateRight: InsertKeyRecord (right) returned false!"); + err = fsBTBadRotateErr; + goto ErrorExit; + } +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/BTreeTreeOps.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/BTreeTreeOps.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/CatalogCheck.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/CatalogCheck.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/HardLinkCheck.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/HardLinkCheck.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/hfs_endian.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/hfs_endian.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/hfs_endian.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/hfs_endian.c 2008-07-02 00:10:48.000000000 +0200 +@@ -31,7 +31,11 @@ + #include + #include + ++#if LINUX ++#include "missing.h" ++#else + #include ++#endif + #include + + #include "Scavenger.h" +@@ -194,7 +198,7 @@ + BTNodeDescriptor *srcDesc = src->buffer; + BTreeControlBlockPtr btcb = fcb->fcbBtree; + UInt16 *srcOffs = NULL; +- UInt32 i; ++ int i; + int error = 0; + + // WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum); +@@ -433,7 +437,7 @@ + BTNodeDescriptor *srcDesc = src->buffer; + UInt16 *srcOffs = (UInt16 *)((char *)src->buffer + (src->blockSize - (srcDesc->numRecords * sizeof (UInt16)))); + char *nextRecord; /* Points to start of record following current one */ +- UInt32 i; ++ int i; + UInt32 j; + + if (fileID == kHFSExtentsFileID) { +@@ -559,7 +563,7 @@ + /* Make sure name length is consistent with key length */ + if (keyLength < sizeof(srcKey->parentID) + sizeof(srcKey->nodeName.length) + + srcKey->nodeName.length*sizeof(srcKey->nodeName.unicode[0])) { +- if (debug) printf("hfs_swap_HFSPlusBTInternalNode: catalog record #%d keyLength=%d expected=%lu\n", ++ if (debug) printf("hfs_swap_HFSPlusBTInternalNode: catalog record #%d keyLength=%d expected=%i\n", + srcDesc->numRecords-i, keyLength, sizeof(srcKey->parentID) + sizeof(srcKey->nodeName.length) + + srcKey->nodeName.length*sizeof(srcKey->nodeName.unicode[0])); + WriteError(fcb->fcbVolume->vcbGPtr, E_KeyLen, fcb->fcbFileID, src->blockNum); +@@ -854,7 +858,7 @@ + UInt16 *srcOffs = (UInt16 *)((char *)src->buffer + (src->blockSize - (srcDesc->numRecords * sizeof (UInt16)))); + char *nextRecord; /* Points to start of record following current one */ + +- UInt32 i; ++ int i; + UInt32 j; + + if (fileID == kHFSExtentsFileID) { +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/hfs_endian.h diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/hfs_endian.h +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/hfs_endian.h 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/hfs_endian.h 2008-07-01 22:30:11.000000000 +0200 +@@ -27,9 +27,14 @@ + * + * This file prototypes endian swapping routines for the HFS/HFS Plus + * volume format. +- */ ++*/ + #include ++#if LINUX ++#include ++#include ++#else + #include ++#endif + #include "SRuntime.h" + + /*********************/ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/hfs_endian.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/hfs_endian.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/libdfa.a and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/libdfa.a differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/Makefile.lnx diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/Makefile.lnx +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/Makefile.lnx 1970-01-01 01:00:00.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/Makefile.lnx 2008-07-01 22:30:11.000000000 +0200 +@@ -0,0 +1,15 @@ ++CFILES = hfs_endian.c BlockCache.c\ ++ BTree.c BTreeAllocate.c BTreeMiscOps.c \ ++ BTreeNodeOps.c BTreeScanner.c BTreeTreeOps.c\ ++ CatalogCheck.c HardLinkCheck.c\ ++ SBTree.c SControl.c SVerify1.c SVerify2.c\ ++ SRepair.c SRebuildCatalogBTree.c\ ++ SUtils.c SKeyCompare.c SDevice.c SExtents.c SAllocate.c\ ++ SCatalog.c SStubs.c VolumeBitmapCheck.c ++OFILES = $(CFILES:.c=.o) ++ ++libdfa.a: $(OFILES) ++ ar rc $@ $? ++ ++clean: ++ $(RM) $(OFILES) libdfa.a +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SAllocate.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SAllocate.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SBTree.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SBTree.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SBTree.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SBTree.c 2008-07-01 22:30:11.000000000 +0200 +@@ -93,7 +93,7 @@ + CopyMemory(&resultIterator->key, foundKey, CalcKeySize(btcb, &resultIterator->key)); //¥¥ warning, this could overflow user's buffer!!! + + if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, *dataSize) ) +- DebugStr("\pSearchBTreeRecord: bad record?"); ++ DebugStr("SearchBTreeRecord: bad record?"); + } + + ErrorExit: +@@ -190,7 +190,7 @@ + CopyMemory(&iterator->key, key, CalcKeySize(btcb, &iterator->key)); //¥¥ warning, this could overflow user's buffer!!! + + if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, *dataSize) ) +- DebugStr("\pGetBTreeRecord: bad record?"); ++ DebugStr("GetBTreeRecord: bad record?"); + + } + +@@ -222,7 +222,7 @@ + CopyMemory(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //¥¥ should we range check against maxkeylen? + + if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, dataSize) ) +- DebugStr("\pInsertBTreeRecord: bad record?"); ++ DebugStr("InsertBTreeRecord: bad record?"); + + result = BTInsertRecord( fcb, &iterator, &btRecord, dataSize ); + +@@ -284,7 +284,7 @@ + CopyMemory(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //¥¥ should we range check against maxkeylen? + + if ( DEBUG_BUILD && !ValidHFSRecord(newData, btcb, dataSize) ) +- DebugStr("\pReplaceBTreeRecord: bad record?"); ++ DebugStr("ReplaceBTreeRecord: bad record?"); + + result = BTReplaceRecord( fcb, &iterator, &btRecord, dataSize ); + +@@ -301,7 +301,9 @@ + OSStatus + SetEndOfForkProc ( SFCB *filePtr, FSSize minEOF, FSSize maxEOF ) + { ++#if !LINUX + #pragma unused (maxEOF) ++#endif + + OSStatus result; + UInt32 actualSectorsAdded; +@@ -321,7 +323,7 @@ + else + { + if ( DEBUG_BUILD ) +- DebugStr("\pSetEndOfForkProc: minEOF is smaller than current size!"); ++ DebugStr("SetEndOfForkProc: minEOF is smaller than current size!"); + return -1; + } + +@@ -347,7 +349,7 @@ + // Make sure we got at least as much space as we needed + // + if (filePtr->fcbLogicalSize < minEOF) { +- Panic("\pSetEndOfForkProc: disk too full to extend B-tree file"); ++ Panic("SetEndOfForkProc: disk too full to extend B-tree file"); + return dskFulErr; + } + +@@ -419,7 +421,7 @@ + if ( (keyLen < 6) || (keyLen > btcb->maxKeyLength) ) + { + if ( DEBUG_BUILD ) +- DebugStr("\pCheckBTreeKey: bad key length!"); ++ DebugStr("CheckBTreeKey: bad key length!"); + return fsBTInvalidKeyLengthErr; + } + +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SBTree.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SBTree.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SCatalog.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SCatalog.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/Scavenger.h diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/Scavenger.h +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/Scavenger.h 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/Scavenger.h 2008-07-01 22:30:11.000000000 +0200 +@@ -35,11 +35,16 @@ + #include "BTreeScanner.h" + #include "hfs_endian.h" + ++#if LINUX ++#define XATTR_MAXNAMELEN 127 ++#include ++#else + #include + #include + #include +-#include + #include ++#endif ++#include + + #ifdef __cplusplus + extern "C" { +@@ -1434,4 +1439,8 @@ + }; + #endif + ++#if LINUX ++#undef XATTR_MAXNAMELEN ++#endif ++ + #endif /* __SCAVENGER__ */ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SControl.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SControl.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SControl.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SControl.c 2008-07-01 22:30:11.000000000 +0200 +@@ -739,7 +739,7 @@ + pointer = (ScavStaticStructures *) AllocateClearMemory( sizeof(ScavStaticStructures) ); + if ( pointer == nil ) { + if ( GPtr->logLevel >= kDebugLog ) { +- printf( "\t error %d - could not allocate %ld bytes of memory \n", ++ printf( "\t error %d - could not allocate %i bytes of memory \n", + R_NoMem, sizeof(ScavStaticStructures) ); + } + return( R_NoMem ); +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SControl.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SControl.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SDevice.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SDevice.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SDevice.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SDevice.c 2008-07-01 22:30:11.000000000 +0200 +@@ -28,24 +28,61 @@ + #include + #include + #include +- ++#if LINUX ++#include ++#include ++#else + #include +- ++#endif /* LINUX */ + #else +- + #include + #include + #include + +-#endif +- ++#endif + + OSErr GetDeviceSize(int driveRefNum, UInt64 *numBlocks, UInt32 *blockSize) + { + #if BSD + UInt64 devBlockCount = 0; + int devBlockSize = 0; ++#if LINUX ++ struct stat stbuf; ++ ++ devBlockSize = 512; + ++#ifndef BLKGETSIZE ++#define BLKGETSIZE _IO(0x12,96) ++#endif ++#ifndef BLKGETSIZE64 ++#define BLKGETSIZE64 _IOR(0x12,114,size_t) ++#endif ++ if (fstat(driveRefNum, &stbuf) < 0){ ++ printf("Error: %s\n", strerror(errno)); ++ return(-1); ++ } ++ ++ if (S_ISREG(stbuf.st_mode)) { ++ devBlockCount = stbuf.st_size / 512; ++ } ++ else if (S_ISBLK(stbuf.st_mode)) { ++ unsigned long size; ++ u_int64_t size64; ++ if (!ioctl(driveRefNum, BLKGETSIZE64, &size64)) ++ devBlockCount = size64 / 512; ++ else if (!ioctl(driveRefNum, BLKGETSIZE, &size)) ++ devBlockCount = size; ++ else{ ++ printf("Error: %s\n", strerror(errno)); ++ return(-1); ++ } ++ ++ } ++ else{ ++ printf("Device is not a block device"); ++ return(-1); ++ } ++#elif BSD + if (ioctl(driveRefNum, DKIOCGETBLOCKCOUNT, &devBlockCount) < 0) { + printf("ioctl(DKIOCGETBLOCKCOUNT) for fd %d: %s\n", driveRefNum, strerror(errno)); + return (-1); +@@ -55,6 +92,7 @@ + printf("ioctl(DKIOCGETBLOCKSIZE) for fd %d: %s\n", driveRefNum, strerror(errno)); + return (-1); + } ++#endif /* BSD */ + + if (devBlockSize != 512) { + *numBlocks = (devBlockCount * (UInt64)devBlockSize) / 512; +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SDevice.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SDevice.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SExtents.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SExtents.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SKeyCompare.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SKeyCompare.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SKeyCompare.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SKeyCompare.c 2008-07-01 22:30:11.000000000 +0200 +@@ -454,7 +454,9 @@ + * The name portion of the key is compared using a 16-bit binary comparison. + * This is called from the b-tree code. + */ ++#if !LINUX + __private_extern__ ++#endif + SInt32 + CompareAttributeKeys(const AttributeKey *searchKey, const AttributeKey *trialKey) + { +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SKeyCompare.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SKeyCompare.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SRebuildCatalogBTree.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SRebuildCatalogBTree.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SRepair.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SRepair.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SRepair.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SRepair.c 2008-07-01 22:30:11.000000000 +0200 +@@ -1593,7 +1593,9 @@ + + static OSErr FixWrapperExtents( SGlobPtr GPtr, RepairOrderPtr p ) + { ++#if !LINUX + #pragma unused (p) ++#endif + + OSErr err; + HFSMasterDirectoryBlock *mdb; +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SRepair.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SRepair.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SRuntime.h diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SRuntime.h +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SRuntime.h 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SRuntime.h 2008-07-01 22:30:11.000000000 +0200 +@@ -27,8 +27,11 @@ + #define __SRUNTIME__ + + #if BSD +- ++#if LINUX ++#include "missing.h" ++#else + #include ++#endif + #include + #include + #include +@@ -91,10 +94,12 @@ + + typedef u_int32_t HFSCatalogNodeID; + ++#if !LINUX + enum { + false = 0, + true = 1 + }; ++#endif + + /* OS error codes */ + enum { +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SStubs.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SStubs.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SUtils.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SUtils.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SUtils.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SUtils.c 2008-07-01 22:30:11.000000000 +0200 +@@ -380,7 +380,8 @@ + // GPtr->realVCB Real in-memory vcb + //------------------------------------------------------------------------------ + +-#if !BSD ++#if BSD ++#if !LINUX + OSErr GetVolumeFeatures( SGlobPtr GPtr ) + { + OSErr err; +@@ -418,7 +419,7 @@ + return( noErr ); + } + #endif +- ++#endif + + + /*------------------------------------------------------------------------------- +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SUtils.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SUtils.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SVerify1.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SVerify1.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SVerify2.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SVerify2.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SVerify2.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SVerify2.c 2008-07-01 22:30:11.000000000 +0200 +@@ -32,7 +32,9 @@ + */ + + #include ++#if !LINUX + #include ++#endif + + #include "BTree.h" + #include "BTreePrivate.h" +@@ -1240,8 +1242,13 @@ + * clump size for read-only media is irrelevant we skip the clump size + * check to avoid non useful warnings. + */ ++#if LINUX ++ // FIXME ++ isWriteable = 1; ++#else + isWriteable = 0; + ioctl( GPtr->DrvNum, DKIOCISWRITABLE, &isWriteable ); ++#endif + if ( isWriteable != 0 && + volumeHeader->catalogFile.clumpSize != vcb->vcbCatalogFile->fcbClumpSize ) { + PrintError(GPtr, E_InvalidClumpSize, 0); +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/SVerify2.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/SVerify2.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/dfalib/VolumeBitmapCheck.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/dfalib/VolumeBitmapCheck.o differ +Files diskdev_cmds-332.14/fsck_hfs.tproj/fsck_hfs and diskdev_cmds-332.14-patched/fsck_hfs.tproj/fsck_hfs differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/fsck_hfs.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/fsck_hfs.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/fsck_hfs.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/fsck_hfs.c 2008-07-01 22:36:12.000000000 +0200 +@@ -24,10 +24,14 @@ + #include + #include + #include ++#if !LINUX + #include ++#endif + #include + #include ++#if !LINUX + #include ++#endif + + #include + +@@ -105,7 +109,7 @@ + else + progname = *argv; + +- while ((ch = getopt(argc, argv, "dfglm:npqruy")) != EOF) { ++ while ((ch = getopt(argc, argv, "dfglm:napqruy")) != EOF) { + switch (ch) { + case 'd': + debug++; +@@ -141,6 +145,7 @@ + yflag = 0; + break; + ++ case 'a': + case 'p': + preen++; + break; +@@ -170,10 +175,12 @@ + + if (guiControl) + debug = 0; /* debugging is for command line only */ +- ++#if LINUX ++// FIXME ++#else + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + (void)signal(SIGINT, catch); +- ++#endif + if (argc < 1) { + (void) fprintf(stderr, "%s: missing special-device\n", progname); + usage(); +@@ -194,7 +201,9 @@ + int chkLev, repLev, logLev; + int blockDevice_fd, canWrite; + char *unraw, *mntonname; ++#if !LINUX + struct statfs *fsinfo; ++#endif + int fs_fd=-1; // fd to the root-dir of the fs we're checking (only w/lfag == 1) + + flags = 0; +@@ -203,7 +212,9 @@ + canWrite = 0; + unraw = NULL; + mntonname = NULL; +- ++#if LINUX ++ // FIXME ++#else + if (lflag) { + result = getmntinfo(&fsinfo, MNT_NOWAIT); + +@@ -233,7 +244,7 @@ + } + } + } +- ++#endif + if (debug && preen) + pwarn("starting\n"); + +@@ -306,6 +317,9 @@ + } + } + } else { ++#if LINUX ++ // FIXME ++#else + struct statfs stfs_buf; + /* + * Check to see if root is mounted read-write. +@@ -315,18 +329,24 @@ + else + flags = 0; + ckfini(flags & MNT_RDONLY); ++#endif + } + + /* XXX free any allocated memory here */ + + if (hotroot && fsmodified) { ++#if !LINUX + struct hfs_mount_args args; ++#endif + /* + * We modified the root. Do a mount update on + * it, unless it is read-write, so we can continue. + */ + if (!preen) + printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); ++#if LINUX ++ // FIXME ++#else + if (flags & MNT_RDONLY) { + bzero(&args, sizeof(args)); + flags |= MNT_UPDATE | MNT_RELOAD; +@@ -335,6 +355,7 @@ + goto ExitThisRoutine; + } + } ++#endif + if (!preen) + printf("\n***** REBOOT NOW *****\n"); + sync(); +@@ -380,11 +401,13 @@ + printf("Can't stat %s: %s\n", dev, strerror(errno)); + return (0); + } ++#if !LINUX + if ((statb.st_mode & S_IFMT) != S_IFCHR) { + pfatal("%s is not a character device", dev); + if (reply("CONTINUE") == 0) + return (0); + } ++#endif + if ((fsreadfd = open(dev, O_RDONLY)) < 0) { + printf("Can't open %s: %s\n", dev, strerror(errno)); + return (0); +@@ -407,10 +430,14 @@ + printf("\n"); + + /* Get device block size to initialize cache */ ++#if LINUX ++ devBlockSize = 512; ++#else + if (ioctl(fsreadfd, DKIOCGETBLOCKSIZE, &devBlockSize) < 0) { + pfatal ("Can't get device block size\n"); + return (0); + } ++#endif + /* Initialize the cache */ + if (CacheInit (&fscache, fsreadfd, fswritefd, devBlockSize, + CACHE_IOSIZE, CACHE_BLOCKS, CACHE_HASHSIZE) != EOK) { +@@ -431,11 +458,15 @@ + + static void getWriteAccess( char *dev, int *blockDevice_fdPtr, int *canWritePtr ) + { ++#if !LINUX + int i; + int myMountsCount; ++#endif + void * myPtr; + char * myCharPtr; ++#if !LINUX + struct statfs * myBufPtr; ++#endif + void * myNamePtr; + + myPtr = NULL; +@@ -456,18 +487,19 @@ + *canWritePtr = 1; + goto ExitThisRoutine; + } +- + // get count of mounts then get the info for each ++#if LINUX ++ // FIXME ++#else + myMountsCount = getfsstat( NULL, 0, MNT_NOWAIT ); + if ( myMountsCount < 0 ) + goto ExitThisRoutine; +- + myPtr = (void *) malloc( sizeof(struct statfs) * myMountsCount ); + if ( myPtr == NULL ) + goto ExitThisRoutine; + myMountsCount = getfsstat( myPtr, +- (sizeof(struct statfs) * myMountsCount), +- MNT_NOWAIT ); ++ (sizeof(struct statfs) * myMountsCount), ++ MNT_NOWAIT ); + if ( myMountsCount < 0 ) + goto ExitThisRoutine; + +@@ -481,8 +513,8 @@ + } + myBufPtr++; + } ++#endif + *canWritePtr = 1; // single user will get us here, f_mntfromname is not /dev/diskXXXX +- + ExitThisRoutine: + if ( myPtr != NULL ) + free( myPtr ); +@@ -504,7 +536,7 @@ + (void) fprintf(stderr, " l = live fsck (lock down and test-only)\n"); + (void) fprintf(stderr, " m arg = octal mode used when creating lost+found directory \n"); + (void) fprintf(stderr, " n = assume a no response \n"); +- (void) fprintf(stderr, " p = just fix normal inconsistencies \n"); ++ (void) fprintf(stderr, " p, a = just fix normal inconsistencies \n"); + (void) fprintf(stderr, " q = quick check returns clean, dirty, or failure \n"); + (void) fprintf(stderr, " r = rebuild catalog btree \n"); + (void) fprintf(stderr, " u = usage \n"); +Files diskdev_cmds-332.14/fsck_hfs.tproj/fsck_hfs.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/fsck_hfs.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/Makefile.lnx diskdev_cmds-332.14-patched/fsck_hfs.tproj/Makefile.lnx +--- diskdev_cmds-332.14/fsck_hfs.tproj/Makefile.lnx 1970-01-01 01:00:00.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/Makefile.lnx 2008-07-01 22:30:11.000000000 +0200 +@@ -0,0 +1,15 @@ ++CFILES = fsck_hfs.c strings.c utilities.c cache.c ++OFILES = $(CFILES:.c=.o) ++ ++all: fsck_hfs ++ ++fsck_hfs: $(OFILES) dfalib/libdfa.a ++ ++dfalib/libdfa.a: FORCE ++ $(MAKE) -C dfalib -f Makefile.lnx libdfa.a ++ ++clean: ++ $(RM) fsck_hfs $(OFILES) ++ $(MAKE) -C dfalib -f Makefile.lnx clean ++ ++.PHONY : FORCE clean +Files diskdev_cmds-332.14/fsck_hfs.tproj/strings.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/strings.o differ +diff -druN diskdev_cmds-332.14/fsck_hfs.tproj/utilities.c diskdev_cmds-332.14-patched/fsck_hfs.tproj/utilities.c +--- diskdev_cmds-332.14/fsck_hfs.tproj/utilities.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/fsck_hfs.tproj/utilities.c 2008-07-01 22:30:11.000000000 +0200 +@@ -183,12 +183,14 @@ + printf("Can't stat %s\n", raw); + return (origname); + } ++#if !LINUX + if ((stchar.st_mode & S_IFMT) == S_IFCHR) { + return (raw); + } else { + printf("%s is not a character device\n", raw); + return (origname); + } ++#endif + } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) { + newname = unrawname(newname); + retried++; +@@ -214,7 +216,11 @@ + *dp = 0; + (void)strcpy(rawbuf, name); + *dp = '/'; +- (void)strcat(rawbuf, "/r"); ++#if LINUX ++ (void)strcat(rawbuf, "/"); ++#else ++ (void)strcat(rawbuf,"/r"); ++#endif + (void)strcat(rawbuf, &dp[1]); + + return (rawbuf); +Files diskdev_cmds-332.14/fsck_hfs.tproj/utilities.o and diskdev_cmds-332.14-patched/fsck_hfs.tproj/utilities.o differ +diff -druN diskdev_cmds-332.14/include/bitstring.h diskdev_cmds-332.14-patched/include/bitstring.h +--- diskdev_cmds-332.14/include/bitstring.h 1970-01-01 01:00:00.000000000 +0100 ++++ diskdev_cmds-332.14-patched/include/bitstring.h 2008-07-01 22:30:11.000000000 +0200 +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ++ * ++ * @APPLE_LICENSE_HEADER_START@ ++ * ++ * The contents of this file constitute Original Code as defined in and ++ * are subject to the Apple Public Source License Version 1.1 (the ++ * "License"). You may not use this file except in compliance with the ++ * License. Please obtain a copy of the License at ++ * http://www.apple.com/publicsource and read it before using this file. ++ * ++ * This Original Code and all software distributed under the License are ++ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ++ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ++ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ++ * License for the specific language governing rights and limitations ++ * under the License. ++ * ++ * @APPLE_LICENSE_HEADER_END@ ++ */ ++/* ++ * Copyright (c) 1989, 1993 ++ * The Regents of the University of California. All rights reserved. ++ * ++ * This code is derived from software contributed to Berkeley by ++ * Paul Vixie. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by the University of ++ * California, Berkeley and its contributors. ++ * 4. Neither the name of the University nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * @(#)bitstring.h 8.1 (Berkeley) 7/19/93 ++ */ ++ ++#ifndef _BITSTRING_H_ ++#define _BITSTRING_H_ ++ ++typedef unsigned char bitstr_t; ++ ++/* internal macros */ ++ /* byte of the bitstring bit is in */ ++#define _bit_byte(bit) \ ++ ((bit) >> 3) ++ ++ /* mask for the bit within its byte */ ++#define _bit_mask(bit) \ ++ (1 << ((bit)&0x7)) ++ ++/* external macros */ ++ /* bytes in a bitstring of nbits bits */ ++#define bitstr_size(nbits) \ ++ ((((nbits) - 1) >> 3) + 1) ++ ++ /* allocate a bitstring */ ++#define bit_alloc(nbits) \ ++ (bitstr_t *)calloc(1, \ ++ (unsigned int)bitstr_size(nbits) * sizeof(bitstr_t)) ++ ++ /* allocate a bitstring on the stack */ ++#define bit_decl(name, nbits) \ ++ (name)[bitstr_size(nbits)] ++ ++ /* is bit N of bitstring name set? */ ++#define bit_test(name, bit) \ ++ ((name)[_bit_byte(bit)] & _bit_mask(bit)) ++ ++ /* set bit N of bitstring name */ ++#define bit_set(name, bit) \ ++ (name)[_bit_byte(bit)] |= _bit_mask(bit) ++ ++ /* clear bit N of bitstring name */ ++#define bit_clear(name, bit) \ ++ (name)[_bit_byte(bit)] &= ~_bit_mask(bit) ++ ++ /* clear bits start ... stop in bitstring */ ++#define bit_nclear(name, start, stop) { \ ++ register bitstr_t *_name = name; \ ++ register int _start = start, _stop = stop; \ ++ register int _startbyte = _bit_byte(_start); \ ++ register int _stopbyte = _bit_byte(_stop); \ ++ if (_startbyte == _stopbyte) { \ ++ _name[_startbyte] &= ((0xff >> (8 - (_start&0x7))) | \ ++ (0xff << ((_stop&0x7) + 1))); \ ++ } else { \ ++ _name[_startbyte] &= 0xff >> (8 - (_start&0x7)); \ ++ while (++_startbyte < _stopbyte) \ ++ _name[_startbyte] = 0; \ ++ _name[_stopbyte] &= 0xff << ((_stop&0x7) + 1); \ ++ } \ ++} ++ ++ /* set bits start ... stop in bitstring */ ++#define bit_nset(name, start, stop) { \ ++ register bitstr_t *_name = name; \ ++ register int _start = start, _stop = stop; \ ++ register int _startbyte = _bit_byte(_start); \ ++ register int _stopbyte = _bit_byte(_stop); \ ++ if (_startbyte == _stopbyte) { \ ++ _name[_startbyte] |= ((0xff << (_start&0x7)) & \ ++ (0xff >> (7 - (_stop&0x7)))); \ ++ } else { \ ++ _name[_startbyte] |= 0xff << ((_start)&0x7); \ ++ while (++_startbyte < _stopbyte) \ ++ _name[_startbyte] = 0xff; \ ++ _name[_stopbyte] |= 0xff >> (7 - (_stop&0x7)); \ ++ } \ ++} ++ ++ /* find first bit clear in name */ ++#define bit_ffc(name, nbits, value) { \ ++ register bitstr_t *_name = name; \ ++ register int _byte, _nbits = nbits; \ ++ register int _stopbyte = _bit_byte(_nbits), _value = -1; \ ++ for (_byte = 0; _byte <= _stopbyte; ++_byte) \ ++ if (_name[_byte] != 0xff) { \ ++ _value = _byte << 3; \ ++ for (_stopbyte = _name[_byte]; (_stopbyte&0x1); \ ++ ++_value, _stopbyte >>= 1); \ ++ break; \ ++ } \ ++ *(value) = _value; \ ++} ++ ++ /* find first bit set in name */ ++#define bit_ffs(name, nbits, value) { \ ++ register bitstr_t *_name = name; \ ++ register int _byte, _nbits = nbits; \ ++ register int _stopbyte = _bit_byte(_nbits), _value = -1; \ ++ for (_byte = 0; _byte <= _stopbyte; ++_byte) \ ++ if (_name[_byte]) { \ ++ _value = _byte << 3; \ ++ for (_stopbyte = _name[_byte]; !(_stopbyte&0x1); \ ++ ++_value, _stopbyte >>= 1); \ ++ break; \ ++ } \ ++ *(value) = _value; \ ++} ++ ++#endif /* !_BITSTRING_H_ */ +diff -druN diskdev_cmds-332.14/include/hfs/hfs_format.h diskdev_cmds-332.14-patched/include/hfs/hfs_format.h +--- diskdev_cmds-332.14/include/hfs/hfs_format.h 1970-01-01 01:00:00.000000000 +0100 ++++ diskdev_cmds-332.14-patched/include/hfs/hfs_format.h 2008-07-01 22:30:11.000000000 +0200 +@@ -0,0 +1,689 @@ ++/* ++ * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. ++ * ++ * @APPLE_LICENSE_HEADER_START@ ++ * ++ * The contents of this file constitute Original Code as defined in and ++ * are subject to the Apple Public Source License Version 1.1 (the ++ * "License"). You may not use this file except in compliance with the ++ * License. Please obtain a copy of the License at ++ * http://www.apple.com/publicsource and read it before using this file. ++ * ++ * This Original Code and all software distributed under the License are ++ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ++ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ++ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ++ * License for the specific language governing rights and limitations ++ * under the License. ++ * ++ * @APPLE_LICENSE_HEADER_END@ ++ */ ++#ifndef __HFS_FORMAT__ ++#define __HFS_FORMAT__ ++ ++#include "missing.h" ++ ++#include ++ ++/* ++ * hfs_format.c ++ * ++ * This file describes the on-disk format for HFS and HFS Plus volumes. ++ * The HFS Plus volume format is desciibed in detail in Apple Technote 1150. ++ * ++ * http://developer.apple.com/technotes/tn/tn1150.html ++ * ++ */ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* some on-disk hfs structures have 68K alignment (misaligned) */ ++ ++#define PACKED_S __attribute__((packed)) ++ ++/* Signatures used to differentiate between HFS and HFS Plus volumes */ ++enum { ++ kHFSSigWord = 0x4244, /* 'BD' in ASCII */ ++ kHFSPlusSigWord = 0x482B, /* 'H+' in ASCII */ ++ kHFSXSigWord = 0x4858, /* 'HX' in ASCII */ ++ ++ kHFSPlusVersion = 0x0004, /* 'H+' volumes are version 4 only */ ++ kHFSXVersion = 0x0005, /* 'HX' volumes start with version 5 */ ++ ++ kHFSPlusMountVersion = 0x31302E30, /* '10.0' for Mac OS X */ ++ kHFSJMountVersion = 0x4846534a, /* 'HFSJ' for journaled HFS+ on OS X */ ++ kFSKMountVersion = 0x46534b21 /* 'FSK!' for failed journal replay */ ++}PACKED_S; ++ ++ ++#ifdef __APPLE_API_PRIVATE ++/* ++ * Mac OS X has a special directory for linked and unlinked files (HFS Plus only). ++ * This directory and its contents are never exported from the filesystem under ++ * Mac OS X. ++ * ++ * To make this folder name sort last, it has embedded null prefix. ++ * (0xC0, 0x80 in UTF-8) ++ */ ++#define HFSPLUSMETADATAFOLDER "\xC0\x80\xC0\x80\xC0\x80\xC0\x80HFS+ Private Data" ++ ++/* ++ * Files in the HFS Private Data folder have one of the following prefixes ++ * followed by a decimal number (no leading zeros). For indirect nodes this ++ * number is a 32 bit random number. For unlinked (deleted) files that are ++ * still open, the number is the file ID for that file. ++ * ++ * e.g. iNode7182000 and temp3296 ++ */ ++#define HFS_INODE_PREFIX "iNode" ++#define HFS_DELETE_PREFIX "temp" ++ ++#endif /* __APPLE_API_PRIVATE */ ++ ++/* ++ * Indirect link files (hard links) have the following type/creator. ++ */ ++enum { ++ kHardLinkFileType = 0x686C6E6B, /* 'hlnk' */ ++ kHFSPlusCreator = 0x6866732B /* 'hfs+' */ ++}PACKED_S; ++ ++ ++#ifndef _HFSUNISTR255_DEFINED_ ++#define _HFSUNISTR255_DEFINED_ ++/* Unicode strings are used for HFS Plus file and folder names */ ++struct HFSUniStr255 { ++ u_int16_t length; /* number of unicode characters */ ++ u_int16_t unicode[255]; /* unicode characters */ ++} PACKED_S; ++typedef struct HFSUniStr255 HFSUniStr255; ++typedef const HFSUniStr255 *ConstHFSUniStr255Param; ++#endif /* _HFSUNISTR255_DEFINED_ */ ++ ++enum { ++ kHFSMaxVolumeNameChars = 27, ++ kHFSMaxFileNameChars = 31, ++ kHFSPlusMaxFileNameChars = 255 ++}PACKED_S; ++ ++ ++/* Extent overflow file data structures */ ++ ++/* HFS Extent key */ ++struct HFSExtentKey { ++ u_int8_t keyLength; /* length of key, excluding this field */ ++ u_int8_t forkType; /* 0 = data fork, FF = resource fork */ ++ u_int32_t fileID; /* file ID */ ++ u_int16_t startBlock; /* first file allocation block number in this extent */ ++}PACKED_S; ++typedef struct HFSExtentKey HFSExtentKey; ++ ++/* HFS Plus Extent key */ ++struct HFSPlusExtentKey { ++ u_int16_t keyLength; /* length of key, excluding this field */ ++ u_int8_t forkType; /* 0 = data fork, FF = resource fork */ ++ u_int8_t pad; /* make the other fields align on 32-bit boundary */ ++ u_int32_t fileID; /* file ID */ ++ u_int32_t startBlock; /* first file allocation block number in this extent */ ++}PACKED_S; ++typedef struct HFSPlusExtentKey HFSPlusExtentKey; ++ ++/* Number of extent descriptors per extent record */ ++enum { ++ kHFSExtentDensity = 3, ++ kHFSPlusExtentDensity = 8 ++}PACKED_S; ++ ++/* HFS extent descriptor */ ++struct HFSExtentDescriptor { ++ u_int16_t startBlock; /* first allocation block */ ++ u_int16_t blockCount; /* number of allocation blocks */ ++}PACKED_S; ++typedef struct HFSExtentDescriptor HFSExtentDescriptor; ++ ++/* HFS Plus extent descriptor */ ++struct HFSPlusExtentDescriptor { ++ u_int32_t startBlock; /* first allocation block */ ++ u_int32_t blockCount; /* number of allocation blocks */ ++}PACKED_S; ++typedef struct HFSPlusExtentDescriptor HFSPlusExtentDescriptor; ++ ++/* HFS extent record */ ++typedef HFSExtentDescriptor HFSExtentRecord[3]; ++ ++/* HFS Plus extent record */ ++typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[8]; ++ ++ ++/* Finder information */ ++struct FndrFileInfo { ++ u_int32_t fdType; /* file type */ ++ u_int32_t fdCreator; /* file creator */ ++ u_int16_t fdFlags; /* Finder flags */ ++ struct { ++ int16_t v; /* file's location */ ++ int16_t h; ++ } PACKED_S fdLocation; ++ int16_t opaque; ++}PACKED_S; ++typedef struct FndrFileInfo FndrFileInfo; ++ ++struct FndrDirInfo { ++ struct { /* folder's window rectangle */ ++ int16_t top; ++ int16_t left; ++ int16_t bottom; ++ int16_t right; ++ }PACKED_S frRect; ++ unsigned short frFlags; /* Finder flags */ ++ struct { ++ u_int16_t v; /* folder's location */ ++ u_int16_t h; ++ }PACKED_S frLocation; ++ int16_t opaque; ++}PACKED_S; ++typedef struct FndrDirInfo FndrDirInfo; ++ ++struct FndrOpaqueInfo { ++ int8_t opaque[16]; ++}PACKED_S; ++typedef struct FndrOpaqueInfo FndrOpaqueInfo; ++ ++ ++/* HFS Plus Fork data info - 80 bytes */ ++struct HFSPlusForkData { ++ u_int64_t logicalSize; /* fork's logical size in bytes */ ++ u_int32_t clumpSize; /* fork's clump size in bytes */ ++ u_int32_t totalBlocks; /* total blocks used by this fork */ ++ HFSPlusExtentRecord extents; /* initial set of extents */ ++}PACKED_S; ++typedef struct HFSPlusForkData HFSPlusForkData; ++ ++ ++/* Mac OS X has 16 bytes worth of "BSD" info. ++ * ++ * Note: Mac OS 9 implementations and applications ++ * should preserve, but not change, this information. ++ */ ++struct HFSPlusBSDInfo { ++ u_int32_t ownerID; /* user or group ID of file/folder owner */ ++ u_int32_t groupID; /* additional user of group ID */ ++ u_int8_t adminFlags; /* super-user changeable flags */ ++ u_int8_t ownerFlags; /* owner changeable flags */ ++ u_int16_t fileMode; /* file type and permission bits */ ++ union { ++ u_int32_t iNodeNum; /* indirect node number (hard links only) */ ++ u_int32_t linkCount; /* links that refer to this indirect node */ ++ u_int32_t rawDevice; /* special file device (FBLK and FCHR only) */ ++ }PACKED_S special; ++}PACKED_S; ++typedef struct HFSPlusBSDInfo HFSPlusBSDInfo; ++ ++ ++/* Catalog file data structures */ ++ ++enum { ++ kHFSRootParentID = 1, /* Parent ID of the root folder */ ++ kHFSRootFolderID = 2, /* Folder ID of the root folder */ ++ kHFSExtentsFileID = 3, /* File ID of the extents file */ ++ kHFSCatalogFileID = 4, /* File ID of the catalog file */ ++ kHFSBadBlockFileID = 5, /* File ID of the bad allocation block file */ ++ kHFSAllocationFileID = 6, /* File ID of the allocation file (HFS Plus only) */ ++ kHFSStartupFileID = 7, /* File ID of the startup file (HFS Plus only) */ ++ kHFSAttributesFileID = 8, /* File ID of the attribute file (HFS Plus only) */ ++ kHFSRepairCatalogFileID = 14, /* Used when rebuilding Catalog B-tree */ ++ kHFSBogusExtentFileID = 15, /* Used for exchanging extents in extents file */ ++ kHFSFirstUserCatalogNodeID = 16 ++}PACKED_S; ++ ++/* HFS catalog key */ ++struct HFSCatalogKey { ++ u_int8_t keyLength; /* key length (in bytes) */ ++ u_int8_t reserved; /* reserved (set to zero) */ ++ u_int32_t parentID; /* parent folder ID */ ++ u_int8_t nodeName[kHFSMaxFileNameChars + 1]; /* catalog node name */ ++}PACKED_S; ++typedef struct HFSCatalogKey HFSCatalogKey; ++ ++/* HFS Plus catalog key */ ++struct HFSPlusCatalogKey { ++ u_int16_t keyLength; /* key length (in bytes) */ ++ u_int32_t parentID; /* parent folder ID */ ++ HFSUniStr255 nodeName; /* catalog node name */ ++}PACKED_S; ++typedef struct HFSPlusCatalogKey HFSPlusCatalogKey; ++ ++/* Catalog record types */ ++enum { ++ /* HFS Catalog Records */ ++ kHFSFolderRecord = 0x0100, /* Folder record */ ++ kHFSFileRecord = 0x0200, /* File record */ ++ kHFSFolderThreadRecord = 0x0300, /* Folder thread record */ ++ kHFSFileThreadRecord = 0x0400, /* File thread record */ ++ ++ /* HFS Plus Catalog Records */ ++ kHFSPlusFolderRecord = 1, /* Folder record */ ++ kHFSPlusFileRecord = 2, /* File record */ ++ kHFSPlusFolderThreadRecord = 3, /* Folder thread record */ ++ kHFSPlusFileThreadRecord = 4 /* File thread record */ ++}PACKED_S; ++ ++ ++/* Catalog file record flags */ ++enum { ++ kHFSFileLockedBit = 0x0000, /* file is locked and cannot be written to */ ++ kHFSFileLockedMask = 0x0001, ++ ++ kHFSThreadExistsBit = 0x0001, /* a file thread record exists for this file */ ++ kHFSThreadExistsMask = 0x0002, ++ ++ kHFSHasAttributesBit = 0x0002, /* object has extended attributes */ ++ kHFSHasAttributesMask = 0x0004, ++ ++ kHFSHasSecurityBit = 0x0003, /* object has security data (ACLs) */ ++ kHFSHasSecurityMask = 0x0008 ++}PACKED_S; ++ ++ ++/* HFS catalog folder record - 70 bytes */ ++struct HFSCatalogFolder { ++ int16_t recordType; /* == kHFSFolderRecord */ ++ u_int16_t flags; /* folder flags */ ++ u_int16_t valence; /* folder valence */ ++ u_int32_t folderID; /* folder ID */ ++ u_int32_t createDate; /* date and time of creation */ ++ u_int32_t modifyDate; /* date and time of last modification */ ++ u_int32_t backupDate; /* date and time of last backup */ ++ FndrDirInfo userInfo; /* Finder information */ ++ FndrOpaqueInfo finderInfo; /* additional Finder information */ ++ u_int32_t reserved[4]; /* reserved - initialized as zero */ ++}PACKED_S; ++typedef struct HFSCatalogFolder HFSCatalogFolder; ++ ++/* HFS Plus catalog folder record - 88 bytes */ ++struct HFSPlusCatalogFolder { ++ int16_t recordType; /* == kHFSPlusFolderRecord */ ++ u_int16_t flags; /* file flags */ ++ u_int32_t valence; /* folder's valence (limited to 2^16 in Mac OS) */ ++ u_int32_t folderID; /* folder ID */ ++ u_int32_t createDate; /* date and time of creation */ ++ u_int32_t contentModDate; /* date and time of last content modification */ ++ u_int32_t attributeModDate; /* date and time of last attribute modification */ ++ u_int32_t accessDate; /* date and time of last access (MacOS X only) */ ++ u_int32_t backupDate; /* date and time of last backup */ ++ HFSPlusBSDInfo bsdInfo; /* permissions (for MacOS X) */ ++ FndrDirInfo userInfo; /* Finder information */ ++ FndrOpaqueInfo finderInfo; /* additional Finder information */ ++ u_int32_t textEncoding; /* hint for name conversions */ ++ u_int32_t attrBlocks; /* cached count of attribute data blocks */ ++}PACKED_S; ++typedef struct HFSPlusCatalogFolder HFSPlusCatalogFolder; ++ ++/* HFS catalog file record - 102 bytes */ ++struct HFSCatalogFile { ++ int16_t recordType; /* == kHFSFileRecord */ ++ u_int8_t flags; /* file flags */ ++ int8_t fileType; /* file type (unused ?) */ ++ FndrFileInfo userInfo; /* Finder information */ ++ u_int32_t fileID; /* file ID */ ++ u_int16_t dataStartBlock; /* not used - set to zero */ ++ int32_t dataLogicalSize; /* logical EOF of data fork */ ++ int32_t dataPhysicalSize; /* physical EOF of data fork */ ++ u_int16_t rsrcStartBlock; /* not used - set to zero */ ++ int32_t rsrcLogicalSize; /* logical EOF of resource fork */ ++ int32_t rsrcPhysicalSize; /* physical EOF of resource fork */ ++ u_int32_t createDate; /* date and time of creation */ ++ u_int32_t modifyDate; /* date and time of last modification */ ++ u_int32_t backupDate; /* date and time of last backup */ ++ FndrOpaqueInfo finderInfo; /* additional Finder information */ ++ u_int16_t clumpSize; /* file clump size (not used) */ ++ HFSExtentRecord dataExtents; /* first data fork extent record */ ++ HFSExtentRecord rsrcExtents; /* first resource fork extent record */ ++ u_int32_t reserved; /* reserved - initialized as zero */ ++}PACKED_S; ++typedef struct HFSCatalogFile HFSCatalogFile; ++ ++/* HFS Plus catalog file record - 248 bytes */ ++struct HFSPlusCatalogFile { ++ int16_t recordType; /* == kHFSPlusFileRecord */ ++ u_int16_t flags; /* file flags */ ++ u_int32_t reserved1; /* reserved - initialized as zero */ ++ u_int32_t fileID; /* file ID */ ++ u_int32_t createDate; /* date and time of creation */ ++ u_int32_t contentModDate; /* date and time of last content modification */ ++ u_int32_t attributeModDate; /* date and time of last attribute modification */ ++ u_int32_t accessDate; /* date and time of last access (MacOS X only) */ ++ u_int32_t backupDate; /* date and time of last backup */ ++ HFSPlusBSDInfo bsdInfo; /* permissions (for MacOS X) */ ++ FndrFileInfo userInfo; /* Finder information */ ++ FndrOpaqueInfo finderInfo; /* additional Finder information */ ++ u_int32_t textEncoding; /* hint for name conversions */ ++ u_int32_t attrBlocks; /* cached count of attribute data blocks */ ++ ++ /* Note: these start on double long (64 bit) boundry */ ++ HFSPlusForkData dataFork; /* size and block data for data fork */ ++ HFSPlusForkData resourceFork; /* size and block data for resource fork */ ++}PACKED_S; ++typedef struct HFSPlusCatalogFile HFSPlusCatalogFile; ++ ++/* HFS catalog thread record - 46 bytes */ ++struct HFSCatalogThread { ++ int16_t recordType; /* == kHFSFolderThreadRecord or kHFSFileThreadRecord */ ++ int32_t reserved[2]; /* reserved - initialized as zero */ ++ u_int32_t parentID; /* parent ID for this catalog node */ ++ u_int8_t nodeName[kHFSMaxFileNameChars + 1]; /* name of this catalog node */ ++}PACKED_S; ++typedef struct HFSCatalogThread HFSCatalogThread; ++ ++/* HFS Plus catalog thread record -- 264 bytes */ ++struct HFSPlusCatalogThread { ++ int16_t recordType; /* == kHFSPlusFolderThreadRecord or kHFSPlusFileThreadRecord */ ++ int16_t reserved; /* reserved - initialized as zero */ ++ u_int32_t parentID; /* parent ID for this catalog node */ ++ HFSUniStr255 nodeName; /* name of this catalog node (variable length) */ ++}PACKED_S; ++typedef struct HFSPlusCatalogThread HFSPlusCatalogThread; ++ ++#ifdef __APPLE_API_UNSTABLE ++/* ++ These are the types of records in the attribute B-tree. The values were ++ chosen so that they wouldn't conflict with the catalog record types. ++*/ ++enum { ++ kHFSPlusAttrInlineData = 0x10, /* if size < kAttrOverflowSize */ ++ kHFSPlusAttrForkData = 0x20, /* if size >= kAttrOverflowSize */ ++ kHFSPlusAttrExtents = 0x30 /* overflow extents for large attributes */ ++}PACKED_S; ++ ++ ++/* ++ HFSPlusAttrForkData ++ For larger attributes, whose value is stored in allocation blocks. ++ If the attribute has more than 8 extents, there will be additonal ++ records (of type HFSPlusAttrExtents) for this attribute. ++*/ ++struct HFSPlusAttrForkData { ++ u_int32_t recordType; /* == kHFSPlusAttrForkData*/ ++ u_int32_t reserved; ++ HFSPlusForkData theFork; /* size and first extents of value*/ ++}PACKED_S; ++typedef struct HFSPlusAttrForkData HFSPlusAttrForkData; ++ ++/* ++ HFSPlusAttrExtents ++ This record contains information about overflow extents for large, ++ fragmented attributes. ++*/ ++struct HFSPlusAttrExtents { ++ u_int32_t recordType; /* == kHFSPlusAttrExtents*/ ++ u_int32_t reserved; ++ HFSPlusExtentRecord extents; /* additional extents*/ ++}PACKED_S; ++typedef struct HFSPlusAttrExtents HFSPlusAttrExtents; ++ ++/* ++ * Atrributes B-tree Data Record ++ * ++ * For small attributes, whose entire value is stored ++ * within a single B-tree record. ++ */ ++struct HFSPlusAttrData { ++ u_int32_t recordType; /* == kHFSPlusAttrInlineData */ ++ u_int32_t reserved[2]; ++ u_int32_t attrSize; /* size of attribute data in bytes */ ++ u_int8_t attrData[2]; /* variable length */ ++}PACKED_S; ++typedef struct HFSPlusAttrData HFSPlusAttrData; ++ ++ ++/* HFSPlusAttrInlineData is obsolete use HFSPlusAttrData instead */ ++struct HFSPlusAttrInlineData { ++ u_int32_t recordType; ++ u_int32_t reserved; ++ u_int32_t logicalSize; ++ u_int8_t userData[2]; ++}PACKED_S; ++typedef struct HFSPlusAttrInlineData HFSPlusAttrInlineData; ++ ++ ++/* A generic Attribute Record*/ ++union HFSPlusAttrRecord { ++ u_int32_t recordType; ++ HFSPlusAttrInlineData inlineData; /* NOT USED */ ++ HFSPlusAttrData attrData; ++ HFSPlusAttrForkData forkData; ++ HFSPlusAttrExtents overflowExtents; ++}PACKED_S; ++typedef union HFSPlusAttrRecord HFSPlusAttrRecord; ++ ++/* Attribute key */ ++enum { kHFSMaxAttrNameLen = 127 }; ++struct HFSPlusAttrKey { ++ u_int16_t keyLength; /* key length (in bytes) */ ++ u_int16_t pad; /* set to zero */ ++ u_int32_t fileID; /* file associated with attribute */ ++ u_int32_t startBlock; /* first attribue allocation block number for extents */ ++ u_int16_t attrNameLen; /* number of unicode characters */ ++ u_int16_t attrName[127]; /* attribute name (Unicode) */ ++}PACKED_S; ++typedef struct HFSPlusAttrKey HFSPlusAttrKey; ++ ++#define kHFSPlusAttrKeyMaximumLength (sizeof(HFSPlusAttrKey) - sizeof(u_int16_t)) ++#define kHFSPlusAttrKeyMinimumLength (kHFSPlusAttrKeyMaximumLength - (127 * sizeof(u_int16_t))) ++ ++#endif /* __APPLE_API_UNSTABLE */ ++ ++ ++/* Key and node lengths */ ++enum { ++ kHFSPlusExtentKeyMaximumLength = sizeof(HFSPlusExtentKey) - sizeof(u_int16_t), ++ kHFSExtentKeyMaximumLength = sizeof(HFSExtentKey) - sizeof(u_int8_t), ++ kHFSPlusCatalogKeyMaximumLength = sizeof(HFSPlusCatalogKey) - sizeof(u_int16_t), ++ kHFSPlusCatalogKeyMinimumLength = kHFSPlusCatalogKeyMaximumLength - sizeof(HFSUniStr255) + sizeof(u_int16_t), ++ kHFSCatalogKeyMaximumLength = sizeof(HFSCatalogKey) - sizeof(u_int8_t), ++ kHFSCatalogKeyMinimumLength = kHFSCatalogKeyMaximumLength - (kHFSMaxFileNameChars + 1) + sizeof(u_int8_t), ++ kHFSPlusCatalogMinNodeSize = 4096, ++ kHFSPlusExtentMinNodeSize = 512, ++ kHFSPlusAttrMinNodeSize = 4096 ++}PACKED_S; ++ ++/* HFS and HFS Plus volume attribute bits */ ++enum { ++ /* Bits 0-6 are reserved (always cleared by MountVol call) */ ++ kHFSVolumeHardwareLockBit = 7, /* volume is locked by hardware */ ++ kHFSVolumeUnmountedBit = 8, /* volume was successfully unmounted */ ++ kHFSVolumeSparedBlocksBit = 9, /* volume has bad blocks spared */ ++ kHFSVolumeNoCacheRequiredBit = 10, /* don't cache volume blocks (i.e. RAM or ROM disk) */ ++ kHFSBootVolumeInconsistentBit = 11, /* boot volume is inconsistent (System 7.6 and later) */ ++ kHFSCatalogNodeIDsReusedBit = 12, ++ kHFSVolumeJournaledBit = 13, /* this volume has a journal on it */ ++ kHFSVolumeInconsistentBit = 14, /* serious inconsistencies detected at runtime */ ++ kHFSVolumeSoftwareLockBit = 15, /* volume is locked by software */ ++ ++ kHFSVolumeHardwareLockMask = 1 << kHFSVolumeHardwareLockBit, ++ kHFSVolumeUnmountedMask = 1 << kHFSVolumeUnmountedBit, ++ kHFSVolumeSparedBlocksMask = 1 << kHFSVolumeSparedBlocksBit, ++ kHFSVolumeNoCacheRequiredMask = 1 << kHFSVolumeNoCacheRequiredBit, ++ kHFSBootVolumeInconsistentMask = 1 << kHFSBootVolumeInconsistentBit, ++ kHFSCatalogNodeIDsReusedMask = 1 << kHFSCatalogNodeIDsReusedBit, ++ kHFSVolumeJournaledMask = 1 << kHFSVolumeJournaledBit, ++ kHFSVolumeInconsistentMask = 1 << kHFSVolumeInconsistentBit, ++ kHFSVolumeSoftwareLockMask = 1 << kHFSVolumeSoftwareLockBit, ++ kHFSMDBAttributesMask = 0x8380 ++}PACKED_S; ++ ++ ++/* HFS Master Directory Block - 162 bytes */ ++/* Stored at sector #2 (3rd sector) and second-to-last sector. */ ++struct HFSMasterDirectoryBlock { ++ u_int16_t drSigWord; /* == kHFSSigWord */ ++ u_int32_t drCrDate; /* date and time of volume creation */ ++ u_int32_t drLsMod; /* date and time of last modification */ ++ u_int16_t drAtrb; /* volume attributes */ ++ u_int16_t drNmFls; /* number of files in root folder */ ++ u_int16_t drVBMSt; /* first block of volume bitmap */ ++ u_int16_t drAllocPtr; /* start of next allocation search */ ++ u_int16_t drNmAlBlks; /* number of allocation blocks in volume */ ++ u_int32_t drAlBlkSiz; /* size (in bytes) of allocation blocks */ ++ u_int32_t drClpSiz; /* default clump size */ ++ u_int16_t drAlBlSt; /* first allocation block in volume */ ++ u_int32_t drNxtCNID; /* next unused catalog node ID */ ++ u_int16_t drFreeBks; /* number of unused allocation blocks */ ++ u_int8_t drVN[kHFSMaxVolumeNameChars + 1]; /* volume name */ ++ u_int32_t drVolBkUp; /* date and time of last backup */ ++ u_int16_t drVSeqNum; /* volume backup sequence number */ ++ u_int32_t drWrCnt; /* volume write count */ ++ u_int32_t drXTClpSiz; /* clump size for extents overflow file */ ++ u_int32_t drCTClpSiz; /* clump size for catalog file */ ++ u_int16_t drNmRtDirs; /* number of directories in root folder */ ++ u_int32_t drFilCnt; /* number of files in volume */ ++ u_int32_t drDirCnt; /* number of directories in volume */ ++ u_int32_t drFndrInfo[8]; /* information used by the Finder */ ++ u_int16_t drEmbedSigWord; /* embedded volume signature (formerly drVCSize) */ ++ HFSExtentDescriptor drEmbedExtent; /* embedded volume location and size (formerly drVBMCSize and drCtlCSize) */ ++ u_int32_t drXTFlSize; /* size of extents overflow file */ ++ HFSExtentRecord drXTExtRec; /* extent record for extents overflow file */ ++ u_int32_t drCTFlSize; /* size of catalog file */ ++ HFSExtentRecord drCTExtRec; /* extent record for catalog file */ ++}PACKED_S; ++typedef struct HFSMasterDirectoryBlock HFSMasterDirectoryBlock; ++ ++ ++#ifdef __APPLE_API_UNSTABLE ++#define SET_HFS_TEXT_ENCODING(hint) \ ++ (0x656e6300 | ((hint) & 0xff)) ++#define GET_HFS_TEXT_ENCODING(hint) \ ++ (((hint) & 0xffffff00) == 0x656e6300 ? (hint) & 0x000000ff : 0xffffffffU) ++#endif /* __APPLE_API_UNSTABLE */ ++ ++ ++/* HFS Plus Volume Header - 512 bytes */ ++/* Stored at sector #2 (3rd sector) and second-to-last sector. */ ++struct HFSPlusVolumeHeader { ++ u_int16_t signature; /* == kHFSPlusSigWord */ ++ u_int16_t version; /* == kHFSPlusVersion */ ++ u_int32_t attributes; /* volume attributes */ ++ u_int32_t lastMountedVersion; /* implementation version which last mounted volume */ ++ u_int32_t journalInfoBlock; /* block addr of journal info (if volume is journaled, zero otherwise) */ ++ ++ u_int32_t createDate; /* date and time of volume creation */ ++ u_int32_t modifyDate; /* date and time of last modification */ ++ u_int32_t backupDate; /* date and time of last backup */ ++ u_int32_t checkedDate; /* date and time of last disk check */ ++ ++ u_int32_t fileCount; /* number of files in volume */ ++ u_int32_t folderCount; /* number of directories in volume */ ++ ++ u_int32_t blockSize; /* size (in bytes) of allocation blocks */ ++ u_int32_t totalBlocks; /* number of allocation blocks in volume (includes this header and VBM*/ ++ u_int32_t freeBlocks; /* number of unused allocation blocks */ ++ ++ u_int32_t nextAllocation; /* start of next allocation search */ ++ u_int32_t rsrcClumpSize; /* default resource fork clump size */ ++ u_int32_t dataClumpSize; /* default data fork clump size */ ++ u_int32_t nextCatalogID; /* next unused catalog node ID */ ++ ++ u_int32_t writeCount; /* volume write count */ ++ u_int64_t encodingsBitmap; /* which encodings have been use on this volume */ ++ ++ u_int8_t finderInfo[32]; /* information used by the Finder */ ++ ++ HFSPlusForkData allocationFile; /* allocation bitmap file */ ++ HFSPlusForkData extentsFile; /* extents B-tree file */ ++ HFSPlusForkData catalogFile; /* catalog B-tree file */ ++ HFSPlusForkData attributesFile; /* extended attributes B-tree file */ ++ HFSPlusForkData startupFile; /* boot file (secondary loader) */ ++}PACKED_S; ++typedef struct HFSPlusVolumeHeader HFSPlusVolumeHeader; ++ ++ ++/* B-tree structures */ ++ ++enum BTreeKeyLimits{ ++ kMaxKeyLength = 520 ++}PACKED_S; ++ ++union BTreeKey{ ++ u_int8_t length8; ++ u_int16_t length16; ++ u_int8_t rawData [kMaxKeyLength+2]; ++}PACKED_S; ++typedef union BTreeKey BTreeKey; ++ ++/* BTNodeDescriptor -- Every B-tree node starts with these fields. */ ++struct BTNodeDescriptor { ++ u_int32_t fLink; /* next node at this level*/ ++ u_int32_t bLink; /* previous node at this level*/ ++ int8_t kind; /* kind of node (leaf, index, header, map)*/ ++ u_int8_t height; /* zero for header, map; child is one more than parent*/ ++ u_int16_t numRecords; /* number of records in this node*/ ++ u_int16_t reserved; /* reserved - initialized as zero */ ++}PACKED_S; ++typedef struct BTNodeDescriptor BTNodeDescriptor; ++ ++/* Constants for BTNodeDescriptor kind */ ++enum { ++ kBTLeafNode = -1, ++ kBTIndexNode = 0, ++ kBTHeaderNode = 1, ++ kBTMapNode = 2 ++}PACKED_S; ++ ++/* BTHeaderRec -- The first record of a B-tree header node */ ++struct BTHeaderRec { ++ u_int16_t treeDepth; /* maximum height (usually leaf nodes) */ ++ u_int32_t rootNode; /* node number of root node */ ++ u_int32_t leafRecords; /* number of leaf records in all leaf nodes */ ++ u_int32_t firstLeafNode; /* node number of first leaf node */ ++ u_int32_t lastLeafNode; /* node number of last leaf node */ ++ u_int16_t nodeSize; /* size of a node, in bytes */ ++ u_int16_t maxKeyLength; /* reserved */ ++ u_int32_t totalNodes; /* total number of nodes in tree */ ++ u_int32_t freeNodes; /* number of unused (free) nodes in tree */ ++ u_int16_t reserved1; /* unused */ ++ u_int32_t clumpSize; /* reserved */ ++ u_int8_t btreeType; /* reserved */ ++ u_int8_t keyCompareType; /* Key string Comparison Type */ ++ u_int32_t attributes; /* persistent attributes about the tree */ ++ u_int32_t reserved3[16]; /* reserved */ ++}PACKED_S; ++typedef struct BTHeaderRec BTHeaderRec; ++ ++/* Constants for BTHeaderRec attributes */ ++enum { ++ kBTBadCloseMask = 0x00000001, /* reserved */ ++ kBTBigKeysMask = 0x00000002, /* key length field is 16 bits */ ++ kBTVariableIndexKeysMask = 0x00000004 /* keys in index nodes are variable length */ ++}PACKED_S; ++ ++ ++/* Catalog Key Name Comparison Type */ ++enum { ++ kHFSCaseFolding = 0xCF, /* case folding (case-insensitive) */ ++ kHFSBinaryCompare = 0xBC /* binary compare (case-sensitive) */ ++}PACKED_S; ++ ++/* JournalInfoBlock - Structure that describes where our journal lives */ ++struct JournalInfoBlock { ++ u_int32_t flags; ++ u_int32_t device_signature[8]; // signature used to locate our device. ++ u_int64_t offset; // byte offset to the journal on the device ++ u_int64_t size; // size in bytes of the journal ++ u_int32_t reserved[32]; ++}PACKED_S; ++typedef struct JournalInfoBlock JournalInfoBlock; ++ ++enum { ++ kJIJournalInFSMask = 0x00000001, ++ kJIJournalOnOtherDeviceMask = 0x00000002, ++ kJIJournalNeedInitMask = 0x00000004 ++}PACKED_S; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __HFS_FORMAT__ */ +diff -druN diskdev_cmds-332.14/include/hfs/hfs_mount.h diskdev_cmds-332.14-patched/include/hfs/hfs_mount.h +--- diskdev_cmds-332.14/include/hfs/hfs_mount.h 1970-01-01 01:00:00.000000000 +0100 ++++ diskdev_cmds-332.14-patched/include/hfs/hfs_mount.h 2008-07-01 22:30:11.000000000 +0200 +@@ -0,0 +1,78 @@ ++/* ++ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. ++ * ++ * @APPLE_LICENSE_HEADER_START@ ++ * ++ * The contents of this file constitute Original Code as defined in and ++ * are subject to the Apple Public Source License Version 1.1 (the ++ * "License"). You may not use this file except in compliance with the ++ * License. Please obtain a copy of the License at ++ * http://www.apple.com/publicsource and read it before using this file. ++ * ++ * This Original Code and all software distributed under the License are ++ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ++ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ++ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ++ * License for the specific language governing rights and limitations ++ * under the License. ++ * ++ * @APPLE_LICENSE_HEADER_END@ ++ */ ++/* ++ * Copyright (c) 1997-2002 Apple Computer, Inc. All Rights Reserved ++ * ++ */ ++ ++#ifndef _HFS_MOUNT_H_ ++#define _HFS_MOUNT_H_ ++ ++#include ++ ++#include ++#include ++ ++/* ++ * Arguments to mount HFS-based filesystems ++ */ ++ ++#define OVERRIDE_UNKNOWN_PERMISSIONS 0 ++ ++#define UNKNOWNUID ((uid_t)99) ++#define UNKNOWNGID ((gid_t)99) ++#define UNKNOWNPERMISSIONS (S_IRWXU | S_IROTH | S_IXOTH) /* 705 */ ++ ++#ifdef __APPLE_API_UNSTABLE ++struct hfs_mount_args { ++#ifndef KERNEL ++ char *fspec; /* block special device to mount */ ++#endif ++ uid_t hfs_uid; /* uid that owns hfs files (standard HFS only) */ ++ gid_t hfs_gid; /* gid that owns hfs files (standard HFS only) */ ++ mode_t hfs_mask; /* mask to be applied for hfs perms (standard HFS only) */ ++ u_int32_t hfs_encoding; /* encoding for this volume (standard HFS only) */ ++ struct timezone hfs_timezone; /* user time zone info (standard HFS only) */ ++ int flags; /* mounting flags, see below */ ++ int journal_tbuffer_size; /* size in bytes of the journal transaction buffer */ ++ int journal_flags; /* flags to pass to journal_open/create */ ++ int journal_disable; /* don't use journaling (potentially dangerous) */ ++}; ++ ++#define HFSFSMNT_NOXONFILES 0x1 /* disable execute permissions for files */ ++#define HFSFSMNT_WRAPPER 0x2 /* mount HFS wrapper (if it exists) */ ++#define HFSFSMNT_EXTENDED_ARGS 0x4 /* indicates new fields after "flags" are valid */ ++ ++/* ++ * Sysctl values for HFS ++ */ ++#define HFS_ENCODINGBIAS 1 /* encoding matching CJK bias */ ++#define HFS_EXTEND_FS 2 ++#define HFS_ENCODINGHINT 3 /* guess encoding for string */ ++#define HFS_ENABLE_JOURNALING 0x082969 ++#define HFS_DISABLE_JOURNALING 0x031272 ++#define HFS_GET_JOURNAL_INFO 0x6a6e6c69 ++#define HFS_SET_PKG_EXTENSIONS 0x121031 ++ ++#endif /* __APPLE_API_UNSTABLE */ ++ ++#endif /* ! _HFS_MOUNT_H_ */ +diff -druN diskdev_cmds-332.14/include/missing.h diskdev_cmds-332.14-patched/include/missing.h +--- diskdev_cmds-332.14/include/missing.h 1970-01-01 01:00:00.000000000 +0100 ++++ diskdev_cmds-332.14-patched/include/missing.h 2008-07-01 22:30:11.000000000 +0200 +@@ -0,0 +1,113 @@ ++#ifndef _MISSING_H_ ++#define _MISSING_H_ ++ ++#include ++#include ++#include ++#include ++ ++#define MAXBSIZE (256 * 4096) ++ ++#ifndef true ++#define true 1 ++#endif ++#ifndef false ++#define false 0 ++#endif ++ ++/* Mac types */ ++ ++/* 8 Bit */ ++#ifndef UInt8 ++#define UInt8 uint8_t ++#endif ++#ifndef u_int8_t ++#define u_int8_t UInt8 ++#endif ++#ifndef SInt8 ++#define SInt8 int8_t ++#endif ++ ++/* 16 Bit */ ++#ifndef UInt16 ++#define UInt16 uint16_t ++#endif ++#ifndef u_int16_t ++#define u_int16_t UInt16 ++#endif ++#ifndef SInt16 ++#define SInt16 int16_t ++#endif ++ ++/* 32 Bit */ ++#ifndef UInt32 ++#define UInt32 uint32_t ++#endif ++#ifndef u_int32_t ++#define u_int32_t UInt32 ++#endif ++#ifndef SInt32 ++#define SInt32 int32_t ++#endif ++ ++/* 64 Bit */ ++#ifndef UInt64 ++#define UInt64 uint64_t ++#endif ++#ifndef u_int64_t ++#define u_int64_t UInt64 ++#endif ++#ifndef SInt64 ++#define SInt64 int64_t ++#endif ++ ++#define UniChar u_int16_t ++#define Boolean u_int8_t ++ ++#define UF_NODUMP 0x00000001 ++ ++/* syslimits.h */ ++#define NAME_MAX 255 ++ ++/* Byteswap stuff */ ++#define NXSwapHostLongToBig(x) cpu_to_be64(x) ++#define NXSwapBigShortToHost(x) be16_to_cpu(x) ++#define OSSwapBigToHostInt16(x) be16_to_cpu(x) ++#define NXSwapBigLongToHost(x) be32_to_cpu(x) ++#define OSSwapBigToHostInt32(x) be32_to_cpu(x) ++#define NXSwapBigLongLongToHost(x) be64_to_cpu(x) ++#define OSSwapBigToHostInt64(x) be64_to_cpu(x) ++ ++#if __BYTE_ORDER == __LITTLE_ENDIAN ++/* Big Endian Swaps */ ++#ifndef be16_to_cpu ++#define be16_to_cpu(x) bswap_16(x) ++#endif ++#ifndef be32_to_cpu ++#define be32_to_cpu(x) bswap_32(x) ++#endif ++#ifndef be64_to_cpu ++#define be64_to_cpu(x) bswap_64(x) ++#endif ++#ifndef cpu_to_be64 ++#define cpu_to_be64(x) bswap_64(x) ++#endif ++#elif __BYTE_ORDER == __BIG_ENDIAN ++/* Big endian doesn't swap */ ++#ifndef be16_to_cpu ++#define be16_to_cpu(x) (x) ++#endif ++#ifndef be32_to_cpu ++#define be32_to_cpu(x) (x) ++#endif ++#ifndef be64_to_cpu ++#define be64_to_cpu(x) (x) ++#endif ++#ifndef cpu_to_be64 ++#define cpu_to_be64(x) (x) ++#endif ++#endif ++ ++#define KAUTH_FILESEC_XATTR "com.apple.system.Security" ++ ++#endif +diff -druN diskdev_cmds-332.14/include/sys/appleapiopts.h diskdev_cmds-332.14-patched/include/sys/appleapiopts.h +--- diskdev_cmds-332.14/include/sys/appleapiopts.h 1970-01-01 01:00:00.000000000 +0100 ++++ diskdev_cmds-332.14-patched/include/sys/appleapiopts.h 2008-07-01 22:30:11.000000000 +0200 +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. ++ * ++ * @APPLE_LICENSE_HEADER_START@ ++ * ++ * The contents of this file constitute Original Code as defined in and ++ * are subject to the Apple Public Source License Version 1.1 (the ++ * "License"). You may not use this file except in compliance with the ++ * License. Please obtain a copy of the License at ++ * http://www.apple.com/publicsource and read it before using this file. ++ * ++ * This Original Code and all software distributed under the License are ++ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ++ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ++ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ++ * License for the specific language governing rights and limitations ++ * under the License. ++ * ++ * @APPLE_LICENSE_HEADER_END@ ++ */ ++ ++#ifndef __SYS_APPLEAPIOPTS_H__ ++#define __SYS_APPLEAPIOPTS_H__ ++ ++ ++#ifndef __APPLE_API_STANDARD ++#define __APPLE_API_STANDARD ++#endif /* __APPLE_API_STANDARD */ ++ ++#ifndef __APPLE_API_STABLE ++#define __APPLE_API_STABLE ++#endif /* __APPLE_API_STABLE */ ++ ++#ifndef __APPLE_API_STRICT_CONFORMANCE ++ ++#ifndef __APPLE_API_EVOLVING ++#define __APPLE_API_EVOLVING ++#endif /* __APPLE_API_EVOLVING */ ++ ++#ifndef __APPLE_API_UNSTABLE ++#define __APPLE_API_UNSTABLE ++#endif /* __APPLE_API_UNSTABLE */ ++ ++#ifndef __APPLE_API_PRIVATE ++#define __APPLE_API_PRIVATE ++#endif /* __APPLE_API_PRIVATE */ ++ ++#ifndef __APPLE_API_OBSOLETE ++#define __APPLE_API_OBSOLETE ++#endif /* __APPLE_API_OBSOLETE */ ++ ++#endif /* __APPLE_API_STRICT_CONFORMANCE */ ++ ++#endif /* __SYS_APPLEAPIOPTS_H__ */ ++ +diff -druN diskdev_cmds-332.14/Makefile.lnx diskdev_cmds-332.14-patched/Makefile.lnx +--- diskdev_cmds-332.14/Makefile.lnx 1970-01-01 01:00:00.000000000 +0100 ++++ diskdev_cmds-332.14-patched/Makefile.lnx 2008-07-01 22:30:11.000000000 +0200 +@@ -0,0 +1,8 @@ ++CC := gcc ++CFLAGS := -g3 -Wall -I$(PWD)/include -DDEBUG_BUILD=0 -D_FILE_OFFSET_BITS=64 -D LINUX=1 -D BSD=1 ++SUBDIRS := newfs_hfs.tproj fsck_hfs.tproj ++ ++all clean: ++ for d in $(SUBDIRS); do $(MAKE) -C $$d -f Makefile.lnx $@; done ++ ++export CC CFLAGS +diff -druN diskdev_cmds-332.14/newfs_hfs.tproj/hfs_endian.c diskdev_cmds-332.14-patched/newfs_hfs.tproj/hfs_endian.c +--- diskdev_cmds-332.14/newfs_hfs.tproj/hfs_endian.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/newfs_hfs.tproj/hfs_endian.c 2008-07-01 22:30:11.000000000 +0200 +@@ -30,7 +30,12 @@ + #include + #include + ++#if LINUX ++#include "missing.h" ++#else + #include ++#endif ++ + #include + + #include "hfs_endian.h" +diff -druN diskdev_cmds-332.14/newfs_hfs.tproj/hfs_endian.h diskdev_cmds-332.14-patched/newfs_hfs.tproj/hfs_endian.h +--- diskdev_cmds-332.14/newfs_hfs.tproj/hfs_endian.h 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/newfs_hfs.tproj/hfs_endian.h 2008-07-01 22:30:11.000000000 +0200 +@@ -29,7 +29,12 @@ + * volume format. + */ + #include ++#if LINUX ++#include ++#include ++#else + #include ++#endif + + /*********************/ + /* BIG ENDIAN Macros */ +Files diskdev_cmds-332.14/newfs_hfs.tproj/hfs_endian.o and diskdev_cmds-332.14-patched/newfs_hfs.tproj/hfs_endian.o differ +diff -druN diskdev_cmds-332.14/newfs_hfs.tproj/Makefile.lnx diskdev_cmds-332.14-patched/newfs_hfs.tproj/Makefile.lnx +--- diskdev_cmds-332.14/newfs_hfs.tproj/Makefile.lnx 1970-01-01 01:00:00.000000000 +0100 ++++ diskdev_cmds-332.14-patched/newfs_hfs.tproj/Makefile.lnx 2008-07-01 22:30:11.000000000 +0200 +@@ -0,0 +1,12 @@ ++CFILES = hfs_endian.c makehfs.c newfs_hfs.c ++OFILES = $(CFILES:.c=.o) ++ ++all: newfs_hfs ++ ++newfs_hfs: $(OFILES) ++ ${CC} ${CFLAGS} -o newfs_hfs ${OFILES} -lcrypto ++ ++clean: ++ $(RM) newfs_hfs $(OFILES) ++ ++.PHONY : FORCE clean +diff -druN diskdev_cmds-332.14/newfs_hfs.tproj/makehfs.c diskdev_cmds-332.14-patched/newfs_hfs.tproj/makehfs.c +--- diskdev_cmds-332.14/newfs_hfs.tproj/makehfs.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/newfs_hfs.tproj/makehfs.c 2008-07-01 22:36:05.000000000 +0200 +@@ -31,10 +31,16 @@ + #include + #include + #include ++#if LINUX ++#include ++#include "missing.h" ++#endif + #include + #include + #include ++#if !LINUX + #include ++#endif + + #include + #include +@@ -47,13 +53,14 @@ + + #include + ++#if !LINUX + #include + + #include + #include + + extern Boolean _CFStringGetFileSystemRepresentation(CFStringRef string, UInt8 *buffer, CFIndex maxBufLen); +- ++#endif + + #include + #include +@@ -63,7 +70,7 @@ + #include "readme.h" + + +-#define HFS_BOOT_DATA "/usr/share/misc/hfsbootdata" ++#define HFS_BOOT_DATA "/usr/share/hfsprogs/hfsbootdata" + + #define HFS_JOURNAL_FILE ".journal" + #define HFS_JOURNAL_INFO ".journal_info_block" +@@ -129,7 +136,9 @@ + static void MarkBitInAllocationBuffer __P((HFSPlusVolumeHeader *header, + UInt32 allocationBlock, void* sectorBuffer, UInt32 *sector)); + ++#if !LINUX + static UInt32 GetDefaultEncoding(); ++#endif + + static UInt32 UTCToLocal __P((UInt32 utcTime)); + +@@ -158,11 +167,14 @@ + + #define ROUNDUP(x, u) (((x) % (u) == 0) ? (x) : ((x)/(u) + 1) * (u)) + +-#define ENCODING_TO_BIT(e) \ ++#if LINUX ++#define ENCODING_TO_BIT(e) (e) ++#else ++#define ENCODING_TO_BIT(e) + ((e) < 48 ? (e) : \ + ((e) == kCFStringEncodingMacUkrainian ? 48 : \ + ((e) == kCFStringEncodingMacFarsi ? 49 : 0))) +- ++#endif + /* + * make_hfs + * +@@ -528,6 +540,7 @@ + * Map UTF-8 input into a Mac encoding. + * On conversion errors "untitled" is used as a fallback. + */ ++#if !LINUX + { + UniChar unibuf[kHFSMaxVolumeNameChars]; + CFStringRef cfstr; +@@ -553,7 +566,11 @@ + bcopy(&mdbp->drVN[1], defaults->volumeName, mdbp->drVN[0]); + defaults->volumeName[mdbp->drVN[0]] = '\0'; + } ++#endif + /* Save the encoding hint in the Finder Info (field 4). */ ++ mdbp->drVN[0] = strlen(defaults->volumeName); ++ bcopy(defaults->volumeName,&mdbp->drVN[1],mdbp->drVN[0]); ++ + mdbp->drFndrInfo[4] = SET_HFS_TEXT_ENCODING(defaults->encodingHint); + + mdbp->drWrCnt = kWriteSeqNum; +@@ -1100,9 +1117,11 @@ + UInt16 nodeSize; + SInt16 offset; + UInt32 unicodeBytes; ++#if !LINUX + UInt8 canonicalName[256]; + CFStringRef cfstr; + Boolean cfOK; ++#endif + int index = 0; + + nodeSize = dp->catalogNodeSize; +@@ -1122,7 +1141,9 @@ + * First record is always the root directory... + */ + ckp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset); +- ++#if LINUX ++ ConvertUTF8toUnicode(dp->volumeName, sizeof(ckp->nodeName.unicode), ckp->nodeName.unicode, &ckp->nodeName.length); ++#else + /* Use CFString functions to get a HFSPlus Canonical name */ + cfstr = CFStringCreateWithCString(kCFAllocatorDefault, (char *)dp->volumeName, kCFStringEncodingUTF8); + cfOK = _CFStringGetFileSystemRepresentation(cfstr, canonicalName, sizeof(canonicalName)); +@@ -1139,6 +1160,7 @@ + dp->volumeName, kDefaultVolumeNameStr); + } + CFRelease(cfstr); ++#endif + ckp->nodeName.length = SWAP_BE16 (ckp->nodeName.length); + + unicodeBytes = sizeof(UniChar) * SWAP_BE16 (ckp->nodeName.length); +@@ -1821,15 +1843,15 @@ + off_t sector; + + if ((byteCount % driveInfo->sectorSize) != 0) +- errx(1, "WriteBuffer: byte count %ld is not sector size multiple", byteCount); ++ errx(1, "WriteBuffer: byte count %i is not sector size multiple", byteCount); + + sector = driveInfo->sectorOffset + startingSector; + + if (lseek(driveInfo->fd, sector * driveInfo->sectorSize, SEEK_SET) < 0) +- err(1, "seek (sector %qd)", sector); ++ err(1, "seek (sector %lld)", sector); + + if (write(driveInfo->fd, buffer, byteCount) != byteCount) +- err(1, "write (sector %qd, %ld bytes)", sector, byteCount); ++ err(1, "write (sector %lld, %i bytes)", sector, byteCount); + } + + +@@ -1913,7 +1935,7 @@ + return quotient; + } + +- ++#if !LINUX + #define __kCFUserEncodingFileName ("/.CFUserTextEncoding") + + static UInt32 +@@ -1939,7 +1961,7 @@ + } + return 0; + } +- ++#endif + + static int + ConvertUTF8toUnicode(const UInt8* source, UInt32 bufsize, UniChar* unibuf, +@@ -2006,6 +2028,9 @@ + static int + getencodinghint(unsigned char *name) + { ++#if LINUX ++ return(0); ++#else + int mib[3]; + size_t buflen = sizeof(int); + struct vfsconf vfc; +@@ -2023,7 +2048,8 @@ + return (hint); + error: + hint = GetDefaultEncoding(); +- return (hint); ++ return (0); ++#endif + } + + +@@ -2034,12 +2060,14 @@ + unsigned char digest[20]; + time_t now; + clock_t uptime; +- int mib[2]; +- int sysdata; +- char sysctlstring[128]; + size_t datalen; + double sysloadavg[3]; ++#if !LINUX ++ int sysdata; ++ int mib[2]; ++ char sysctlstring[128]; + struct vmtotal sysvmtotal; ++#endif + + do { + /* Initialize the SHA-1 context for processing: */ +@@ -2052,52 +2080,58 @@ + SHA1_Update(&context, &uptime, sizeof(uptime)); + + /* The kernel's boot time: */ ++#if !LINUX + mib[0] = CTL_KERN; + mib[1] = KERN_BOOTTIME; + datalen = sizeof(sysdata); + sysctl(mib, 2, &sysdata, &datalen, NULL, 0); + SHA1_Update(&context, &sysdata, datalen); +- ++#endif + /* The system's host id: */ ++#if !LINUX + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTID; + datalen = sizeof(sysdata); + sysctl(mib, 2, &sysdata, &datalen, NULL, 0); + SHA1_Update(&context, &sysdata, datalen); +- ++#endif + /* The system's host name: */ ++#if !LINUX + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTNAME; + datalen = sizeof(sysctlstring); + sysctl(mib, 2, sysctlstring, &datalen, NULL, 0); + SHA1_Update(&context, sysctlstring, datalen); +- ++#endif + /* The running kernel's OS release string: */ ++#if !LINUX + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELEASE; + datalen = sizeof(sysctlstring); + sysctl(mib, 2, sysctlstring, &datalen, NULL, 0); + SHA1_Update(&context, sysctlstring, datalen); +- ++#endif + /* The running kernel's version string: */ ++#if !LINUX + mib[0] = CTL_KERN; + mib[1] = KERN_VERSION; + datalen = sizeof(sysctlstring); + sysctl(mib, 2, sysctlstring, &datalen, NULL, 0); + SHA1_Update(&context, sysctlstring, datalen); +- ++#endif + /* The system's load average: */ + datalen = sizeof(sysloadavg); + getloadavg(sysloadavg, 3); + SHA1_Update(&context, &sysloadavg, datalen); + + /* The system's VM statistics: */ ++#if !LINUX + mib[0] = CTL_VM; + mib[1] = VM_METER; + datalen = sizeof(sysvmtotal); + sysctl(mib, 2, &sysvmtotal, &datalen, NULL, 0); + SHA1_Update(&context, &sysvmtotal, datalen); +- ++#endif + /* The current GMT (26 ASCII characters): */ + time(&now); + strncpy(randomInputBuffer, asctime(gmtime(&now)), 26); /* "Mon Mar 27 13:46:26 2000" */ +Files diskdev_cmds-332.14/newfs_hfs.tproj/makehfs.o and diskdev_cmds-332.14-patched/newfs_hfs.tproj/makehfs.o differ +Files diskdev_cmds-332.14/newfs_hfs.tproj/newfs_hfs and diskdev_cmds-332.14-patched/newfs_hfs.tproj/newfs_hfs differ +diff -druN diskdev_cmds-332.14/newfs_hfs.tproj/newfs_hfs.8 diskdev_cmds-332.14-patched/newfs_hfs.tproj/newfs_hfs.8 +--- diskdev_cmds-332.14/newfs_hfs.tproj/newfs_hfs.8 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/newfs_hfs.tproj/newfs_hfs.8 2008-07-01 22:35:53.000000000 +0200 +@@ -93,7 +93,7 @@ + option followed by a comma + separated list of the form arg=blocks. + .Pp +-Example: -c c=5000,e=500 ++Example: \-c c=5000,e=500 + .Bl -tag -width Fl + .It Em a=blocks + Set the attribute file clump size. +@@ -126,7 +126,7 @@ + size must be a power of two and no larger than + 32768 bytes. + .Pp +-Example: -n c=8192,e=4096 ++Example: \-n c=8192,e=4096 + .Bl -tag -width Fl + .It Em a=bytes + Set the attribute b-tree node size. +diff -druN diskdev_cmds-332.14/newfs_hfs.tproj/newfs_hfs.c diskdev_cmds-332.14-patched/newfs_hfs.tproj/newfs_hfs.c +--- diskdev_cmds-332.14/newfs_hfs.tproj/newfs_hfs.c 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/newfs_hfs.tproj/newfs_hfs.c 2008-07-01 22:30:11.000000000 +0200 +@@ -38,8 +38,13 @@ + #include + #include + #include ++#if LINUX ++#include ++#endif + ++#if !LINUX + #include ++#endif + + #include + #include "newfs_hfs.h" +@@ -73,7 +78,9 @@ + + char *progname; + char gVolumeName[kHFSPlusMaxFileNameChars + 1] = {kDefaultVolumeNameStr}; +-char rawdevice[MAXPATHLEN]; ++#if !LINUX ++char rawdevice[MAXPATHLEN]; ++#endif + char blkdevice[MAXPATHLEN]; + UInt32 gBlockSize = 0; + UInt32 gNextCNID = kHFSFirstUserCatalogNodeID; +@@ -137,8 +144,10 @@ + extern int optind; + int ch; + int forceHFS; ++#if !LINUX + char *cp, *special; + struct statfs *mp; ++#endif + int n; + + if ((progname = strrchr(*argv, '/'))) +@@ -238,7 +247,9 @@ + + if (argc != 1) + usage(); +- ++#if LINUX ++ (void) sprintf(blkdevice, "%s", argv[0]); ++#else + special = argv[0]; + cp = strrchr(special, '/'); + if (cp != 0) +@@ -247,6 +258,7 @@ + special++; + (void) sprintf(rawdevice, "%sr%s", _PATH_DEV, special); + (void) sprintf(blkdevice, "%s%s", _PATH_DEV, special); ++#endif + + if (forceHFS && gJournaled) { + fprintf(stderr, "-h -J: incompatible options specified\n"); +@@ -268,6 +280,9 @@ + /* + * Check if target device is aready mounted + */ ++#if LINUX ++ // FIXME ++#else + n = getmntinfo(&mp, MNT_NOWAIT); + if (n == 0) + fatal("%s: getmntinfo: %s", blkdevice, strerror(errno)); +@@ -277,14 +292,19 @@ + fatal("%s is mounted on %s", blkdevice, mp->f_mntonname); + ++mp; + } ++#endif + +- if (hfs_newfs(rawdevice, forceHFS, true) < 0) { ++ if (hfs_newfs(blkdevice, forceHFS, true) < 0) { ++#if LINUX ++ err(1, NULL); ++#else + /* On ENXIO error use the block device (to get de-blocking) */ + if (errno == ENXIO) { + if (hfs_newfs(blkdevice, forceHFS, false) < 0) + err(1, NULL); + } else + err(1, NULL); ++#endif + } + + exit(0); +@@ -458,7 +478,7 @@ + fatal("%s: block size is too small for %lld sectors", optarg, gBlockSize, sectorCount); + + if (gBlockSize < HFSOPTIMALBLKSIZE) +- warnx("Warning: %ld is a non-optimal block size (4096 would be a better choice)", gBlockSize); ++ warnx("Warning: %i is a non-optimal block size (4096 would be a better choice)", gBlockSize); + } + } + +@@ -472,7 +492,9 @@ + int fso = 0; + int retval = 0; + hfsparams_t defaults = {0}; ++#if !LINUX + u_int64_t maxSectorsPerIO; ++#endif + + if (gNoCreate) { + fso = open( device, O_RDONLY | O_NDELAY, 0 ); +@@ -485,7 +507,33 @@ + + if (fstat( fso, &stbuf) < 0) + fatal("%s: %s", device, strerror(errno)); ++#if LINUX ++ dip.sectorSize = 512; ++ dip.sectorsPerIO = 256; + ++#ifndef BLKGETSIZE ++#define BLKGETSIZE _IO(0x12,96) ++#endif ++#ifndef BLKGETSIZE64 ++#define BLKGETSIZE64 _IOR(0x12,114,size_t) ++#endif ++ ++ if (S_ISREG(stbuf.st_mode)) { ++ dip.totalSectors = stbuf.st_size / 512; ++ } ++ else if (S_ISBLK(stbuf.st_mode)) { ++ unsigned long size; ++ u_int64_t size64; ++ if (!ioctl(fso, BLKGETSIZE64, &size64)) ++ dip.totalSectors = size64 / 512; ++ else if (!ioctl(fso, BLKGETSIZE, &size)) ++ dip.totalSectors = size; ++ else ++ fatal("%s: %s", device, strerror(errno)); ++ } ++ else ++ fatal("%s: is not a block device", device); ++#else + if (ioctl(fso, DKIOCGETBLOCKCOUNT, &dip.totalSectors) < 0) + fatal("%s: %s", device, strerror(errno)); + +@@ -493,14 +541,17 @@ + fatal("%s: %s", device, strerror(errno)); + + if (ioctl(fso, DKIOCGETMAXBLOCKCOUNTWRITE, &maxSectorsPerIO) < 0) +- dip.sectorsPerIO = (128 * 1024) / dip.sectorSize; /* use 128K as default */ ++ dip.sectorsPerIO = (128 * 1024) / dip.sectorSize; /* use 128K as default */ + else + dip.sectorsPerIO = MIN(maxSectorsPerIO, (1024 * 1024) / dip.sectorSize); ++#endif ++ + /* +- * The make_hfs code currentlydoes 512 byte sized I/O. ++ * The make_hfs code currently does 512 byte sized I/O. + * If the sector size is bigger than 512, start over + * using the block device (to get de-blocking). + */ ++#if !LINUX + if (dip.sectorSize != kBytesPerSector) { + if (isRaw) { + close(fso); +@@ -515,7 +566,8 @@ + dip.sectorSize = kBytesPerSector; + } + } +- ++#endif ++ + dip.fd = fso; + dip.sectorOffset = 0; + time(&createtime); +@@ -693,7 +745,7 @@ + defaults->catalogClumpSize = clumpSize; + defaults->catalogNodeSize = catnodesiz; + if (gBlockSize < 4096 && gBlockSize < catnodesiz) +- warnx("Warning: block size %ld is less than catalog b-tree node size %ld", gBlockSize, catnodesiz); ++ warnx("Warning: block size %i is less than catalog b-tree node size %i", gBlockSize, catnodesiz); + + if (extclumpblks == 0) { + clumpSize = CalcHFSPlusBTreeClumpSize(gBlockSize, extnodesiz, sectorCount, FALSE); +@@ -706,7 +758,7 @@ + defaults->extentsClumpSize = clumpSize; + defaults->extentsNodeSize = extnodesiz; + if (gBlockSize < extnodesiz) +- warnx("Warning: block size %ld is less than extents b-tree node size %ld", gBlockSize, extnodesiz); ++ warnx("Warning: block size %i is less than extents b-tree node size %i", gBlockSize, extnodesiz); + + if (atrclumpblks == 0) { + clumpSize = 0; +@@ -754,22 +806,22 @@ + + if (gNoCreate) { + if (!gWrapper) +- printf("%qd sectors (%lu bytes per sector)\n", sectorCount, sectorSize); ++ printf("%lld sectors (%u bytes per sector)\n", sectorCount, sectorSize); + printf("HFS Plus format parameters:\n"); + printf("\tvolume name: \"%s\"\n", gVolumeName); +- printf("\tblock-size: %lu\n", defaults->blockSize); +- printf("\ttotal blocks: %lu\n", totalBlocks); ++ printf("\tblock-size: %u\n", defaults->blockSize); ++ printf("\ttotal blocks: %u\n", totalBlocks); + if (gJournaled) + printf("\tjournal-size: %dk\n", (int)defaults->journalSize/1024); +- printf("\tfirst free catalog node id: %lu\n", defaults->nextFreeFileID); +- printf("\tcatalog b-tree node size: %lu\n", defaults->catalogNodeSize); +- printf("\tinitial catalog file size: %lu\n", defaults->catalogClumpSize); +- printf("\textents b-tree node size: %lu\n", defaults->extentsNodeSize); +- printf("\tinitial extents file size: %lu\n", defaults->extentsClumpSize); +- printf("\tinitial allocation file size: %lu (%lu blocks)\n", ++ printf("\tfirst free catalog node id: %u\n", defaults->nextFreeFileID); ++ printf("\tcatalog b-tree node size: %u\n", defaults->catalogNodeSize); ++ printf("\tinitial catalog file size: %u\n", defaults->catalogClumpSize); ++ printf("\textents b-tree node size: %u\n", defaults->extentsNodeSize); ++ printf("\tinitial extents file size: %u\n", defaults->extentsClumpSize); ++ printf("\tinitial allocation file size: %u (%u blocks)\n", + defaults->allocationClumpSize, defaults->allocationClumpSize / gBlockSize); +- printf("\tdata fork clump size: %lu\n", defaults->dataClumpSize); +- printf("\tresource fork clump size: %lu\n", defaults->rsrcClumpSize); ++ printf("\tdata fork clump size: %u\n", defaults->dataClumpSize); ++ printf("\tresource fork clump size: %u\n", defaults->rsrcClumpSize); + if (defaults->flags & kUseAccessPerms) { + printf("\tuser ID: %d\n", (int)defaults->owner); + printf("\tgroup ID: %d\n", (int)defaults->group); +@@ -844,17 +896,17 @@ + } + + if (gNoCreate) { +- printf("%ld sectors at %ld bytes per sector\n", sectorCount, sectorSize); ++ printf("%i sectors at %i bytes per sector\n", sectorCount, sectorSize); + printf("%s format parameters:\n", gWrapper ? "HFS Wrapper" : "HFS"); + printf("\tvolume name: \"%s\"\n", gVolumeName); +- printf("\tblock-size: %ld\n", defaults->blockSize); +- printf("\ttotal blocks: %ld\n", sectorCount / (alBlkSize / sectorSize) ); +- printf("\tfirst free catalog node id: %ld\n", defaults->nextFreeFileID); +- printf("\tinitial catalog file size: %ld\n", defaults->catalogClumpSize); +- printf("\tinitial extents file size: %ld\n", defaults->extentsClumpSize); +- printf("\tfile clump size: %ld\n", defaults->dataClumpSize); ++ printf("\tblock-size: %i\n", defaults->blockSize); ++ printf("\ttotal blocks: %i\n", sectorCount / (alBlkSize / sectorSize) ); ++ printf("\tfirst free catalog node id: %i\n", defaults->nextFreeFileID); ++ printf("\tinitial catalog file size: %i\n", defaults->catalogClumpSize); ++ printf("\tinitial extents file size: %i\n", defaults->extentsClumpSize); ++ printf("\tfile clump size: %i\n", defaults->dataClumpSize); + if (hfsgrowblks) +- printf("\twrapper growable from %ld to %ld sectors\n", sectorCount, hfsgrowblks); ++ printf("\twrapper growable from %i to %i sectors\n", sectorCount, hfsgrowblks); + } + } + +diff -druN diskdev_cmds-332.14/newfs_hfs.tproj/newfs_hfs.h diskdev_cmds-332.14-patched/newfs_hfs.tproj/newfs_hfs.h +--- diskdev_cmds-332.14/newfs_hfs.tproj/newfs_hfs.h 2006-02-20 22:45:15.000000000 +0100 ++++ diskdev_cmds-332.14-patched/newfs_hfs.tproj/newfs_hfs.h 2008-07-01 22:30:11.000000000 +0200 +@@ -19,8 +19,12 @@ + * + * @APPLE_LICENSE_HEADER_END@ + */ +- +-#include ++ ++#if LINUX ++#include "missing.h" ++#else ++#include */ ++#endif + + /* + * Mac OS Finder flags +@@ -122,33 +126,33 @@ + #define kDTDF_FileID 16 + #define kDTDF_Name "Desktop DF" + #define kDTDF_Chars 10 +-#define kDTDF_Type 'DTFL' +-#define kDTDF_Creator 'DMGR' ++#define kDTDF_Type 0x4454464C /* 'DTFL' */ ++#define kDTDF_Creator 0x444D4752 /* 'DMGR' */ + + #define kDTDB_FileID 17 + #define kDTDB_Name "Desktop DB" + #define kDTDB_Chars 10 +-#define kDTDB_Type 'BTFL' +-#define kDTDB_Creator 'DMGR' ++#define kDTDB_Type 0x4254464C /* 'BTFL' */ ++#define kDTDB_Creator 0x444D4752 /* 'DMGR' */ + #define kDTDB_Size 1024 + + #define kReadMe_FileID 18 + #define kReadMe_Name "ReadMe" + #define kReadMe_Chars 6 +-#define kReadMe_Type 'ttro' +-#define kReadMe_Creator 'ttxt' ++#define kReadMe_Type 0x7474726F /* 'ttro' */ ++#define kReadMe_Creator 0x74747974 /* 'ttxt' */ + + #define kFinder_FileID 19 + #define kFinder_Name "Finder" + #define kFinder_Chars 6 +-#define kFinder_Type 'FNDR' +-#define kFinder_Creator 'MACS' ++#define kFinder_Type 0x464E4452 /* 'FNDR' */ ++#define kFinder_Creator 0x4D414353 /* 'MACS' */ + + #define kSystem_FileID 20 + #define kSystem_Name "System" + #define kSystem_Chars 6 +-#define kSystem_Type 'zsys' +-#define kSystem_Creator 'MACS' ++#define kSystem_Type 0x7A737973 /* 'zsys' */ ++#define kSystem_Creator 0x4D414353 /* 'MACS' */ + + + +Files diskdev_cmds-332.14/newfs_hfs.tproj/newfs_hfs.o and diskdev_cmds-332.14-patched/newfs_hfs.tproj/newfs_hfs.o differ diff --git a/packages/sysutils/diskdev_cmds/patches/diskdev_cmds-332.14-respect-cflags.patch b/packages/sysutils/diskdev_cmds/patches/diskdev_cmds-332.14-respect-cflags.patch new file mode 100644 index 0000000000..181f10c76b --- /dev/null +++ b/packages/sysutils/diskdev_cmds/patches/diskdev_cmds-332.14-respect-cflags.patch @@ -0,0 +1,9 @@ +--- diskdev_cmds-332.14/Makefile.lnx.bak 2009-07-22 11:58:10.000000000 -0400 ++++ diskdev_cmds-332.14/Makefile.lnx 2009-07-22 11:57:37.000000000 -0400 +@@ -1,5 +1,5 @@ + CC := gcc +-CFLAGS := -g3 -Wall -I$(PWD)/include -DDEBUG_BUILD=0 -D_FILE_OFFSET_BITS=64 -D LINUX=1 -D BSD=1 ++CFLAGS += -Wall -I$(PWD)/include -DDEBUG_BUILD=0 -D_FILE_OFFSET_BITS=64 -D LINUX=1 -D BSD=1 + SUBDIRS := newfs_hfs.tproj fsck_hfs.tproj + + all clean: From 6bf86aa1e1c7f28940aecb9ea125e2ce287f5a9a Mon Sep 17 00:00:00 2001 From: Travis Glenn Hansen Date: Sun, 8 May 2011 01:55:37 -0600 Subject: [PATCH 23/31] cleanup --- .../mysql-5.1.55-010_crosscompiling.patch | 128 ------------------ projects/ATV/options | 3 + scripts/image | 3 + 3 files changed, 6 insertions(+), 128 deletions(-) delete mode 100644 packages/databases/mysql/patches/mysql-5.1.55-010_crosscompiling.patch diff --git a/packages/databases/mysql/patches/mysql-5.1.55-010_crosscompiling.patch b/packages/databases/mysql/patches/mysql-5.1.55-010_crosscompiling.patch deleted file mode 100644 index b6c3e068a1..0000000000 --- a/packages/databases/mysql/patches/mysql-5.1.55-010_crosscompiling.patch +++ /dev/null @@ -1,128 +0,0 @@ -diff -Naur mysql-5.1.38/dbug/Makefile.am mysql-5.1.38.patch/dbug/Makefile.am ---- mysql-5.1.38/dbug/Makefile.am 2009-08-21 14:09:22.000000000 +0200 -+++ mysql-5.1.38.patch/dbug/Makefile.am 2009-09-10 02:57:59.000000000 +0200 -@@ -44,19 +44,19 @@ - -groff -mm user.r > $@ - - output1.r: factorial -- ./factorial 1 2 3 4 5 | cat > $@ -+ mysql-factorial 1 2 3 4 5 | cat > $@ - - output2.r: factorial -- ./factorial -\#t:o 2 3 | cat >$@ -+ mysql-factorial -\#t:o 2 3 | cat >$@ - - output3.r: factorial -- ./factorial -\#d:t:o 3 | cat >$@ -+ mysql-factorial -\#d:t:o 3 | cat >$@ - - output4.r: factorial -- ./factorial -\#d,result:o 4 | cat >$@ -+ mysql-factorial -\#d,result:o 4 | cat >$@ - - output5.r: factorial -- ./factorial -\#d:f,factorial:F:L:o 3 | cat >$@ -+ mysql-factorial -\#d:f,factorial:F:L:o 3 | cat >$@ - .c.r: - @RM@ -f $@ - @SED@ -e 's!\\!\\\\!g' $< > $@ -diff -Naur mysql-5.1.38/dbug/Makefile.in mysql-5.1.38.patch/dbug/Makefile.in ---- mysql-5.1.38/dbug/Makefile.in 2009-08-21 14:17:15.000000000 +0200 -+++ mysql-5.1.38.patch/dbug/Makefile.in 2009-09-10 02:58:14.000000000 +0200 -@@ -746,19 +746,19 @@ - -groff -mm user.r > $@ - - output1.r: factorial -- ./factorial 1 2 3 4 5 | cat > $@ -+ mysql-factorial 1 2 3 4 5 | cat > $@ - - output2.r: factorial -- ./factorial -\#t:o 2 3 | cat >$@ -+ mysql-factorial -\#t:o 2 3 | cat >$@ - - output3.r: factorial -- ./factorial -\#d:t:o 3 | cat >$@ -+ mysql-factorial -\#d:t:o 3 | cat >$@ - - output4.r: factorial -- ./factorial -\#d,result:o 4 | cat >$@ -+ mysql-factorial -\#d,result:o 4 | cat >$@ - - output5.r: factorial -- ./factorial -\#d:f,factorial:F:L:o 3 | cat >$@ -+ mysql-factorial -\#d:f,factorial:F:L:o 3 | cat >$@ - .c.r: - @RM@ -f $@ - @SED@ -e 's!\\!\\\\!g' $< > $@ -diff -Naur mysql-5.1.38/extra/Makefile.am mysql-5.1.38.patch/extra/Makefile.am ---- mysql-5.1.38/extra/Makefile.am 2009-08-21 14:09:23.000000000 +0200 -+++ mysql-5.1.38.patch/extra/Makefile.am 2009-09-10 02:53:50.000000000 +0200 -@@ -32,7 +32,7 @@ - $(top_builddir)/include/mysqld_error.h: comp_err.c \ - $(top_srcdir)/sql/share/errmsg.txt - $(MAKE) $(AM_MAKEFLAGS) comp_err$(EXEEXT) -- $(top_builddir)/extra/comp_err$(EXEEXT) \ -+ mysql-comp_err$(EXEEXT) \ - --charset=$(top_srcdir)/sql/share/charsets \ - --out-dir=$(top_builddir)/sql/share/ \ - --header_file=$(top_builddir)/include/mysqld_error.h \ -diff -Naur mysql-5.1.38/extra/Makefile.in mysql-5.1.38.patch/extra/Makefile.in ---- mysql-5.1.38/extra/Makefile.in 2009-08-21 14:17:16.000000000 +0200 -+++ mysql-5.1.38.patch/extra/Makefile.in 2009-09-10 02:53:16.000000000 +0200 -@@ -936,7 +936,7 @@ - $(top_builddir)/include/mysqld_error.h: comp_err.c \ - $(top_srcdir)/sql/share/errmsg.txt - $(MAKE) $(AM_MAKEFLAGS) comp_err$(EXEEXT) -- $(top_builddir)/extra/comp_err$(EXEEXT) \ -+ mysql-comp_err$(EXEEXT) \ - --charset=$(top_srcdir)/sql/share/charsets \ - --out-dir=$(top_builddir)/sql/share/ \ - --header_file=$(top_builddir)/include/mysqld_error.h \ -diff -Naur mysql-5.1.38/scripts/Makefile.am mysql-5.1.38.patch/scripts/Makefile.am ---- mysql-5.1.38/scripts/Makefile.am 2009-08-21 14:11:26.000000000 +0200 -+++ mysql-5.1.38.patch/scripts/Makefile.am 2009-09-10 02:57:01.000000000 +0200 -@@ -121,7 +121,7 @@ - mysql_fix_privilege_tables_sql.c: comp_sql.c mysql_fix_privilege_tables.sql - $(MAKE) $(AM_MAKEFLAGS) comp_sql$(EXEEXT) - sleep 2 -- $(top_builddir)/scripts/comp_sql$(EXEEXT) \ -+ mysql-comp_sql$(EXEEXT) \ - mysql_fix_privilege_tables \ - $(top_srcdir)/scripts/mysql_fix_privilege_tables.sql $@ - -diff -Naur mysql-5.1.38/scripts/Makefile.in mysql-5.1.38.patch/scripts/Makefile.in ---- mysql-5.1.38/scripts/Makefile.in 2009-08-21 14:17:23.000000000 +0200 -+++ mysql-5.1.38.patch/scripts/Makefile.in 2009-09-10 02:57:11.000000000 +0200 -@@ -802,7 +802,7 @@ - mysql_fix_privilege_tables_sql.c: comp_sql.c mysql_fix_privilege_tables.sql - $(MAKE) $(AM_MAKEFLAGS) comp_sql$(EXEEXT) - sleep 2 -- $(top_builddir)/scripts/comp_sql$(EXEEXT) \ -+ mysql-comp_sql$(EXEEXT) \ - mysql_fix_privilege_tables \ - $(top_srcdir)/scripts/mysql_fix_privilege_tables.sql $@ - -diff -Naur mysql-5.1.38/sql/Makefile.am mysql-5.1.38.patch/sql/Makefile.am ---- mysql-5.1.38/sql/Makefile.am 2009-08-21 14:12:24.000000000 +0200 -+++ mysql-5.1.38.patch/sql/Makefile.am 2009-09-10 02:55:09.000000000 +0200 -@@ -174,7 +174,7 @@ - # this avoid the rebuild of the built files in a source dist - lex_hash.h: gen_lex_hash.cc lex.h - $(MAKE) $(AM_MAKEFLAGS) gen_lex_hash$(EXEEXT) -- ./gen_lex_hash$(EXEEXT) > $@-t -+ mysql-gen_lex_hash$(EXEEXT) > $@-t - $(MV) $@-t $@ - - # For testing of udf_example.so -diff -Naur mysql-5.1.38/sql/Makefile.in mysql-5.1.38.patch/sql/Makefile.in ---- mysql-5.1.38/sql/Makefile.in 2009-08-21 14:17:25.000000000 +0200 -+++ mysql-5.1.38.patch/sql/Makefile.in 2009-09-10 02:55:22.000000000 +0200 -@@ -1302,7 +1302,7 @@ - # this avoid the rebuild of the built files in a source dist - lex_hash.h: gen_lex_hash.cc lex.h - $(MAKE) $(AM_MAKEFLAGS) gen_lex_hash$(EXEEXT) -- ./gen_lex_hash$(EXEEXT) > $@-t -+ mysql-gen_lex_hash$(EXEEXT) > $@-t - $(MV) $@-t $@ - - # We might have some stuff not built in this build, but that we want to install diff --git a/projects/ATV/options b/projects/ATV/options index 6d8d97d5fc..2bf127f60b 100644 --- a/projects/ATV/options +++ b/projects/ATV/options @@ -155,6 +155,9 @@ # build and install NTFS-3G fuse support (yes / no) NTFS3G="yes" +# build and install hfs filesystem utilities (yes / no) + HFSTOOLS="yes" + # build and install Apple device mount support (via ifuse) (yes / no) APPLEMOUNT="yes" diff --git a/scripts/image b/scripts/image index 706c350fe3..f35613919e 100755 --- a/scripts/image +++ b/scripts/image @@ -112,6 +112,9 @@ mkdir -p $INSTALL # NTFS 3G support [ "$NTFS3G" = "yes" ] && $SCRIPTS/install ntfs-3g_ntfsprogs +# hfs utils support + [ "$HFSTOOLS" = "yes" ] && $SCRIPTS/install diskdev_cmds + # Apple mount (ifuse) support [ "$APPLEMOUNT" = "yes" ] && $SCRIPTS/install ifuse From 2558c90106e3f7a45153ca58e0fe9295c0c10209 Mon Sep 17 00:00:00 2001 From: Travis Glenn Hansen Date: Sun, 8 May 2011 02:11:43 -0600 Subject: [PATCH 24/31] fixing libcap trying to use pam when installed on build host --- packages/devel/libcap/build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/devel/libcap/build b/packages/devel/libcap/build index a201d162f1..e98284fea5 100755 --- a/packages/devel/libcap/build +++ b/packages/devel/libcap/build @@ -25,6 +25,8 @@ cd $PKG_BUILD +sed -i -e "/^PAM_CAP/s:=.*:=no:" Make.Rules + setup_toolchain host make CC=$HOST_CC -C libcap _makenames From 516052bd2afa340a04ba4e25aac452eb10f10cbe Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 8 May 2011 10:25:43 +0200 Subject: [PATCH 25/31] glew: remove unneeded patch Signed-off-by: Stephan Raue --- packages/graphics/glew/patches/test.patch | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 packages/graphics/glew/patches/test.patch diff --git a/packages/graphics/glew/patches/test.patch b/packages/graphics/glew/patches/test.patch deleted file mode 100644 index a064d19f42..0000000000 --- a/packages/graphics/glew/patches/test.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- glew-1.6.0/config/Makefile.linux.orig 2011-05-07 12:08:25.427908940 -0600 -+++ glew-1.6.0/config/Makefile.linux 2011-05-07 12:08:50.345126195 -0600 -@@ -1,15 +1,9 @@ - NAME = $(GLEW_NAME) --CC = cc --LD = cc -+CC = $(CC) -+LD = $(CC) - PICFLAG = -fPIC - M_ARCH ?= $(shell uname -m) --ifeq (x86_64,${M_ARCH}) --LDFLAGS.EXTRA = -L/usr/X11R6/lib64 --LIBDIR = $(GLEW_DEST)/lib64 --else --LDFLAGS.EXTRA = -L/usr/X11R6/lib - LIBDIR = $(GLEW_DEST)/lib --endif - LDFLAGS.GL = -lXmu -lXi -lGLU -lGL -lXext -lX11 - LDFLAGS.STATIC = -Wl,-Bstatic - LDFLAGS.DYNAMIC = -Wl,-Bdynamic From 5d064b86a326ac326efd8e4795015857244761cf Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 8 May 2011 10:45:38 +0200 Subject: [PATCH 26/31] projects/*/options: add missing options Signed-off-by: Stephan Raue --- projects/Generic/options | 3 +++ projects/ION/options | 3 +++ 2 files changed, 6 insertions(+) diff --git a/projects/Generic/options b/projects/Generic/options index f1edc83c92..8b8093a784 100644 --- a/projects/Generic/options +++ b/projects/Generic/options @@ -155,6 +155,9 @@ # build and install NTFS-3G fuse support (yes / no) NTFS3G="yes" +# build and install hfs filesystem utilities (yes / no) + HFSTOOLS="yes" + # build and install Apple device mount support (via ifuse) (yes / no) APPLEMOUNT="yes" diff --git a/projects/ION/options b/projects/ION/options index f9e023deec..c1d12b252e 100644 --- a/projects/ION/options +++ b/projects/ION/options @@ -155,6 +155,9 @@ # build and install NTFS-3G fuse support (yes / no) NTFS3G="yes" +# build and install hfs filesystem utilities (yes / no) + HFSTOOLS="yes" + # build and install Apple device mount support (via ifuse) (yes / no) APPLEMOUNT="yes" From 5fea3042868739c40d9e574a59b49cdf9abeff2c Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 8 May 2011 10:46:08 +0200 Subject: [PATCH 27/31] projects/*/options: add missing options Signed-off-by: Stephan Raue --- projects/Intel/options | 3 +++ 1 file changed, 3 insertions(+) diff --git a/projects/Intel/options b/projects/Intel/options index b62e1b32ba..ad07c64753 100644 --- a/projects/Intel/options +++ b/projects/Intel/options @@ -155,6 +155,9 @@ # build and install NTFS-3G fuse support (yes / no) NTFS3G="yes" +# build and install hfs filesystem utilities (yes / no) + HFSTOOLS="yes" + # build and install Apple device mount support (via ifuse) (yes / no) APPLEMOUNT="yes" From 87ca0cbcaaaa09f781fad35f1c62280f42bf2173 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 8 May 2011 10:50:58 +0200 Subject: [PATCH 28/31] openssh: make installing of SFTP server optional at buildtime Signed-off-by: Stephan Raue --- packages/network/openssh/install | 6 ++++-- projects/ATV/options | 3 +++ projects/Generic/options | 3 +++ projects/ION/options | 3 +++ projects/Intel/options | 3 +++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/network/openssh/install b/packages/network/openssh/install index 31437bb4c9..c7d5d48a5a 100755 --- a/packages/network/openssh/install +++ b/packages/network/openssh/install @@ -39,5 +39,7 @@ mkdir -p $INSTALL/usr/bin mkdir -p $INSTALL/usr/sbin cp $PKG_BUILD/sshd $INSTALL/usr/sbin/ -mkdir -p $INSTALL/usr/libexec - cp $PKG_BUILD/sftp-server $INSTALL/usr/libexec +if [ $SFTP_SERVER = "yes" ]; then + mkdir -p $INSTALL/usr/libexec + cp $PKG_BUILD/sftp-server $INSTALL/usr/libexec +fi diff --git a/projects/ATV/options b/projects/ATV/options index 2bf127f60b..0b52d8d9f6 100644 --- a/projects/ATV/options +++ b/projects/ATV/options @@ -140,6 +140,9 @@ # build and install Samba Server (yes / no) SAMBA_SERVER="yes" +# build and install SFTP Server (yes / no) + SFTP_SERVER="yes" + # build and install some tools for including in release (yes / no) # some of this tools are: htop, nano, wgetpaste TOOLS="yes" diff --git a/projects/Generic/options b/projects/Generic/options index 8b8093a784..f973bbecb3 100644 --- a/projects/Generic/options +++ b/projects/Generic/options @@ -140,6 +140,9 @@ # build and install Samba Server (yes / no) SAMBA_SERVER="yes" +# build and install SFTP Server (yes / no) + SFTP_SERVER="yes" + # build and install some tools for including in release (yes / no) # some of this tools are: htop, nano, wgetpaste TOOLS="yes" diff --git a/projects/ION/options b/projects/ION/options index c1d12b252e..c6f869ea41 100644 --- a/projects/ION/options +++ b/projects/ION/options @@ -140,6 +140,9 @@ # build and install Samba Server (yes / no) SAMBA_SERVER="yes" +# build and install SFTP Server (yes / no) + SFTP_SERVER="yes" + # build and install some tools for including in release (yes / no) # some of this tools are: htop, nano, wgetpaste TOOLS="yes" diff --git a/projects/Intel/options b/projects/Intel/options index ad07c64753..43d9876d2e 100644 --- a/projects/Intel/options +++ b/projects/Intel/options @@ -140,6 +140,9 @@ # build and install Samba Server (yes / no) SAMBA_SERVER="yes" +# build and install SFTP Server (yes / no) + SFTP_SERVER="yes" + # build and install some tools for including in release (yes / no) # some of this tools are: htop, nano, wgetpaste TOOLS="yes" From d4502bc705679dd887b457ccba48f84e18f87139 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 8 May 2011 12:12:31 +0200 Subject: [PATCH 29/31] busybox-initramfs: add support for OEM Splash, dont load splash if framebuffer is not enabled Signed-off-by: Stephan Raue --- .../sysutils/busybox-initramfs/scripts/init | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/sysutils/busybox-initramfs/scripts/init b/packages/sysutils/busybox-initramfs/scripts/init index 8953a4eef4..c6e8c4eede 100755 --- a/packages/sysutils/busybox-initramfs/scripts/init +++ b/packages/sysutils/busybox-initramfs/scripts/init @@ -63,11 +63,23 @@ REBOOT="0" } show_splash() { + if [ ! -e /dev/fb0 ]; then + SPLASH=no + fi + + if [ -f /flash/oemsplash.png ]; then + SPLASHIMAGE="/flash/oemsplash.png" + elif [ -f /splash/splash.png ]; then + SPLASHIMAGE="/splash/splash.png" + else + SPLASH=no + fi + if [ "$SPLASH" = "no" ]; then break else - if [ -f "/sbin/ply-image" -a -f "/splash/splash.png" ]; then - /sbin/ply-image /splash/splash.png + if [ -f "/sbin/ply-image" ]; then + /sbin/ply-image "$SPLASHIMAGE" fi fi } @@ -103,10 +115,10 @@ REBOOT="0" fi } - show_splash - mount_part "$boot" "/flash" "ro,noatime" + show_splash + if [ -n "$disk" ]; then mount_part "$disk" "/storage" "rw,noatime" update "Kernel" "$IMAGE_KERNEL" "/flash/$IMAGE_KERNEL" From 9d9ef07c19f49805d2247798b21083d4d5cae594 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 8 May 2011 12:33:43 +0200 Subject: [PATCH 30/31] projects/*/options: disable build from hfstools on unsupported systems Signed-off-by: Stephan Raue --- projects/Generic/options | 2 +- projects/ION/options | 2 +- projects/Intel/options | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/Generic/options b/projects/Generic/options index f973bbecb3..22242adec3 100644 --- a/projects/Generic/options +++ b/projects/Generic/options @@ -159,7 +159,7 @@ NTFS3G="yes" # build and install hfs filesystem utilities (yes / no) - HFSTOOLS="yes" + HFSTOOLS="no" # build and install Apple device mount support (via ifuse) (yes / no) APPLEMOUNT="yes" diff --git a/projects/ION/options b/projects/ION/options index c6f869ea41..6e188ab045 100644 --- a/projects/ION/options +++ b/projects/ION/options @@ -159,7 +159,7 @@ NTFS3G="yes" # build and install hfs filesystem utilities (yes / no) - HFSTOOLS="yes" + HFSTOOLS="no" # build and install Apple device mount support (via ifuse) (yes / no) APPLEMOUNT="yes" diff --git a/projects/Intel/options b/projects/Intel/options index 43d9876d2e..28126b3e77 100644 --- a/projects/Intel/options +++ b/projects/Intel/options @@ -159,7 +159,7 @@ NTFS3G="yes" # build and install hfs filesystem utilities (yes / no) - HFSTOOLS="yes" + HFSTOOLS="no" # build and install Apple device mount support (via ifuse) (yes / no) APPLEMOUNT="yes" From 1c0fd3ff9371ccdc4f0e76675a2a3c0d3e5f45a7 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Mon, 9 May 2011 11:53:41 +0200 Subject: [PATCH 31/31] linux: update/readd nouveau upstream patches Signed-off-by: Stephan Raue --- ...c6-110-drm_nouveau_upstream-20110509.patch | 9012 +++++++++++++++++ 1 file changed, 9012 insertions(+) create mode 100644 packages/linux/patches/linux-2.6.39-rc6-110-drm_nouveau_upstream-20110509.patch diff --git a/packages/linux/patches/linux-2.6.39-rc6-110-drm_nouveau_upstream-20110509.patch b/packages/linux/patches/linux-2.6.39-rc6-110-drm_nouveau_upstream-20110509.patch new file mode 100644 index 0000000000..2572644720 --- /dev/null +++ b/packages/linux/patches/linux-2.6.39-rc6-110-drm_nouveau_upstream-20110509.patch @@ -0,0 +1,9012 @@ +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/Makefile linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/Makefile +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/Makefile 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/Makefile 2011-05-09 00:36:22.000000000 +0200 +@@ -20,6 +20,8 @@ + nv40_graph.o nv50_graph.o nvc0_graph.o \ + nv40_grctx.o nv50_grctx.o nvc0_grctx.o \ + nv84_crypt.o \ ++ nva3_copy.o nvc0_copy.o \ ++ nv40_mpeg.o nv50_mpeg.o \ + nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ + nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ + nv50_cursor.o nv50_display.o \ +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_bios.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_bios.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_bios.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_bios.c 2011-05-09 00:36:22.000000000 +0200 +@@ -5049,11 +5049,7 @@ + pll_lim->vco1.max_n = record[11]; + pll_lim->min_p = record[12]; + pll_lim->max_p = record[13]; +- /* where did this go to?? */ +- if ((entry[0] & 0xf0) == 0x80) +- pll_lim->refclk = 27000; +- else +- pll_lim->refclk = 100000; ++ pll_lim->refclk = ROM16(entry[9]) * 1000; + } + + /* +@@ -6035,6 +6031,7 @@ + case DCB_CONNECTOR_DVI_I: + case DCB_CONNECTOR_DVI_D: + case DCB_CONNECTOR_LVDS: ++ case DCB_CONNECTOR_LVDS_SPWG: + case DCB_CONNECTOR_DP: + case DCB_CONNECTOR_eDP: + case DCB_CONNECTOR_HDMI_0: +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_bios.h linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_bios.h +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_bios.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_bios.h 2011-05-09 00:36:22.000000000 +0200 +@@ -82,6 +82,7 @@ + DCB_CONNECTOR_DVI_I = 0x30, + DCB_CONNECTOR_DVI_D = 0x31, + DCB_CONNECTOR_LVDS = 0x40, ++ DCB_CONNECTOR_LVDS_SPWG = 0x41, + DCB_CONNECTOR_DP = 0x46, + DCB_CONNECTOR_eDP = 0x47, + DCB_CONNECTOR_HDMI_0 = 0x60, +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_channel.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_channel.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_channel.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_channel.c 2011-05-09 00:36:22.000000000 +0200 +@@ -268,9 +268,8 @@ + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt; + unsigned long flags; ++ int i; + + /* decrement the refcount, and we're done if there's still refs */ + if (likely(!atomic_dec_and_test(&chan->users))) { +@@ -294,19 +293,12 @@ + /* boot it off the hardware */ + pfifo->reassign(dev, false); + +- /* We want to give pgraph a chance to idle and get rid of all +- * potential errors. We need to do this without the context +- * switch lock held, otherwise the irq handler is unable to +- * process them. +- */ +- if (pgraph->channel(dev) == chan) +- nouveau_wait_for_idle(dev); +- + /* destroy the engine specific contexts */ + pfifo->destroy_context(chan); +- pgraph->destroy_context(chan); +- if (pcrypt->destroy_context) +- pcrypt->destroy_context(chan); ++ for (i = 0; i < NVOBJ_ENGINE_NR; i++) { ++ if (chan->engctx[i]) ++ dev_priv->eng[i]->context_del(chan, i); ++ } + + pfifo->reassign(dev, true); + +@@ -414,7 +406,7 @@ + struct nouveau_channel *chan; + int ret; + +- if (dev_priv->engine.graph.accel_blocked) ++ if (!dev_priv->eng[NVOBJ_ENGINE_GR]) + return -ENODEV; + + if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0) +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_connector.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_connector.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_connector.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_connector.c 2011-05-09 00:36:22.000000000 +0200 +@@ -442,7 +442,7 @@ + } + + /* LVDS always needs gpu scaling */ +- if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS && ++ if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS && + value == DRM_MODE_SCALE_NONE) + return -EINVAL; + +@@ -650,6 +650,7 @@ + ret = get_slave_funcs(encoder)->get_modes(encoder, connector); + + if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS || ++ nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG || + nv_connector->dcb->type == DCB_CONNECTOR_eDP) + ret += nouveau_connector_scaler_modes_add(connector); + +@@ -810,6 +811,7 @@ + type = DRM_MODE_CONNECTOR_HDMIA; + break; + case DCB_CONNECTOR_LVDS: ++ case DCB_CONNECTOR_LVDS_SPWG: + type = DRM_MODE_CONNECTOR_LVDS; + funcs = &nouveau_connector_funcs_lvds; + break; +@@ -838,7 +840,7 @@ + drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); + + /* Check if we need dithering enabled */ +- if (dcb->type == DCB_CONNECTOR_LVDS) { ++ if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) { + bool dummy, is_24bit = false; + + ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &is_24bit); +@@ -883,7 +885,7 @@ + nv_connector->use_dithering ? + DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF); + +- if (dcb->type != DCB_CONNECTOR_LVDS) { ++ if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) { + if (dev_priv->card_type >= NV_50) + connector->polled = DRM_CONNECTOR_POLL_HPD; + else +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_display.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_display.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_display.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_display.c 2011-05-09 00:36:22.000000000 +0200 +@@ -276,7 +276,7 @@ + struct nouveau_fence *fence; + int ret; + +- if (dev_priv->engine.graph.accel_blocked) ++ if (!dev_priv->channel) + return -ENODEV; + + s = kzalloc(sizeof(*s), GFP_KERNEL); +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_drv.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_drv.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_drv.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_drv.c 2011-05-09 00:36:22.000000000 +0200 +@@ -162,11 +162,10 @@ + struct drm_device *dev = pci_get_drvdata(pdev); + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nouveau_channel *chan; + struct drm_crtc *crtc; +- int ret, i; ++ int ret, i, e; + + if (pm_state.event == PM_EVENT_PRETHAW) + return 0; +@@ -206,12 +205,17 @@ + nouveau_channel_idle(chan); + } + +- pgraph->fifo_access(dev, false); +- nouveau_wait_for_idle(dev); + pfifo->reassign(dev, false); + pfifo->disable(dev); + pfifo->unload_context(dev); +- pgraph->unload_context(dev); ++ ++ for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) { ++ if (dev_priv->eng[e]) { ++ ret = dev_priv->eng[e]->fini(dev, e); ++ if (ret) ++ goto out_abort; ++ } ++ } + + ret = pinstmem->suspend(dev); + if (ret) { +@@ -242,9 +246,12 @@ + + out_abort: + NV_INFO(dev, "Re-enabling acceleration..\n"); ++ for (e = e + 1; e < NVOBJ_ENGINE_NR; e++) { ++ if (dev_priv->eng[e]) ++ dev_priv->eng[e]->init(dev, e); ++ } + pfifo->enable(dev); + pfifo->reassign(dev, true); +- pgraph->fifo_access(dev, true); + return ret; + } + +@@ -299,8 +306,10 @@ + engine->mc.init(dev); + engine->timer.init(dev); + engine->fb.init(dev); +- engine->graph.init(dev); +- engine->crypt.init(dev); ++ for (i = 0; i < NVOBJ_ENGINE_NR; i++) { ++ if (dev_priv->eng[i]) ++ dev_priv->eng[i]->init(dev, i); ++ } + engine->fifo.init(dev); + + nouveau_irq_postinstall(dev); +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_drv.h linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_drv.h +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_drv.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_drv.h 2011-05-09 00:36:22.000000000 +0200 +@@ -150,13 +150,12 @@ + + #define NVOBJ_ENGINE_SW 0 + #define NVOBJ_ENGINE_GR 1 +-#define NVOBJ_ENGINE_PPP 2 +-#define NVOBJ_ENGINE_COPY 3 +-#define NVOBJ_ENGINE_VP 4 +-#define NVOBJ_ENGINE_CRYPT 5 +-#define NVOBJ_ENGINE_BSP 6 +-#define NVOBJ_ENGINE_DISPLAY 0xcafe0001 +-#define NVOBJ_ENGINE_INT 0xdeadbeef ++#define NVOBJ_ENGINE_CRYPT 2 ++#define NVOBJ_ENGINE_COPY0 3 ++#define NVOBJ_ENGINE_COPY1 4 ++#define NVOBJ_ENGINE_MPEG 5 ++#define NVOBJ_ENGINE_DISPLAY 15 ++#define NVOBJ_ENGINE_NR 16 + + #define NVOBJ_FLAG_DONT_MAP (1 << 0) + #define NVOBJ_FLAG_ZERO_ALLOC (1 << 1) +@@ -245,11 +244,8 @@ + struct nouveau_gpuobj *cache; + void *fifo_priv; + +- /* PGRAPH context */ +- /* XXX may be merge 2 pointers as private data ??? */ +- struct nouveau_gpuobj *ramin_grctx; +- struct nouveau_gpuobj *crypt_ctx; +- void *pgraph_ctx; ++ /* Execution engine contexts */ ++ void *engctx[NVOBJ_ENGINE_NR]; + + /* NV50 VM */ + struct nouveau_vm *vm; +@@ -298,6 +294,18 @@ + } debugfs; + }; + ++struct nouveau_exec_engine { ++ void (*destroy)(struct drm_device *, int engine); ++ int (*init)(struct drm_device *, int engine); ++ int (*fini)(struct drm_device *, int engine); ++ int (*context_new)(struct nouveau_channel *, int engine); ++ void (*context_del)(struct nouveau_channel *, int engine); ++ int (*object_new)(struct nouveau_channel *, int engine, ++ u32 handle, u16 class); ++ void (*set_tile_region)(struct drm_device *dev, int i); ++ void (*tlb_flush)(struct drm_device *, int engine); ++}; ++ + struct nouveau_instmem_engine { + void *priv; + +@@ -364,30 +372,6 @@ + void (*tlb_flush)(struct drm_device *dev); + }; + +-struct nouveau_pgraph_engine { +- bool accel_blocked; +- bool registered; +- int grctx_size; +- void *priv; +- +- /* NV2x/NV3x context table (0x400780) */ +- struct nouveau_gpuobj *ctx_table; +- +- int (*init)(struct drm_device *); +- void (*takedown)(struct drm_device *); +- +- void (*fifo_access)(struct drm_device *, bool); +- +- struct nouveau_channel *(*channel)(struct drm_device *); +- int (*create_context)(struct nouveau_channel *); +- void (*destroy_context)(struct nouveau_channel *); +- int (*load_context)(struct nouveau_channel *); +- int (*unload_context)(struct drm_device *); +- void (*tlb_flush)(struct drm_device *dev); +- +- void (*set_tile_region)(struct drm_device *dev, int i); +-}; +- + struct nouveau_display_engine { + void *priv; + int (*early_init)(struct drm_device *); +@@ -426,6 +410,19 @@ + int nr_level; + }; + ++struct nouveau_pm_memtiming { ++ int id; ++ u32 reg_100220; ++ u32 reg_100224; ++ u32 reg_100228; ++ u32 reg_10022c; ++ u32 reg_100230; ++ u32 reg_100234; ++ u32 reg_100238; ++ u32 reg_10023c; ++ u32 reg_100240; ++}; ++ + #define NOUVEAU_PM_MAX_LEVEL 8 + struct nouveau_pm_level { + struct device_attribute dev_attr; +@@ -436,11 +433,13 @@ + u32 memory; + u32 shader; + u32 unk05; ++ u32 unk0a; + + u8 voltage; + u8 fanspeed; + + u16 memscript; ++ struct nouveau_pm_memtiming *timing; + }; + + struct nouveau_pm_temp_sensor_constants { +@@ -457,17 +456,6 @@ + s16 fan_boost; + }; + +-struct nouveau_pm_memtiming { +- u32 reg_100220; +- u32 reg_100224; +- u32 reg_100228; +- u32 reg_10022c; +- u32 reg_100230; +- u32 reg_100234; +- u32 reg_100238; +- u32 reg_10023c; +-}; +- + struct nouveau_pm_memtimings { + bool supported; + struct nouveau_pm_memtiming *timing; +@@ -499,16 +487,6 @@ + int (*temp_get)(struct drm_device *); + }; + +-struct nouveau_crypt_engine { +- bool registered; +- +- int (*init)(struct drm_device *); +- void (*takedown)(struct drm_device *); +- int (*create_context)(struct nouveau_channel *); +- void (*destroy_context)(struct nouveau_channel *); +- void (*tlb_flush)(struct drm_device *dev); +-}; +- + struct nouveau_vram_engine { + int (*init)(struct drm_device *); + int (*get)(struct drm_device *, u64, u32 align, u32 size_nc, +@@ -523,12 +501,10 @@ + struct nouveau_mc_engine mc; + struct nouveau_timer_engine timer; + struct nouveau_fb_engine fb; +- struct nouveau_pgraph_engine graph; + struct nouveau_fifo_engine fifo; + struct nouveau_display_engine display; + struct nouveau_gpio_engine gpio; + struct nouveau_pm_engine pm; +- struct nouveau_crypt_engine crypt; + struct nouveau_vram_engine vram; + }; + +@@ -637,6 +613,7 @@ + enum nouveau_card_type card_type; + /* exact chipset, derived from NV_PMC_BOOT_0 */ + int chipset; ++ int stepping; + int flags; + + void __iomem *mmio; +@@ -647,6 +624,7 @@ + u32 ramin_base; + bool ramin_available; + struct drm_mm ramin_heap; ++ struct nouveau_exec_engine *eng[NVOBJ_ENGINE_NR]; + struct list_head gpuobj_list; + struct list_head classes; + +@@ -745,10 +723,6 @@ + uint32_t crtc_owner; + uint32_t dac_users[4]; + +- struct nouveau_suspend_resume { +- uint32_t *ramin_copy; +- } susres; +- + struct backlight_device *backlight; + + struct { +@@ -757,8 +731,6 @@ + + struct nouveau_fbdev *nfbdev; + struct apertures_struct *apertures; +- +- bool powered_down; + }; + + static inline struct drm_nouveau_private * +@@ -883,17 +855,27 @@ + extern void nouveau_channel_idle(struct nouveau_channel *chan); + + /* nouveau_object.c */ +-#define NVOBJ_CLASS(d,c,e) do { \ ++#define NVOBJ_ENGINE_ADD(d, e, p) do { \ ++ struct drm_nouveau_private *dev_priv = (d)->dev_private; \ ++ dev_priv->eng[NVOBJ_ENGINE_##e] = (p); \ ++} while (0) ++ ++#define NVOBJ_ENGINE_DEL(d, e) do { \ ++ struct drm_nouveau_private *dev_priv = (d)->dev_private; \ ++ dev_priv->eng[NVOBJ_ENGINE_##e] = NULL; \ ++} while (0) ++ ++#define NVOBJ_CLASS(d, c, e) do { \ + int ret = nouveau_gpuobj_class_new((d), (c), NVOBJ_ENGINE_##e); \ + if (ret) \ + return ret; \ +-} while(0) ++} while (0) + +-#define NVOBJ_MTHD(d,c,m,e) do { \ ++#define NVOBJ_MTHD(d, c, m, e) do { \ + int ret = nouveau_gpuobj_mthd_new((d), (c), (m), (e)); \ + if (ret) \ + return ret; \ +-} while(0) ++} while (0) + + extern int nouveau_gpuobj_early_init(struct drm_device *); + extern int nouveau_gpuobj_init(struct drm_device *); +@@ -903,7 +885,7 @@ + extern int nouveau_gpuobj_class_new(struct drm_device *, u32 class, u32 eng); + extern int nouveau_gpuobj_mthd_new(struct drm_device *, u32 class, u32 mthd, + int (*exec)(struct nouveau_channel *, +- u32 class, u32 mthd, u32 data)); ++ u32 class, u32 mthd, u32 data)); + extern int nouveau_gpuobj_mthd_call(struct nouveau_channel *, u32, u32, u32); + extern int nouveau_gpuobj_mthd_call2(struct drm_device *, int, u32, u32, u32); + extern int nouveau_gpuobj_channel_init(struct nouveau_channel *, +@@ -1137,81 +1119,50 @@ + extern int nvc0_fifo_unload_context(struct drm_device *); + + /* nv04_graph.c */ +-extern int nv04_graph_init(struct drm_device *); +-extern void nv04_graph_takedown(struct drm_device *); ++extern int nv04_graph_create(struct drm_device *); + extern void nv04_graph_fifo_access(struct drm_device *, bool); +-extern struct nouveau_channel *nv04_graph_channel(struct drm_device *); +-extern int nv04_graph_create_context(struct nouveau_channel *); +-extern void nv04_graph_destroy_context(struct nouveau_channel *); +-extern int nv04_graph_load_context(struct nouveau_channel *); +-extern int nv04_graph_unload_context(struct drm_device *); ++extern int nv04_graph_object_new(struct nouveau_channel *, int, u32, u16); + extern int nv04_graph_mthd_page_flip(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data); + extern struct nouveau_bitfield nv04_graph_nsource[]; + + /* nv10_graph.c */ +-extern int nv10_graph_init(struct drm_device *); +-extern void nv10_graph_takedown(struct drm_device *); ++extern int nv10_graph_create(struct drm_device *); + extern struct nouveau_channel *nv10_graph_channel(struct drm_device *); +-extern int nv10_graph_create_context(struct nouveau_channel *); +-extern void nv10_graph_destroy_context(struct nouveau_channel *); +-extern int nv10_graph_load_context(struct nouveau_channel *); +-extern int nv10_graph_unload_context(struct drm_device *); +-extern void nv10_graph_set_tile_region(struct drm_device *dev, int i); + extern struct nouveau_bitfield nv10_graph_intr[]; + extern struct nouveau_bitfield nv10_graph_nstatus[]; + + /* nv20_graph.c */ +-extern int nv20_graph_create_context(struct nouveau_channel *); +-extern void nv20_graph_destroy_context(struct nouveau_channel *); +-extern int nv20_graph_load_context(struct nouveau_channel *); +-extern int nv20_graph_unload_context(struct drm_device *); +-extern int nv20_graph_init(struct drm_device *); +-extern void nv20_graph_takedown(struct drm_device *); +-extern int nv30_graph_init(struct drm_device *); +-extern void nv20_graph_set_tile_region(struct drm_device *dev, int i); ++extern int nv20_graph_create(struct drm_device *); + + /* nv40_graph.c */ +-extern int nv40_graph_init(struct drm_device *); +-extern void nv40_graph_takedown(struct drm_device *); +-extern struct nouveau_channel *nv40_graph_channel(struct drm_device *); +-extern int nv40_graph_create_context(struct nouveau_channel *); +-extern void nv40_graph_destroy_context(struct nouveau_channel *); +-extern int nv40_graph_load_context(struct nouveau_channel *); +-extern int nv40_graph_unload_context(struct drm_device *); ++extern int nv40_graph_create(struct drm_device *); + extern void nv40_grctx_init(struct nouveau_grctx *); +-extern void nv40_graph_set_tile_region(struct drm_device *dev, int i); + + /* nv50_graph.c */ +-extern int nv50_graph_init(struct drm_device *); +-extern void nv50_graph_takedown(struct drm_device *); +-extern void nv50_graph_fifo_access(struct drm_device *, bool); +-extern struct nouveau_channel *nv50_graph_channel(struct drm_device *); +-extern int nv50_graph_create_context(struct nouveau_channel *); +-extern void nv50_graph_destroy_context(struct nouveau_channel *); +-extern int nv50_graph_load_context(struct nouveau_channel *); +-extern int nv50_graph_unload_context(struct drm_device *); ++extern int nv50_graph_create(struct drm_device *); + extern int nv50_grctx_init(struct nouveau_grctx *); +-extern void nv50_graph_tlb_flush(struct drm_device *dev); +-extern void nv84_graph_tlb_flush(struct drm_device *dev); + extern struct nouveau_enum nv50_data_error_names[]; ++extern int nv50_graph_isr_chid(struct drm_device *dev, u64 inst); + + /* nvc0_graph.c */ +-extern int nvc0_graph_init(struct drm_device *); +-extern void nvc0_graph_takedown(struct drm_device *); +-extern void nvc0_graph_fifo_access(struct drm_device *, bool); +-extern struct nouveau_channel *nvc0_graph_channel(struct drm_device *); +-extern int nvc0_graph_create_context(struct nouveau_channel *); +-extern void nvc0_graph_destroy_context(struct nouveau_channel *); +-extern int nvc0_graph_load_context(struct nouveau_channel *); +-extern int nvc0_graph_unload_context(struct drm_device *); ++extern int nvc0_graph_create(struct drm_device *); ++extern int nvc0_graph_isr_chid(struct drm_device *dev, u64 inst); + + /* nv84_crypt.c */ +-extern int nv84_crypt_init(struct drm_device *dev); +-extern void nv84_crypt_fini(struct drm_device *dev); +-extern int nv84_crypt_create_context(struct nouveau_channel *); +-extern void nv84_crypt_destroy_context(struct nouveau_channel *); +-extern void nv84_crypt_tlb_flush(struct drm_device *dev); ++extern int nv84_crypt_create(struct drm_device *); ++ ++/* nva3_copy.c */ ++extern int nva3_copy_create(struct drm_device *dev); ++ ++/* nvc0_copy.c */ ++extern int nvc0_copy_create(struct drm_device *dev, int engine); ++ ++/* nv40_mpeg.c */ ++extern int nv40_mpeg_create(struct drm_device *dev); ++ ++/* nv50_mpeg.c */ ++extern int nv50_mpeg_create(struct drm_device *dev); + + /* nv04_instmem.c */ + extern int nv04_instmem_init(struct drm_device *); +@@ -1402,8 +1353,8 @@ + /* nv50_calc. */ + int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk, + int *N1, int *M1, int *N2, int *M2, int *P); +-int nv50_calc_pll2(struct drm_device *, struct pll_lims *, +- int clk, int *N, int *fN, int *M, int *P); ++int nva3_calc_pll(struct drm_device *, struct pll_lims *, ++ int clk, int *N, int *fN, int *M, int *P); + + #ifndef ioread32_native + #ifdef __BIG_ENDIAN +@@ -1579,6 +1530,13 @@ + dev->pdev->subsystem_device == sub_device; + } + ++static inline void * ++nv_engine(struct drm_device *dev, int engine) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ return (void *)dev_priv->eng[engine]; ++} ++ + /* returns 1 if device is one of the nv4x using the 0x4497 object class, + * helpful to determine a number of other hardware features + */ +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_grctx.h linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_grctx.h +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_grctx.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_grctx.h 2011-05-09 00:36:22.000000000 +0200 +@@ -87,10 +87,10 @@ + cp_out(ctx, CP_BRA | (mod << 18) | ip | flag | + (state ? 0 : CP_BRA_IF_CLEAR)); + } +-#define cp_bra(c,f,s,n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n) ++#define cp_bra(c, f, s, n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n) + #ifdef CP_BRA_MOD +-#define cp_cal(c,f,s,n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n) +-#define cp_ret(c,f,s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0) ++#define cp_cal(c, f, s, n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n) ++#define cp_ret(c, f, s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0) + #endif + + static inline void +@@ -98,14 +98,14 @@ + { + cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0)); + } +-#define cp_wait(c,f,s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s) ++#define cp_wait(c, f, s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s) + + static inline void + _cp_set(struct nouveau_grctx *ctx, int flag, int state) + { + cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0)); + } +-#define cp_set(c,f,s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s) ++#define cp_set(c, f, s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s) + + static inline void + cp_pos(struct nouveau_grctx *ctx, int offset) +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_mem.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_mem.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_mem.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_mem.c 2011-05-09 00:36:22.000000000 +0200 +@@ -51,8 +51,7 @@ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- int i = tile - dev_priv->tile.reg; ++ int i = tile - dev_priv->tile.reg, j; + unsigned long save; + + nouveau_fence_unref(&tile->fence); +@@ -70,7 +69,10 @@ + nouveau_wait_for_idle(dev); + + pfb->set_tile_region(dev, i); +- pgraph->set_tile_region(dev, i); ++ for (j = 0; j < NVOBJ_ENGINE_NR; j++) { ++ if (dev_priv->eng[j] && dev_priv->eng[j]->set_tile_region) ++ dev_priv->eng[j]->set_tile_region(dev, i); ++ } + + pfifo->cache_pull(dev, true); + pfifo->reassign(dev, true); +@@ -152,8 +154,6 @@ + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + +- nouveau_bo_ref(NULL, &dev_priv->vga_ram); +- + ttm_bo_device_release(&dev_priv->ttm.bdev); + + nouveau_ttm_global_release(dev_priv); +@@ -597,10 +597,10 @@ + if (!memtimings->timing) + return; + +- /* Get "some number" from the timing reg for NV_40 ++ /* Get "some number" from the timing reg for NV_40 and NV_50 + * Used in calculations later */ +- if(dev_priv->card_type == NV_40) { +- magic_number = (nv_rd32(dev,0x100228) & 0x0f000000) >> 24; ++ if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) { ++ magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24; + } + + entry = mem + mem[1]; +@@ -643,51 +643,68 @@ + /* XXX: I don't trust the -1's and +1's... they must come + * from somewhere! */ + timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 | +- tUNK_18 << 16 | ++ max(tUNK_18, (u8) 1) << 16 | + (tUNK_1 + tUNK_19 + 1 + magic_number) << 8; +- if(dev_priv->chipset == 0xa8) { ++ if (dev_priv->chipset == 0xa8) { + timing->reg_100224 |= (tUNK_2 - 1); + } else { + timing->reg_100224 |= (tUNK_2 + 2 - magic_number); + } + + timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); +- if(dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) { ++ if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) + timing->reg_100228 |= (tUNK_19 - 1) << 24; +- } ++ else ++ timing->reg_100228 |= magic_number << 24; + +- if(dev_priv->card_type == NV_40) { ++ if (dev_priv->card_type == NV_40) { + /* NV40: don't know what the rest of the regs are.. + * And don't need to know either */ +- timing->reg_100228 |= 0x20200000 | magic_number << 24; +- } else if(dev_priv->card_type >= NV_50) { +- /* XXX: reg_10022c */ +- timing->reg_10022c = tUNK_2 - 1; ++ timing->reg_100228 |= 0x20200000; ++ } else if (dev_priv->card_type >= NV_50) { ++ if (dev_priv->chipset < 0x98 || ++ (dev_priv->chipset == 0x98 && ++ dev_priv->stepping <= 0xa1)) { ++ timing->reg_10022c = (0x14 + tUNK_2) << 24 | ++ 0x16 << 16 | ++ (tUNK_2 - 1) << 8 | ++ (tUNK_2 - 1); ++ } else { ++ /* XXX: reg_10022c for recentish cards */ ++ timing->reg_10022c = tUNK_2 - 1; ++ } + + timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | + tUNK_13 << 8 | tUNK_13); + + timing->reg_100234 = (tRAS << 24 | tRC); +- timing->reg_100234 += max(tUNK_10,tUNK_11) << 16; ++ timing->reg_100234 += max(tUNK_10, tUNK_11) << 16; + +- if(dev_priv->chipset < 0xa3) { ++ if (dev_priv->chipset < 0x98 || ++ (dev_priv->chipset == 0x98 && ++ dev_priv->stepping <= 0xa1)) { + timing->reg_100234 |= (tUNK_2 + 2) << 8; + } else { + /* XXX: +6? */ + timing->reg_100234 |= (tUNK_19 + 6) << 8; + } + +- /* XXX; reg_100238, reg_10023c +- * reg_100238: 0x00?????? +- * reg_10023c: 0x!!??0202 for NV50+ cards (empirical evidence) */ ++ /* XXX; reg_100238 ++ * reg_100238: 0x00?????? */ + timing->reg_10023c = 0x202; +- if(dev_priv->chipset < 0xa3) { ++ if (dev_priv->chipset < 0x98 || ++ (dev_priv->chipset == 0x98 && ++ dev_priv->stepping <= 0xa1)) { + timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16; + } else { +- /* currently unknown ++ /* XXX: reg_10023c ++ * currently unknown + * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ + } ++ ++ /* XXX: reg_100240? */ + } ++ timing->id = i; + + NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, + timing->reg_100220, timing->reg_100224, +@@ -695,10 +712,11 @@ + NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", + timing->reg_100230, timing->reg_100234, + timing->reg_100238, timing->reg_10023c); ++ NV_DEBUG(dev, " 240: %08x\n", timing->reg_100240); + } + + memtimings->nr_timing = entries; +- memtimings->supported = true; ++ memtimings->supported = (dev_priv->chipset <= 0x98); + } + + void +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_object.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_object.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_object.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_object.c 2011-05-09 00:36:22.000000000 +0200 +@@ -361,20 +361,6 @@ + return 0; + } + +- +-static uint32_t +-nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- +- /*XXX: dodgy hack for now */ +- if (dev_priv->card_type >= NV_50) +- return 24; +- if (dev_priv->card_type >= NV_40) +- return 32; +- return 16; +-} +- + /* + DMA objects are used to reference a piece of memory in the + framebuffer, PCI or AGP address space. Each object is 16 bytes big +@@ -606,11 +592,11 @@ + set to 0? + */ + static int +-nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class, +- struct nouveau_gpuobj **gpuobj_ret) ++nouveau_gpuobj_sw_new(struct nouveau_channel *chan, u32 handle, u16 class) + { + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct nouveau_gpuobj *gpuobj; ++ int ret; + + gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL); + if (!gpuobj) +@@ -624,8 +610,10 @@ + spin_lock(&dev_priv->ramin_lock); + list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); + spin_unlock(&dev_priv->ramin_lock); +- *gpuobj_ret = gpuobj; +- return 0; ++ ++ ret = nouveau_ramht_insert(chan, handle, gpuobj); ++ nouveau_gpuobj_ref(NULL, &gpuobj); ++ return ret; + } + + int +@@ -634,101 +622,30 @@ + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct drm_device *dev = chan->dev; + struct nouveau_gpuobj_class *oc; +- struct nouveau_gpuobj *gpuobj; + int ret; + + NV_DEBUG(dev, "ch%d class=0x%04x\n", chan->id, class); + + list_for_each_entry(oc, &dev_priv->classes, head) { +- if (oc->id == class) +- goto found; +- } ++ struct nouveau_exec_engine *eng = dev_priv->eng[oc->engine]; + +- NV_ERROR(dev, "illegal object class: 0x%x\n", class); +- return -EINVAL; ++ if (oc->id != class) ++ continue; + +-found: +- switch (oc->engine) { +- case NVOBJ_ENGINE_SW: +- if (dev_priv->card_type < NV_C0) { +- ret = nouveau_gpuobj_sw_new(chan, class, &gpuobj); +- if (ret) +- return ret; +- goto insert; +- } +- break; +- case NVOBJ_ENGINE_GR: +- if ((dev_priv->card_type >= NV_20 && !chan->ramin_grctx) || +- (dev_priv->card_type < NV_20 && !chan->pgraph_ctx)) { +- struct nouveau_pgraph_engine *pgraph = +- &dev_priv->engine.graph; ++ if (oc->engine == NVOBJ_ENGINE_SW) ++ return nouveau_gpuobj_sw_new(chan, handle, class); + +- ret = pgraph->create_context(chan); ++ if (!chan->engctx[oc->engine]) { ++ ret = eng->context_new(chan, oc->engine); + if (ret) + return ret; + } +- break; +- case NVOBJ_ENGINE_CRYPT: +- if (!chan->crypt_ctx) { +- struct nouveau_crypt_engine *pcrypt = +- &dev_priv->engine.crypt; + +- ret = pcrypt->create_context(chan); +- if (ret) +- return ret; +- } +- break; +- } +- +- /* we're done if this is fermi */ +- if (dev_priv->card_type >= NV_C0) +- return 0; +- +- ret = nouveau_gpuobj_new(dev, chan, +- nouveau_gpuobj_class_instmem_size(dev, class), +- 16, +- NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, +- &gpuobj); +- if (ret) { +- NV_ERROR(dev, "error creating gpuobj: %d\n", ret); +- return ret; ++ return eng->object_new(chan, oc->engine, handle, class); + } + +- if (dev_priv->card_type >= NV_50) { +- nv_wo32(gpuobj, 0, class); +- nv_wo32(gpuobj, 20, 0x00010000); +- } else { +- switch (class) { +- case NV_CLASS_NULL: +- nv_wo32(gpuobj, 0, 0x00001030); +- nv_wo32(gpuobj, 4, 0xFFFFFFFF); +- break; +- default: +- if (dev_priv->card_type >= NV_40) { +- nv_wo32(gpuobj, 0, class); +-#ifdef __BIG_ENDIAN +- nv_wo32(gpuobj, 8, 0x01000000); +-#endif +- } else { +-#ifdef __BIG_ENDIAN +- nv_wo32(gpuobj, 0, class | 0x00080000); +-#else +- nv_wo32(gpuobj, 0, class); +-#endif +- } +- } +- } +- dev_priv->engine.instmem.flush(dev); +- +- gpuobj->engine = oc->engine; +- gpuobj->class = oc->id; +- +-insert: +- ret = nouveau_ramht_insert(chan, handle, gpuobj); +- if (ret) +- NV_ERROR(dev, "error adding gpuobj to RAMHT: %d\n", ret); +- nouveau_gpuobj_ref(NULL, &gpuobj); +- return ret; ++ NV_ERROR(dev, "illegal object class: 0x%x\n", class); ++ return -EINVAL; + } + + static int +@@ -746,9 +663,6 @@ + size = 0x2000; + base = 0; + +- /* PGRAPH context */ +- size += dev_priv->engine.graph.grctx_size; +- + if (dev_priv->card_type == NV_50) { + /* Various fixed table thingos */ + size += 0x1400; /* mostly unknown stuff */ +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_perf.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_perf.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_perf.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_perf.c 2011-05-09 00:36:22.000000000 +0200 +@@ -72,6 +72,68 @@ + pm->nr_perflvl = 1; + } + ++static struct nouveau_pm_memtiming * ++nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P, ++ u16 memclk, u8 *entry, u8 recordlen, u8 entries) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_pm_engine *pm = &dev_priv->engine.pm; ++ struct nvbios *bios = &dev_priv->vbios; ++ u8 ramcfg; ++ int i; ++ ++ /* perf v2 has a separate "timing map" table, we have to match ++ * the target memory clock to a specific entry, *then* use ++ * ramcfg to select the correct subentry ++ */ ++ if (P->version == 2) { ++ u8 *tmap = ROMPTR(bios, P->data[4]); ++ if (!tmap) { ++ NV_DEBUG(dev, "no timing map pointer\n"); ++ return NULL; ++ } ++ ++ if (tmap[0] != 0x10) { ++ NV_WARN(dev, "timing map 0x%02x unknown\n", tmap[0]); ++ return NULL; ++ } ++ ++ entry = tmap + tmap[1]; ++ recordlen = tmap[2] + (tmap[4] * tmap[3]); ++ for (i = 0; i < tmap[5]; i++, entry += recordlen) { ++ if (memclk >= ROM16(entry[0]) && ++ memclk <= ROM16(entry[2])) ++ break; ++ } ++ ++ if (i == tmap[5]) { ++ NV_WARN(dev, "no match in timing map table\n"); ++ return NULL; ++ } ++ ++ entry += tmap[2]; ++ recordlen = tmap[3]; ++ entries = tmap[4]; ++ } ++ ++ ramcfg = (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x0000003c) >> 2; ++ if (bios->ram_restrict_tbl_ptr) ++ ramcfg = bios->data[bios->ram_restrict_tbl_ptr + ramcfg]; ++ ++ if (ramcfg >= entries) { ++ NV_WARN(dev, "ramcfg strap out of bounds!\n"); ++ return NULL; ++ } ++ ++ entry += ramcfg * recordlen; ++ if (entry[1] >= pm->memtimings.nr_timing) { ++ NV_WARN(dev, "timingset %d does not exist\n", entry[1]); ++ return NULL; ++ } ++ ++ return &pm->memtimings.timing[entry[1]]; ++} ++ + void + nouveau_perf_init(struct drm_device *dev) + { +@@ -124,6 +186,8 @@ + for (i = 0; i < entries; i++) { + struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl]; + ++ perflvl->timing = NULL; ++ + if (entry[0] == 0xff) { + entry += recordlen; + continue; +@@ -174,9 +238,21 @@ + #define subent(n) entry[perf[2] + ((n) * perf[3])] + perflvl->fanspeed = 0; /*XXX*/ + perflvl->voltage = entry[2]; +- perflvl->core = (ROM16(subent(0)) & 0xfff) * 1000; +- perflvl->shader = (ROM16(subent(1)) & 0xfff) * 1000; +- perflvl->memory = (ROM16(subent(2)) & 0xfff) * 1000; ++ if (dev_priv->card_type == NV_50) { ++ perflvl->core = ROM16(subent(0)) & 0xfff; ++ perflvl->shader = ROM16(subent(1)) & 0xfff; ++ perflvl->memory = ROM16(subent(2)) & 0xfff; ++ } else { ++ perflvl->shader = ROM16(subent(3)) & 0xfff; ++ perflvl->core = perflvl->shader / 2; ++ perflvl->unk0a = ROM16(subent(4)) & 0xfff; ++ perflvl->memory = ROM16(subent(5)) & 0xfff; ++ } ++ ++ perflvl->core *= 1000; ++ perflvl->shader *= 1000; ++ perflvl->memory *= 1000; ++ perflvl->unk0a *= 1000; + break; + } + +@@ -190,6 +266,16 @@ + } + } + ++ /* get the corresponding memory timings */ ++ if (version > 0x15) { ++ /* last 3 args are for < 0x40, ignored for >= 0x40 */ ++ perflvl->timing = ++ nouveau_perf_timing(dev, &P, ++ perflvl->memory / 1000, ++ entry + perf[3], ++ perf[5], perf[4]); ++ } ++ + snprintf(perflvl->name, sizeof(perflvl->name), + "performance_level_%d", i); + perflvl->id = i; +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_pm.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_pm.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_pm.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_pm.c 2011-05-09 00:36:22.000000000 +0200 +@@ -156,7 +156,7 @@ + static void + nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) + { +- char c[16], s[16], v[16], f[16]; ++ char c[16], s[16], v[16], f[16], t[16]; + + c[0] = '\0'; + if (perflvl->core) +@@ -174,8 +174,12 @@ + if (perflvl->fanspeed) + snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed); + +- snprintf(ptr, len, "memory %dMHz%s%s%s%s\n", perflvl->memory / 1000, +- c, s, v, f); ++ t[0] = '\0'; ++ if (perflvl->timing) ++ snprintf(t, sizeof(t), " timing %d", perflvl->timing->id); ++ ++ snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000, ++ c, s, v, f, t); + } + + static ssize_t +@@ -449,7 +453,7 @@ + #endif + } + +-#ifdef CONFIG_ACPI ++#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) + static int + nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data) + { +@@ -476,10 +480,10 @@ + char info[256]; + int ret, i; + ++ nouveau_mem_timing_init(dev); + nouveau_volt_init(dev); + nouveau_perf_init(dev); + nouveau_temp_init(dev); +- nouveau_mem_timing_init(dev); + + NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl); + for (i = 0; i < pm->nr_perflvl; i++) { +@@ -490,6 +494,7 @@ + /* determine current ("boot") performance level */ + ret = nouveau_pm_perflvl_get(dev, &pm->boot); + if (ret == 0) { ++ strncpy(pm->boot.name, "boot", 4); + pm->cur = &pm->boot; + + nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info)); +@@ -507,7 +512,7 @@ + + nouveau_sysfs_init(dev); + nouveau_hwmon_init(dev); +-#ifdef CONFIG_ACPI ++#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) + pm->acpi_nb.notifier_call = nouveau_pm_acpi_event; + register_acpi_notifier(&pm->acpi_nb); + #endif +@@ -524,12 +529,12 @@ + if (pm->cur != &pm->boot) + nouveau_pm_perflvl_set(dev, &pm->boot); + +- nouveau_mem_timing_fini(dev); + nouveau_temp_fini(dev); + nouveau_perf_fini(dev); + nouveau_volt_fini(dev); ++ nouveau_mem_timing_fini(dev); + +-#ifdef CONFIG_ACPI ++#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) + unregister_acpi_notifier(&pm->acpi_nb); + #endif + nouveau_hwmon_fini(dev); +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_reg.h linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_reg.h +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_reg.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_reg.h 2011-05-09 00:36:22.000000000 +0200 +@@ -639,9 +639,9 @@ + # define NV50_PCONNECTOR_I2C_PORT_4 0x0000e240 + # define NV50_PCONNECTOR_I2C_PORT_5 0x0000e258 + +-#define NV50_AUXCH_DATA_OUT(i,n) ((n) * 4 + (i) * 0x50 + 0x0000e4c0) ++#define NV50_AUXCH_DATA_OUT(i, n) ((n) * 4 + (i) * 0x50 + 0x0000e4c0) + #define NV50_AUXCH_DATA_OUT__SIZE 4 +-#define NV50_AUXCH_DATA_IN(i,n) ((n) * 4 + (i) * 0x50 + 0x0000e4d0) ++#define NV50_AUXCH_DATA_IN(i, n) ((n) * 4 + (i) * 0x50 + 0x0000e4d0) + #define NV50_AUXCH_DATA_IN__SIZE 4 + #define NV50_AUXCH_ADDR(i) ((i) * 0x50 + 0x0000e4e0) + #define NV50_AUXCH_CTRL(i) ((i) * 0x50 + 0x0000e4e4) +@@ -829,7 +829,7 @@ + #define NV50_PDISPLAY_SOR_BACKLIGHT 0x0061c084 + #define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000 + #define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff +-#define NV50_SOR_DP_CTRL(i,l) (0x0061c10c + (i) * 0x800 + (l) * 0x80) ++#define NV50_SOR_DP_CTRL(i, l) (0x0061c10c + (i) * 0x800 + (l) * 0x80) + #define NV50_SOR_DP_CTRL_ENABLED 0x00000001 + #define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED 0x00004000 + #define NV50_SOR_DP_CTRL_LANE_MASK 0x001f0000 +@@ -841,10 +841,10 @@ + #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_DISABLED 0x00000000 + #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_1 0x01000000 + #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2 0x02000000 +-#define NV50_SOR_DP_UNK118(i,l) (0x0061c118 + (i) * 0x800 + (l) * 0x80) +-#define NV50_SOR_DP_UNK120(i,l) (0x0061c120 + (i) * 0x800 + (l) * 0x80) +-#define NV50_SOR_DP_UNK128(i,l) (0x0061c128 + (i) * 0x800 + (l) * 0x80) +-#define NV50_SOR_DP_UNK130(i,l) (0x0061c130 + (i) * 0x800 + (l) * 0x80) ++#define NV50_SOR_DP_UNK118(i, l) (0x0061c118 + (i) * 0x800 + (l) * 0x80) ++#define NV50_SOR_DP_UNK120(i, l) (0x0061c120 + (i) * 0x800 + (l) * 0x80) ++#define NV50_SOR_DP_UNK128(i, l) (0x0061c128 + (i) * 0x800 + (l) * 0x80) ++#define NV50_SOR_DP_UNK130(i, l) (0x0061c130 + (i) * 0x800 + (l) * 0x80) + + #define NV50_PDISPLAY_USER(i) ((i) * 0x1000 + 0x00640000) + #define NV50_PDISPLAY_USER_PUT(i) ((i) * 0x1000 + 0x00640000) +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_state.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_state.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_state.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_state.c 2011-05-09 00:36:22.000000000 +0200 +@@ -65,14 +65,6 @@ + engine->timer.takedown = nv04_timer_takedown; + engine->fb.init = nv04_fb_init; + engine->fb.takedown = nv04_fb_takedown; +- engine->graph.init = nv04_graph_init; +- engine->graph.takedown = nv04_graph_takedown; +- engine->graph.fifo_access = nv04_graph_fifo_access; +- engine->graph.channel = nv04_graph_channel; +- engine->graph.create_context = nv04_graph_create_context; +- engine->graph.destroy_context = nv04_graph_destroy_context; +- engine->graph.load_context = nv04_graph_load_context; +- engine->graph.unload_context = nv04_graph_unload_context; + engine->fifo.channels = 16; + engine->fifo.init = nv04_fifo_init; + engine->fifo.takedown = nv04_fifo_fini; +@@ -98,8 +90,6 @@ + engine->pm.clock_get = nv04_pm_clock_get; + engine->pm.clock_pre = nv04_pm_clock_pre; + engine->pm.clock_set = nv04_pm_clock_set; +- engine->crypt.init = nouveau_stub_init; +- engine->crypt.takedown = nouveau_stub_takedown; + engine->vram.init = nouveau_mem_detect; + engine->vram.flags_valid = nouveau_mem_flags_valid; + break; +@@ -123,15 +113,6 @@ + engine->fb.init_tile_region = nv10_fb_init_tile_region; + engine->fb.set_tile_region = nv10_fb_set_tile_region; + engine->fb.free_tile_region = nv10_fb_free_tile_region; +- engine->graph.init = nv10_graph_init; +- engine->graph.takedown = nv10_graph_takedown; +- engine->graph.channel = nv10_graph_channel; +- engine->graph.create_context = nv10_graph_create_context; +- engine->graph.destroy_context = nv10_graph_destroy_context; +- engine->graph.fifo_access = nv04_graph_fifo_access; +- engine->graph.load_context = nv10_graph_load_context; +- engine->graph.unload_context = nv10_graph_unload_context; +- engine->graph.set_tile_region = nv10_graph_set_tile_region; + engine->fifo.channels = 32; + engine->fifo.init = nv10_fifo_init; + engine->fifo.takedown = nv04_fifo_fini; +@@ -157,8 +138,6 @@ + engine->pm.clock_get = nv04_pm_clock_get; + engine->pm.clock_pre = nv04_pm_clock_pre; + engine->pm.clock_set = nv04_pm_clock_set; +- engine->crypt.init = nouveau_stub_init; +- engine->crypt.takedown = nouveau_stub_takedown; + engine->vram.init = nouveau_mem_detect; + engine->vram.flags_valid = nouveau_mem_flags_valid; + break; +@@ -182,15 +161,6 @@ + engine->fb.init_tile_region = nv10_fb_init_tile_region; + engine->fb.set_tile_region = nv10_fb_set_tile_region; + engine->fb.free_tile_region = nv10_fb_free_tile_region; +- engine->graph.init = nv20_graph_init; +- engine->graph.takedown = nv20_graph_takedown; +- engine->graph.channel = nv10_graph_channel; +- engine->graph.create_context = nv20_graph_create_context; +- engine->graph.destroy_context = nv20_graph_destroy_context; +- engine->graph.fifo_access = nv04_graph_fifo_access; +- engine->graph.load_context = nv20_graph_load_context; +- engine->graph.unload_context = nv20_graph_unload_context; +- engine->graph.set_tile_region = nv20_graph_set_tile_region; + engine->fifo.channels = 32; + engine->fifo.init = nv10_fifo_init; + engine->fifo.takedown = nv04_fifo_fini; +@@ -216,8 +186,6 @@ + engine->pm.clock_get = nv04_pm_clock_get; + engine->pm.clock_pre = nv04_pm_clock_pre; + engine->pm.clock_set = nv04_pm_clock_set; +- engine->crypt.init = nouveau_stub_init; +- engine->crypt.takedown = nouveau_stub_takedown; + engine->vram.init = nouveau_mem_detect; + engine->vram.flags_valid = nouveau_mem_flags_valid; + break; +@@ -241,15 +209,6 @@ + engine->fb.init_tile_region = nv30_fb_init_tile_region; + engine->fb.set_tile_region = nv10_fb_set_tile_region; + engine->fb.free_tile_region = nv30_fb_free_tile_region; +- engine->graph.init = nv30_graph_init; +- engine->graph.takedown = nv20_graph_takedown; +- engine->graph.fifo_access = nv04_graph_fifo_access; +- engine->graph.channel = nv10_graph_channel; +- engine->graph.create_context = nv20_graph_create_context; +- engine->graph.destroy_context = nv20_graph_destroy_context; +- engine->graph.load_context = nv20_graph_load_context; +- engine->graph.unload_context = nv20_graph_unload_context; +- engine->graph.set_tile_region = nv20_graph_set_tile_region; + engine->fifo.channels = 32; + engine->fifo.init = nv10_fifo_init; + engine->fifo.takedown = nv04_fifo_fini; +@@ -277,8 +236,6 @@ + engine->pm.clock_set = nv04_pm_clock_set; + engine->pm.voltage_get = nouveau_voltage_gpio_get; + engine->pm.voltage_set = nouveau_voltage_gpio_set; +- engine->crypt.init = nouveau_stub_init; +- engine->crypt.takedown = nouveau_stub_takedown; + engine->vram.init = nouveau_mem_detect; + engine->vram.flags_valid = nouveau_mem_flags_valid; + break; +@@ -303,15 +260,6 @@ + engine->fb.init_tile_region = nv30_fb_init_tile_region; + engine->fb.set_tile_region = nv40_fb_set_tile_region; + engine->fb.free_tile_region = nv30_fb_free_tile_region; +- engine->graph.init = nv40_graph_init; +- engine->graph.takedown = nv40_graph_takedown; +- engine->graph.fifo_access = nv04_graph_fifo_access; +- engine->graph.channel = nv40_graph_channel; +- engine->graph.create_context = nv40_graph_create_context; +- engine->graph.destroy_context = nv40_graph_destroy_context; +- engine->graph.load_context = nv40_graph_load_context; +- engine->graph.unload_context = nv40_graph_unload_context; +- engine->graph.set_tile_region = nv40_graph_set_tile_region; + engine->fifo.channels = 32; + engine->fifo.init = nv40_fifo_init; + engine->fifo.takedown = nv04_fifo_fini; +@@ -340,8 +288,6 @@ + engine->pm.voltage_get = nouveau_voltage_gpio_get; + engine->pm.voltage_set = nouveau_voltage_gpio_set; + engine->pm.temp_get = nv40_temp_get; +- engine->crypt.init = nouveau_stub_init; +- engine->crypt.takedown = nouveau_stub_takedown; + engine->vram.init = nouveau_mem_detect; + engine->vram.flags_valid = nouveau_mem_flags_valid; + break; +@@ -368,19 +314,6 @@ + engine->timer.takedown = nv04_timer_takedown; + engine->fb.init = nv50_fb_init; + engine->fb.takedown = nv50_fb_takedown; +- engine->graph.init = nv50_graph_init; +- engine->graph.takedown = nv50_graph_takedown; +- engine->graph.fifo_access = nv50_graph_fifo_access; +- engine->graph.channel = nv50_graph_channel; +- engine->graph.create_context = nv50_graph_create_context; +- engine->graph.destroy_context = nv50_graph_destroy_context; +- engine->graph.load_context = nv50_graph_load_context; +- engine->graph.unload_context = nv50_graph_unload_context; +- if (dev_priv->chipset == 0x50 || +- dev_priv->chipset == 0xac) +- engine->graph.tlb_flush = nv50_graph_tlb_flush; +- else +- engine->graph.tlb_flush = nv84_graph_tlb_flush; + engine->fifo.channels = 128; + engine->fifo.init = nv50_fifo_init; + engine->fifo.takedown = nv50_fifo_takedown; +@@ -432,24 +365,6 @@ + engine->pm.temp_get = nv84_temp_get; + else + engine->pm.temp_get = nv40_temp_get; +- switch (dev_priv->chipset) { +- case 0x84: +- case 0x86: +- case 0x92: +- case 0x94: +- case 0x96: +- case 0xa0: +- engine->crypt.init = nv84_crypt_init; +- engine->crypt.takedown = nv84_crypt_fini; +- engine->crypt.create_context = nv84_crypt_create_context; +- engine->crypt.destroy_context = nv84_crypt_destroy_context; +- engine->crypt.tlb_flush = nv84_crypt_tlb_flush; +- break; +- default: +- engine->crypt.init = nouveau_stub_init; +- engine->crypt.takedown = nouveau_stub_takedown; +- break; +- } + engine->vram.init = nv50_vram_init; + engine->vram.get = nv50_vram_new; + engine->vram.put = nv50_vram_del; +@@ -472,14 +387,6 @@ + engine->timer.takedown = nv04_timer_takedown; + engine->fb.init = nvc0_fb_init; + engine->fb.takedown = nvc0_fb_takedown; +- engine->graph.init = nvc0_graph_init; +- engine->graph.takedown = nvc0_graph_takedown; +- engine->graph.fifo_access = nvc0_graph_fifo_access; +- engine->graph.channel = nvc0_graph_channel; +- engine->graph.create_context = nvc0_graph_create_context; +- engine->graph.destroy_context = nvc0_graph_destroy_context; +- engine->graph.load_context = nvc0_graph_load_context; +- engine->graph.unload_context = nvc0_graph_unload_context; + engine->fifo.channels = 128; + engine->fifo.init = nvc0_fifo_init; + engine->fifo.takedown = nvc0_fifo_takedown; +@@ -503,8 +410,6 @@ + engine->gpio.irq_register = nv50_gpio_irq_register; + engine->gpio.irq_unregister = nv50_gpio_irq_unregister; + engine->gpio.irq_enable = nv50_gpio_irq_enable; +- engine->crypt.init = nouveau_stub_init; +- engine->crypt.takedown = nouveau_stub_takedown; + engine->vram.init = nvc0_vram_init; + engine->vram.get = nvc0_vram_new; + engine->vram.put = nv50_vram_del; +@@ -593,7 +498,7 @@ + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_engine *engine; +- int ret; ++ int ret, e = 0; + + vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); + vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state, +@@ -658,23 +563,80 @@ + if (ret) + goto out_timer; + +- if (nouveau_noaccel) +- engine->graph.accel_blocked = true; +- else { +- /* PGRAPH */ +- ret = engine->graph.init(dev); +- if (ret) +- goto out_fb; ++ switch (dev_priv->card_type) { ++ case NV_04: ++ nv04_graph_create(dev); ++ break; ++ case NV_10: ++ nv10_graph_create(dev); ++ break; ++ case NV_20: ++ case NV_30: ++ nv20_graph_create(dev); ++ break; ++ case NV_40: ++ nv40_graph_create(dev); ++ break; ++ case NV_50: ++ nv50_graph_create(dev); ++ break; ++ case NV_C0: ++ nvc0_graph_create(dev); ++ break; ++ default: ++ break; ++ } + +- /* PCRYPT */ +- ret = engine->crypt.init(dev); +- if (ret) +- goto out_graph; ++ switch (dev_priv->chipset) { ++ case 0x84: ++ case 0x86: ++ case 0x92: ++ case 0x94: ++ case 0x96: ++ case 0xa0: ++ nv84_crypt_create(dev); ++ break; ++ } ++ ++ switch (dev_priv->card_type) { ++ case NV_50: ++ switch (dev_priv->chipset) { ++ case 0xa3: ++ case 0xa5: ++ case 0xa8: ++ case 0xaf: ++ nva3_copy_create(dev); ++ break; ++ } ++ break; ++ case NV_C0: ++ nvc0_copy_create(dev, 0); ++ nvc0_copy_create(dev, 1); ++ break; ++ default: ++ break; ++ } ++ ++ if (dev_priv->card_type == NV_40) ++ nv40_mpeg_create(dev); ++ else ++ if (dev_priv->card_type == NV_50 && ++ (dev_priv->chipset < 0x98 || dev_priv->chipset == 0xa0)) ++ nv50_mpeg_create(dev); ++ ++ if (!nouveau_noaccel) { ++ for (e = 0; e < NVOBJ_ENGINE_NR; e++) { ++ if (dev_priv->eng[e]) { ++ ret = dev_priv->eng[e]->init(dev, e); ++ if (ret) ++ goto out_engine; ++ } ++ } + + /* PFIFO */ + ret = engine->fifo.init(dev); + if (ret) +- goto out_crypt; ++ goto out_engine; + } + + ret = engine->display.create(dev); +@@ -691,7 +653,7 @@ + + /* what about PVIDEO/PCRTC/PRAMDAC etc? */ + +- if (!engine->graph.accel_blocked) { ++ if (dev_priv->eng[NVOBJ_ENGINE_GR]) { + ret = nouveau_fence_init(dev); + if (ret) + goto out_irq; +@@ -715,13 +677,16 @@ + out_fifo: + if (!nouveau_noaccel) + engine->fifo.takedown(dev); +-out_crypt: +- if (!nouveau_noaccel) +- engine->crypt.takedown(dev); +-out_graph: +- if (!nouveau_noaccel) +- engine->graph.takedown(dev); +-out_fb: ++out_engine: ++ if (!nouveau_noaccel) { ++ for (e = e - 1; e >= 0; e--) { ++ if (!dev_priv->eng[e]) ++ continue; ++ dev_priv->eng[e]->fini(dev, e); ++ dev_priv->eng[e]->destroy(dev,e ); ++ } ++ } ++ + engine->fb.takedown(dev); + out_timer: + engine->timer.takedown(dev); +@@ -751,16 +716,21 @@ + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_engine *engine = &dev_priv->engine; ++ int e; + +- if (!engine->graph.accel_blocked) { ++ if (dev_priv->channel) { + nouveau_fence_fini(dev); + nouveau_channel_put_unlocked(&dev_priv->channel); + } + + if (!nouveau_noaccel) { + engine->fifo.takedown(dev); +- engine->crypt.takedown(dev); +- engine->graph.takedown(dev); ++ for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) { ++ if (dev_priv->eng[e]) { ++ dev_priv->eng[e]->fini(dev, e); ++ dev_priv->eng[e]->destroy(dev,e ); ++ } ++ } + } + engine->fb.takedown(dev); + engine->timer.takedown(dev); +@@ -768,6 +738,11 @@ + engine->mc.takedown(dev); + engine->display.late_takedown(dev); + ++ if (dev_priv->vga_ram) { ++ nouveau_bo_unpin(dev_priv->vga_ram); ++ nouveau_bo_ref(NULL, &dev_priv->vga_ram); ++ } ++ + mutex_lock(&dev->struct_mutex); + ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); + ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); +@@ -861,7 +836,7 @@ + #ifdef CONFIG_X86 + primary = dev->pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; + #endif +- ++ + remove_conflicting_framebuffers(dev_priv->apertures, "nouveaufb", primary); + return 0; + } +@@ -913,11 +888,13 @@ + + /* Time to determine the card architecture */ + reg0 = nv_rd32(dev, NV03_PMC_BOOT_0); ++ dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */ + + /* We're dealing with >=NV10 */ + if ((reg0 & 0x0f000000) > 0) { + /* Bit 27-20 contain the architecture in hex */ + dev_priv->chipset = (reg0 & 0xff00000) >> 20; ++ dev_priv->stepping = (reg0 & 0xff); + /* NV04 or NV05 */ + } else if ((reg0 & 0xff00fff0) == 0x20004000) { + if (reg0 & 0x00f00000) +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_vm.h linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_vm.h +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_vm.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_vm.h 2011-05-09 00:36:22.000000000 +0200 +@@ -53,8 +53,7 @@ + int refcount; + + struct list_head pgd_list; +- atomic_t pgraph_refs; +- atomic_t pcrypt_refs; ++ atomic_t engref[16]; + + struct nouveau_vm_pgt *pgt; + u32 fpde; +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_volt.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_volt.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nouveau_volt.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nouveau_volt.c 2011-05-09 00:36:22.000000000 +0200 +@@ -159,8 +159,16 @@ + headerlen = volt[1]; + recordlen = volt[2]; + entries = volt[3]; +- vidshift = hweight8(volt[5]); + vidmask = volt[4]; ++ /* no longer certain what volt[5] is, if it's related to ++ * the vid shift then it's definitely not a function of ++ * how many bits are set. ++ * ++ * after looking at a number of nva3+ vbios images, they ++ * all seem likely to have a static shift of 2.. lets ++ * go with that for now until proven otherwise. ++ */ ++ vidshift = 2; + break; + default: + NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]); +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv04_crtc.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv04_crtc.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv04_crtc.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv04_crtc.c 2011-05-09 00:36:22.000000000 +0200 +@@ -790,8 +790,7 @@ + if (atomic) { + drm_fb = passed_fb; + fb = nouveau_framebuffer(passed_fb); +- } +- else { ++ } else { + /* If not atomic, we can go ahead and pin, and unpin the + * old fb we were passed. + */ +@@ -944,14 +943,14 @@ + struct drm_gem_object *gem; + int ret = 0; + +- if (width != 64 || height != 64) +- return -EINVAL; +- + if (!buffer_handle) { + nv_crtc->cursor.hide(nv_crtc, true); + return 0; + } + ++ if (width != 64 || height != 64) ++ return -EINVAL; ++ + gem = drm_gem_object_lookup(dev, file_priv, buffer_handle); + if (!gem) + return -ENOENT; +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv04_graph.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv04_graph.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv04_graph.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv04_graph.c 2011-05-09 00:36:22.000000000 +0200 +@@ -28,9 +28,11 @@ + #include "nouveau_drv.h" + #include "nouveau_hw.h" + #include "nouveau_util.h" ++#include "nouveau_ramht.h" + +-static int nv04_graph_register(struct drm_device *dev); +-static void nv04_graph_isr(struct drm_device *dev); ++struct nv04_graph_engine { ++ struct nouveau_exec_engine base; ++}; + + static uint32_t nv04_graph_ctx_regs[] = { + 0x0040053c, +@@ -350,7 +352,7 @@ + uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)]; + }; + +-struct nouveau_channel * ++static struct nouveau_channel * + nv04_graph_channel(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -365,26 +367,6 @@ + return dev_priv->channels.ptr[chid]; + } + +-static void +-nv04_graph_context_switch(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct nouveau_channel *chan = NULL; +- int chid; +- +- nouveau_wait_for_idle(dev); +- +- /* If previous context is valid, we need to save it */ +- pgraph->unload_context(dev); +- +- /* Load context for next channel */ +- chid = dev_priv->engine.fifo.channel_id(dev); +- chan = dev_priv->channels.ptr[chid]; +- if (chan) +- nv04_graph_load_context(chan); +-} +- + static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg) + { + int i; +@@ -397,48 +379,11 @@ + return NULL; + } + +-int nv04_graph_create_context(struct nouveau_channel *chan) +-{ +- struct graph_state *pgraph_ctx; +- NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id); +- +- chan->pgraph_ctx = pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), +- GFP_KERNEL); +- if (pgraph_ctx == NULL) +- return -ENOMEM; +- +- *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31; +- +- return 0; +-} +- +-void nv04_graph_destroy_context(struct nouveau_channel *chan) +-{ +- struct drm_device *dev = chan->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct graph_state *pgraph_ctx = chan->pgraph_ctx; +- unsigned long flags; +- +- spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- pgraph->fifo_access(dev, false); +- +- /* Unload the context if it's the currently active one */ +- if (pgraph->channel(dev) == chan) +- pgraph->unload_context(dev); +- +- /* Free the context resources */ +- kfree(pgraph_ctx); +- chan->pgraph_ctx = NULL; +- +- pgraph->fifo_access(dev, true); +- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +-} +- +-int nv04_graph_load_context(struct nouveau_channel *chan) ++static int ++nv04_graph_load_context(struct nouveau_channel *chan) + { ++ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR]; + struct drm_device *dev = chan->dev; +- struct graph_state *pgraph_ctx = chan->pgraph_ctx; + uint32_t tmp; + int i; + +@@ -456,20 +401,19 @@ + return 0; + } + +-int ++static int + nv04_graph_unload_context(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_channel *chan = NULL; + struct graph_state *ctx; + uint32_t tmp; + int i; + +- chan = pgraph->channel(dev); ++ chan = nv04_graph_channel(dev); + if (!chan) + return 0; +- ctx = chan->pgraph_ctx; ++ ctx = chan->engctx[NVOBJ_ENGINE_GR]; + + for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) + ctx->nv04[i] = nv_rd32(dev, nv04_graph_ctx_regs[i]); +@@ -481,23 +425,85 @@ + return 0; + } + +-int nv04_graph_init(struct drm_device *dev) ++static int ++nv04_graph_context_new(struct nouveau_channel *chan, int engine) + { ++ struct graph_state *pgraph_ctx; ++ NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id); ++ ++ pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL); ++ if (pgraph_ctx == NULL) ++ return -ENOMEM; ++ ++ *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31; ++ ++ chan->engctx[engine] = pgraph_ctx; ++ return 0; ++} ++ ++static void ++nv04_graph_context_del(struct nouveau_channel *chan, int engine) ++{ ++ struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- uint32_t tmp; ++ struct graph_state *pgraph_ctx = chan->engctx[engine]; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv04_graph_fifo_access(dev, false); ++ ++ /* Unload the context if it's the currently active one */ ++ if (nv04_graph_channel(dev) == chan) ++ nv04_graph_unload_context(dev); ++ ++ nv04_graph_fifo_access(dev, true); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ ++ /* Free the context resources */ ++ kfree(pgraph_ctx); ++ chan->engctx[engine] = NULL; ++} ++ ++int ++nv04_graph_object_new(struct nouveau_channel *chan, int engine, ++ u32 handle, u16 class) ++{ ++ struct drm_device *dev = chan->dev; ++ struct nouveau_gpuobj *obj = NULL; + int ret; + ++ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj); ++ if (ret) ++ return ret; ++ obj->engine = 1; ++ obj->class = class; ++ ++#ifdef __BIG_ENDIAN ++ nv_wo32(obj, 0x00, 0x00080000 | class); ++#else ++ nv_wo32(obj, 0x00, class); ++#endif ++ nv_wo32(obj, 0x04, 0x00000000); ++ nv_wo32(obj, 0x08, 0x00000000); ++ nv_wo32(obj, 0x0c, 0x00000000); ++ ++ ret = nouveau_ramht_insert(chan, handle, obj); ++ nouveau_gpuobj_ref(NULL, &obj); ++ return ret; ++} ++ ++static int ++nv04_graph_init(struct drm_device *dev, int engine) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ uint32_t tmp; ++ + nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & + ~NV_PMC_ENABLE_PGRAPH); + nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | + NV_PMC_ENABLE_PGRAPH); + +- ret = nv04_graph_register(dev); +- if (ret) +- return ret; +- + /* Enable PGRAPH interrupts */ +- nouveau_irq_register(dev, 12, nv04_graph_isr); + nv_wr32(dev, NV03_PGRAPH_INTR, 0xFFFFFFFF); + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + +@@ -507,7 +513,7 @@ + nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/ + nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x1231c000); + /*1231C000 blob, 001 haiku*/ +- //*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/ ++ /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/ + nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x72111100); + /*0x72111100 blob , 01 haiku*/ + /*nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/ +@@ -531,10 +537,12 @@ + return 0; + } + +-void nv04_graph_takedown(struct drm_device *dev) ++static int ++nv04_graph_fini(struct drm_device *dev, int engine) + { ++ nv04_graph_unload_context(dev); + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); +- nouveau_irq_unregister(dev, 12); ++ return 0; + } + + void +@@ -969,13 +977,138 @@ + return 1; + } + +-static int +-nv04_graph_register(struct drm_device *dev) ++static struct nouveau_bitfield nv04_graph_intr[] = { ++ { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" }, ++ {} ++}; ++ ++static struct nouveau_bitfield nv04_graph_nstatus[] = { ++ { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, ++ { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" }, ++ { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" }, ++ { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }, ++ {} ++}; ++ ++struct nouveau_bitfield nv04_graph_nsource[] = { ++ { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" }, ++ { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" }, ++ { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" }, ++ { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" }, ++ { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" }, ++ { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" }, ++ { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" }, ++ { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" }, ++ { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" }, ++ { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" }, ++ { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" }, ++ { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" }, ++ { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" }, ++ { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" }, ++ { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" }, ++ { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" }, ++ { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" }, ++ { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" }, ++ { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" }, ++ {} ++}; ++ ++static void ++nv04_graph_context_switch(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_channel *chan = NULL; ++ int chid; + +- if (dev_priv->engine.graph.registered) +- return 0; ++ nouveau_wait_for_idle(dev); ++ ++ /* If previous context is valid, we need to save it */ ++ nv04_graph_unload_context(dev); ++ ++ /* Load context for next channel */ ++ chid = dev_priv->engine.fifo.channel_id(dev); ++ chan = dev_priv->channels.ptr[chid]; ++ if (chan) ++ nv04_graph_load_context(chan); ++} ++ ++static void ++nv04_graph_isr(struct drm_device *dev) ++{ ++ u32 stat; ++ ++ while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) { ++ u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); ++ u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS); ++ u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); ++ u32 chid = (addr & 0x0f000000) >> 24; ++ u32 subc = (addr & 0x0000e000) >> 13; ++ u32 mthd = (addr & 0x00001ffc); ++ u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); ++ u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff; ++ u32 show = stat; ++ ++ if (stat & NV_PGRAPH_INTR_NOTIFY) { ++ if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { ++ if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) ++ show &= ~NV_PGRAPH_INTR_NOTIFY; ++ } ++ } ++ ++ if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { ++ nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); ++ stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; ++ show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; ++ nv04_graph_context_switch(dev); ++ } ++ ++ nv_wr32(dev, NV03_PGRAPH_INTR, stat); ++ nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001); ++ ++ if (show && nouveau_ratelimit()) { ++ NV_INFO(dev, "PGRAPH -"); ++ nouveau_bitfield_print(nv04_graph_intr, show); ++ printk(" nsource:"); ++ nouveau_bitfield_print(nv04_graph_nsource, nsource); ++ printk(" nstatus:"); ++ nouveau_bitfield_print(nv04_graph_nstatus, nstatus); ++ printk("\n"); ++ NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x " ++ "mthd 0x%04x data 0x%08x\n", ++ chid, subc, class, mthd, data); ++ } ++ } ++} ++ ++static void ++nv04_graph_destroy(struct drm_device *dev, int engine) ++{ ++ struct nv04_graph_engine *pgraph = nv_engine(dev, engine); ++ ++ nouveau_irq_unregister(dev, 12); ++ ++ NVOBJ_ENGINE_DEL(dev, GR); ++ kfree(pgraph); ++} ++ ++int ++nv04_graph_create(struct drm_device *dev) ++{ ++ struct nv04_graph_engine *pgraph; ++ ++ pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL); ++ if (!pgraph) ++ return -ENOMEM; ++ ++ pgraph->base.destroy = nv04_graph_destroy; ++ pgraph->base.init = nv04_graph_init; ++ pgraph->base.fini = nv04_graph_fini; ++ pgraph->base.context_new = nv04_graph_context_new; ++ pgraph->base.context_del = nv04_graph_context_del; ++ pgraph->base.object_new = nv04_graph_object_new; ++ ++ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); ++ nouveau_irq_register(dev, 12, nv04_graph_isr); + + /* dvd subpicture */ + NVOBJ_CLASS(dev, 0x0038, GR); +@@ -1222,93 +1355,5 @@ + NVOBJ_CLASS(dev, 0x506e, SW); + NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref); + NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); +- +- dev_priv->engine.graph.registered = true; + return 0; +-}; +- +-static struct nouveau_bitfield nv04_graph_intr[] = { +- { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" }, +- {} +-}; +- +-static struct nouveau_bitfield nv04_graph_nstatus[] = +-{ +- { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, +- { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" }, +- { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" }, +- { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }, +- {} +-}; +- +-struct nouveau_bitfield nv04_graph_nsource[] = +-{ +- { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" }, +- { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" }, +- { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" }, +- { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" }, +- { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" }, +- { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" }, +- { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" }, +- { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" }, +- { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" }, +- { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" }, +- { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" }, +- { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" }, +- { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" }, +- { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" }, +- { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" }, +- { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" }, +- { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" }, +- { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" }, +- { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" }, +- {} +-}; +- +-static void +-nv04_graph_isr(struct drm_device *dev) +-{ +- u32 stat; +- +- while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) { +- u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); +- u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS); +- u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); +- u32 chid = (addr & 0x0f000000) >> 24; +- u32 subc = (addr & 0x0000e000) >> 13; +- u32 mthd = (addr & 0x00001ffc); +- u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); +- u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff; +- u32 show = stat; +- +- if (stat & NV_PGRAPH_INTR_NOTIFY) { +- if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { +- if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) +- show &= ~NV_PGRAPH_INTR_NOTIFY; +- } +- } +- +- if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { +- nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); +- stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; +- show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; +- nv04_graph_context_switch(dev); +- } +- +- nv_wr32(dev, NV03_PGRAPH_INTR, stat); +- nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001); +- +- if (show && nouveau_ratelimit()) { +- NV_INFO(dev, "PGRAPH -"); +- nouveau_bitfield_print(nv04_graph_intr, show); +- printk(" nsource:"); +- nouveau_bitfield_print(nv04_graph_nsource, nsource); +- printk(" nstatus:"); +- nouveau_bitfield_print(nv04_graph_nstatus, nstatus); +- printk("\n"); +- NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x " +- "mthd 0x%04x data 0x%08x\n", +- chid, subc, class, mthd, data); +- } +- } + } +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv04_instmem.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv04_instmem.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv04_instmem.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv04_instmem.c 2011-05-09 00:36:22.000000000 +0200 +@@ -95,6 +95,9 @@ + nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL); + nouveau_gpuobj_ref(NULL, &dev_priv->ramro); + nouveau_gpuobj_ref(NULL, &dev_priv->ramfc); ++ ++ if (drm_mm_initialized(&dev_priv->ramin_heap)) ++ drm_mm_takedown(&dev_priv->ramin_heap); + } + + int +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv10_graph.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv10_graph.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv10_graph.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv10_graph.c 2011-05-09 00:36:22.000000000 +0200 +@@ -28,10 +28,9 @@ + #include "nouveau_drv.h" + #include "nouveau_util.h" + +-static int nv10_graph_register(struct drm_device *); +-static void nv10_graph_isr(struct drm_device *); +- +-#define NV10_FIFO_NUMBER 32 ++struct nv10_graph_engine { ++ struct nouveau_exec_engine base; ++}; + + struct pipe_state { + uint32_t pipe_0x0000[0x040/4]; +@@ -414,9 +413,9 @@ + + static void nv10_graph_save_pipe(struct nouveau_channel *chan) + { +- struct drm_device *dev = chan->dev; +- struct graph_state *pgraph_ctx = chan->pgraph_ctx; ++ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR]; + struct pipe_state *pipe = &pgraph_ctx->pipe_state; ++ struct drm_device *dev = chan->dev; + + PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400); + PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200); +@@ -432,9 +431,9 @@ + + static void nv10_graph_load_pipe(struct nouveau_channel *chan) + { +- struct drm_device *dev = chan->dev; +- struct graph_state *pgraph_ctx = chan->pgraph_ctx; ++ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR]; + struct pipe_state *pipe = &pgraph_ctx->pipe_state; ++ struct drm_device *dev = chan->dev; + uint32_t xfmode0, xfmode1; + int i; + +@@ -482,9 +481,9 @@ + + static void nv10_graph_create_pipe(struct nouveau_channel *chan) + { +- struct drm_device *dev = chan->dev; +- struct graph_state *pgraph_ctx = chan->pgraph_ctx; ++ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR]; + struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state; ++ struct drm_device *dev = chan->dev; + uint32_t *fifo_pipe_state_addr; + int i; + #define PIPE_INIT(addr) \ +@@ -661,8 +660,6 @@ + uint32_t inst) + { + struct drm_device *dev = chan->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4]; + uint32_t ctx_user, ctx_switch[5]; + int i, subchan = -1; +@@ -711,8 +708,8 @@ + 0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c); + nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst); + nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); +- pgraph->fifo_access(dev, true); +- pgraph->fifo_access(dev, false); ++ nv04_graph_fifo_access(dev, true); ++ nv04_graph_fifo_access(dev, false); + + /* Restore the FIFO state */ + for (i = 0; i < ARRAY_SIZE(fifo); i++) +@@ -729,11 +726,12 @@ + nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user); + } + +-int nv10_graph_load_context(struct nouveau_channel *chan) ++static int ++nv10_graph_load_context(struct nouveau_channel *chan) + { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct graph_state *pgraph_ctx = chan->pgraph_ctx; ++ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR]; + uint32_t tmp; + int i; + +@@ -757,21 +755,20 @@ + return 0; + } + +-int ++static int + nv10_graph_unload_context(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nouveau_channel *chan; + struct graph_state *ctx; + uint32_t tmp; + int i; + +- chan = pgraph->channel(dev); ++ chan = nv10_graph_channel(dev); + if (!chan) + return 0; +- ctx = chan->pgraph_ctx; ++ ctx = chan->engctx[NVOBJ_ENGINE_GR]; + + for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++) + ctx->nv10[i] = nv_rd32(dev, nv10_graph_ctx_regs[i]); +@@ -805,7 +802,7 @@ + /* Load context for next channel */ + chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; + chan = dev_priv->channels.ptr[chid]; +- if (chan && chan->pgraph_ctx) ++ if (chan && chan->engctx[NVOBJ_ENGINE_GR]) + nv10_graph_load_context(chan); + } + +@@ -836,7 +833,8 @@ + return dev_priv->channels.ptr[chid]; + } + +-int nv10_graph_create_context(struct nouveau_channel *chan) ++static int ++nv10_graph_context_new(struct nouveau_channel *chan, int engine) + { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -844,11 +842,10 @@ + + NV_DEBUG(dev, "nv10_graph_context_create %d\n", chan->id); + +- chan->pgraph_ctx = pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), +- GFP_KERNEL); ++ pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL); + if (pgraph_ctx == NULL) + return -ENOMEM; +- ++ chan->engctx[engine] = pgraph_ctx; + + NV_WRITE_CTX(0x00400e88, 0x08000000); + NV_WRITE_CTX(0x00400e9c, 0x4b7fffff); +@@ -873,30 +870,30 @@ + return 0; + } + +-void nv10_graph_destroy_context(struct nouveau_channel *chan) ++static void ++nv10_graph_context_del(struct nouveau_channel *chan, int engine) + { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct graph_state *pgraph_ctx = chan->pgraph_ctx; ++ struct graph_state *pgraph_ctx = chan->engctx[engine]; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- pgraph->fifo_access(dev, false); ++ nv04_graph_fifo_access(dev, false); + + /* Unload the context if it's the currently active one */ +- if (pgraph->channel(dev) == chan) +- pgraph->unload_context(dev); ++ if (nv10_graph_channel(dev) == chan) ++ nv10_graph_unload_context(dev); ++ ++ nv04_graph_fifo_access(dev, true); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + + /* Free the context resources */ ++ chan->engctx[engine] = NULL; + kfree(pgraph_ctx); +- chan->pgraph_ctx = NULL; +- +- pgraph->fifo_access(dev, true); +- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + } + +-void ++static void + nv10_graph_set_tile_region(struct drm_device *dev, int i) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -907,22 +904,18 @@ + nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr); + } + +-int nv10_graph_init(struct drm_device *dev) ++static int ++nv10_graph_init(struct drm_device *dev, int engine) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- uint32_t tmp; +- int ret, i; ++ u32 tmp; ++ int i; + + nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & + ~NV_PMC_ENABLE_PGRAPH); + nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | + NV_PMC_ENABLE_PGRAPH); + +- ret = nv10_graph_register(dev); +- if (ret) +- return ret; +- +- nouveau_irq_register(dev, 12, nv10_graph_isr); + nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + +@@ -963,18 +956,20 @@ + return 0; + } + +-void nv10_graph_takedown(struct drm_device *dev) ++static int ++nv10_graph_fini(struct drm_device *dev, int engine) + { ++ nv10_graph_unload_context(dev); + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); +- nouveau_irq_unregister(dev, 12); ++ return 0; + } + + static int + nv17_graph_mthd_lma_window(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) + { ++ struct graph_state *ctx = chan->engctx[NVOBJ_ENGINE_GR]; + struct drm_device *dev = chan->dev; +- struct graph_state *ctx = chan->pgraph_ctx; + struct pipe_state *pipe = &ctx->pipe_state; + uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3]; + uint32_t xfmode0, xfmode1; +@@ -1061,64 +1056,13 @@ + return 0; + } + +-static int +-nv10_graph_register(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- +- if (dev_priv->engine.graph.registered) +- return 0; +- +- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ +- NVOBJ_CLASS(dev, 0x0030, GR); /* null */ +- NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ +- NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ +- NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */ +- NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ +- NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ +- NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ +- NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ +- NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ +- NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ +- NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ +- NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ +- NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ +- NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */ +- NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */ +- NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */ +- NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */ +- +- /* celcius */ +- if (dev_priv->chipset <= 0x10) { +- NVOBJ_CLASS(dev, 0x0056, GR); +- } else +- if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) { +- NVOBJ_CLASS(dev, 0x0096, GR); +- } else { +- NVOBJ_CLASS(dev, 0x0099, GR); +- NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window); +- NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window); +- NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window); +- NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window); +- NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable); +- } +- +- /* nvsw */ +- NVOBJ_CLASS(dev, 0x506e, SW); +- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); +- +- dev_priv->engine.graph.registered = true; +- return 0; +-} +- + struct nouveau_bitfield nv10_graph_intr[] = { + { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" }, + { NV_PGRAPH_INTR_ERROR, "ERROR" }, + {} + }; + +-struct nouveau_bitfield nv10_graph_nstatus[] = +-{ ++struct nouveau_bitfield nv10_graph_nstatus[] = { + { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, + { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" }, + { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" }, +@@ -1173,3 +1117,73 @@ + } + } + } ++ ++static void ++nv10_graph_destroy(struct drm_device *dev, int engine) ++{ ++ struct nv10_graph_engine *pgraph = nv_engine(dev, engine); ++ ++ nouveau_irq_unregister(dev, 12); ++ kfree(pgraph); ++} ++ ++int ++nv10_graph_create(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv10_graph_engine *pgraph; ++ ++ pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL); ++ if (!pgraph) ++ return -ENOMEM; ++ ++ pgraph->base.destroy = nv10_graph_destroy; ++ pgraph->base.init = nv10_graph_init; ++ pgraph->base.fini = nv10_graph_fini; ++ pgraph->base.context_new = nv10_graph_context_new; ++ pgraph->base.context_del = nv10_graph_context_del; ++ pgraph->base.object_new = nv04_graph_object_new; ++ pgraph->base.set_tile_region = nv10_graph_set_tile_region; ++ ++ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); ++ nouveau_irq_register(dev, 12, nv10_graph_isr); ++ ++ /* nvsw */ ++ NVOBJ_CLASS(dev, 0x506e, SW); ++ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); ++ ++ NVOBJ_CLASS(dev, 0x0030, GR); /* null */ ++ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ ++ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ ++ NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */ ++ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ ++ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ ++ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ ++ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ ++ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ ++ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ ++ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ ++ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ ++ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ ++ NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */ ++ NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */ ++ NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */ ++ NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */ ++ ++ /* celcius */ ++ if (dev_priv->chipset <= 0x10) { ++ NVOBJ_CLASS(dev, 0x0056, GR); ++ } else ++ if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) { ++ NVOBJ_CLASS(dev, 0x0096, GR); ++ } else { ++ NVOBJ_CLASS(dev, 0x0099, GR); ++ NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window); ++ NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window); ++ NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window); ++ NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window); ++ NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable); ++ } ++ ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv20_graph.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv20_graph.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv20_graph.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv20_graph.c 2011-05-09 00:36:22.000000000 +0200 +@@ -24,6 +24,14 @@ + * + */ + ++struct nv20_graph_engine { ++ struct nouveau_exec_engine base; ++ struct nouveau_gpuobj *ctxtab; ++ void (*grctx_init)(struct nouveau_gpuobj *); ++ u32 grctx_size; ++ u32 grctx_user; ++}; ++ + #define NV20_GRCTX_SIZE (3580*4) + #define NV25_GRCTX_SIZE (3529*4) + #define NV2A_GRCTX_SIZE (3500*4) +@@ -32,12 +40,54 @@ + #define NV34_GRCTX_SIZE (18140) + #define NV35_36_GRCTX_SIZE (22396) + +-static int nv20_graph_register(struct drm_device *); +-static int nv30_graph_register(struct drm_device *); +-static void nv20_graph_isr(struct drm_device *); ++int ++nv20_graph_unload_context(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; ++ struct nouveau_channel *chan; ++ struct nouveau_gpuobj *grctx; ++ u32 tmp; ++ ++ chan = nv10_graph_channel(dev); ++ if (!chan) ++ return 0; ++ grctx = chan->engctx[NVOBJ_ENGINE_GR]; ++ ++ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, grctx->pinst >> 4); ++ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER, ++ NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE); ++ ++ nouveau_wait_for_idle(dev); ++ ++ nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000); ++ tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff; ++ tmp |= (pfifo->channels - 1) << 24; ++ nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp); ++ return 0; ++} + + static void +-nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) ++nv20_graph_rdi(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ int i, writecount = 32; ++ uint32_t rdi_index = 0x2c80000; ++ ++ if (dev_priv->chipset == 0x20) { ++ rdi_index = 0x3d0000; ++ writecount = 15; ++ } ++ ++ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index); ++ for (i = 0; i < writecount; i++) ++ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0); ++ ++ nouveau_wait_for_idle(dev); ++} ++ ++static void ++nv20_graph_context_init(struct nouveau_gpuobj *ctx) + { + int i; + +@@ -87,7 +137,7 @@ + } + + static void +-nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) ++nv25_graph_context_init(struct nouveau_gpuobj *ctx) + { + int i; + +@@ -146,7 +196,7 @@ + } + + static void +-nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) ++nv2a_graph_context_init(struct nouveau_gpuobj *ctx) + { + int i; + +@@ -196,7 +246,7 @@ + } + + static void +-nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) ++nv30_31_graph_context_init(struct nouveau_gpuobj *ctx) + { + int i; + +@@ -254,7 +304,7 @@ + } + + static void +-nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) ++nv34_graph_context_init(struct nouveau_gpuobj *ctx) + { + int i; + +@@ -312,7 +362,7 @@ + } + + static void +-nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) ++nv35_36_graph_context_init(struct nouveau_gpuobj *ctx) + { + int i; + +@@ -370,148 +420,57 @@ + } + + int +-nv20_graph_create_context(struct nouveau_channel *chan) ++nv20_graph_context_new(struct nouveau_channel *chan, int engine) + { ++ struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine); ++ struct nouveau_gpuobj *grctx = NULL; + struct drm_device *dev = chan->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *); +- unsigned int idoffs = 0x28; + int ret; + +- switch (dev_priv->chipset) { +- case 0x20: +- ctx_init = nv20_graph_context_init; +- idoffs = 0; +- break; +- case 0x25: +- case 0x28: +- ctx_init = nv25_graph_context_init; +- break; +- case 0x2a: +- ctx_init = nv2a_graph_context_init; +- idoffs = 0; +- break; +- case 0x30: +- case 0x31: +- ctx_init = nv30_31_graph_context_init; +- break; +- case 0x34: +- ctx_init = nv34_graph_context_init; +- break; +- case 0x35: +- case 0x36: +- ctx_init = nv35_36_graph_context_init; +- break; +- default: +- BUG_ON(1); +- } +- +- ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16, +- NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx); ++ ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16, ++ NVOBJ_FLAG_ZERO_ALLOC, &grctx); + if (ret) + return ret; + + /* Initialise default context values */ +- ctx_init(dev, chan->ramin_grctx); ++ pgraph->grctx_init(grctx); + + /* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */ +- nv_wo32(chan->ramin_grctx, idoffs, +- (chan->id << 24) | 0x1); /* CTX_USER */ ++ /* CTX_USER */ ++ nv_wo32(grctx, pgraph->grctx_user, (chan->id << 24) | 0x1); + +- nv_wo32(pgraph->ctx_table, chan->id * 4, chan->ramin_grctx->pinst >> 4); ++ nv_wo32(pgraph->ctxtab, chan->id * 4, grctx->pinst >> 4); ++ chan->engctx[engine] = grctx; + return 0; + } + + void +-nv20_graph_destroy_context(struct nouveau_channel *chan) ++nv20_graph_context_del(struct nouveau_channel *chan, int engine) + { ++ struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine); ++ struct nouveau_gpuobj *grctx = chan->engctx[engine]; + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- pgraph->fifo_access(dev, false); ++ nv04_graph_fifo_access(dev, false); + + /* Unload the context if it's the currently active one */ +- if (pgraph->channel(dev) == chan) +- pgraph->unload_context(dev); ++ if (nv10_graph_channel(dev) == chan) ++ nv20_graph_unload_context(dev); + +- pgraph->fifo_access(dev, true); ++ nv04_graph_fifo_access(dev, true); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + + /* Free the context resources */ +- nv_wo32(pgraph->ctx_table, chan->id * 4, 0); +- nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); +-} +- +-int +-nv20_graph_load_context(struct nouveau_channel *chan) +-{ +- struct drm_device *dev = chan->dev; +- uint32_t inst; +- +- if (!chan->ramin_grctx) +- return -EINVAL; +- inst = chan->ramin_grctx->pinst >> 4; ++ nv_wo32(pgraph->ctxtab, chan->id * 4, 0); + +- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); +- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER, +- NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD); +- nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100); +- +- nouveau_wait_for_idle(dev); +- return 0; +-} +- +-int +-nv20_graph_unload_context(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; +- struct nouveau_channel *chan; +- uint32_t inst, tmp; +- +- chan = pgraph->channel(dev); +- if (!chan) +- return 0; +- inst = chan->ramin_grctx->pinst >> 4; +- +- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); +- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER, +- NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE); +- +- nouveau_wait_for_idle(dev); +- +- nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000); +- tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff; +- tmp |= (pfifo->channels - 1) << 24; +- nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp); +- return 0; ++ nouveau_gpuobj_ref(NULL, &grctx); ++ chan->engctx[engine] = NULL; + } + + static void +-nv20_graph_rdi(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- int i, writecount = 32; +- uint32_t rdi_index = 0x2c80000; +- +- if (dev_priv->chipset == 0x20) { +- rdi_index = 0x3d0000; +- writecount = 15; +- } +- +- nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index); +- for (i = 0; i < writecount; i++) +- nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0); +- +- nouveau_wait_for_idle(dev); +-} +- +-void + nv20_graph_set_tile_region(struct drm_device *dev, int i) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -536,56 +495,22 @@ + } + + int +-nv20_graph_init(struct drm_device *dev) ++nv20_graph_init(struct drm_device *dev, int engine) + { ++ struct nv20_graph_engine *pgraph = nv_engine(dev, engine); + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + uint32_t tmp, vramsz; +- int ret, i; +- +- switch (dev_priv->chipset) { +- case 0x20: +- pgraph->grctx_size = NV20_GRCTX_SIZE; +- break; +- case 0x25: +- case 0x28: +- pgraph->grctx_size = NV25_GRCTX_SIZE; +- break; +- case 0x2a: +- pgraph->grctx_size = NV2A_GRCTX_SIZE; +- break; +- default: +- NV_ERROR(dev, "unknown chipset, disabling acceleration\n"); +- pgraph->accel_blocked = true; +- return 0; +- } ++ int i; + + nv_wr32(dev, NV03_PMC_ENABLE, + nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); + nv_wr32(dev, NV03_PMC_ENABLE, + nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); + +- if (!pgraph->ctx_table) { +- /* Create Context Pointer Table */ +- ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, +- NVOBJ_FLAG_ZERO_ALLOC, +- &pgraph->ctx_table); +- if (ret) +- return ret; +- } +- +- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, +- pgraph->ctx_table->pinst >> 4); ++ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4); + + nv20_graph_rdi(dev); + +- ret = nv20_graph_register(dev); +- if (ret) { +- nouveau_gpuobj_ref(NULL, &pgraph->ctx_table); +- return ret; +- } +- +- nouveau_irq_register(dev, 12, nv20_graph_isr); + nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + +@@ -657,67 +582,20 @@ + return 0; + } + +-void +-nv20_graph_takedown(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- +- nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); +- nouveau_irq_unregister(dev, 12); +- +- nouveau_gpuobj_ref(NULL, &pgraph->ctx_table); +-} +- + int +-nv30_graph_init(struct drm_device *dev) ++nv30_graph_init(struct drm_device *dev, int engine) + { ++ struct nv20_graph_engine *pgraph = nv_engine(dev, engine); + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- int ret, i; +- +- switch (dev_priv->chipset) { +- case 0x30: +- case 0x31: +- pgraph->grctx_size = NV30_31_GRCTX_SIZE; +- break; +- case 0x34: +- pgraph->grctx_size = NV34_GRCTX_SIZE; +- break; +- case 0x35: +- case 0x36: +- pgraph->grctx_size = NV35_36_GRCTX_SIZE; +- break; +- default: +- NV_ERROR(dev, "unknown chipset, disabling acceleration\n"); +- pgraph->accel_blocked = true; +- return 0; +- } ++ int i; + + nv_wr32(dev, NV03_PMC_ENABLE, + nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); + nv_wr32(dev, NV03_PMC_ENABLE, + nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); + +- if (!pgraph->ctx_table) { +- /* Create Context Pointer Table */ +- ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, +- NVOBJ_FLAG_ZERO_ALLOC, +- &pgraph->ctx_table); +- if (ret) +- return ret; +- } +- +- ret = nv30_graph_register(dev); +- if (ret) { +- nouveau_gpuobj_ref(NULL, &pgraph->ctx_table); +- return ret; +- } ++ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4); + +- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, +- pgraph->ctx_table->pinst >> 4); +- +- nouveau_irq_register(dev, 12, nv20_graph_isr); + nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + +@@ -775,85 +653,11 @@ + return 0; + } + +-static int +-nv20_graph_register(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- +- if (dev_priv->engine.graph.registered) +- return 0; +- +- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ +- NVOBJ_CLASS(dev, 0x0030, GR); /* null */ +- NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ +- NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ +- NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ +- NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ +- NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ +- NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ +- NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ +- NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ +- NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ +- NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ +- NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ +- NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */ +- NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */ +- +- /* kelvin */ +- if (dev_priv->chipset < 0x25) +- NVOBJ_CLASS(dev, 0x0097, GR); +- else +- NVOBJ_CLASS(dev, 0x0597, GR); +- +- /* nvsw */ +- NVOBJ_CLASS(dev, 0x506e, SW); +- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); +- +- dev_priv->engine.graph.registered = true; +- return 0; +-} +- +-static int +-nv30_graph_register(struct drm_device *dev) ++int ++nv20_graph_fini(struct drm_device *dev, int engine) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- +- if (dev_priv->engine.graph.registered) +- return 0; +- +- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ +- NVOBJ_CLASS(dev, 0x0030, GR); /* null */ +- NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ +- NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ +- NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ +- NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ +- NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */ +- NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ +- NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */ +- NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ +- NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */ +- NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ +- NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ +- NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ +- NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ +- NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ +- NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */ +- +- /* rankine */ +- if (0x00000003 & (1 << (dev_priv->chipset & 0x0f))) +- NVOBJ_CLASS(dev, 0x0397, GR); +- else +- if (0x00000010 & (1 << (dev_priv->chipset & 0x0f))) +- NVOBJ_CLASS(dev, 0x0697, GR); +- else +- if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f))) +- NVOBJ_CLASS(dev, 0x0497, GR); +- +- /* nvsw */ +- NVOBJ_CLASS(dev, 0x506e, SW); +- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); +- +- dev_priv->engine.graph.registered = true; ++ nv20_graph_unload_context(dev); ++ nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); + return 0; + } + +@@ -897,3 +701,135 @@ + } + } + } ++ ++static void ++nv20_graph_destroy(struct drm_device *dev, int engine) ++{ ++ struct nv20_graph_engine *pgraph = nv_engine(dev, engine); ++ ++ nouveau_irq_unregister(dev, 12); ++ nouveau_gpuobj_ref(NULL, &pgraph->ctxtab); ++ ++ NVOBJ_ENGINE_DEL(dev, GR); ++ kfree(pgraph); ++} ++ ++int ++nv20_graph_create(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv20_graph_engine *pgraph; ++ int ret; ++ ++ pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL); ++ if (!pgraph) ++ return -ENOMEM; ++ ++ pgraph->base.destroy = nv20_graph_destroy; ++ pgraph->base.fini = nv20_graph_fini; ++ pgraph->base.context_new = nv20_graph_context_new; ++ pgraph->base.context_del = nv20_graph_context_del; ++ pgraph->base.object_new = nv04_graph_object_new; ++ pgraph->base.set_tile_region = nv20_graph_set_tile_region; ++ ++ pgraph->grctx_user = 0x0028; ++ if (dev_priv->card_type == NV_20) { ++ pgraph->base.init = nv20_graph_init; ++ switch (dev_priv->chipset) { ++ case 0x20: ++ pgraph->grctx_init = nv20_graph_context_init; ++ pgraph->grctx_size = NV20_GRCTX_SIZE; ++ pgraph->grctx_user = 0x0000; ++ break; ++ case 0x25: ++ case 0x28: ++ pgraph->grctx_init = nv25_graph_context_init; ++ pgraph->grctx_size = NV25_GRCTX_SIZE; ++ break; ++ case 0x2a: ++ pgraph->grctx_init = nv2a_graph_context_init; ++ pgraph->grctx_size = NV2A_GRCTX_SIZE; ++ pgraph->grctx_user = 0x0000; ++ break; ++ default: ++ NV_ERROR(dev, "PGRAPH: unknown chipset\n"); ++ return 0; ++ } ++ } else { ++ pgraph->base.init = nv30_graph_init; ++ switch (dev_priv->chipset) { ++ case 0x30: ++ case 0x31: ++ pgraph->grctx_init = nv30_31_graph_context_init; ++ pgraph->grctx_size = NV30_31_GRCTX_SIZE; ++ break; ++ case 0x34: ++ pgraph->grctx_init = nv34_graph_context_init; ++ pgraph->grctx_size = NV34_GRCTX_SIZE; ++ break; ++ case 0x35: ++ case 0x36: ++ pgraph->grctx_init = nv35_36_graph_context_init; ++ pgraph->grctx_size = NV35_36_GRCTX_SIZE; ++ break; ++ default: ++ NV_ERROR(dev, "PGRAPH: unknown chipset\n"); ++ return 0; ++ } ++ } ++ ++ /* Create Context Pointer Table */ ++ ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC, ++ &pgraph->ctxtab); ++ if (ret) { ++ kfree(pgraph); ++ return ret; ++ } ++ ++ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); ++ nouveau_irq_register(dev, 12, nv20_graph_isr); ++ ++ /* nvsw */ ++ NVOBJ_CLASS(dev, 0x506e, SW); ++ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); ++ ++ NVOBJ_CLASS(dev, 0x0030, GR); /* null */ ++ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ ++ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ ++ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ ++ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ ++ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ ++ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ ++ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ ++ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ ++ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ ++ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ ++ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ ++ if (dev_priv->card_type == NV_20) { ++ NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */ ++ NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */ ++ ++ /* kelvin */ ++ if (dev_priv->chipset < 0x25) ++ NVOBJ_CLASS(dev, 0x0097, GR); ++ else ++ NVOBJ_CLASS(dev, 0x0597, GR); ++ } else { ++ NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */ ++ NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */ ++ NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */ ++ NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */ ++ ++ /* rankine */ ++ if (0x00000003 & (1 << (dev_priv->chipset & 0x0f))) ++ NVOBJ_CLASS(dev, 0x0397, GR); ++ else ++ if (0x00000010 & (1 << (dev_priv->chipset & 0x0f))) ++ NVOBJ_CLASS(dev, 0x0697, GR); ++ else ++ if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f))) ++ NVOBJ_CLASS(dev, 0x0497, GR); ++ } ++ ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv40_fifo.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv40_fifo.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv40_fifo.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv40_fifo.c 2011-05-09 00:36:22.000000000 +0200 +@@ -115,6 +115,7 @@ + nv_wr32(dev, 0x32e8, nv_ri32(dev, fc + 68)); + nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76)); + nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80)); ++ nv_wr32(dev, 0x330c, nv_ri32(dev, fc + 84)); + + nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); + nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); +@@ -186,6 +187,7 @@ + tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16); + nv_wi32(dev, fc + 72, tmp); + #endif ++ nv_wi32(dev, fc + 84, nv_rd32(dev, 0x330c)); + + nv40_fifo_do_load_context(dev, pfifo->channels - 1); + nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv40_graph.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv40_graph.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv40_graph.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv40_graph.c 2011-05-09 00:36:22.000000000 +0200 +@@ -28,14 +28,18 @@ + #include "drm.h" + #include "nouveau_drv.h" + #include "nouveau_grctx.h" ++#include "nouveau_ramht.h" + +-static int nv40_graph_register(struct drm_device *); +-static void nv40_graph_isr(struct drm_device *); ++struct nv40_graph_engine { ++ struct nouveau_exec_engine base; ++ u32 grctx_size; ++}; + +-struct nouveau_channel * ++static struct nouveau_channel * + nv40_graph_channel(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *grctx; + uint32_t inst; + int i; + +@@ -45,74 +49,17 @@ + inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4; + + for (i = 0; i < dev_priv->engine.fifo.channels; i++) { +- struct nouveau_channel *chan = dev_priv->channels.ptr[i]; ++ if (!dev_priv->channels.ptr[i]) ++ continue; + +- if (chan && chan->ramin_grctx && +- chan->ramin_grctx->pinst == inst) +- return chan; ++ grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR]; ++ if (grctx && grctx->pinst == inst) ++ return dev_priv->channels.ptr[i]; + } + + return NULL; + } + +-int +-nv40_graph_create_context(struct nouveau_channel *chan) +-{ +- struct drm_device *dev = chan->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct nouveau_grctx ctx = {}; +- unsigned long flags; +- int ret; +- +- ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16, +- NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx); +- if (ret) +- return ret; +- +- /* Initialise default context values */ +- ctx.dev = chan->dev; +- ctx.mode = NOUVEAU_GRCTX_VALS; +- ctx.data = chan->ramin_grctx; +- nv40_grctx_init(&ctx); +- +- nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst); +- +- /* init grctx pointer in ramfc, and on PFIFO if channel is +- * already active there +- */ +- spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- nv_wo32(chan->ramfc, 0x38, chan->ramin_grctx->pinst >> 4); +- nv_mask(dev, 0x002500, 0x00000001, 0x00000000); +- if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id) +- nv_wr32(dev, 0x0032e0, chan->ramin_grctx->pinst >> 4); +- nv_mask(dev, 0x002500, 0x00000001, 0x00000001); +- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +- return 0; +-} +- +-void +-nv40_graph_destroy_context(struct nouveau_channel *chan) +-{ +- struct drm_device *dev = chan->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- unsigned long flags; +- +- spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- pgraph->fifo_access(dev, false); +- +- /* Unload the context if it's the currently active one */ +- if (pgraph->channel(dev) == chan) +- pgraph->unload_context(dev); +- +- pgraph->fifo_access(dev, true); +- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +- +- /* Free the context resources */ +- nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); +-} +- + static int + nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save) + { +@@ -154,57 +101,115 @@ + return 0; + } + +-/* Restore the context for a specific channel into PGRAPH */ +-int +-nv40_graph_load_context(struct nouveau_channel *chan) ++static int ++nv40_graph_unload_context(struct drm_device *dev) + { +- struct drm_device *dev = chan->dev; + uint32_t inst; + int ret; + +- if (!chan->ramin_grctx) +- return -EINVAL; +- inst = chan->ramin_grctx->pinst >> 4; ++ inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR); ++ if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED)) ++ return 0; ++ inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE; ++ ++ ret = nv40_graph_transfer_context(dev, inst, 1); ++ ++ nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst); ++ return ret; ++} ++ ++static int ++nv40_graph_context_new(struct nouveau_channel *chan, int engine) ++{ ++ struct nv40_graph_engine *pgraph = nv_engine(chan->dev, engine); ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *grctx = NULL; ++ struct nouveau_grctx ctx = {}; ++ unsigned long flags; ++ int ret; + +- ret = nv40_graph_transfer_context(dev, inst, 0); ++ ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16, ++ NVOBJ_FLAG_ZERO_ALLOC, &grctx); + if (ret) + return ret; + +- /* 0x40032C, no idea of it's exact function. Could simply be a +- * record of the currently active PGRAPH context. It's currently +- * unknown as to what bit 24 does. The nv ddx has it set, so we will +- * set it here too. +- */ +- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, +- (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) | +- NV40_PGRAPH_CTXCTL_CUR_LOADED); +- /* 0x32E0 records the instance address of the active FIFO's PGRAPH +- * context. If at any time this doesn't match 0x40032C, you will +- * receive PGRAPH_INTR_CONTEXT_SWITCH ++ /* Initialise default context values */ ++ ctx.dev = chan->dev; ++ ctx.mode = NOUVEAU_GRCTX_VALS; ++ ctx.data = grctx; ++ nv40_grctx_init(&ctx); ++ ++ nv_wo32(grctx, 0, grctx->vinst); ++ ++ /* init grctx pointer in ramfc, and on PFIFO if channel is ++ * already active there + */ +- nv_wr32(dev, NV40_PFIFO_GRCTX_INSTANCE, inst); ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv_wo32(chan->ramfc, 0x38, grctx->vinst >> 4); ++ nv_mask(dev, 0x002500, 0x00000001, 0x00000000); ++ if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id) ++ nv_wr32(dev, 0x0032e0, grctx->vinst >> 4); ++ nv_mask(dev, 0x002500, 0x00000001, 0x00000001); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ ++ chan->engctx[engine] = grctx; + return 0; + } + ++static void ++nv40_graph_context_del(struct nouveau_channel *chan, int engine) ++{ ++ struct nouveau_gpuobj *grctx = chan->engctx[engine]; ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv04_graph_fifo_access(dev, false); ++ ++ /* Unload the context if it's the currently active one */ ++ if (nv40_graph_channel(dev) == chan) ++ nv40_graph_unload_context(dev); ++ ++ nv04_graph_fifo_access(dev, true); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ ++ /* Free the context resources */ ++ nouveau_gpuobj_ref(NULL, &grctx); ++ chan->engctx[engine] = NULL; ++} ++ + int +-nv40_graph_unload_context(struct drm_device *dev) ++nv40_graph_object_new(struct nouveau_channel *chan, int engine, ++ u32 handle, u16 class) + { +- uint32_t inst; ++ struct drm_device *dev = chan->dev; ++ struct nouveau_gpuobj *obj = NULL; + int ret; + +- inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR); +- if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED)) +- return 0; +- inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE; ++ ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_FREE, &obj); ++ if (ret) ++ return ret; ++ obj->engine = 1; ++ obj->class = class; + +- ret = nv40_graph_transfer_context(dev, inst, 1); ++ nv_wo32(obj, 0x00, class); ++ nv_wo32(obj, 0x04, 0x00000000); ++#ifndef __BIG_ENDIAN ++ nv_wo32(obj, 0x08, 0x00000000); ++#else ++ nv_wo32(obj, 0x08, 0x01000000); ++#endif ++ nv_wo32(obj, 0x0c, 0x00000000); ++ nv_wo32(obj, 0x10, 0x00000000); + +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst); ++ ret = nouveau_ramht_insert(chan, handle, obj); ++ nouveau_gpuobj_ref(NULL, &obj); + return ret; + } + +-void ++static void + nv40_graph_set_tile_region(struct drm_device *dev, int i) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -257,14 +262,14 @@ + * C51 0x4e + */ + int +-nv40_graph_init(struct drm_device *dev) ++nv40_graph_init(struct drm_device *dev, int engine) + { +- struct drm_nouveau_private *dev_priv = +- (struct drm_nouveau_private *)dev->dev_private; ++ struct nv40_graph_engine *pgraph = nv_engine(dev, engine); ++ struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + struct nouveau_grctx ctx = {}; + uint32_t vramsz, *cp; +- int ret, i, j; ++ int i, j; + + nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & + ~NV_PMC_ENABLE_PGRAPH); +@@ -280,7 +285,7 @@ + ctx.data = cp; + ctx.ctxprog_max = 256; + nv40_grctx_init(&ctx); +- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4; ++ pgraph->grctx_size = ctx.ctxvals_pos * 4; + + nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); + for (i = 0; i < ctx.ctxprog_len; i++) +@@ -288,14 +293,9 @@ + + kfree(cp); + +- ret = nv40_graph_register(dev); +- if (ret) +- return ret; +- + /* No context present currently */ + nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); + +- nouveau_irq_register(dev, 12, nv40_graph_isr); + nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF); + +@@ -428,47 +428,10 @@ + return 0; + } + +-void nv40_graph_takedown(struct drm_device *dev) +-{ +- nouveau_irq_unregister(dev, 12); +-} +- + static int +-nv40_graph_register(struct drm_device *dev) ++nv40_graph_fini(struct drm_device *dev, int engine) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- +- if (dev_priv->engine.graph.registered) +- return 0; +- +- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ +- NVOBJ_CLASS(dev, 0x0030, GR); /* null */ +- NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ +- NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ +- NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ +- NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ +- NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ +- NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */ +- NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ +- NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */ +- NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ +- NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ +- NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ +- NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ +- NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ +- NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */ +- +- /* curie */ +- if (nv44_graph_class(dev)) +- NVOBJ_CLASS(dev, 0x4497, GR); +- else +- NVOBJ_CLASS(dev, 0x4097, GR); +- +- /* nvsw */ +- NVOBJ_CLASS(dev, 0x506e, SW); +- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); +- +- dev_priv->engine.graph.registered = true; ++ nv40_graph_unload_context(dev); + return 0; + } + +@@ -476,17 +439,17 @@ + nv40_graph_isr_chid(struct drm_device *dev, u32 inst) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_channel *chan; ++ struct nouveau_gpuobj *grctx; + unsigned long flags; + int i; + + spin_lock_irqsave(&dev_priv->channels.lock, flags); + for (i = 0; i < dev_priv->engine.fifo.channels; i++) { +- chan = dev_priv->channels.ptr[i]; +- if (!chan || !chan->ramin_grctx) ++ if (!dev_priv->channels.ptr[i]) + continue; ++ grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR]; + +- if (inst == chan->ramin_grctx->pinst) ++ if (grctx && grctx->pinst == inst) + break; + } + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); +@@ -537,3 +500,63 @@ + } + } + } ++ ++static void ++nv40_graph_destroy(struct drm_device *dev, int engine) ++{ ++ struct nv40_graph_engine *pgraph = nv_engine(dev, engine); ++ ++ nouveau_irq_unregister(dev, 12); ++ ++ NVOBJ_ENGINE_DEL(dev, GR); ++ kfree(pgraph); ++} ++ ++int ++nv40_graph_create(struct drm_device *dev) ++{ ++ struct nv40_graph_engine *pgraph; ++ ++ pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL); ++ if (!pgraph) ++ return -ENOMEM; ++ ++ pgraph->base.destroy = nv40_graph_destroy; ++ pgraph->base.init = nv40_graph_init; ++ pgraph->base.fini = nv40_graph_fini; ++ pgraph->base.context_new = nv40_graph_context_new; ++ pgraph->base.context_del = nv40_graph_context_del; ++ pgraph->base.object_new = nv40_graph_object_new; ++ pgraph->base.set_tile_region = nv40_graph_set_tile_region; ++ ++ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); ++ nouveau_irq_register(dev, 12, nv40_graph_isr); ++ ++ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ ++ NVOBJ_CLASS(dev, 0x0030, GR); /* null */ ++ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ ++ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ ++ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ ++ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ ++ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ ++ NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */ ++ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ ++ NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */ ++ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ ++ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ ++ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ ++ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ ++ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ ++ NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */ ++ ++ /* curie */ ++ if (nv44_graph_class(dev)) ++ NVOBJ_CLASS(dev, 0x4497, GR); ++ else ++ NVOBJ_CLASS(dev, 0x4097, GR); ++ ++ /* nvsw */ ++ NVOBJ_CLASS(dev, 0x506e, SW); ++ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv40_mpeg.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv40_mpeg.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv40_mpeg.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv40_mpeg.c 2011-05-09 00:36:22.000000000 +0200 +@@ -0,0 +1,311 @@ ++/* ++ * Copyright 2011 Red Hat Inc. ++ * ++ * 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 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 HOLDER(S) OR AUTHOR(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: Ben Skeggs ++ */ ++ ++#include "drmP.h" ++#include "nouveau_drv.h" ++#include "nouveau_ramht.h" ++ ++struct nv40_mpeg_engine { ++ struct nouveau_exec_engine base; ++}; ++ ++static int ++nv40_mpeg_context_new(struct nouveau_channel *chan, int engine) ++{ ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *ctx = NULL; ++ unsigned long flags; ++ int ret; ++ ++ NV_DEBUG(dev, "ch%d\n", chan->id); ++ ++ ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &ctx); ++ if (ret) ++ return ret; ++ ++ nv_wo32(ctx, 0x78, 0x02001ec1); ++ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv_mask(dev, 0x002500, 0x00000001, 0x00000000); ++ if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id) ++ nv_wr32(dev, 0x00330c, ctx->pinst >> 4); ++ nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4); ++ nv_mask(dev, 0x002500, 0x00000001, 0x00000001); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ ++ chan->engctx[engine] = ctx; ++ return 0; ++} ++ ++static void ++nv40_mpeg_context_del(struct nouveau_channel *chan, int engine) ++{ ++ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; ++ struct nouveau_gpuobj *ctx = chan->engctx[engine]; ++ struct drm_device *dev = chan->dev; ++ unsigned long flags; ++ u32 inst = 0x80000000 | (ctx->pinst >> 4); ++ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); ++ if (nv_rd32(dev, 0x00b318) == inst) ++ nv_mask(dev, 0x00b318, 0x80000000, 0x00000000); ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ ++ nouveau_gpuobj_ref(NULL, &ctx); ++ chan->engctx[engine] = NULL; ++} ++ ++static int ++nv40_mpeg_object_new(struct nouveau_channel *chan, int engine, ++ u32 handle, u16 class) ++{ ++ struct drm_device *dev = chan->dev; ++ struct nouveau_gpuobj *obj = NULL; ++ int ret; ++ ++ ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &obj); ++ if (ret) ++ return ret; ++ obj->engine = 2; ++ obj->class = class; ++ ++ nv_wo32(obj, 0x00, class); ++ ++ ret = nouveau_ramht_insert(chan, handle, obj); ++ nouveau_gpuobj_ref(NULL, &obj); ++ return ret; ++} ++ ++static int ++nv40_mpeg_init(struct drm_device *dev, int engine) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine); ++ int i; ++ ++ /* VPE init */ ++ nv_mask(dev, 0x000200, 0x00000002, 0x00000000); ++ nv_mask(dev, 0x000200, 0x00000002, 0x00000002); ++ nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ ++ nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ ++ ++ for (i = 0; i < dev_priv->engine.fb.num_tiles; i++) ++ pmpeg->base.set_tile_region(dev, i); ++ ++ /* PMPEG init */ ++ nv_wr32(dev, 0x00b32c, 0x00000000); ++ nv_wr32(dev, 0x00b314, 0x00000100); ++ nv_wr32(dev, 0x00b220, 0x00000044); ++ nv_wr32(dev, 0x00b300, 0x02001ec1); ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); ++ ++ nv_wr32(dev, 0x00b100, 0xffffffff); ++ nv_wr32(dev, 0x00b140, 0xffffffff); ++ ++ if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) { ++ NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200)); ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++static int ++nv40_mpeg_fini(struct drm_device *dev, int engine) ++{ ++ /*XXX: context save? */ ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); ++ nv_wr32(dev, 0x00b140, 0x00000000); ++ return 0; ++} ++ ++static int ++nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) ++{ ++ struct drm_device *dev = chan->dev; ++ u32 inst = data << 4; ++ u32 dma0 = nv_ri32(dev, inst + 0); ++ u32 dma1 = nv_ri32(dev, inst + 4); ++ u32 dma2 = nv_ri32(dev, inst + 8); ++ u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); ++ u32 size = dma1 + 1; ++ ++ /* only allow linear DMA objects */ ++ if (!(dma0 & 0x00002000)) ++ return -EINVAL; ++ ++ if (mthd == 0x0190) { ++ /* DMA_CMD */ ++ nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000)); ++ nv_wr32(dev, 0x00b334, base); ++ nv_wr32(dev, 0x00b324, size); ++ } else ++ if (mthd == 0x01a0) { ++ /* DMA_DATA */ ++ nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); ++ nv_wr32(dev, 0x00b360, base); ++ nv_wr32(dev, 0x00b364, size); ++ } else { ++ /* DMA_IMAGE, VRAM only */ ++ if (dma0 & 0x000c0000) ++ return -EINVAL; ++ ++ nv_wr32(dev, 0x00b370, base); ++ nv_wr32(dev, 0x00b374, size); ++ } ++ ++ return 0; ++} ++ ++static int ++nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *ctx; ++ unsigned long flags; ++ int i; ++ ++ spin_lock_irqsave(&dev_priv->channels.lock, flags); ++ for (i = 0; i < dev_priv->engine.fifo.channels; i++) { ++ if (!dev_priv->channels.ptr[i]) ++ continue; ++ ++ ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG]; ++ if (ctx && ctx->pinst == inst) ++ break; ++ } ++ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); ++ return i; ++} ++ ++static void ++nv40_vpe_set_tile_region(struct drm_device *dev, int i) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; ++ ++ nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch); ++ nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit); ++ nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr); ++} ++ ++static void ++nv40_mpeg_isr(struct drm_device *dev) ++{ ++ u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4; ++ u32 chid = nv40_mpeg_isr_chid(dev, inst); ++ u32 stat = nv_rd32(dev, 0x00b100); ++ u32 type = nv_rd32(dev, 0x00b230); ++ u32 mthd = nv_rd32(dev, 0x00b234); ++ u32 data = nv_rd32(dev, 0x00b238); ++ u32 show = stat; ++ ++ if (stat & 0x01000000) { ++ /* happens on initial binding of the object */ ++ if (type == 0x00000020 && mthd == 0x0000) { ++ nv_mask(dev, 0x00b308, 0x00000000, 0x00000000); ++ show &= ~0x01000000; ++ } ++ ++ if (type == 0x00000010) { ++ if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data)) ++ show &= ~0x01000000; ++ } ++ } ++ ++ nv_wr32(dev, 0x00b100, stat); ++ nv_wr32(dev, 0x00b230, 0x00000001); ++ ++ if (show && nouveau_ratelimit()) { ++ NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ chid, inst, stat, type, mthd, data); ++ } ++} ++ ++static void ++nv40_vpe_isr(struct drm_device *dev) ++{ ++ if (nv_rd32(dev, 0x00b100)) ++ nv40_mpeg_isr(dev); ++ ++ if (nv_rd32(dev, 0x00b800)) { ++ u32 stat = nv_rd32(dev, 0x00b800); ++ NV_INFO(dev, "PMSRCH: 0x%08x\n", stat); ++ nv_wr32(dev, 0xb800, stat); ++ } ++} ++ ++static void ++nv40_mpeg_destroy(struct drm_device *dev, int engine) ++{ ++ struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine); ++ ++ nouveau_irq_unregister(dev, 0); ++ ++ NVOBJ_ENGINE_DEL(dev, MPEG); ++ kfree(pmpeg); ++} ++ ++int ++nv40_mpeg_create(struct drm_device *dev) ++{ ++ struct nv40_mpeg_engine *pmpeg; ++ ++ pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); ++ if (!pmpeg) ++ return -ENOMEM; ++ ++ pmpeg->base.destroy = nv40_mpeg_destroy; ++ pmpeg->base.init = nv40_mpeg_init; ++ pmpeg->base.fini = nv40_mpeg_fini; ++ pmpeg->base.context_new = nv40_mpeg_context_new; ++ pmpeg->base.context_del = nv40_mpeg_context_del; ++ pmpeg->base.object_new = nv40_mpeg_object_new; ++ ++ /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between ++ * all VPE engines, for this driver's purposes the PMPEG engine ++ * will be treated as the "master" and handle the global VPE ++ * bits too ++ */ ++ pmpeg->base.set_tile_region = nv40_vpe_set_tile_region; ++ nouveau_irq_register(dev, 0, nv40_vpe_isr); ++ ++ NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); ++ NVOBJ_CLASS(dev, 0x3174, MPEG); ++ NVOBJ_MTHD (dev, 0x3174, 0x0190, nv40_mpeg_mthd_dma); ++ NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv40_mpeg_mthd_dma); ++ NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv40_mpeg_mthd_dma); ++ ++#if 0 ++ NVOBJ_ENGINE_ADD(dev, ME, &pme->base); ++ NVOBJ_CLASS(dev, 0x4075, ME); ++#endif ++ return 0; ++ ++} +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_calc.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_calc.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_calc.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_calc.c 2011-05-09 00:36:22.000000000 +0200 +@@ -23,7 +23,6 @@ + */ + + #include "drmP.h" +-#include "drm_fixed.h" + #include "nouveau_drv.h" + #include "nouveau_hw.h" + +@@ -47,45 +46,52 @@ + } + + int +-nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk, +- int *N, int *fN, int *M, int *P) ++nva3_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk, ++ int *pN, int *pfN, int *pM, int *P) + { +- fixed20_12 fb_div, a, b; +- u32 refclk = pll->refclk / 10; +- u32 max_vco_freq = pll->vco1.maxfreq / 10; +- u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10; +- clk /= 10; ++ u32 best_err = ~0, err; ++ int M, lM, hM, N, fN; + +- *P = max_vco_freq / clk; ++ *P = pll->vco1.maxfreq / clk; + if (*P > pll->max_p) + *P = pll->max_p; + if (*P < pll->min_p) + *P = pll->min_p; + +- /* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */ +- a.full = dfixed_const(refclk + max_vco_inputfreq); +- b.full = dfixed_const(max_vco_inputfreq); +- a.full = dfixed_div(a, b); +- a.full = dfixed_floor(a); +- *M = dfixed_trunc(a); +- +- /* fb_div = (vco * *M) / refclk; */ +- fb_div.full = dfixed_const(clk * *P); +- fb_div.full = dfixed_mul(fb_div, a); +- a.full = dfixed_const(refclk); +- fb_div.full = dfixed_div(fb_div, a); +- +- /* *N = floor(fb_div); */ +- a.full = dfixed_floor(fb_div); +- *N = dfixed_trunc(fb_div); +- +- /* *fN = (fmod(fb_div, 1.0) * 8192) - 4096; */ +- b.full = dfixed_const(8192); +- a.full = dfixed_mul(a, b); +- fb_div.full = dfixed_mul(fb_div, b); +- fb_div.full = fb_div.full - a.full; +- *fN = dfixed_trunc(fb_div) - 4096; +- *fN &= 0xffff; ++ lM = (pll->refclk + pll->vco1.max_inputfreq) / pll->vco1.max_inputfreq; ++ lM = max(lM, (int)pll->vco1.min_m); ++ hM = (pll->refclk + pll->vco1.min_inputfreq) / pll->vco1.min_inputfreq; ++ hM = min(hM, (int)pll->vco1.max_m); ++ ++ for (M = lM; M <= hM; M++) { ++ u32 tmp = clk * *P * M; ++ N = tmp / pll->refclk; ++ fN = tmp % pll->refclk; ++ if (!pfN && fN >= pll->refclk / 2) ++ N++; ++ ++ if (N < pll->vco1.min_n) ++ continue; ++ if (N > pll->vco1.max_n) ++ break; ++ ++ err = abs(clk - (pll->refclk * N / M / *P)); ++ if (err < best_err) { ++ best_err = err; ++ *pN = N; ++ *pM = M; ++ } ++ ++ if (pfN) { ++ *pfN = (((fN << 13) / pll->refclk) - 4096) & 0xffff; ++ return clk; ++ } ++ } ++ ++ if (unlikely(best_err == ~0)) { ++ NV_ERROR(dev, "unable to find matching pll values\n"); ++ return -EINVAL; ++ } + +- return clk; ++ return pll->refclk * *pN / *pM / *P; + } +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_crtc.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_crtc.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_crtc.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_crtc.c 2011-05-09 00:36:22.000000000 +0200 +@@ -286,7 +286,7 @@ + nv_wr32(dev, pll.reg + 8, reg2 | (P << 28) | (M2 << 16) | N2); + } else + if (dev_priv->chipset < NV_C0) { +- ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P); ++ ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P); + if (ret <= 0) + return 0; + +@@ -298,7 +298,7 @@ + nv_wr32(dev, pll.reg + 4, reg1 | (P << 16) | (M1 << 8) | N1); + nv_wr32(dev, pll.reg + 8, N2); + } else { +- ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P); ++ ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P); + if (ret <= 0) + return 0; + +@@ -349,14 +349,14 @@ + struct drm_gem_object *gem; + int ret = 0, i; + +- if (width != 64 || height != 64) +- return -EINVAL; +- + if (!buffer_handle) { + nv_crtc->cursor.hide(nv_crtc, true); + return 0; + } + ++ if (width != 64 || height != 64) ++ return -EINVAL; ++ + gem = drm_gem_object_lookup(dev, file_priv, buffer_handle); + if (!gem) + return -ENOENT; +@@ -532,8 +532,7 @@ + if (atomic) { + drm_fb = passed_fb; + fb = nouveau_framebuffer(passed_fb); +- } +- else { ++ } else { + /* If not atomic, we can go ahead and pin, and unpin the + * old fb we were passed. + */ +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_display.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_display.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_display.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_display.c 2011-05-09 00:36:22.000000000 +0200 +@@ -517,13 +517,25 @@ + if (bios->fp.if_is_24bit) + script |= 0x0200; + } else { ++ /* determine number of lvds links */ ++ if (nv_connector && nv_connector->edid && ++ nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) { ++ /* http://www.spwg.org */ ++ if (((u8 *)nv_connector->edid)[121] == 2) ++ script |= 0x0100; ++ } else + if (pxclk >= bios->fp.duallink_transition_clk) { + script |= 0x0100; ++ } ++ ++ /* determine panel depth */ ++ if (script & 0x0100) { + if (bios->fp.strapless_is_24bit & 2) + script |= 0x0200; +- } else +- if (bios->fp.strapless_is_24bit & 1) +- script |= 0x0200; ++ } else { ++ if (bios->fp.strapless_is_24bit & 1) ++ script |= 0x0200; ++ } + + if (nv_connector && nv_connector->edid && + (nv_connector->edid->revision >= 4) && +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_graph.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_graph.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_graph.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_graph.c 2011-05-09 00:36:22.000000000 +0200 +@@ -31,10 +31,95 @@ + #include "nouveau_grctx.h" + #include "nouveau_dma.h" + #include "nouveau_vm.h" ++#include "nouveau_ramht.h" + #include "nv50_evo.h" + +-static int nv50_graph_register(struct drm_device *); +-static void nv50_graph_isr(struct drm_device *); ++struct nv50_graph_engine { ++ struct nouveau_exec_engine base; ++ u32 ctxprog[512]; ++ u32 ctxprog_size; ++ u32 grctx_size; ++}; ++ ++static void ++nv50_graph_fifo_access(struct drm_device *dev, bool enabled) ++{ ++ const uint32_t mask = 0x00010001; ++ ++ if (enabled) ++ nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask); ++ else ++ nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask); ++} ++ ++static struct nouveau_channel * ++nv50_graph_channel(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ uint32_t inst; ++ int i; ++ ++ /* Be sure we're not in the middle of a context switch or bad things ++ * will happen, such as unloading the wrong pgraph context. ++ */ ++ if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000)) ++ NV_ERROR(dev, "Ctxprog is still running\n"); ++ ++ inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR); ++ if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED)) ++ return NULL; ++ inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12; ++ ++ for (i = 0; i < dev_priv->engine.fifo.channels; i++) { ++ struct nouveau_channel *chan = dev_priv->channels.ptr[i]; ++ ++ if (chan && chan->ramin && chan->ramin->vinst == inst) ++ return chan; ++ } ++ ++ return NULL; ++} ++ ++static int ++nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst) ++{ ++ uint32_t fifo = nv_rd32(dev, 0x400500); ++ ++ nv_wr32(dev, 0x400500, fifo & ~1); ++ nv_wr32(dev, 0x400784, inst); ++ nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40); ++ nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11); ++ nv_wr32(dev, 0x400040, 0xffffffff); ++ (void)nv_rd32(dev, 0x400040); ++ nv_wr32(dev, 0x400040, 0x00000000); ++ nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1); ++ ++ if (nouveau_wait_for_idle(dev)) ++ nv_wr32(dev, 0x40032c, inst | (1<<31)); ++ nv_wr32(dev, 0x400500, fifo); ++ ++ return 0; ++} ++ ++static int ++nv50_graph_unload_context(struct drm_device *dev) ++{ ++ uint32_t inst; ++ ++ inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR); ++ if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED)) ++ return 0; ++ inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE; ++ ++ nouveau_wait_for_idle(dev); ++ nv_wr32(dev, 0x400784, inst); ++ nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20); ++ nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01); ++ nouveau_wait_for_idle(dev); ++ ++ nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst); ++ return 0; ++} + + static void + nv50_graph_init_reset(struct drm_device *dev) +@@ -52,7 +137,6 @@ + { + NV_DEBUG(dev, "\n"); + +- nouveau_irq_register(dev, 12, nv50_graph_isr); + nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff); + nv_wr32(dev, 0x400138, 0xffffffff); + nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff); +@@ -135,34 +219,14 @@ + static int + nv50_graph_init_ctxctl(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_grctx ctx = {}; +- uint32_t *cp; ++ struct nv50_graph_engine *pgraph = nv_engine(dev, NVOBJ_ENGINE_GR); + int i; + + NV_DEBUG(dev, "\n"); + +- cp = kmalloc(512 * 4, GFP_KERNEL); +- if (!cp) { +- NV_ERROR(dev, "failed to allocate ctxprog\n"); +- dev_priv->engine.graph.accel_blocked = true; +- return 0; +- } +- +- ctx.dev = dev; +- ctx.mode = NOUVEAU_GRCTX_PROG; +- ctx.data = cp; +- ctx.ctxprog_max = 512; +- if (!nv50_grctx_init(&ctx)) { +- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4; +- +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); +- for (i = 0; i < ctx.ctxprog_len; i++) +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]); +- } else { +- dev_priv->engine.graph.accel_blocked = true; +- } +- kfree(cp); ++ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); ++ for (i = 0; i < pgraph->ctxprog_size; i++) ++ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, pgraph->ctxprog[i]); + + nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */ + nv_wr32(dev, 0x400320, 4); +@@ -171,8 +235,8 @@ + return 0; + } + +-int +-nv50_graph_init(struct drm_device *dev) ++static int ++nv50_graph_init(struct drm_device *dev, int engine) + { + int ret; + +@@ -186,105 +250,66 @@ + if (ret) + return ret; + +- ret = nv50_graph_register(dev); +- if (ret) +- return ret; + nv50_graph_init_intr(dev); + return 0; + } + +-void +-nv50_graph_takedown(struct drm_device *dev) ++static int ++nv50_graph_fini(struct drm_device *dev, int engine) + { + NV_DEBUG(dev, "\n"); ++ nv50_graph_unload_context(dev); + nv_wr32(dev, 0x40013c, 0x00000000); +- nouveau_irq_unregister(dev, 12); +-} +- +-void +-nv50_graph_fifo_access(struct drm_device *dev, bool enabled) +-{ +- const uint32_t mask = 0x00010001; +- +- if (enabled) +- nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask); +- else +- nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask); +-} +- +-struct nouveau_channel * +-nv50_graph_channel(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- uint32_t inst; +- int i; +- +- /* Be sure we're not in the middle of a context switch or bad things +- * will happen, such as unloading the wrong pgraph context. +- */ +- if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000)) +- NV_ERROR(dev, "Ctxprog is still running\n"); +- +- inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR); +- if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED)) +- return NULL; +- inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12; +- +- for (i = 0; i < dev_priv->engine.fifo.channels; i++) { +- struct nouveau_channel *chan = dev_priv->channels.ptr[i]; +- +- if (chan && chan->ramin && chan->ramin->vinst == inst) +- return chan; +- } +- +- return NULL; ++ return 0; + } + +-int +-nv50_graph_create_context(struct nouveau_channel *chan) ++static int ++nv50_graph_context_new(struct nouveau_channel *chan, int engine) + { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *ramin = chan->ramin; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; ++ struct nouveau_gpuobj *grctx = NULL; ++ struct nv50_graph_engine *pgraph = nv_engine(dev, engine); + struct nouveau_grctx ctx = {}; + int hdr, ret; + + NV_DEBUG(dev, "ch%d\n", chan->id); + +- ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0, ++ ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 0, + NVOBJ_FLAG_ZERO_ALLOC | +- NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx); ++ NVOBJ_FLAG_ZERO_FREE, &grctx); + if (ret) + return ret; + + hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; + nv_wo32(ramin, hdr + 0x00, 0x00190002); +- nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->vinst + +- pgraph->grctx_size - 1); +- nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->vinst); ++ nv_wo32(ramin, hdr + 0x04, grctx->vinst + grctx->size - 1); ++ nv_wo32(ramin, hdr + 0x08, grctx->vinst); + nv_wo32(ramin, hdr + 0x0c, 0); + nv_wo32(ramin, hdr + 0x10, 0); + nv_wo32(ramin, hdr + 0x14, 0x00010000); + + ctx.dev = chan->dev; + ctx.mode = NOUVEAU_GRCTX_VALS; +- ctx.data = chan->ramin_grctx; ++ ctx.data = grctx; + nv50_grctx_init(&ctx); + +- nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12); ++ nv_wo32(grctx, 0x00000, chan->ramin->vinst >> 12); + + dev_priv->engine.instmem.flush(dev); +- atomic_inc(&chan->vm->pgraph_refs); ++ ++ atomic_inc(&chan->vm->engref[NVOBJ_ENGINE_GR]); ++ chan->engctx[NVOBJ_ENGINE_GR] = grctx; + return 0; + } + +-void +-nv50_graph_destroy_context(struct nouveau_channel *chan) ++static void ++nv50_graph_context_del(struct nouveau_channel *chan, int engine) + { ++ struct nouveau_gpuobj *grctx = chan->engctx[engine]; + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; + unsigned long flags; +@@ -296,72 +321,49 @@ + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + pfifo->reassign(dev, false); +- pgraph->fifo_access(dev, false); ++ nv50_graph_fifo_access(dev, false); + +- if (pgraph->channel(dev) == chan) +- pgraph->unload_context(dev); ++ if (nv50_graph_channel(dev) == chan) ++ nv50_graph_unload_context(dev); + + for (i = hdr; i < hdr + 24; i += 4) + nv_wo32(chan->ramin, i, 0); + dev_priv->engine.instmem.flush(dev); + +- pgraph->fifo_access(dev, true); ++ nv50_graph_fifo_access(dev, true); + pfifo->reassign(dev, true); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + +- nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); ++ nouveau_gpuobj_ref(NULL, &grctx); + +- atomic_dec(&chan->vm->pgraph_refs); ++ atomic_dec(&chan->vm->engref[engine]); ++ chan->engctx[engine] = NULL; + } + + static int +-nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst) +-{ +- uint32_t fifo = nv_rd32(dev, 0x400500); +- +- nv_wr32(dev, 0x400500, fifo & ~1); +- nv_wr32(dev, 0x400784, inst); +- nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40); +- nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11); +- nv_wr32(dev, 0x400040, 0xffffffff); +- (void)nv_rd32(dev, 0x400040); +- nv_wr32(dev, 0x400040, 0x00000000); +- nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1); +- +- if (nouveau_wait_for_idle(dev)) +- nv_wr32(dev, 0x40032c, inst | (1<<31)); +- nv_wr32(dev, 0x400500, fifo); +- +- return 0; +-} +- +-int +-nv50_graph_load_context(struct nouveau_channel *chan) +-{ +- uint32_t inst = chan->ramin->vinst >> 12; +- +- NV_DEBUG(chan->dev, "ch%d\n", chan->id); +- return nv50_graph_do_load_context(chan->dev, inst); +-} +- +-int +-nv50_graph_unload_context(struct drm_device *dev) ++nv50_graph_object_new(struct nouveau_channel *chan, int engine, ++ u32 handle, u16 class) + { +- uint32_t inst; ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *obj = NULL; ++ int ret; + +- inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR); +- if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED)) +- return 0; +- inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE; ++ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj); ++ if (ret) ++ return ret; ++ obj->engine = 1; ++ obj->class = class; + +- nouveau_wait_for_idle(dev); +- nv_wr32(dev, 0x400784, inst); +- nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20); +- nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01); +- nouveau_wait_for_idle(dev); ++ nv_wo32(obj, 0x00, class); ++ nv_wo32(obj, 0x04, 0x00000000); ++ nv_wo32(obj, 0x08, 0x00000000); ++ nv_wo32(obj, 0x0c, 0x00000000); ++ dev_priv->engine.instmem.flush(dev); + +- nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst); +- return 0; ++ ret = nouveau_ramht_insert(chan, handle, obj); ++ nouveau_gpuobj_ref(NULL, &obj); ++ return ret; + } + + static void +@@ -442,68 +444,15 @@ + return 0; + } + +-static int +-nv50_graph_register(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- +- if (dev_priv->engine.graph.registered) +- return 0; +- +- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ +- NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem); +- NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset); +- NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val); +- NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release); +- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip); +- +- NVOBJ_CLASS(dev, 0x0030, GR); /* null */ +- NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */ +- NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */ +- +- /* tesla */ +- if (dev_priv->chipset == 0x50) +- NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */ +- else +- if (dev_priv->chipset < 0xa0) +- NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */ +- else { +- switch (dev_priv->chipset) { +- case 0xa0: +- case 0xaa: +- case 0xac: +- NVOBJ_CLASS(dev, 0x8397, GR); +- break; +- case 0xa3: +- case 0xa5: +- case 0xa8: +- NVOBJ_CLASS(dev, 0x8597, GR); +- break; +- case 0xaf: +- NVOBJ_CLASS(dev, 0x8697, GR); +- break; +- } +- } +- +- /* compute */ +- NVOBJ_CLASS(dev, 0x50c0, GR); +- if (dev_priv->chipset > 0xa0 && +- dev_priv->chipset != 0xaa && +- dev_priv->chipset != 0xac) +- NVOBJ_CLASS(dev, 0x85c0, GR); +- +- dev_priv->engine.graph.registered = true; +- return 0; +-} + +-void +-nv50_graph_tlb_flush(struct drm_device *dev) ++static void ++nv50_graph_tlb_flush(struct drm_device *dev, int engine) + { + nv50_vm_flush_engine(dev, 0); + } + +-void +-nv84_graph_tlb_flush(struct drm_device *dev) ++static void ++nv84_graph_tlb_flush(struct drm_device *dev, int engine) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; +@@ -548,8 +497,7 @@ + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + } + +-static struct nouveau_enum nv50_mp_exec_error_names[] = +-{ ++static struct nouveau_enum nv50_mp_exec_error_names[] = { + { 3, "STACK_UNDERFLOW", NULL }, + { 4, "QUADON_ACTIVE", NULL }, + { 8, "TIMEOUT", NULL }, +@@ -663,7 +611,7 @@ + nv_rd32(dev, addr + 0x20); + pc = nv_rd32(dev, addr + 0x24); + oplow = nv_rd32(dev, addr + 0x70); +- ophigh= nv_rd32(dev, addr + 0x74); ++ ophigh = nv_rd32(dev, addr + 0x74); + NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - " + "TP %d MP %d: ", tpid, i); + nouveau_enum_print(nv50_mp_exec_error_names, status); +@@ -991,7 +939,7 @@ + return 1; + } + +-static int ++int + nv50_graph_isr_chid(struct drm_device *dev, u64 inst) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -1073,3 +1021,101 @@ + if (nv_rd32(dev, 0x400824) & (1 << 31)) + nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); + } ++ ++static void ++nv50_graph_destroy(struct drm_device *dev, int engine) ++{ ++ struct nv50_graph_engine *pgraph = nv_engine(dev, engine); ++ ++ NVOBJ_ENGINE_DEL(dev, GR); ++ ++ nouveau_irq_unregister(dev, 12); ++ kfree(pgraph); ++} ++ ++int ++nv50_graph_create(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv50_graph_engine *pgraph; ++ struct nouveau_grctx ctx = {}; ++ int ret; ++ ++ pgraph = kzalloc(sizeof(*pgraph),GFP_KERNEL); ++ if (!pgraph) ++ return -ENOMEM; ++ ++ ctx.dev = dev; ++ ctx.mode = NOUVEAU_GRCTX_PROG; ++ ctx.data = pgraph->ctxprog; ++ ctx.ctxprog_max = ARRAY_SIZE(pgraph->ctxprog); ++ ++ ret = nv50_grctx_init(&ctx); ++ if (ret) { ++ NV_ERROR(dev, "PGRAPH: ctxprog build failed\n"); ++ kfree(pgraph); ++ return 0; ++ } ++ ++ pgraph->grctx_size = ctx.ctxvals_pos * 4; ++ pgraph->ctxprog_size = ctx.ctxprog_len; ++ ++ pgraph->base.destroy = nv50_graph_destroy; ++ pgraph->base.init = nv50_graph_init; ++ pgraph->base.fini = nv50_graph_fini; ++ pgraph->base.context_new = nv50_graph_context_new; ++ pgraph->base.context_del = nv50_graph_context_del; ++ pgraph->base.object_new = nv50_graph_object_new; ++ if (dev_priv->chipset == 0x50 || dev_priv->chipset == 0xac) ++ pgraph->base.tlb_flush = nv50_graph_tlb_flush; ++ else ++ pgraph->base.tlb_flush = nv84_graph_tlb_flush; ++ ++ nouveau_irq_register(dev, 12, nv50_graph_isr); ++ ++ /* NVSW really doesn't live here... */ ++ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ ++ NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem); ++ NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset); ++ NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val); ++ NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release); ++ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip); ++ ++ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); ++ NVOBJ_CLASS(dev, 0x0030, GR); /* null */ ++ NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */ ++ NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */ ++ ++ /* tesla */ ++ if (dev_priv->chipset == 0x50) ++ NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */ ++ else ++ if (dev_priv->chipset < 0xa0) ++ NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */ ++ else { ++ switch (dev_priv->chipset) { ++ case 0xa0: ++ case 0xaa: ++ case 0xac: ++ NVOBJ_CLASS(dev, 0x8397, GR); ++ break; ++ case 0xa3: ++ case 0xa5: ++ case 0xa8: ++ NVOBJ_CLASS(dev, 0x8597, GR); ++ break; ++ case 0xaf: ++ NVOBJ_CLASS(dev, 0x8697, GR); ++ break; ++ } ++ } ++ ++ /* compute */ ++ NVOBJ_CLASS(dev, 0x50c0, GR); ++ if (dev_priv->chipset > 0xa0 && ++ dev_priv->chipset != 0xaa && ++ dev_priv->chipset != 0xac) ++ NVOBJ_CLASS(dev, 0x85c0, GR); ++ ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_grctx.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_grctx.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_grctx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_grctx.c 2011-05-09 00:36:22.000000000 +0200 +@@ -747,7 +747,7 @@ + gr_def(ctx, offset + 0x64, 0x0000001f); + gr_def(ctx, offset + 0x68, 0x0000000f); + gr_def(ctx, offset + 0x6c, 0x0000000f); +- } else if(dev_priv->chipset < 0xa0) { ++ } else if (dev_priv->chipset < 0xa0) { + cp_ctx(ctx, offset + 0x50, 1); + cp_ctx(ctx, offset + 0x70, 1); + } else { +@@ -924,7 +924,7 @@ + dd_emit(ctx, 1, 0); /* 0000007f MULTISAMPLE_SAMPLES_LOG2 */ + } else { + dd_emit(ctx, 1, 0); /* 0000000f MULTISAMPLE_SAMPLES_LOG2 */ +- } ++ } + dd_emit(ctx, 1, 0xc); /* 000000ff SEMANTIC_COLOR.BFC0_ID */ + if (dev_priv->chipset != 0x50) + dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_COLOR.CLMP_EN */ +@@ -1803,9 +1803,7 @@ + xf_emit(ctx, 1, 0); /* 1ff */ + xf_emit(ctx, 8, 0); /* 0? */ + xf_emit(ctx, 9, 0); /* ffffffff, 7ff */ +- } +- else +- { ++ } else { + xf_emit(ctx, 0xc, 0); /* RO */ + /* SEEK */ + xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */ +@@ -2836,7 +2834,7 @@ + xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */ + if (IS_NVA3F(dev_priv->chipset)) + xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */ +- if(dev_priv->chipset == 0x50) ++ if (dev_priv->chipset == 0x50) + xf_emit(ctx, 1, 0); /* ff */ + else + xf_emit(ctx, 3, 0); /* 1, 7, 3ff */ +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_mpeg.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_mpeg.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_mpeg.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_mpeg.c 2011-05-09 00:36:22.000000000 +0200 +@@ -0,0 +1,256 @@ ++/* ++ * Copyright 2011 Red Hat Inc. ++ * ++ * 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 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 HOLDER(S) OR AUTHOR(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: Ben Skeggs ++ */ ++ ++#include "drmP.h" ++#include "nouveau_drv.h" ++#include "nouveau_ramht.h" ++ ++struct nv50_mpeg_engine { ++ struct nouveau_exec_engine base; ++}; ++ ++static inline u32 ++CTX_PTR(struct drm_device *dev, u32 offset) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ ++ if (dev_priv->chipset == 0x50) ++ offset += 0x0260; ++ else ++ offset += 0x0060; ++ ++ return offset; ++} ++ ++static int ++nv50_mpeg_context_new(struct nouveau_channel *chan, int engine) ++{ ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *ramin = chan->ramin; ++ struct nouveau_gpuobj *ctx = NULL; ++ int ret; ++ ++ NV_DEBUG(dev, "ch%d\n", chan->id); ++ ++ ret = nouveau_gpuobj_new(dev, chan, 128 * 4, 0, NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &ctx); ++ if (ret) ++ return ret; ++ ++ nv_wo32(ramin, CTX_PTR(dev, 0x00), 0x80190002); ++ nv_wo32(ramin, CTX_PTR(dev, 0x04), ctx->vinst + ctx->size - 1); ++ nv_wo32(ramin, CTX_PTR(dev, 0x08), ctx->vinst); ++ nv_wo32(ramin, CTX_PTR(dev, 0x0c), 0); ++ nv_wo32(ramin, CTX_PTR(dev, 0x10), 0); ++ nv_wo32(ramin, CTX_PTR(dev, 0x14), 0x00010000); ++ ++ nv_wo32(ctx, 0x70, 0x00801ec1); ++ nv_wo32(ctx, 0x7c, 0x0000037c); ++ dev_priv->engine.instmem.flush(dev); ++ ++ chan->engctx[engine] = ctx; ++ return 0; ++} ++ ++static void ++nv50_mpeg_context_del(struct nouveau_channel *chan, int engine) ++{ ++ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; ++ struct nouveau_gpuobj *ctx = chan->engctx[engine]; ++ struct drm_device *dev = chan->dev; ++ unsigned long flags; ++ u32 inst, i; ++ ++ if (!chan->ramin) ++ return; ++ ++ inst = chan->ramin->vinst >> 12; ++ inst |= 0x80000000; ++ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); ++ if (nv_rd32(dev, 0x00b318) == inst) ++ nv_mask(dev, 0x00b318, 0x80000000, 0x00000000); ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ ++ for (i = 0x00; i <= 0x14; i += 4) ++ nv_wo32(chan->ramin, CTX_PTR(dev, i), 0x00000000); ++ nouveau_gpuobj_ref(NULL, &ctx); ++ chan->engctx[engine] = NULL; ++} ++ ++static int ++nv50_mpeg_object_new(struct nouveau_channel *chan, int engine, ++ u32 handle, u16 class) ++{ ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *obj = NULL; ++ int ret; ++ ++ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj); ++ if (ret) ++ return ret; ++ obj->engine = 2; ++ obj->class = class; ++ ++ nv_wo32(obj, 0x00, class); ++ nv_wo32(obj, 0x04, 0x00000000); ++ nv_wo32(obj, 0x08, 0x00000000); ++ nv_wo32(obj, 0x0c, 0x00000000); ++ dev_priv->engine.instmem.flush(dev); ++ ++ ret = nouveau_ramht_insert(chan, handle, obj); ++ nouveau_gpuobj_ref(NULL, &obj); ++ return ret; ++} ++ ++static void ++nv50_mpeg_tlb_flush(struct drm_device *dev, int engine) ++{ ++ nv50_vm_flush_engine(dev, 0x08); ++} ++ ++static int ++nv50_mpeg_init(struct drm_device *dev, int engine) ++{ ++ nv_wr32(dev, 0x00b32c, 0x00000000); ++ nv_wr32(dev, 0x00b314, 0x00000100); ++ nv_wr32(dev, 0x00b0e0, 0x0000001a); ++ ++ nv_wr32(dev, 0x00b220, 0x00000044); ++ nv_wr32(dev, 0x00b300, 0x00801ec1); ++ nv_wr32(dev, 0x00b390, 0x00000000); ++ nv_wr32(dev, 0x00b394, 0x00000000); ++ nv_wr32(dev, 0x00b398, 0x00000000); ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); ++ ++ nv_wr32(dev, 0x00b100, 0xffffffff); ++ nv_wr32(dev, 0x00b140, 0xffffffff); ++ ++ if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) { ++ NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200)); ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++static int ++nv50_mpeg_fini(struct drm_device *dev, int engine) ++{ ++ /*XXX: context save for s/r */ ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); ++ nv_wr32(dev, 0x00b140, 0x00000000); ++ return 0; ++} ++ ++static void ++nv50_mpeg_isr(struct drm_device *dev) ++{ ++ u32 stat = nv_rd32(dev, 0x00b100); ++ u32 type = nv_rd32(dev, 0x00b230); ++ u32 mthd = nv_rd32(dev, 0x00b234); ++ u32 data = nv_rd32(dev, 0x00b238); ++ u32 show = stat; ++ ++ if (stat & 0x01000000) { ++ /* happens on initial binding of the object */ ++ if (type == 0x00000020 && mthd == 0x0000) { ++ nv_wr32(dev, 0x00b308, 0x00000100); ++ show &= ~0x01000000; ++ } ++ } ++ ++ if (show && nouveau_ratelimit()) { ++ NV_INFO(dev, "PMPEG - 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ stat, type, mthd, data); ++ } ++ ++ nv_wr32(dev, 0x00b100, stat); ++ nv_wr32(dev, 0x00b230, 0x00000001); ++ nv50_fb_vm_trap(dev, 1); ++} ++ ++static void ++nv50_vpe_isr(struct drm_device *dev) ++{ ++ if (nv_rd32(dev, 0x00b100)) ++ nv50_mpeg_isr(dev); ++ ++ if (nv_rd32(dev, 0x00b800)) { ++ u32 stat = nv_rd32(dev, 0x00b800); ++ NV_INFO(dev, "PMSRCH: 0x%08x\n", stat); ++ nv_wr32(dev, 0xb800, stat); ++ } ++} ++ ++static void ++nv50_mpeg_destroy(struct drm_device *dev, int engine) ++{ ++ struct nv50_mpeg_engine *pmpeg = nv_engine(dev, engine); ++ ++ nouveau_irq_unregister(dev, 0); ++ ++ NVOBJ_ENGINE_DEL(dev, MPEG); ++ kfree(pmpeg); ++} ++ ++int ++nv50_mpeg_create(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv50_mpeg_engine *pmpeg; ++ ++ pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); ++ if (!pmpeg) ++ return -ENOMEM; ++ ++ pmpeg->base.destroy = nv50_mpeg_destroy; ++ pmpeg->base.init = nv50_mpeg_init; ++ pmpeg->base.fini = nv50_mpeg_fini; ++ pmpeg->base.context_new = nv50_mpeg_context_new; ++ pmpeg->base.context_del = nv50_mpeg_context_del; ++ pmpeg->base.object_new = nv50_mpeg_object_new; ++ pmpeg->base.tlb_flush = nv50_mpeg_tlb_flush; ++ ++ if (dev_priv->chipset == 0x50) { ++ nouveau_irq_register(dev, 0, nv50_vpe_isr); ++ NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); ++ NVOBJ_CLASS(dev, 0x3174, MPEG); ++#if 0 ++ NVOBJ_ENGINE_ADD(dev, ME, &pme->base); ++ NVOBJ_CLASS(dev, 0x4075, ME); ++#endif ++ } else { ++ nouveau_irq_register(dev, 0, nv50_mpeg_isr); ++ NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); ++ NVOBJ_CLASS(dev, 0x8274, MPEG); ++ } ++ ++ return 0; ++ ++} +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_pm.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_pm.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_pm.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_pm.c 2011-05-09 00:36:22.000000000 +0200 +@@ -47,6 +47,21 @@ + + reg0 = nv_rd32(dev, pll.reg + 0); + reg1 = nv_rd32(dev, pll.reg + 4); ++ ++ if ((reg0 & 0x80000000) == 0) { ++ if (id == PLL_SHADER) { ++ NV_DEBUG(dev, "Shader PLL is disabled. " ++ "Shader clock is twice the core\n"); ++ ret = nv50_pm_clock_get(dev, PLL_CORE); ++ if (ret > 0) ++ return ret << 1; ++ } else if (id == PLL_MEMORY) { ++ NV_DEBUG(dev, "Memory PLL is disabled. " ++ "Memory clock is equal to the ref_clk\n"); ++ return pll.refclk; ++ } ++ } ++ + P = (reg0 & 0x00070000) >> 16; + N = (reg1 & 0x0000ff00) >> 8; + M = (reg1 & 0x000000ff); +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_vm.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_vm.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv50_vm.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv50_vm.c 2011-05-09 00:36:22.000000000 +0200 +@@ -151,8 +151,7 @@ + struct drm_nouveau_private *dev_priv = vm->dev->dev_private; + struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt; ++ int i; + + pinstmem->flush(vm->dev); + +@@ -163,11 +162,10 @@ + } + + pfifo->tlb_flush(vm->dev); +- +- if (atomic_read(&vm->pgraph_refs)) +- pgraph->tlb_flush(vm->dev); +- if (atomic_read(&vm->pcrypt_refs)) +- pcrypt->tlb_flush(vm->dev); ++ for (i = 0; i < NVOBJ_ENGINE_NR; i++) { ++ if (atomic_read(&vm->engref[i])) ++ dev_priv->eng[i]->tlb_flush(vm->dev, i); ++ } + } + + void +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv84_crypt.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv84_crypt.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nv84_crypt.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nv84_crypt.c 2011-05-09 00:36:22.000000000 +0200 +@@ -26,46 +26,48 @@ + #include "nouveau_drv.h" + #include "nouveau_util.h" + #include "nouveau_vm.h" ++#include "nouveau_ramht.h" + +-static void nv84_crypt_isr(struct drm_device *); ++struct nv84_crypt_engine { ++ struct nouveau_exec_engine base; ++}; + +-int +-nv84_crypt_create_context(struct nouveau_channel *chan) ++static int ++nv84_crypt_context_new(struct nouveau_channel *chan, int engine) + { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *ramin = chan->ramin; ++ struct nouveau_gpuobj *ctx; + int ret; + + NV_DEBUG(dev, "ch%d\n", chan->id); + +- ret = nouveau_gpuobj_new(dev, chan, 256, 0, +- NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, +- &chan->crypt_ctx); ++ ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &ctx); + if (ret) + return ret; + + nv_wo32(ramin, 0xa0, 0x00190000); +- nv_wo32(ramin, 0xa4, chan->crypt_ctx->vinst + 0xff); +- nv_wo32(ramin, 0xa8, chan->crypt_ctx->vinst); ++ nv_wo32(ramin, 0xa4, ctx->vinst + ctx->size - 1); ++ nv_wo32(ramin, 0xa8, ctx->vinst); + nv_wo32(ramin, 0xac, 0); + nv_wo32(ramin, 0xb0, 0); + nv_wo32(ramin, 0xb4, 0); +- + dev_priv->engine.instmem.flush(dev); +- atomic_inc(&chan->vm->pcrypt_refs); ++ ++ atomic_inc(&chan->vm->engref[engine]); ++ chan->engctx[engine] = ctx; + return 0; + } + +-void +-nv84_crypt_destroy_context(struct nouveau_channel *chan) ++static void ++nv84_crypt_context_del(struct nouveau_channel *chan, int engine) + { ++ struct nouveau_gpuobj *ctx = chan->engctx[engine]; + struct drm_device *dev = chan->dev; + u32 inst; + +- if (!chan->crypt_ctx) +- return; +- + inst = (chan->ramin->vinst >> 12); + inst |= 0x80000000; + +@@ -80,43 +82,39 @@ + nv_mask(dev, 0x10218c, 0x80000000, 0x00000000); + nv_wr32(dev, 0x10200c, 0x00000010); + +- nouveau_gpuobj_ref(NULL, &chan->crypt_ctx); +- atomic_dec(&chan->vm->pcrypt_refs); +-} ++ nouveau_gpuobj_ref(NULL, &ctx); + +-void +-nv84_crypt_tlb_flush(struct drm_device *dev) +-{ +- nv50_vm_flush_engine(dev, 0x0a); ++ atomic_dec(&chan->vm->engref[engine]); ++ chan->engctx[engine] = NULL; + } + +-int +-nv84_crypt_init(struct drm_device *dev) ++static int ++nv84_crypt_object_new(struct nouveau_channel *chan, int engine, ++ u32 handle, u16 class) + { ++ struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt; +- +- if (!pcrypt->registered) { +- NVOBJ_CLASS(dev, 0x74c1, CRYPT); +- pcrypt->registered = true; +- } ++ struct nouveau_gpuobj *obj = NULL; ++ int ret; + +- nv_mask(dev, 0x000200, 0x00004000, 0x00000000); +- nv_mask(dev, 0x000200, 0x00004000, 0x00004000); ++ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj); ++ if (ret) ++ return ret; ++ obj->engine = 5; ++ obj->class = class; + +- nouveau_irq_register(dev, 14, nv84_crypt_isr); +- nv_wr32(dev, 0x102130, 0xffffffff); +- nv_wr32(dev, 0x102140, 0xffffffbf); ++ nv_wo32(obj, 0x00, class); ++ dev_priv->engine.instmem.flush(dev); + +- nv_wr32(dev, 0x10200c, 0x00000010); +- return 0; ++ ret = nouveau_ramht_insert(chan, handle, obj); ++ nouveau_gpuobj_ref(NULL, &obj); ++ return ret; + } + +-void +-nv84_crypt_fini(struct drm_device *dev) ++static void ++nv84_crypt_tlb_flush(struct drm_device *dev, int engine) + { +- nv_wr32(dev, 0x102140, 0x00000000); +- nouveau_irq_unregister(dev, 14); ++ nv50_vm_flush_engine(dev, 0x0a); + } + + static void +@@ -138,3 +136,58 @@ + + nv50_fb_vm_trap(dev, show); + } ++ ++static int ++nv84_crypt_fini(struct drm_device *dev, int engine) ++{ ++ nv_wr32(dev, 0x102140, 0x00000000); ++ return 0; ++} ++ ++static int ++nv84_crypt_init(struct drm_device *dev, int engine) ++{ ++ nv_mask(dev, 0x000200, 0x00004000, 0x00000000); ++ nv_mask(dev, 0x000200, 0x00004000, 0x00004000); ++ ++ nv_wr32(dev, 0x102130, 0xffffffff); ++ nv_wr32(dev, 0x102140, 0xffffffbf); ++ ++ nv_wr32(dev, 0x10200c, 0x00000010); ++ return 0; ++} ++ ++static void ++nv84_crypt_destroy(struct drm_device *dev, int engine) ++{ ++ struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine); ++ ++ NVOBJ_ENGINE_DEL(dev, CRYPT); ++ ++ nouveau_irq_unregister(dev, 14); ++ kfree(pcrypt); ++} ++ ++int ++nv84_crypt_create(struct drm_device *dev) ++{ ++ struct nv84_crypt_engine *pcrypt; ++ ++ pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL); ++ if (!pcrypt) ++ return -ENOMEM; ++ ++ pcrypt->base.destroy = nv84_crypt_destroy; ++ pcrypt->base.init = nv84_crypt_init; ++ pcrypt->base.fini = nv84_crypt_fini; ++ pcrypt->base.context_new = nv84_crypt_context_new; ++ pcrypt->base.context_del = nv84_crypt_context_del; ++ pcrypt->base.object_new = nv84_crypt_object_new; ++ pcrypt->base.tlb_flush = nv84_crypt_tlb_flush; ++ ++ nouveau_irq_register(dev, 14, nv84_crypt_isr); ++ ++ NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base); ++ NVOBJ_CLASS (dev, 0x74c1, CRYPT); ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nva3_copy.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nva3_copy.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nva3_copy.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nva3_copy.c 2011-05-09 00:36:22.000000000 +0200 +@@ -0,0 +1,226 @@ ++/* ++ * Copyright 2011 Red Hat Inc. ++ * ++ * 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 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 HOLDER(S) OR AUTHOR(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: Ben Skeggs ++ */ ++ ++#include ++#include "drmP.h" ++#include "nouveau_drv.h" ++#include "nouveau_util.h" ++#include "nouveau_vm.h" ++#include "nouveau_ramht.h" ++#include "nva3_copy.fuc.h" ++ ++struct nva3_copy_engine { ++ struct nouveau_exec_engine base; ++}; ++ ++static int ++nva3_copy_context_new(struct nouveau_channel *chan, int engine) ++{ ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *ramin = chan->ramin; ++ struct nouveau_gpuobj *ctx = NULL; ++ int ret; ++ ++ NV_DEBUG(dev, "ch%d\n", chan->id); ++ ++ ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &ctx); ++ if (ret) ++ return ret; ++ ++ nv_wo32(ramin, 0xc0, 0x00190000); ++ nv_wo32(ramin, 0xc4, ctx->vinst + ctx->size - 1); ++ nv_wo32(ramin, 0xc8, ctx->vinst); ++ nv_wo32(ramin, 0xcc, 0x00000000); ++ nv_wo32(ramin, 0xd0, 0x00000000); ++ nv_wo32(ramin, 0xd4, 0x00000000); ++ dev_priv->engine.instmem.flush(dev); ++ ++ atomic_inc(&chan->vm->engref[engine]); ++ chan->engctx[engine] = ctx; ++ return 0; ++} ++ ++static int ++nva3_copy_object_new(struct nouveau_channel *chan, int engine, ++ u32 handle, u16 class) ++{ ++ struct nouveau_gpuobj *ctx = chan->engctx[engine]; ++ ++ /* fuc engine doesn't need an object, our ramht code does.. */ ++ ctx->engine = 3; ++ ctx->class = class; ++ return nouveau_ramht_insert(chan, handle, ctx); ++} ++ ++static void ++nva3_copy_context_del(struct nouveau_channel *chan, int engine) ++{ ++ struct nouveau_gpuobj *ctx = chan->engctx[engine]; ++ struct drm_device *dev = chan->dev; ++ u32 inst; ++ ++ inst = (chan->ramin->vinst >> 12); ++ inst |= 0x40000000; ++ ++ /* disable fifo access */ ++ nv_wr32(dev, 0x104048, 0x00000000); ++ /* mark channel as unloaded if it's currently active */ ++ if (nv_rd32(dev, 0x104050) == inst) ++ nv_mask(dev, 0x104050, 0x40000000, 0x00000000); ++ /* mark next channel as invalid if it's about to be loaded */ ++ if (nv_rd32(dev, 0x104054) == inst) ++ nv_mask(dev, 0x104054, 0x40000000, 0x00000000); ++ /* restore fifo access */ ++ nv_wr32(dev, 0x104048, 0x00000003); ++ ++ for (inst = 0xc0; inst <= 0xd4; inst += 4) ++ nv_wo32(chan->ramin, inst, 0x00000000); ++ ++ nouveau_gpuobj_ref(NULL, &ctx); ++ ++ atomic_dec(&chan->vm->engref[engine]); ++ chan->engctx[engine] = ctx; ++} ++ ++static void ++nva3_copy_tlb_flush(struct drm_device *dev, int engine) ++{ ++ nv50_vm_flush_engine(dev, 0x0d); ++} ++ ++static int ++nva3_copy_init(struct drm_device *dev, int engine) ++{ ++ int i; ++ ++ nv_mask(dev, 0x000200, 0x00002000, 0x00000000); ++ nv_mask(dev, 0x000200, 0x00002000, 0x00002000); ++ nv_wr32(dev, 0x104014, 0xffffffff); /* disable all interrupts */ ++ ++ /* upload ucode */ ++ nv_wr32(dev, 0x1041c0, 0x01000000); ++ for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++) ++ nv_wr32(dev, 0x1041c4, nva3_pcopy_data[i]); ++ ++ nv_wr32(dev, 0x104180, 0x01000000); ++ for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) { ++ if ((i & 0x3f) == 0) ++ nv_wr32(dev, 0x104188, i >> 6); ++ nv_wr32(dev, 0x104184, nva3_pcopy_code[i]); ++ } ++ ++ /* start it running */ ++ nv_wr32(dev, 0x10410c, 0x00000000); ++ nv_wr32(dev, 0x104104, 0x00000000); /* ENTRY */ ++ nv_wr32(dev, 0x104100, 0x00000002); /* TRIGGER */ ++ return 0; ++} ++ ++static int ++nva3_copy_fini(struct drm_device *dev, int engine) ++{ ++ nv_mask(dev, 0x104048, 0x00000003, 0x00000000); ++ ++ /* trigger fuc context unload */ ++ nv_wait(dev, 0x104008, 0x0000000c, 0x00000000); ++ nv_mask(dev, 0x104054, 0x40000000, 0x00000000); ++ nv_wr32(dev, 0x104000, 0x00000008); ++ nv_wait(dev, 0x104008, 0x00000008, 0x00000000); ++ ++ nv_wr32(dev, 0x104014, 0xffffffff); ++ return 0; ++} ++ ++static struct nouveau_enum nva3_copy_isr_error_name[] = { ++ { 0x0001, "ILLEGAL_MTHD" }, ++ { 0x0002, "INVALID_ENUM" }, ++ { 0x0003, "INVALID_BITFIELD" }, ++ {} ++}; ++ ++static void ++nva3_copy_isr(struct drm_device *dev) ++{ ++ u32 dispatch = nv_rd32(dev, 0x10401c); ++ u32 stat = nv_rd32(dev, 0x104008) & dispatch & ~(dispatch >> 16); ++ u32 inst = nv_rd32(dev, 0x104050) & 0x3fffffff; ++ u32 ssta = nv_rd32(dev, 0x104040) & 0x0000ffff; ++ u32 addr = nv_rd32(dev, 0x104040) >> 16; ++ u32 mthd = (addr & 0x07ff) << 2; ++ u32 subc = (addr & 0x3800) >> 11; ++ u32 data = nv_rd32(dev, 0x104044); ++ int chid = nv50_graph_isr_chid(dev, inst); ++ ++ if (stat & 0x00000040) { ++ NV_INFO(dev, "PCOPY: DISPATCH_ERROR ["); ++ nouveau_enum_print(nva3_copy_isr_error_name, ssta); ++ printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n", ++ chid, inst, subc, mthd, data); ++ nv_wr32(dev, 0x104004, 0x00000040); ++ stat &= ~0x00000040; ++ } ++ ++ if (stat) { ++ NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat); ++ nv_wr32(dev, 0x104004, stat); ++ } ++ nv50_fb_vm_trap(dev, 1); ++} ++ ++static void ++nva3_copy_destroy(struct drm_device *dev, int engine) ++{ ++ struct nva3_copy_engine *pcopy = nv_engine(dev, engine); ++ ++ nouveau_irq_unregister(dev, 22); ++ ++ NVOBJ_ENGINE_DEL(dev, COPY0); ++ kfree(pcopy); ++} ++ ++int ++nva3_copy_create(struct drm_device *dev) ++{ ++ struct nva3_copy_engine *pcopy; ++ ++ pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL); ++ if (!pcopy) ++ return -ENOMEM; ++ ++ pcopy->base.destroy = nva3_copy_destroy; ++ pcopy->base.init = nva3_copy_init; ++ pcopy->base.fini = nva3_copy_fini; ++ pcopy->base.context_new = nva3_copy_context_new; ++ pcopy->base.context_del = nva3_copy_context_del; ++ pcopy->base.object_new = nva3_copy_object_new; ++ pcopy->base.tlb_flush = nva3_copy_tlb_flush; ++ ++ nouveau_irq_register(dev, 22, nva3_copy_isr); ++ ++ NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base); ++ NVOBJ_CLASS(dev, 0x85b5, COPY0); ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nva3_copy.fuc linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nva3_copy.fuc +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nva3_copy.fuc 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nva3_copy.fuc 2011-05-09 00:36:22.000000000 +0200 +@@ -0,0 +1,870 @@ ++/* fuc microcode for copy engine on nva3- chipsets ++ * ++ * Copyright 2011 Red Hat Inc. ++ * ++ * 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 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 HOLDER(S) OR AUTHOR(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: Ben Skeggs ++ */ ++ ++/* To build for nva3:nvc0 ++ * m4 -DNVA3 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nva3_copy.fuc.h ++ * ++ * To build for nvc0- ++ * m4 -DNVC0 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_copy.fuc.h ++ */ ++ ++ifdef(`NVA3', ++.section nva3_pcopy_data, ++.section nvc0_pcopy_data ++) ++ ++ctx_object: .b32 0 ++ifdef(`NVA3', ++ctx_dma: ++ctx_dma_query: .b32 0 ++ctx_dma_src: .b32 0 ++ctx_dma_dst: .b32 0 ++,) ++.equ ctx_dma_count 3 ++ctx_query_address_high: .b32 0 ++ctx_query_address_low: .b32 0 ++ctx_query_counter: .b32 0 ++ctx_src_address_high: .b32 0 ++ctx_src_address_low: .b32 0 ++ctx_src_pitch: .b32 0 ++ctx_src_tile_mode: .b32 0 ++ctx_src_xsize: .b32 0 ++ctx_src_ysize: .b32 0 ++ctx_src_zsize: .b32 0 ++ctx_src_zoff: .b32 0 ++ctx_src_xoff: .b32 0 ++ctx_src_yoff: .b32 0 ++ctx_src_cpp: .b32 0 ++ctx_dst_address_high: .b32 0 ++ctx_dst_address_low: .b32 0 ++ctx_dst_pitch: .b32 0 ++ctx_dst_tile_mode: .b32 0 ++ctx_dst_xsize: .b32 0 ++ctx_dst_ysize: .b32 0 ++ctx_dst_zsize: .b32 0 ++ctx_dst_zoff: .b32 0 ++ctx_dst_xoff: .b32 0 ++ctx_dst_yoff: .b32 0 ++ctx_dst_cpp: .b32 0 ++ctx_format: .b32 0 ++ctx_swz_const0: .b32 0 ++ctx_swz_const1: .b32 0 ++ctx_xcnt: .b32 0 ++ctx_ycnt: .b32 0 ++.align 256 ++ ++dispatch_table: ++// mthd 0x0000, NAME ++.b16 0x000 1 ++.b32 ctx_object ~0xffffffff ++// mthd 0x0100, NOP ++.b16 0x040 1 ++.b32 0x00010000 + cmd_nop ~0xffffffff ++// mthd 0x0140, PM_TRIGGER ++.b16 0x050 1 ++.b32 0x00010000 + cmd_pm_trigger ~0xffffffff ++ifdef(`NVA3', ` ++// mthd 0x0180-0x018c, DMA_ ++.b16 0x060 ctx_dma_count ++dispatch_dma: ++.b32 0x00010000 + cmd_dma ~0xffffffff ++.b32 0x00010000 + cmd_dma ~0xffffffff ++.b32 0x00010000 + cmd_dma ~0xffffffff ++',) ++// mthd 0x0200-0x0218, SRC_TILE ++.b16 0x80 7 ++.b32 ctx_src_tile_mode ~0x00000fff ++.b32 ctx_src_xsize ~0x0007ffff ++.b32 ctx_src_ysize ~0x00001fff ++.b32 ctx_src_zsize ~0x000007ff ++.b32 ctx_src_zoff ~0x00000fff ++.b32 ctx_src_xoff ~0x0007ffff ++.b32 ctx_src_yoff ~0x00001fff ++// mthd 0x0220-0x0238, DST_TILE ++.b16 0x88 7 ++.b32 ctx_dst_tile_mode ~0x00000fff ++.b32 ctx_dst_xsize ~0x0007ffff ++.b32 ctx_dst_ysize ~0x00001fff ++.b32 ctx_dst_zsize ~0x000007ff ++.b32 ctx_dst_zoff ~0x00000fff ++.b32 ctx_dst_xoff ~0x0007ffff ++.b32 ctx_dst_yoff ~0x00001fff ++// mthd 0x0300-0x0304, EXEC, WRCACHE_FLUSH ++.b16 0xc0 2 ++.b32 0x00010000 + cmd_exec ~0xffffffff ++.b32 0x00010000 + cmd_wrcache_flush ~0xffffffff ++// mthd 0x030c-0x0340, various stuff ++.b16 0xc3 14 ++.b32 ctx_src_address_high ~0x000000ff ++.b32 ctx_src_address_low ~0xfffffff0 ++.b32 ctx_dst_address_high ~0x000000ff ++.b32 ctx_dst_address_low ~0xfffffff0 ++.b32 ctx_src_pitch ~0x0007ffff ++.b32 ctx_dst_pitch ~0x0007ffff ++.b32 ctx_xcnt ~0x0000ffff ++.b32 ctx_ycnt ~0x00001fff ++.b32 ctx_format ~0x0333ffff ++.b32 ctx_swz_const0 ~0xffffffff ++.b32 ctx_swz_const1 ~0xffffffff ++.b32 ctx_query_address_high ~0x000000ff ++.b32 ctx_query_address_low ~0xffffffff ++.b32 ctx_query_counter ~0xffffffff ++.b16 0x800 0 ++ ++ifdef(`NVA3', ++.section nva3_pcopy_code, ++.section nvc0_pcopy_code ++) ++ ++main: ++ clear b32 $r0 ++ mov $sp $r0 ++ ++ // setup i0 handler and route fifo and ctxswitch to it ++ mov $r1 ih ++ mov $iv0 $r1 ++ mov $r1 0x400 ++ movw $r2 0xfff3 ++ sethi $r2 0 ++ iowr I[$r2 + 0x300] $r2 ++ ++ // enable interrupts ++ or $r2 0xc ++ iowr I[$r1] $r2 ++ bset $flags ie0 ++ ++ // enable fifo access and context switching ++ mov $r1 0x1200 ++ mov $r2 3 ++ iowr I[$r1] $r2 ++ ++ // sleep forever, waking for interrupts ++ bset $flags $p0 ++ spin: ++ sleep $p0 ++ bra spin ++ ++// i0 handler ++ih: ++ iord $r1 I[$r0 + 0x200] ++ ++ and $r2 $r1 0x00000008 ++ bra e ih_no_chsw ++ call chsw ++ ih_no_chsw: ++ and $r2 $r1 0x00000004 ++ bra e ih_no_cmd ++ call dispatch ++ ++ ih_no_cmd: ++ and $r1 $r1 0x0000000c ++ iowr I[$r0 + 0x100] $r1 ++ iret ++ ++// $p1 direction (0 = unload, 1 = load) ++// $r3 channel ++swctx: ++ mov $r4 0x7700 ++ mov $xtargets $r4 ++ifdef(`NVA3', ` ++ // target 7 hardcoded to ctx dma object ++ mov $xdbase $r0 ++', ` // NVC0 ++ // read SCRATCH3 to decide if we are PCOPY0 or PCOPY1 ++ mov $r4 0x2100 ++ iord $r4 I[$r4 + 0] ++ and $r4 1 ++ shl b32 $r4 4 ++ add b32 $r4 0x30 ++ ++ // channel is in vram ++ mov $r15 0x61c ++ shl b32 $r15 6 ++ mov $r5 0x114 ++ iowrs I[$r15] $r5 ++ ++ // read 16-byte PCOPYn info, containing context pointer, from channel ++ shl b32 $r5 $r3 4 ++ add b32 $r5 2 ++ mov $xdbase $r5 ++ mov $r5 $sp ++ // get a chunk of stack space, aligned to 256 byte boundary ++ sub b32 $r5 0x100 ++ mov $r6 0xff ++ not b32 $r6 ++ and $r5 $r6 ++ sethi $r5 0x00020000 ++ xdld $r4 $r5 ++ xdwait ++ sethi $r5 0 ++ ++ // set context pointer, from within channel VM ++ mov $r14 0 ++ iowrs I[$r15] $r14 ++ ld b32 $r4 D[$r5 + 0] ++ shr b32 $r4 8 ++ ld b32 $r6 D[$r5 + 4] ++ shl b32 $r6 24 ++ or $r4 $r6 ++ mov $xdbase $r4 ++') ++ // 256-byte context, at start of data segment ++ mov b32 $r4 $r0 ++ sethi $r4 0x60000 ++ ++ // swap! ++ bra $p1 swctx_load ++ xdst $r0 $r4 ++ bra swctx_done ++ swctx_load: ++ xdld $r0 $r4 ++ swctx_done: ++ xdwait ++ ret ++ ++chsw: ++ // read current channel ++ mov $r2 0x1400 ++ iord $r3 I[$r2] ++ ++ // if it's active, unload it and return ++ xbit $r15 $r3 0x1e ++ bra e chsw_no_unload ++ bclr $flags $p1 ++ call swctx ++ bclr $r3 0x1e ++ iowr I[$r2] $r3 ++ mov $r4 1 ++ iowr I[$r2 + 0x200] $r4 ++ ret ++ ++ // read next channel ++ chsw_no_unload: ++ iord $r3 I[$r2 + 0x100] ++ ++ // is there a channel waiting to be loaded? ++ xbit $r13 $r3 0x1e ++ bra e chsw_finish_load ++ bset $flags $p1 ++ call swctx ++ifdef(`NVA3', ++ // load dma objects back into TARGET regs ++ mov $r5 ctx_dma ++ mov $r6 ctx_dma_count ++ chsw_load_ctx_dma: ++ ld b32 $r7 D[$r5 + $r6 * 4] ++ add b32 $r8 $r6 0x180 ++ shl b32 $r8 8 ++ iowr I[$r8] $r7 ++ sub b32 $r6 1 ++ bra nc chsw_load_ctx_dma ++,) ++ ++ chsw_finish_load: ++ mov $r3 2 ++ iowr I[$r2 + 0x200] $r3 ++ ret ++ ++dispatch: ++ // read incoming fifo command ++ mov $r3 0x1900 ++ iord $r2 I[$r3 + 0x100] ++ iord $r3 I[$r3 + 0x000] ++ and $r4 $r2 0x7ff ++ // $r2 will be used to store exception data ++ shl b32 $r2 0x10 ++ ++ // lookup method in the dispatch table, ILLEGAL_MTHD if not found ++ mov $r5 dispatch_table ++ clear b32 $r6 ++ clear b32 $r7 ++ dispatch_loop: ++ ld b16 $r6 D[$r5 + 0] ++ ld b16 $r7 D[$r5 + 2] ++ add b32 $r5 4 ++ cmpu b32 $r4 $r6 ++ bra c dispatch_illegal_mthd ++ add b32 $r7 $r6 ++ cmpu b32 $r4 $r7 ++ bra c dispatch_valid_mthd ++ sub b32 $r7 $r6 ++ shl b32 $r7 3 ++ add b32 $r5 $r7 ++ bra dispatch_loop ++ ++ // ensure no bits set in reserved fields, INVALID_BITFIELD ++ dispatch_valid_mthd: ++ sub b32 $r4 $r6 ++ shl b32 $r4 3 ++ add b32 $r4 $r5 ++ ld b32 $r5 D[$r4 + 4] ++ and $r5 $r3 ++ cmpu b32 $r5 0 ++ bra ne dispatch_invalid_bitfield ++ ++ // depending on dispatch flags: execute method, or save data as state ++ ld b16 $r5 D[$r4 + 0] ++ ld b16 $r6 D[$r4 + 2] ++ cmpu b32 $r6 0 ++ bra ne dispatch_cmd ++ st b32 D[$r5] $r3 ++ bra dispatch_done ++ dispatch_cmd: ++ bclr $flags $p1 ++ call $r5 ++ bra $p1 dispatch_error ++ bra dispatch_done ++ ++ dispatch_invalid_bitfield: ++ or $r2 2 ++ dispatch_illegal_mthd: ++ or $r2 1 ++ ++ // store exception data in SCRATCH0/SCRATCH1, signal hostirq ++ dispatch_error: ++ mov $r4 0x1000 ++ iowr I[$r4 + 0x000] $r2 ++ iowr I[$r4 + 0x100] $r3 ++ mov $r2 0x40 ++ iowr I[$r0] $r2 ++ hostirq_wait: ++ iord $r2 I[$r0 + 0x200] ++ and $r2 0x40 ++ cmpu b32 $r2 0 ++ bra ne hostirq_wait ++ ++ dispatch_done: ++ mov $r2 0x1d00 ++ mov $r3 1 ++ iowr I[$r2] $r3 ++ ret ++ ++// No-operation ++// ++// Inputs: ++// $r1: irqh state ++// $r2: hostirq state ++// $r3: data ++// $r4: dispatch table entry ++// Outputs: ++// $r1: irqh state ++// $p1: set on error ++// $r2: hostirq state ++// $r3: data ++cmd_nop: ++ ret ++ ++// PM_TRIGGER ++// ++// Inputs: ++// $r1: irqh state ++// $r2: hostirq state ++// $r3: data ++// $r4: dispatch table entry ++// Outputs: ++// $r1: irqh state ++// $p1: set on error ++// $r2: hostirq state ++// $r3: data ++cmd_pm_trigger: ++ mov $r2 0x2200 ++ clear b32 $r3 ++ sethi $r3 0x20000 ++ iowr I[$r2] $r3 ++ ret ++ ++ifdef(`NVA3', ++// SET_DMA_* method handler ++// ++// Inputs: ++// $r1: irqh state ++// $r2: hostirq state ++// $r3: data ++// $r4: dispatch table entry ++// Outputs: ++// $r1: irqh state ++// $p1: set on error ++// $r2: hostirq state ++// $r3: data ++cmd_dma: ++ sub b32 $r4 dispatch_dma ++ shr b32 $r4 1 ++ bset $r3 0x1e ++ st b32 D[$r4 + ctx_dma] $r3 ++ add b32 $r4 0x600 ++ shl b32 $r4 6 ++ iowr I[$r4] $r3 ++ ret ++,) ++ ++// Calculates the hw swizzle mask and adjusts the surface's xcnt to match ++// ++cmd_exec_set_format: ++ // zero out a chunk of the stack to store the swizzle into ++ add $sp -0x10 ++ st b32 D[$sp + 0x00] $r0 ++ st b32 D[$sp + 0x04] $r0 ++ st b32 D[$sp + 0x08] $r0 ++ st b32 D[$sp + 0x0c] $r0 ++ ++ // extract cpp, src_ncomp and dst_ncomp from FORMAT ++ ld b32 $r4 D[$r0 + ctx_format] ++ extr $r5 $r4 16:17 ++ add b32 $r5 1 ++ extr $r6 $r4 20:21 ++ add b32 $r6 1 ++ extr $r7 $r4 24:25 ++ add b32 $r7 1 ++ ++ // convert FORMAT swizzle mask to hw swizzle mask ++ bclr $flags $p2 ++ clear b32 $r8 ++ clear b32 $r9 ++ ncomp_loop: ++ and $r10 $r4 0xf ++ shr b32 $r4 4 ++ clear b32 $r11 ++ bpc_loop: ++ cmpu b8 $r10 4 ++ bra nc cmp_c0 ++ mulu $r12 $r10 $r5 ++ add b32 $r12 $r11 ++ bset $flags $p2 ++ bra bpc_next ++ cmp_c0: ++ bra ne cmp_c1 ++ mov $r12 0x10 ++ add b32 $r12 $r11 ++ bra bpc_next ++ cmp_c1: ++ cmpu b8 $r10 6 ++ bra nc cmp_zero ++ mov $r12 0x14 ++ add b32 $r12 $r11 ++ bra bpc_next ++ cmp_zero: ++ mov $r12 0x80 ++ bpc_next: ++ st b8 D[$sp + $r8] $r12 ++ add b32 $r8 1 ++ add b32 $r11 1 ++ cmpu b32 $r11 $r5 ++ bra c bpc_loop ++ add b32 $r9 1 ++ cmpu b32 $r9 $r7 ++ bra c ncomp_loop ++ ++ // SRC_XCNT = (xcnt * src_cpp), or 0 if no src ref in swz (hw will hang) ++ mulu $r6 $r5 ++ st b32 D[$r0 + ctx_src_cpp] $r6 ++ ld b32 $r8 D[$r0 + ctx_xcnt] ++ mulu $r6 $r8 ++ bra $p2 dst_xcnt ++ clear b32 $r6 ++ ++ dst_xcnt: ++ mulu $r7 $r5 ++ st b32 D[$r0 + ctx_dst_cpp] $r7 ++ mulu $r7 $r8 ++ ++ mov $r5 0x810 ++ shl b32 $r5 6 ++ iowr I[$r5 + 0x000] $r6 ++ iowr I[$r5 + 0x100] $r7 ++ add b32 $r5 0x800 ++ ld b32 $r6 D[$r0 + ctx_dst_cpp] ++ sub b32 $r6 1 ++ shl b32 $r6 8 ++ ld b32 $r7 D[$r0 + ctx_src_cpp] ++ sub b32 $r7 1 ++ or $r6 $r7 ++ iowr I[$r5 + 0x000] $r6 ++ add b32 $r5 0x100 ++ ld b32 $r6 D[$sp + 0x00] ++ iowr I[$r5 + 0x000] $r6 ++ ld b32 $r6 D[$sp + 0x04] ++ iowr I[$r5 + 0x100] $r6 ++ ld b32 $r6 D[$sp + 0x08] ++ iowr I[$r5 + 0x200] $r6 ++ ld b32 $r6 D[$sp + 0x0c] ++ iowr I[$r5 + 0x300] $r6 ++ add b32 $r5 0x400 ++ ld b32 $r6 D[$r0 + ctx_swz_const0] ++ iowr I[$r5 + 0x000] $r6 ++ ld b32 $r6 D[$r0 + ctx_swz_const1] ++ iowr I[$r5 + 0x100] $r6 ++ add $sp 0x10 ++ ret ++ ++// Setup to handle a tiled surface ++// ++// Calculates a number of parameters the hardware requires in order ++// to correctly handle tiling. ++// ++// Offset calculation is performed as follows (Tp/Th/Td from TILE_MODE): ++// nTx = round_up(w * cpp, 1 << Tp) >> Tp ++// nTy = round_up(h, 1 << Th) >> Th ++// Txo = (x * cpp) & ((1 << Tp) - 1) ++// Tx = (x * cpp) >> Tp ++// Tyo = y & ((1 << Th) - 1) ++// Ty = y >> Th ++// Tzo = z & ((1 << Td) - 1) ++// Tz = z >> Td ++// ++// off = (Tzo << Tp << Th) + (Tyo << Tp) + Txo ++// off += ((Tz * nTy * nTx)) + (Ty * nTx) + Tx) << Td << Th << Tp; ++// ++// Inputs: ++// $r4: hw command (0x104800) ++// $r5: ctx offset adjustment for src/dst selection ++// $p2: set if dst surface ++// ++cmd_exec_set_surface_tiled: ++ // translate TILE_MODE into Tp, Th, Td shift values ++ ld b32 $r7 D[$r5 + ctx_src_tile_mode] ++ extr $r9 $r7 8:11 ++ extr $r8 $r7 4:7 ++ifdef(`NVA3', ++ add b32 $r8 2 ++, ++ add b32 $r8 3 ++) ++ extr $r7 $r7 0:3 ++ cmp b32 $r7 0xe ++ bra ne xtile64 ++ mov $r7 4 ++ bra xtileok ++ xtile64: ++ xbit $r7 $flags $p2 ++ add b32 $r7 17 ++ bset $r4 $r7 ++ mov $r7 6 ++ xtileok: ++ ++ // Op = (x * cpp) & ((1 << Tp) - 1) ++ // Tx = (x * cpp) >> Tp ++ ld b32 $r10 D[$r5 + ctx_src_xoff] ++ ld b32 $r11 D[$r5 + ctx_src_cpp] ++ mulu $r10 $r11 ++ mov $r11 1 ++ shl b32 $r11 $r7 ++ sub b32 $r11 1 ++ and $r12 $r10 $r11 ++ shr b32 $r10 $r7 ++ ++ // Tyo = y & ((1 << Th) - 1) ++ // Ty = y >> Th ++ ld b32 $r13 D[$r5 + ctx_src_yoff] ++ mov $r14 1 ++ shl b32 $r14 $r8 ++ sub b32 $r14 1 ++ and $r11 $r13 $r14 ++ shr b32 $r13 $r8 ++ ++ // YTILE = ((1 << Th) << 12) | ((1 << Th) - Tyo) ++ add b32 $r14 1 ++ shl b32 $r15 $r14 12 ++ sub b32 $r14 $r11 ++ or $r15 $r14 ++ xbit $r6 $flags $p2 ++ add b32 $r6 0x208 ++ shl b32 $r6 8 ++ iowr I[$r6 + 0x000] $r15 ++ ++ // Op += Tyo << Tp ++ shl b32 $r11 $r7 ++ add b32 $r12 $r11 ++ ++ // nTx = ((w * cpp) + ((1 << Tp) - 1) >> Tp) ++ ld b32 $r15 D[$r5 + ctx_src_xsize] ++ ld b32 $r11 D[$r5 + ctx_src_cpp] ++ mulu $r15 $r11 ++ mov $r11 1 ++ shl b32 $r11 $r7 ++ sub b32 $r11 1 ++ add b32 $r15 $r11 ++ shr b32 $r15 $r7 ++ push $r15 ++ ++ // nTy = (h + ((1 << Th) - 1)) >> Th ++ ld b32 $r15 D[$r5 + ctx_src_ysize] ++ mov $r11 1 ++ shl b32 $r11 $r8 ++ sub b32 $r11 1 ++ add b32 $r15 $r11 ++ shr b32 $r15 $r8 ++ push $r15 ++ ++ // Tys = Tp + Th ++ // CFG_YZ_TILE_SIZE = ((1 << Th) >> 2) << Td ++ add b32 $r7 $r8 ++ sub b32 $r8 2 ++ mov $r11 1 ++ shl b32 $r11 $r8 ++ shl b32 $r11 $r9 ++ ++ // Tzo = z & ((1 << Td) - 1) ++ // Tz = z >> Td ++ // Op += Tzo << Tys ++ // Ts = Tys + Td ++ ld b32 $r8 D[$r5 + ctx_src_zoff] ++ mov $r14 1 ++ shl b32 $r14 $r9 ++ sub b32 $r14 1 ++ and $r15 $r8 $r14 ++ shl b32 $r15 $r7 ++ add b32 $r12 $r15 ++ add b32 $r7 $r9 ++ shr b32 $r8 $r9 ++ ++ // Ot = ((Tz * nTy * nTx) + (Ty * nTx) + Tx) << Ts ++ pop $r15 ++ pop $r9 ++ mulu $r13 $r9 ++ add b32 $r10 $r13 ++ mulu $r8 $r9 ++ mulu $r8 $r15 ++ add b32 $r10 $r8 ++ shl b32 $r10 $r7 ++ ++ // PITCH = (nTx - 1) << Ts ++ sub b32 $r9 1 ++ shl b32 $r9 $r7 ++ iowr I[$r6 + 0x200] $r9 ++ ++ // SRC_ADDRESS_LOW = (Ot + Op) & 0xffffffff ++ // CFG_ADDRESS_HIGH |= ((Ot + Op) >> 32) << 16 ++ ld b32 $r7 D[$r5 + ctx_src_address_low] ++ ld b32 $r8 D[$r5 + ctx_src_address_high] ++ add b32 $r10 $r12 ++ add b32 $r7 $r10 ++ adc b32 $r8 0 ++ shl b32 $r8 16 ++ or $r8 $r11 ++ sub b32 $r6 0x600 ++ iowr I[$r6 + 0x000] $r7 ++ add b32 $r6 0x400 ++ iowr I[$r6 + 0x000] $r8 ++ ret ++ ++// Setup to handle a linear surface ++// ++// Nothing to see here.. Sets ADDRESS and PITCH, pretty non-exciting ++// ++cmd_exec_set_surface_linear: ++ xbit $r6 $flags $p2 ++ add b32 $r6 0x202 ++ shl b32 $r6 8 ++ ld b32 $r7 D[$r5 + ctx_src_address_low] ++ iowr I[$r6 + 0x000] $r7 ++ add b32 $r6 0x400 ++ ld b32 $r7 D[$r5 + ctx_src_address_high] ++ shl b32 $r7 16 ++ iowr I[$r6 + 0x000] $r7 ++ add b32 $r6 0x400 ++ ld b32 $r7 D[$r5 + ctx_src_pitch] ++ iowr I[$r6 + 0x000] $r7 ++ ret ++ ++// wait for regs to be available for use ++cmd_exec_wait: ++ push $r0 ++ push $r1 ++ mov $r0 0x800 ++ shl b32 $r0 6 ++ loop: ++ iord $r1 I[$r0] ++ and $r1 1 ++ bra ne loop ++ pop $r1 ++ pop $r0 ++ ret ++ ++cmd_exec_query: ++ // if QUERY_SHORT not set, write out { -, 0, TIME_LO, TIME_HI } ++ xbit $r4 $r3 13 ++ bra ne query_counter ++ call cmd_exec_wait ++ mov $r4 0x80c ++ shl b32 $r4 6 ++ ld b32 $r5 D[$r0 + ctx_query_address_low] ++ add b32 $r5 4 ++ iowr I[$r4 + 0x000] $r5 ++ iowr I[$r4 + 0x100] $r0 ++ mov $r5 0xc ++ iowr I[$r4 + 0x200] $r5 ++ add b32 $r4 0x400 ++ ld b32 $r5 D[$r0 + ctx_query_address_high] ++ shl b32 $r5 16 ++ iowr I[$r4 + 0x000] $r5 ++ add b32 $r4 0x500 ++ mov $r5 0x00000b00 ++ sethi $r5 0x00010000 ++ iowr I[$r4 + 0x000] $r5 ++ mov $r5 0x00004040 ++ shl b32 $r5 1 ++ sethi $r5 0x80800000 ++ iowr I[$r4 + 0x100] $r5 ++ mov $r5 0x00001110 ++ sethi $r5 0x13120000 ++ iowr I[$r4 + 0x200] $r5 ++ mov $r5 0x00001514 ++ sethi $r5 0x17160000 ++ iowr I[$r4 + 0x300] $r5 ++ mov $r5 0x00002601 ++ sethi $r5 0x00010000 ++ mov $r4 0x800 ++ shl b32 $r4 6 ++ iowr I[$r4 + 0x000] $r5 ++ ++ // write COUNTER ++ query_counter: ++ call cmd_exec_wait ++ mov $r4 0x80c ++ shl b32 $r4 6 ++ ld b32 $r5 D[$r0 + ctx_query_address_low] ++ iowr I[$r4 + 0x000] $r5 ++ iowr I[$r4 + 0x100] $r0 ++ mov $r5 0x4 ++ iowr I[$r4 + 0x200] $r5 ++ add b32 $r4 0x400 ++ ld b32 $r5 D[$r0 + ctx_query_address_high] ++ shl b32 $r5 16 ++ iowr I[$r4 + 0x000] $r5 ++ add b32 $r4 0x500 ++ mov $r5 0x00000300 ++ iowr I[$r4 + 0x000] $r5 ++ mov $r5 0x00001110 ++ sethi $r5 0x13120000 ++ iowr I[$r4 + 0x100] $r5 ++ ld b32 $r5 D[$r0 + ctx_query_counter] ++ add b32 $r4 0x500 ++ iowr I[$r4 + 0x000] $r5 ++ mov $r5 0x00002601 ++ sethi $r5 0x00010000 ++ mov $r4 0x800 ++ shl b32 $r4 6 ++ iowr I[$r4 + 0x000] $r5 ++ ret ++ ++// Execute a copy operation ++// ++// Inputs: ++// $r1: irqh state ++// $r2: hostirq state ++// $r3: data ++// 000002000 QUERY_SHORT ++// 000001000 QUERY ++// 000000100 DST_LINEAR ++// 000000010 SRC_LINEAR ++// 000000001 FORMAT ++// $r4: dispatch table entry ++// Outputs: ++// $r1: irqh state ++// $p1: set on error ++// $r2: hostirq state ++// $r3: data ++cmd_exec: ++ call cmd_exec_wait ++ ++ // if format requested, call function to calculate it, otherwise ++ // fill in cpp/xcnt for both surfaces as if (cpp == 1) ++ xbit $r15 $r3 0 ++ bra e cmd_exec_no_format ++ call cmd_exec_set_format ++ mov $r4 0x200 ++ bra cmd_exec_init_src_surface ++ cmd_exec_no_format: ++ mov $r6 0x810 ++ shl b32 $r6 6 ++ mov $r7 1 ++ st b32 D[$r0 + ctx_src_cpp] $r7 ++ st b32 D[$r0 + ctx_dst_cpp] $r7 ++ ld b32 $r7 D[$r0 + ctx_xcnt] ++ iowr I[$r6 + 0x000] $r7 ++ iowr I[$r6 + 0x100] $r7 ++ clear b32 $r4 ++ ++ cmd_exec_init_src_surface: ++ bclr $flags $p2 ++ clear b32 $r5 ++ xbit $r15 $r3 4 ++ bra e src_tiled ++ call cmd_exec_set_surface_linear ++ bra cmd_exec_init_dst_surface ++ src_tiled: ++ call cmd_exec_set_surface_tiled ++ bset $r4 7 ++ ++ cmd_exec_init_dst_surface: ++ bset $flags $p2 ++ mov $r5 ctx_dst_address_high - ctx_src_address_high ++ xbit $r15 $r3 8 ++ bra e dst_tiled ++ call cmd_exec_set_surface_linear ++ bra cmd_exec_kick ++ dst_tiled: ++ call cmd_exec_set_surface_tiled ++ bset $r4 8 ++ ++ cmd_exec_kick: ++ mov $r5 0x800 ++ shl b32 $r5 6 ++ ld b32 $r6 D[$r0 + ctx_ycnt] ++ iowr I[$r5 + 0x100] $r6 ++ mov $r6 0x0041 ++ // SRC_TARGET = 1, DST_TARGET = 2 ++ sethi $r6 0x44000000 ++ or $r4 $r6 ++ iowr I[$r5] $r4 ++ ++ // if requested, queue up a QUERY write after the copy has completed ++ xbit $r15 $r3 12 ++ bra e cmd_exec_done ++ call cmd_exec_query ++ ++ cmd_exec_done: ++ ret ++ ++// Flush write cache ++// ++// Inputs: ++// $r1: irqh state ++// $r2: hostirq state ++// $r3: data ++// $r4: dispatch table entry ++// Outputs: ++// $r1: irqh state ++// $p1: set on error ++// $r2: hostirq state ++// $r3: data ++cmd_wrcache_flush: ++ mov $r2 0x2200 ++ clear b32 $r3 ++ sethi $r3 0x10000 ++ iowr I[$r2] $r3 ++ ret ++ ++.align 0x100 +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nva3_copy.fuc.h linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nva3_copy.fuc.h +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nva3_copy.fuc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nva3_copy.fuc.h 2011-05-09 00:36:22.000000000 +0200 +@@ -0,0 +1,534 @@ ++uint32_t nva3_pcopy_data[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00010000, ++ 0x00000000, ++ 0x00000000, ++ 0x00010040, ++ 0x00010160, ++ 0x00000000, ++ 0x00010050, ++ 0x00010162, ++ 0x00000000, ++ 0x00030060, ++ 0x00010170, ++ 0x00000000, ++ 0x00010170, ++ 0x00000000, ++ 0x00010170, ++ 0x00000000, ++ 0x00070080, ++ 0x00000028, ++ 0xfffff000, ++ 0x0000002c, ++ 0xfff80000, ++ 0x00000030, ++ 0xffffe000, ++ 0x00000034, ++ 0xfffff800, ++ 0x00000038, ++ 0xfffff000, ++ 0x0000003c, ++ 0xfff80000, ++ 0x00000040, ++ 0xffffe000, ++ 0x00070088, ++ 0x00000054, ++ 0xfffff000, ++ 0x00000058, ++ 0xfff80000, ++ 0x0000005c, ++ 0xffffe000, ++ 0x00000060, ++ 0xfffff800, ++ 0x00000064, ++ 0xfffff000, ++ 0x00000068, ++ 0xfff80000, ++ 0x0000006c, ++ 0xffffe000, ++ 0x000200c0, ++ 0x00010492, ++ 0x00000000, ++ 0x0001051b, ++ 0x00000000, ++ 0x000e00c3, ++ 0x0000001c, ++ 0xffffff00, ++ 0x00000020, ++ 0x0000000f, ++ 0x00000048, ++ 0xffffff00, ++ 0x0000004c, ++ 0x0000000f, ++ 0x00000024, ++ 0xfff80000, ++ 0x00000050, ++ 0xfff80000, ++ 0x00000080, ++ 0xffff0000, ++ 0x00000084, ++ 0xffffe000, ++ 0x00000074, ++ 0xfccc0000, ++ 0x00000078, ++ 0x00000000, ++ 0x0000007c, ++ 0x00000000, ++ 0x00000010, ++ 0xffffff00, ++ 0x00000014, ++ 0x00000000, ++ 0x00000018, ++ 0x00000000, ++ 0x00000800, ++}; ++ ++uint32_t nva3_pcopy_code[] = { ++ 0x04fe04bd, ++ 0x3517f000, ++ 0xf10010fe, ++ 0xf1040017, ++ 0xf0fff327, ++ 0x22d00023, ++ 0x0c25f0c0, ++ 0xf40012d0, ++ 0x17f11031, ++ 0x27f01200, ++ 0x0012d003, ++ 0xf40031f4, ++ 0x0ef40028, ++ 0x8001cffd, ++ 0xf40812c4, ++ 0x21f4060b, ++ 0x0412c472, ++ 0xf4060bf4, ++ 0x11c4c321, ++ 0x4001d00c, ++ 0x47f101f8, ++ 0x4bfe7700, ++ 0x0007fe00, ++ 0xf00204b9, ++ 0x01f40643, ++ 0x0604fa09, ++ 0xfa060ef4, ++ 0x03f80504, ++ 0x27f100f8, ++ 0x23cf1400, ++ 0x1e3fc800, ++ 0xf4170bf4, ++ 0x21f40132, ++ 0x1e3af052, ++ 0xf00023d0, ++ 0x24d00147, ++ 0xcf00f880, ++ 0x3dc84023, ++ 0x220bf41e, ++ 0xf40131f4, ++ 0x57f05221, ++ 0x0367f004, ++ 0xa07856bc, ++ 0xb6018068, ++ 0x87d00884, ++ 0x0162b600, ++ 0xf0f018f4, ++ 0x23d00237, ++ 0xf100f880, ++ 0xcf190037, ++ 0x33cf4032, ++ 0xff24e400, ++ 0x1024b607, ++ 0x010057f1, ++ 0x74bd64bd, ++ 0x58005658, ++ 0x50b60157, ++ 0x0446b804, ++ 0xbb4d08f4, ++ 0x47b80076, ++ 0x0f08f404, ++ 0xb60276bb, ++ 0x57bb0374, ++ 0xdf0ef400, ++ 0xb60246bb, ++ 0x45bb0344, ++ 0x01459800, ++ 0xb00453fd, ++ 0x1bf40054, ++ 0x00455820, ++ 0xb0014658, ++ 0x1bf40064, ++ 0x00538009, ++ 0xf4300ef4, ++ 0x55f90132, ++ 0xf40c01f4, ++ 0x25f0250e, ++ 0x0125f002, ++ 0x100047f1, ++ 0xd00042d0, ++ 0x27f04043, ++ 0x0002d040, ++ 0xf08002cf, ++ 0x24b04024, ++ 0xf71bf400, ++ 0x1d0027f1, ++ 0xd00137f0, ++ 0x00f80023, ++ 0x27f100f8, ++ 0x34bd2200, ++ 0xd00233f0, ++ 0x00f80023, ++ 0x012842b7, ++ 0xf00145b6, ++ 0x43801e39, ++ 0x0040b701, ++ 0x0644b606, ++ 0xf80043d0, ++ 0xf030f400, ++ 0xb00001b0, ++ 0x01b00101, ++ 0x0301b002, ++ 0xc71d0498, ++ 0x50b63045, ++ 0x3446c701, ++ 0xc70160b6, ++ 0x70b63847, ++ 0x0232f401, ++ 0x94bd84bd, ++ 0xb60f4ac4, ++ 0xb4bd0445, ++ 0xf404a430, ++ 0xa5ff0f18, ++ 0x00cbbbc0, ++ 0xf40231f4, ++ 0x1bf4220e, ++ 0x10c7f00c, ++ 0xf400cbbb, ++ 0xa430160e, ++ 0x0c18f406, ++ 0xbb14c7f0, ++ 0x0ef400cb, ++ 0x80c7f107, ++ 0x01c83800, ++ 0xb60180b6, ++ 0xb5b801b0, ++ 0xc308f404, ++ 0xb80190b6, ++ 0x08f40497, ++ 0x0065fdb2, ++ 0x98110680, ++ 0x68fd2008, ++ 0x0502f400, ++ 0x75fd64bd, ++ 0x1c078000, ++ 0xf10078fd, ++ 0xb6081057, ++ 0x56d00654, ++ 0x4057d000, ++ 0x080050b7, ++ 0xb61c0698, ++ 0x64b60162, ++ 0x11079808, ++ 0xfd0172b6, ++ 0x56d00567, ++ 0x0050b700, ++ 0x0060b401, ++ 0xb40056d0, ++ 0x56d00160, ++ 0x0260b440, ++ 0xb48056d0, ++ 0x56d00360, ++ 0x0050b7c0, ++ 0x1e069804, ++ 0x980056d0, ++ 0x56d01f06, ++ 0x1030f440, ++ 0x579800f8, ++ 0x6879c70a, ++ 0xb66478c7, ++ 0x77c70280, ++ 0x0e76b060, ++ 0xf0091bf4, ++ 0x0ef40477, ++ 0x027cf00f, ++ 0xfd1170b6, ++ 0x77f00947, ++ 0x0f5a9806, ++ 0xfd115b98, ++ 0xb7f000ab, ++ 0x04b7bb01, ++ 0xff01b2b6, ++ 0xa7bbc4ab, ++ 0x105d9805, ++ 0xbb01e7f0, ++ 0xe2b604e8, ++ 0xb4deff01, ++ 0xb605d8bb, ++ 0xef9401e0, ++ 0x02ebbb0c, ++ 0xf005fefd, ++ 0x60b7026c, ++ 0x64b60208, ++ 0x006fd008, ++ 0xbb04b7bb, ++ 0x5f9800cb, ++ 0x115b980b, ++ 0xf000fbfd, ++ 0xb7bb01b7, ++ 0x01b2b604, ++ 0xbb00fbbb, ++ 0xf0f905f7, ++ 0xf00c5f98, ++ 0xb8bb01b7, ++ 0x01b2b604, ++ 0xbb00fbbb, ++ 0xf0f905f8, ++ 0xb60078bb, ++ 0xb7f00282, ++ 0x04b8bb01, ++ 0x9804b9bb, ++ 0xe7f00e58, ++ 0x04e9bb01, ++ 0xff01e2b6, ++ 0xf7bbf48e, ++ 0x00cfbb04, ++ 0xbb0079bb, ++ 0xf0fc0589, ++ 0xd9fd90fc, ++ 0x00adbb00, ++ 0xfd0089fd, ++ 0xa8bb008f, ++ 0x04a7bb00, ++ 0xbb0192b6, ++ 0x69d00497, ++ 0x08579880, ++ 0xbb075898, ++ 0x7abb00ac, ++ 0x0081b600, ++ 0xfd1084b6, ++ 0x62b7058b, ++ 0x67d00600, ++ 0x0060b700, ++ 0x0068d004, ++ 0x6cf000f8, ++ 0x0260b702, ++ 0x0864b602, ++ 0xd0085798, ++ 0x60b70067, ++ 0x57980400, ++ 0x1074b607, ++ 0xb70067d0, ++ 0x98040060, ++ 0x67d00957, ++ 0xf900f800, ++ 0xf110f900, ++ 0xb6080007, ++ 0x01cf0604, ++ 0x0114f000, ++ 0xfcfa1bf4, ++ 0xf800fc10, ++ 0x0d34c800, ++ 0xf5701bf4, ++ 0xf103ab21, ++ 0xb6080c47, ++ 0x05980644, ++ 0x0450b605, ++ 0xd00045d0, ++ 0x57f04040, ++ 0x8045d00c, ++ 0x040040b7, ++ 0xb6040598, ++ 0x45d01054, ++ 0x0040b700, ++ 0x0057f105, ++ 0x0153f00b, ++ 0xf10045d0, ++ 0xb6404057, ++ 0x53f10154, ++ 0x45d08080, ++ 0x1057f140, ++ 0x1253f111, ++ 0x8045d013, ++ 0x151457f1, ++ 0x171653f1, ++ 0xf1c045d0, ++ 0xf0260157, ++ 0x47f10153, ++ 0x44b60800, ++ 0x0045d006, ++ 0x03ab21f5, ++ 0x080c47f1, ++ 0x980644b6, ++ 0x45d00505, ++ 0x4040d000, ++ 0xd00457f0, ++ 0x40b78045, ++ 0x05980400, ++ 0x1054b604, ++ 0xb70045d0, ++ 0xf1050040, ++ 0xd0030057, ++ 0x57f10045, ++ 0x53f11110, ++ 0x45d01312, ++ 0x06059840, ++ 0x050040b7, ++ 0xf10045d0, ++ 0xf0260157, ++ 0x47f10153, ++ 0x44b60800, ++ 0x0045d006, ++ 0x21f500f8, ++ 0x3fc803ab, ++ 0x0e0bf400, ++ 0x018921f5, ++ 0x020047f1, ++ 0xf11e0ef4, ++ 0xb6081067, ++ 0x77f00664, ++ 0x11078001, ++ 0x981c0780, ++ 0x67d02007, ++ 0x4067d000, ++ 0x32f444bd, ++ 0xc854bd02, ++ 0x0bf4043f, ++ 0x8221f50a, ++ 0x0a0ef403, ++ 0x027621f5, ++ 0xf40749f0, ++ 0x57f00231, ++ 0x083fc82c, ++ 0xf50a0bf4, ++ 0xf4038221, ++ 0x21f50a0e, ++ 0x49f00276, ++ 0x0057f108, ++ 0x0654b608, ++ 0xd0210698, ++ 0x67f04056, ++ 0x0063f141, ++ 0x0546fd44, ++ 0xc80054d0, ++ 0x0bf40c3f, ++ 0xc521f507, ++ 0xf100f803, ++ 0xbd220027, ++ 0x0133f034, ++ 0xf80023d0, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nva3_pm.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nva3_pm.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nva3_pm.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nva3_pm.c 2011-05-09 00:36:22.000000000 +0200 +@@ -27,32 +27,74 @@ + #include "nouveau_bios.h" + #include "nouveau_pm.h" + +-/*XXX: boards using limits 0x40 need fixing, the register layout +- * is correct here, but, there's some other funny magic +- * that modifies things, so it's not likely we'll set/read +- * the correct timings yet.. working on it... ++/* This is actually a lot more complex than it appears here, but hopefully ++ * this should be able to deal with what the VBIOS leaves for us.. ++ * ++ * If not, well, I'll jump off that bridge when I come to it. + */ + + struct nva3_pm_state { +- struct pll_lims pll; +- int N, M, P; ++ enum pll_types type; ++ u32 src0; ++ u32 src1; ++ u32 ctrl; ++ u32 coef; ++ u32 old_pnm; ++ u32 new_pnm; ++ u32 new_div; + }; + ++static int ++nva3_pm_pll_offset(u32 id) ++{ ++ static const u32 pll_map[] = { ++ 0x00, PLL_CORE, ++ 0x01, PLL_SHADER, ++ 0x02, PLL_MEMORY, ++ 0x00, 0x00 ++ }; ++ const u32 *map = pll_map; ++ ++ while (map[1]) { ++ if (id == map[1]) ++ return map[0]; ++ map += 2; ++ } ++ ++ return -ENOENT; ++} ++ + int + nva3_pm_clock_get(struct drm_device *dev, u32 id) + { ++ u32 src0, src1, ctrl, coef; + struct pll_lims pll; +- int P, N, M, ret; +- u32 reg; ++ int ret, off; ++ int P, N, M; + + ret = get_pll_limits(dev, id, &pll); + if (ret) + return ret; + +- reg = nv_rd32(dev, pll.reg + 4); +- P = (reg & 0x003f0000) >> 16; +- N = (reg & 0x0000ff00) >> 8; +- M = (reg & 0x000000ff); ++ off = nva3_pm_pll_offset(id); ++ if (off < 0) ++ return off; ++ ++ src0 = nv_rd32(dev, 0x4120 + (off * 4)); ++ src1 = nv_rd32(dev, 0x4160 + (off * 4)); ++ ctrl = nv_rd32(dev, pll.reg + 0); ++ coef = nv_rd32(dev, pll.reg + 4); ++ NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ id, src0, src1, ctrl, coef); ++ ++ if (ctrl & 0x00000008) { ++ u32 div = ((src1 & 0x003c0000) >> 18) + 1; ++ return (pll.refclk * 2) / div; ++ } ++ ++ P = (coef & 0x003f0000) >> 16; ++ N = (coef & 0x0000ff00) >> 8; ++ M = (coef & 0x000000ff); + return pll.refclk * N / M / P; + } + +@@ -60,36 +102,103 @@ + nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl, + u32 id, int khz) + { +- struct nva3_pm_state *state; +- int dummy, ret; ++ struct nva3_pm_state *pll; ++ struct pll_lims limits; ++ int N, M, P, diff; ++ int ret, off; + +- state = kzalloc(sizeof(*state), GFP_KERNEL); +- if (!state) +- return ERR_PTR(-ENOMEM); +- +- ret = get_pll_limits(dev, id, &state->pll); +- if (ret < 0) { +- kfree(state); ++ ret = get_pll_limits(dev, id, &limits); ++ if (ret < 0) + return (ret == -ENOENT) ? NULL : ERR_PTR(ret); ++ ++ off = nva3_pm_pll_offset(id); ++ if (id < 0) ++ return ERR_PTR(-EINVAL); ++ ++ ++ pll = kzalloc(sizeof(*pll), GFP_KERNEL); ++ if (!pll) ++ return ERR_PTR(-ENOMEM); ++ pll->type = id; ++ pll->src0 = 0x004120 + (off * 4); ++ pll->src1 = 0x004160 + (off * 4); ++ pll->ctrl = limits.reg + 0; ++ pll->coef = limits.reg + 4; ++ ++ /* If target clock is within [-2, 3) MHz of a divisor, we'll ++ * use that instead of calculating MNP values ++ */ ++ pll->new_div = min((limits.refclk * 2) / (khz - 2999), 16); ++ if (pll->new_div) { ++ diff = khz - ((limits.refclk * 2) / pll->new_div); ++ if (diff < -2000 || diff >= 3000) ++ pll->new_div = 0; + } + +- ret = nv50_calc_pll2(dev, &state->pll, khz, &state->N, &dummy, +- &state->M, &state->P); +- if (ret < 0) { +- kfree(state); +- return ERR_PTR(ret); ++ if (!pll->new_div) { ++ ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ ++ pll->new_pnm = (P << 16) | (N << 8) | M; ++ pll->new_div = 2 - 1; ++ } else { ++ pll->new_pnm = 0; ++ pll->new_div--; + } + +- return state; ++ if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101) ++ pll->old_pnm = nv_rd32(dev, pll->coef); ++ return pll; + } + + void + nva3_pm_clock_set(struct drm_device *dev, void *pre_state) + { +- struct nva3_pm_state *state = pre_state; +- u32 reg = state->pll.reg; ++ struct nva3_pm_state *pll = pre_state; ++ u32 ctrl = 0; ++ ++ /* For the memory clock, NVIDIA will build a "script" describing ++ * the reclocking process and ask PDAEMON to execute it. ++ */ ++ if (pll->type == PLL_MEMORY) { ++ nv_wr32(dev, 0x100210, 0); ++ nv_wr32(dev, 0x1002dc, 1); ++ nv_wr32(dev, 0x004018, 0x00001000); ++ ctrl = 0x18000100; ++ } ++ ++ if (pll->old_pnm || !pll->new_pnm) { ++ nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 | ++ (pll->new_div << 18)); ++ nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl); ++ nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000); ++ } ++ ++ if (pll->new_pnm) { ++ nv_mask(dev, pll->src0, 0x00000101, 0x00000101); ++ nv_wr32(dev, pll->coef, pll->new_pnm); ++ nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl); ++ nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000); ++ nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010); ++ nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl); ++ nv_mask(dev, pll->src1, 0x00000100, 0x00000000); ++ nv_mask(dev, pll->src1, 0x00000001, 0x00000000); ++ if (pll->type == PLL_MEMORY) ++ nv_wr32(dev, 0x4018, 0x10005000); ++ } else { ++ nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000); ++ nv_mask(dev, pll->src0, 0x00000100, 0x00000000); ++ nv_mask(dev, pll->src0, 0x00000001, 0x00000000); ++ if (pll->type == PLL_MEMORY) ++ nv_wr32(dev, 0x4018, 0x1000d000); ++ } ++ ++ if (pll->type == PLL_MEMORY) { ++ nv_wr32(dev, 0x1002dc, 0); ++ nv_wr32(dev, 0x100210, 0x80000000); ++ } + +- nv_wr32(dev, reg + 4, (state->P << 16) | (state->N << 8) | state->M); +- kfree(state); ++ kfree(pll); + } + +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nvc0_copy.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nvc0_copy.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nvc0_copy.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nvc0_copy.c 2011-05-09 00:36:22.000000000 +0200 +@@ -0,0 +1,243 @@ ++/* ++ * Copyright 2011 Red Hat Inc. ++ * ++ * 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 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 HOLDER(S) OR AUTHOR(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: Ben Skeggs ++ */ ++ ++#include ++#include "drmP.h" ++#include "nouveau_drv.h" ++#include "nouveau_util.h" ++#include "nouveau_vm.h" ++#include "nouveau_ramht.h" ++#include "nvc0_copy.fuc.h" ++ ++struct nvc0_copy_engine { ++ struct nouveau_exec_engine base; ++ u32 irq; ++ u32 pmc; ++ u32 fuc; ++ u32 ctx; ++}; ++ ++static int ++nvc0_copy_context_new(struct nouveau_channel *chan, int engine) ++{ ++ struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine); ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *ramin = chan->ramin; ++ struct nouveau_gpuobj *ctx = NULL; ++ int ret; ++ ++ ret = nouveau_gpuobj_new(dev, NULL, 256, 256, ++ NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER | ++ NVOBJ_FLAG_ZERO_ALLOC, &ctx); ++ if (ret) ++ return ret; ++ ++ nv_wo32(ramin, pcopy->ctx + 0, lower_32_bits(ctx->vinst)); ++ nv_wo32(ramin, pcopy->ctx + 4, upper_32_bits(ctx->vinst)); ++ dev_priv->engine.instmem.flush(dev); ++ ++ chan->engctx[engine] = ctx; ++ return 0; ++} ++ ++static int ++nvc0_copy_object_new(struct nouveau_channel *chan, int engine, ++ u32 handle, u16 class) ++{ ++ return 0; ++} ++ ++static void ++nvc0_copy_context_del(struct nouveau_channel *chan, int engine) ++{ ++ struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine); ++ struct nouveau_gpuobj *ctx = chan->engctx[engine]; ++ struct drm_device *dev = chan->dev; ++ u32 inst; ++ ++ inst = (chan->ramin->vinst >> 12); ++ inst |= 0x40000000; ++ ++ /* disable fifo access */ ++ nv_wr32(dev, pcopy->fuc + 0x048, 0x00000000); ++ /* mark channel as unloaded if it's currently active */ ++ if (nv_rd32(dev, pcopy->fuc + 0x050) == inst) ++ nv_mask(dev, pcopy->fuc + 0x050, 0x40000000, 0x00000000); ++ /* mark next channel as invalid if it's about to be loaded */ ++ if (nv_rd32(dev, pcopy->fuc + 0x054) == inst) ++ nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000); ++ /* restore fifo access */ ++ nv_wr32(dev, pcopy->fuc + 0x048, 0x00000003); ++ ++ nv_wo32(chan->ramin, pcopy->ctx + 0, 0x00000000); ++ nv_wo32(chan->ramin, pcopy->ctx + 4, 0x00000000); ++ nouveau_gpuobj_ref(NULL, &ctx); ++ ++ chan->engctx[engine] = ctx; ++} ++ ++static int ++nvc0_copy_init(struct drm_device *dev, int engine) ++{ ++ struct nvc0_copy_engine *pcopy = nv_engine(dev, engine); ++ int i; ++ ++ nv_mask(dev, 0x000200, pcopy->pmc, 0x00000000); ++ nv_mask(dev, 0x000200, pcopy->pmc, pcopy->pmc); ++ nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff); ++ ++ nv_wr32(dev, pcopy->fuc + 0x1c0, 0x01000000); ++ for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++) ++ nv_wr32(dev, pcopy->fuc + 0x1c4, nvc0_pcopy_data[i]); ++ ++ nv_wr32(dev, pcopy->fuc + 0x180, 0x01000000); ++ for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) { ++ if ((i & 0x3f) == 0) ++ nv_wr32(dev, pcopy->fuc + 0x188, i >> 6); ++ nv_wr32(dev, pcopy->fuc + 0x184, nvc0_pcopy_code[i]); ++ } ++ ++ nv_wr32(dev, pcopy->fuc + 0x084, engine - NVOBJ_ENGINE_COPY0); ++ nv_wr32(dev, pcopy->fuc + 0x10c, 0x00000000); ++ nv_wr32(dev, pcopy->fuc + 0x104, 0x00000000); /* ENTRY */ ++ nv_wr32(dev, pcopy->fuc + 0x100, 0x00000002); /* TRIGGER */ ++ return 0; ++} ++ ++static int ++nvc0_copy_fini(struct drm_device *dev, int engine) ++{ ++ struct nvc0_copy_engine *pcopy = nv_engine(dev, engine); ++ ++ nv_mask(dev, pcopy->fuc + 0x048, 0x00000003, 0x00000000); ++ ++ /* trigger fuc context unload */ ++ nv_wait(dev, pcopy->fuc + 0x008, 0x0000000c, 0x00000000); ++ nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000); ++ nv_wr32(dev, pcopy->fuc + 0x000, 0x00000008); ++ nv_wait(dev, pcopy->fuc + 0x008, 0x00000008, 0x00000000); ++ ++ nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff); ++ return 0; ++} ++ ++static struct nouveau_enum nvc0_copy_isr_error_name[] = { ++ { 0x0001, "ILLEGAL_MTHD" }, ++ { 0x0002, "INVALID_ENUM" }, ++ { 0x0003, "INVALID_BITFIELD" }, ++ {} ++}; ++ ++static void ++nvc0_copy_isr(struct drm_device *dev, int engine) ++{ ++ struct nvc0_copy_engine *pcopy = nv_engine(dev, engine); ++ u32 disp = nv_rd32(dev, pcopy->fuc + 0x01c); ++ u32 stat = nv_rd32(dev, pcopy->fuc + 0x008) & disp & ~(disp >> 16); ++ u64 inst = (u64)(nv_rd32(dev, pcopy->fuc + 0x050) & 0x0fffffff) << 12; ++ u32 chid = nvc0_graph_isr_chid(dev, inst); ++ u32 ssta = nv_rd32(dev, pcopy->fuc + 0x040) & 0x0000ffff; ++ u32 addr = nv_rd32(dev, pcopy->fuc + 0x040) >> 16; ++ u32 mthd = (addr & 0x07ff) << 2; ++ u32 subc = (addr & 0x3800) >> 11; ++ u32 data = nv_rd32(dev, pcopy->fuc + 0x044); ++ ++ if (stat & 0x00000040) { ++ NV_INFO(dev, "PCOPY: DISPATCH_ERROR ["); ++ nouveau_enum_print(nvc0_copy_isr_error_name, ssta); ++ printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n", ++ chid, inst, subc, mthd, data); ++ nv_wr32(dev, pcopy->fuc + 0x004, 0x00000040); ++ stat &= ~0x00000040; ++ } ++ ++ if (stat) { ++ NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat); ++ nv_wr32(dev, pcopy->fuc + 0x004, stat); ++ } ++} ++ ++static void ++nvc0_copy_isr_0(struct drm_device *dev) ++{ ++ nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY0); ++} ++ ++static void ++nvc0_copy_isr_1(struct drm_device *dev) ++{ ++ nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY1); ++} ++ ++static void ++nvc0_copy_destroy(struct drm_device *dev, int engine) ++{ ++ struct nvc0_copy_engine *pcopy = nv_engine(dev, engine); ++ ++ nouveau_irq_unregister(dev, pcopy->irq); ++ ++ if (engine == NVOBJ_ENGINE_COPY0) ++ NVOBJ_ENGINE_DEL(dev, COPY0); ++ else ++ NVOBJ_ENGINE_DEL(dev, COPY1); ++ kfree(pcopy); ++} ++ ++int ++nvc0_copy_create(struct drm_device *dev, int engine) ++{ ++ struct nvc0_copy_engine *pcopy; ++ ++ pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL); ++ if (!pcopy) ++ return -ENOMEM; ++ ++ pcopy->base.destroy = nvc0_copy_destroy; ++ pcopy->base.init = nvc0_copy_init; ++ pcopy->base.fini = nvc0_copy_fini; ++ pcopy->base.context_new = nvc0_copy_context_new; ++ pcopy->base.context_del = nvc0_copy_context_del; ++ pcopy->base.object_new = nvc0_copy_object_new; ++ ++ if (engine == 0) { ++ pcopy->irq = 5; ++ pcopy->pmc = 0x00000040; ++ pcopy->fuc = 0x104000; ++ pcopy->ctx = 0x0230; ++ nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_0); ++ NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base); ++ NVOBJ_CLASS(dev, 0x90b5, COPY0); ++ } else { ++ pcopy->irq = 6; ++ pcopy->pmc = 0x00000080; ++ pcopy->fuc = 0x105000; ++ pcopy->ctx = 0x0240; ++ nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_1); ++ NVOBJ_ENGINE_ADD(dev, COPY1, &pcopy->base); ++ NVOBJ_CLASS(dev, 0x90b8, COPY1); ++ } ++ ++ return 0; ++} +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h 2011-05-09 00:36:22.000000000 +0200 +@@ -0,0 +1,527 @@ ++uint32_t nvc0_pcopy_data[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00010000, ++ 0x00000000, ++ 0x00000000, ++ 0x00010040, ++ 0x0001019f, ++ 0x00000000, ++ 0x00010050, ++ 0x000101a1, ++ 0x00000000, ++ 0x00070080, ++ 0x0000001c, ++ 0xfffff000, ++ 0x00000020, ++ 0xfff80000, ++ 0x00000024, ++ 0xffffe000, ++ 0x00000028, ++ 0xfffff800, ++ 0x0000002c, ++ 0xfffff000, ++ 0x00000030, ++ 0xfff80000, ++ 0x00000034, ++ 0xffffe000, ++ 0x00070088, ++ 0x00000048, ++ 0xfffff000, ++ 0x0000004c, ++ 0xfff80000, ++ 0x00000050, ++ 0xffffe000, ++ 0x00000054, ++ 0xfffff800, ++ 0x00000058, ++ 0xfffff000, ++ 0x0000005c, ++ 0xfff80000, ++ 0x00000060, ++ 0xffffe000, ++ 0x000200c0, ++ 0x000104b8, ++ 0x00000000, ++ 0x00010541, ++ 0x00000000, ++ 0x000e00c3, ++ 0x00000010, ++ 0xffffff00, ++ 0x00000014, ++ 0x0000000f, ++ 0x0000003c, ++ 0xffffff00, ++ 0x00000040, ++ 0x0000000f, ++ 0x00000018, ++ 0xfff80000, ++ 0x00000044, ++ 0xfff80000, ++ 0x00000074, ++ 0xffff0000, ++ 0x00000078, ++ 0xffffe000, ++ 0x00000068, ++ 0xfccc0000, ++ 0x0000006c, ++ 0x00000000, ++ 0x00000070, ++ 0x00000000, ++ 0x00000004, ++ 0xffffff00, ++ 0x00000008, ++ 0x00000000, ++ 0x0000000c, ++ 0x00000000, ++ 0x00000800, ++}; ++ ++uint32_t nvc0_pcopy_code[] = { ++ 0x04fe04bd, ++ 0x3517f000, ++ 0xf10010fe, ++ 0xf1040017, ++ 0xf0fff327, ++ 0x22d00023, ++ 0x0c25f0c0, ++ 0xf40012d0, ++ 0x17f11031, ++ 0x27f01200, ++ 0x0012d003, ++ 0xf40031f4, ++ 0x0ef40028, ++ 0x8001cffd, ++ 0xf40812c4, ++ 0x21f4060b, ++ 0x0412c4ca, ++ 0xf5070bf4, ++ 0xc4010221, ++ 0x01d00c11, ++ 0xf101f840, ++ 0xfe770047, ++ 0x47f1004b, ++ 0x44cf2100, ++ 0x0144f000, ++ 0xb60444b6, ++ 0xf7f13040, ++ 0xf4b6061c, ++ 0x1457f106, ++ 0x00f5d101, ++ 0xb6043594, ++ 0x57fe0250, ++ 0x0145fe00, ++ 0x010052b7, ++ 0x00ff67f1, ++ 0x56fd60bd, ++ 0x0253f004, ++ 0xf80545fa, ++ 0x0053f003, ++ 0xd100e7f0, ++ 0x549800fe, ++ 0x0845b600, ++ 0xb6015698, ++ 0x46fd1864, ++ 0x0047fe05, ++ 0xf00204b9, ++ 0x01f40643, ++ 0x0604fa09, ++ 0xfa060ef4, ++ 0x03f80504, ++ 0x27f100f8, ++ 0x23cf1400, ++ 0x1e3fc800, ++ 0xf4170bf4, ++ 0x21f40132, ++ 0x1e3af053, ++ 0xf00023d0, ++ 0x24d00147, ++ 0xcf00f880, ++ 0x3dc84023, ++ 0x090bf41e, ++ 0xf40131f4, ++ 0x37f05321, ++ 0x8023d002, ++ 0x37f100f8, ++ 0x32cf1900, ++ 0x0033cf40, ++ 0x07ff24e4, ++ 0xf11024b6, ++ 0xbd010057, ++ 0x5874bd64, ++ 0x57580056, ++ 0x0450b601, ++ 0xf40446b8, ++ 0x76bb4d08, ++ 0x0447b800, ++ 0xbb0f08f4, ++ 0x74b60276, ++ 0x0057bb03, ++ 0xbbdf0ef4, ++ 0x44b60246, ++ 0x0045bb03, ++ 0xfd014598, ++ 0x54b00453, ++ 0x201bf400, ++ 0x58004558, ++ 0x64b00146, ++ 0x091bf400, ++ 0xf4005380, ++ 0x32f4300e, ++ 0xf455f901, ++ 0x0ef40c01, ++ 0x0225f025, ++ 0xf10125f0, ++ 0xd0100047, ++ 0x43d00042, ++ 0x4027f040, ++ 0xcf0002d0, ++ 0x24f08002, ++ 0x0024b040, ++ 0xf1f71bf4, ++ 0xf01d0027, ++ 0x23d00137, ++ 0xf800f800, ++ 0x0027f100, ++ 0xf034bd22, ++ 0x23d00233, ++ 0xf400f800, ++ 0x01b0f030, ++ 0x0101b000, ++ 0xb00201b0, ++ 0x04980301, ++ 0x3045c71a, ++ 0xc70150b6, ++ 0x60b63446, ++ 0x3847c701, ++ 0xf40170b6, ++ 0x84bd0232, ++ 0x4ac494bd, ++ 0x0445b60f, ++ 0xa430b4bd, ++ 0x0f18f404, ++ 0xbbc0a5ff, ++ 0x31f400cb, ++ 0x220ef402, ++ 0xf00c1bf4, ++ 0xcbbb10c7, ++ 0x160ef400, ++ 0xf406a430, ++ 0xc7f00c18, ++ 0x00cbbb14, ++ 0xf1070ef4, ++ 0x380080c7, ++ 0x80b601c8, ++ 0x01b0b601, ++ 0xf404b5b8, ++ 0x90b6c308, ++ 0x0497b801, ++ 0xfdb208f4, ++ 0x06800065, ++ 0x1d08980e, ++ 0xf40068fd, ++ 0x64bd0502, ++ 0x800075fd, ++ 0x78fd1907, ++ 0x1057f100, ++ 0x0654b608, ++ 0xd00056d0, ++ 0x50b74057, ++ 0x06980800, ++ 0x0162b619, ++ 0x980864b6, ++ 0x72b60e07, ++ 0x0567fd01, ++ 0xb70056d0, ++ 0xb4010050, ++ 0x56d00060, ++ 0x0160b400, ++ 0xb44056d0, ++ 0x56d00260, ++ 0x0360b480, ++ 0xb7c056d0, ++ 0x98040050, ++ 0x56d01b06, ++ 0x1c069800, ++ 0xf44056d0, ++ 0x00f81030, ++ 0xc7075798, ++ 0x78c76879, ++ 0x0380b664, ++ 0xb06077c7, ++ 0x1bf40e76, ++ 0x0477f009, ++ 0xf00f0ef4, ++ 0x70b6027c, ++ 0x0947fd11, ++ 0x980677f0, ++ 0x5b980c5a, ++ 0x00abfd0e, ++ 0xbb01b7f0, ++ 0xb2b604b7, ++ 0xc4abff01, ++ 0x9805a7bb, ++ 0xe7f00d5d, ++ 0x04e8bb01, ++ 0xff01e2b6, ++ 0xd8bbb4de, ++ 0x01e0b605, ++ 0xbb0cef94, ++ 0xfefd02eb, ++ 0x026cf005, ++ 0x020860b7, ++ 0xd00864b6, ++ 0xb7bb006f, ++ 0x00cbbb04, ++ 0x98085f98, ++ 0xfbfd0e5b, ++ 0x01b7f000, ++ 0xb604b7bb, ++ 0xfbbb01b2, ++ 0x05f7bb00, ++ 0x5f98f0f9, ++ 0x01b7f009, ++ 0xb604b8bb, ++ 0xfbbb01b2, ++ 0x05f8bb00, ++ 0x78bbf0f9, ++ 0x0282b600, ++ 0xbb01b7f0, ++ 0xb9bb04b8, ++ 0x0b589804, ++ 0xbb01e7f0, ++ 0xe2b604e9, ++ 0xf48eff01, ++ 0xbb04f7bb, ++ 0x79bb00cf, ++ 0x0589bb00, ++ 0x90fcf0fc, ++ 0xbb00d9fd, ++ 0x89fd00ad, ++ 0x008ffd00, ++ 0xbb00a8bb, ++ 0x92b604a7, ++ 0x0497bb01, ++ 0x988069d0, ++ 0x58980557, ++ 0x00acbb04, ++ 0xb6007abb, ++ 0x84b60081, ++ 0x058bfd10, ++ 0x060062b7, ++ 0xb70067d0, ++ 0xd0040060, ++ 0x00f80068, ++ 0xb7026cf0, ++ 0xb6020260, ++ 0x57980864, ++ 0x0067d005, ++ 0x040060b7, ++ 0xb6045798, ++ 0x67d01074, ++ 0x0060b700, ++ 0x06579804, ++ 0xf80067d0, ++ 0xf900f900, ++ 0x0007f110, ++ 0x0604b608, ++ 0xf00001cf, ++ 0x1bf40114, ++ 0xfc10fcfa, ++ 0xc800f800, ++ 0x1bf40d34, ++ 0xd121f570, ++ 0x0c47f103, ++ 0x0644b608, ++ 0xb6020598, ++ 0x45d00450, ++ 0x4040d000, ++ 0xd00c57f0, ++ 0x40b78045, ++ 0x05980400, ++ 0x1054b601, ++ 0xb70045d0, ++ 0xf1050040, ++ 0xf00b0057, ++ 0x45d00153, ++ 0x4057f100, ++ 0x0154b640, ++ 0x808053f1, ++ 0xf14045d0, ++ 0xf1111057, ++ 0xd0131253, ++ 0x57f18045, ++ 0x53f11514, ++ 0x45d01716, ++ 0x0157f1c0, ++ 0x0153f026, ++ 0x080047f1, ++ 0xd00644b6, ++ 0x21f50045, ++ 0x47f103d1, ++ 0x44b6080c, ++ 0x02059806, ++ 0xd00045d0, ++ 0x57f04040, ++ 0x8045d004, ++ 0x040040b7, ++ 0xb6010598, ++ 0x45d01054, ++ 0x0040b700, ++ 0x0057f105, ++ 0x0045d003, ++ 0x111057f1, ++ 0x131253f1, ++ 0x984045d0, ++ 0x40b70305, ++ 0x45d00500, ++ 0x0157f100, ++ 0x0153f026, ++ 0x080047f1, ++ 0xd00644b6, ++ 0x00f80045, ++ 0x03d121f5, ++ 0xf4003fc8, ++ 0x21f50e0b, ++ 0x47f101af, ++ 0x0ef40200, ++ 0x1067f11e, ++ 0x0664b608, ++ 0x800177f0, ++ 0x07800e07, ++ 0x1d079819, ++ 0xd00067d0, ++ 0x44bd4067, ++ 0xbd0232f4, ++ 0x043fc854, ++ 0xf50a0bf4, ++ 0xf403a821, ++ 0x21f50a0e, ++ 0x49f0029c, ++ 0x0231f407, ++ 0xc82c57f0, ++ 0x0bf4083f, ++ 0xa821f50a, ++ 0x0a0ef403, ++ 0x029c21f5, ++ 0xf10849f0, ++ 0xb6080057, ++ 0x06980654, ++ 0x4056d01e, ++ 0xf14167f0, ++ 0xfd440063, ++ 0x54d00546, ++ 0x0c3fc800, ++ 0xf5070bf4, ++ 0xf803eb21, ++ 0x0027f100, ++ 0xf034bd22, ++ 0x23d00133, ++ 0x0000f800, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nvc0_fifo.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nvc0_fifo.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nvc0_fifo.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nvc0_fifo.c 2011-05-09 00:36:22.000000000 +0200 +@@ -37,7 +37,7 @@ + }; + + struct nvc0_fifo_chan { +- struct nouveau_bo *user; ++ struct nouveau_gpuobj *user; + struct nouveau_gpuobj *ramfc; + }; + +@@ -106,7 +106,7 @@ + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nvc0_fifo_priv *priv = pfifo->priv; + struct nvc0_fifo_chan *fifoch; +- u64 ib_virt, user_vinst; ++ u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4; + int ret; + + chan->fifo_priv = kzalloc(sizeof(*fifoch), GFP_KERNEL); +@@ -115,28 +115,13 @@ + fifoch = chan->fifo_priv; + + /* allocate vram for control regs, map into polling area */ +- ret = nouveau_bo_new(dev, NULL, 0x1000, 0, TTM_PL_FLAG_VRAM, +- 0, 0, &fifoch->user); ++ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, ++ NVOBJ_FLAG_ZERO_ALLOC, &fifoch->user); + if (ret) + goto error; + +- ret = nouveau_bo_pin(fifoch->user, TTM_PL_FLAG_VRAM); +- if (ret) { +- nouveau_bo_ref(NULL, &fifoch->user); +- goto error; +- } +- +- user_vinst = fifoch->user->bo.mem.start << PAGE_SHIFT; +- +- ret = nouveau_bo_map(fifoch->user); +- if (ret) { +- nouveau_bo_unpin(fifoch->user); +- nouveau_bo_ref(NULL, &fifoch->user); +- goto error; +- } +- + nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000, +- fifoch->user->bo.mem.mm_node); ++ *(struct nouveau_mem **)fifoch->user->node); + + chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) + + priv->user_vma.offset + (chan->id * 0x1000), +@@ -146,20 +131,6 @@ + goto error; + } + +- ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4; +- +- /* zero channel regs */ +- nouveau_bo_wr32(fifoch->user, 0x0040/4, 0); +- nouveau_bo_wr32(fifoch->user, 0x0044/4, 0); +- nouveau_bo_wr32(fifoch->user, 0x0048/4, 0); +- nouveau_bo_wr32(fifoch->user, 0x004c/4, 0); +- nouveau_bo_wr32(fifoch->user, 0x0050/4, 0); +- nouveau_bo_wr32(fifoch->user, 0x0058/4, 0); +- nouveau_bo_wr32(fifoch->user, 0x005c/4, 0); +- nouveau_bo_wr32(fifoch->user, 0x0060/4, 0); +- nouveau_bo_wr32(fifoch->user, 0x0088/4, 0); +- nouveau_bo_wr32(fifoch->user, 0x008c/4, 0); +- + /* ramfc */ + ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst, + chan->ramin->vinst, 0x100, +@@ -167,8 +138,8 @@ + if (ret) + goto error; + +- nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(user_vinst)); +- nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(user_vinst)); ++ nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(fifoch->user->vinst)); ++ nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(fifoch->user->vinst)); + nv_wo32(fifoch->ramfc, 0x10, 0x0000face); + nv_wo32(fifoch->ramfc, 0x30, 0xfffff902); + nv_wo32(fifoch->ramfc, 0x48, lower_32_bits(ib_virt)); +@@ -223,11 +194,7 @@ + return; + + nouveau_gpuobj_ref(NULL, &fifoch->ramfc); +- if (fifoch->user) { +- nouveau_bo_unmap(fifoch->user); +- nouveau_bo_unpin(fifoch->user); +- nouveau_bo_ref(NULL, &fifoch->user); +- } ++ nouveau_gpuobj_ref(NULL, &fifoch->user); + kfree(fifoch); + } + +@@ -240,6 +207,21 @@ + int + nvc0_fifo_unload_context(struct drm_device *dev) + { ++ int i; ++ ++ for (i = 0; i < 128; i++) { ++ if (!(nv_rd32(dev, 0x003004 + (i * 4)) & 1)) ++ continue; ++ ++ nv_mask(dev, 0x003004 + (i * 4), 0x00000001, 0x00000000); ++ nv_wr32(dev, 0x002634, i); ++ if (!nv_wait(dev, 0x002634, 0xffffffff, i)) { ++ NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n", ++ i, nv_rd32(dev, 0x002634)); ++ return -EBUSY; ++ } ++ } ++ + return 0; + } + +@@ -309,6 +291,7 @@ + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; ++ struct nouveau_channel *chan; + struct nvc0_fifo_priv *priv; + int ret, i; + +@@ -351,23 +334,74 @@ + nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */ + nv_wr32(dev, 0x002100, 0xffffffff); + nv_wr32(dev, 0x002140, 0xbfffffff); ++ ++ /* restore PFIFO context table */ ++ for (i = 0; i < 128; i++) { ++ chan = dev_priv->channels.ptr[i]; ++ if (!chan || !chan->fifo_priv) ++ continue; ++ ++ nv_wr32(dev, 0x003000 + (i * 8), 0xc0000000 | ++ (chan->ramin->vinst >> 12)); ++ nv_wr32(dev, 0x003004 + (i * 8), 0x001f0001); ++ } ++ nvc0_fifo_playlist_update(dev); ++ + return 0; + } + + struct nouveau_enum nvc0_fifo_fault_unit[] = { +- { 0, "PGRAPH" }, +- { 3, "PEEPHOLE" }, +- { 4, "BAR1" }, +- { 5, "BAR3" }, +- { 7, "PFIFO" }, ++ { 0x00, "PGRAPH" }, ++ { 0x03, "PEEPHOLE" }, ++ { 0x04, "BAR1" }, ++ { 0x05, "BAR3" }, ++ { 0x07, "PFIFO" }, ++ { 0x10, "PBSP" }, ++ { 0x11, "PPPP" }, ++ { 0x13, "PCOUNTER" }, ++ { 0x14, "PVP" }, ++ { 0x15, "PCOPY0" }, ++ { 0x16, "PCOPY1" }, ++ { 0x17, "PDAEMON" }, + {} + }; + + struct nouveau_enum nvc0_fifo_fault_reason[] = { +- { 0, "PT_NOT_PRESENT" }, +- { 1, "PT_TOO_SHORT" }, +- { 2, "PAGE_NOT_PRESENT" }, +- { 3, "VM_LIMIT_EXCEEDED" }, ++ { 0x00, "PT_NOT_PRESENT" }, ++ { 0x01, "PT_TOO_SHORT" }, ++ { 0x02, "PAGE_NOT_PRESENT" }, ++ { 0x03, "VM_LIMIT_EXCEEDED" }, ++ { 0x04, "NO_CHANNEL" }, ++ { 0x05, "PAGE_SYSTEM_ONLY" }, ++ { 0x06, "PAGE_READ_ONLY" }, ++ { 0x0a, "COMPRESSED_SYSRAM" }, ++ { 0x0c, "INVALID_STORAGE_TYPE" }, ++ {} ++}; ++ ++struct nouveau_enum nvc0_fifo_fault_hubclient[] = { ++ { 0x01, "PCOPY0" }, ++ { 0x02, "PCOPY1" }, ++ { 0x04, "DISPATCH" }, ++ { 0x05, "CTXCTL" }, ++ { 0x06, "PFIFO" }, ++ { 0x07, "BAR_READ" }, ++ { 0x08, "BAR_WRITE" }, ++ { 0x0b, "PVP" }, ++ { 0x0c, "PPPP" }, ++ { 0x0d, "PBSP" }, ++ { 0x11, "PCOUNTER" }, ++ { 0x12, "PDAEMON" }, ++ { 0x14, "CCACHE" }, ++ { 0x15, "CCACHE_POST" }, ++ {} ++}; ++ ++struct nouveau_enum nvc0_fifo_fault_gpcclient[] = { ++ { 0x01, "TEX" }, ++ { 0x0c, "ESETUP" }, ++ { 0x0e, "CTXCTL" }, ++ { 0x0f, "PROP" }, + {} + }; + +@@ -385,12 +419,20 @@ + u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10)); + u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10)); + u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10)); ++ u32 client = (stat & 0x00001f00) >> 8; + + NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [", + (stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo); + nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f); + printk("] from "); + nouveau_enum_print(nvc0_fifo_fault_unit, unit); ++ if (stat & 0x00000040) { ++ printk("/"); ++ nouveau_enum_print(nvc0_fifo_fault_hubclient, client); ++ } else { ++ printk("/GPC%d/", (stat & 0x1f000000) >> 24); ++ nouveau_enum_print(nvc0_fifo_fault_gpcclient, client); ++ } + printk(" on channel 0x%010llx\n", (u64)inst << 12); + } + +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nvc0_graph.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nvc0_graph.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nvc0_graph.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nvc0_graph.c 2011-05-09 00:36:22.000000000 +0200 +@@ -30,27 +30,40 @@ + #include "nouveau_mm.h" + #include "nvc0_graph.h" + +-static void nvc0_graph_isr(struct drm_device *); +-static void nvc0_runk140_isr(struct drm_device *); +-static int nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan); +- +-void +-nvc0_graph_fifo_access(struct drm_device *dev, bool enabled) ++static int ++nvc0_graph_load_context(struct nouveau_channel *chan) + { ++ struct drm_device *dev = chan->dev; ++ ++ nv_wr32(dev, 0x409840, 0x00000030); ++ nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12); ++ nv_wr32(dev, 0x409504, 0x00000003); ++ if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010)) ++ NV_ERROR(dev, "PGRAPH: load_ctx timeout\n"); ++ ++ return 0; + } + +-struct nouveau_channel * +-nvc0_graph_channel(struct drm_device *dev) ++static int ++nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan) + { +- return NULL; ++ nv_wr32(dev, 0x409840, 0x00000003); ++ nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12); ++ nv_wr32(dev, 0x409504, 0x00000009); ++ if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) { ++ NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n"); ++ return -EBUSY; ++ } ++ ++ return 0; + } + + static int + nvc0_graph_construct_context(struct nouveau_channel *chan) + { + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; +- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; +- struct nvc0_graph_chan *grch = chan->pgraph_ctx; ++ struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR); ++ struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR]; + struct drm_device *dev = chan->dev; + int ret, i; + u32 *ctx; +@@ -89,9 +102,8 @@ + static int + nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan) + { +- struct drm_nouveau_private *dev_priv = chan->dev->dev_private; +- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; +- struct nvc0_graph_chan *grch = chan->pgraph_ctx; ++ struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR); ++ struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR]; + struct drm_device *dev = chan->dev; + int i = 0, gpc, tp, ret; + u32 magic; +@@ -158,29 +170,27 @@ + return 0; + } + +-int +-nvc0_graph_create_context(struct nouveau_channel *chan) ++static int ++nvc0_graph_context_new(struct nouveau_channel *chan, int engine) + { +- struct drm_nouveau_private *dev_priv = chan->dev->dev_private; ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct nvc0_graph_priv *priv = pgraph->priv; ++ struct nvc0_graph_priv *priv = nv_engine(dev, engine); + struct nvc0_graph_chan *grch; +- struct drm_device *dev = chan->dev; + struct nouveau_gpuobj *grctx; + int ret, i; + +- chan->pgraph_ctx = kzalloc(sizeof(*grch), GFP_KERNEL); +- if (!chan->pgraph_ctx) ++ grch = kzalloc(sizeof(*grch), GFP_KERNEL); ++ if (!grch) + return -ENOMEM; +- grch = chan->pgraph_ctx; ++ chan->engctx[NVOBJ_ENGINE_GR] = grch; + + ret = nouveau_gpuobj_new(dev, NULL, priv->grctx_size, 256, + NVOBJ_FLAG_VM | NVOBJ_FLAG_ZERO_ALLOC, + &grch->grctx); + if (ret) + goto error; +- chan->ramin_grctx = grch->grctx; + grctx = grch->grctx; + + ret = nvc0_graph_create_context_mmio_list(chan); +@@ -200,104 +210,49 @@ + for (i = 0; i < priv->grctx_size; i += 4) + nv_wo32(grctx, i, priv->grctx_vals[i / 4]); + +- nv_wo32(grctx, 0xf4, 0); +- nv_wo32(grctx, 0xf8, 0); +- nv_wo32(grctx, 0x10, grch->mmio_nr); +- nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst)); +- nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst)); +- nv_wo32(grctx, 0x1c, 1); +- nv_wo32(grctx, 0x20, 0); +- nv_wo32(grctx, 0x28, 0); +- nv_wo32(grctx, 0x2c, 0); ++ nv_wo32(grctx, 0xf4, 0); ++ nv_wo32(grctx, 0xf8, 0); ++ nv_wo32(grctx, 0x10, grch->mmio_nr); ++ nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst)); ++ nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst)); ++ nv_wo32(grctx, 0x1c, 1); ++ nv_wo32(grctx, 0x20, 0); ++ nv_wo32(grctx, 0x28, 0); ++ nv_wo32(grctx, 0x2c, 0); + pinstmem->flush(dev); + return 0; + + error: +- pgraph->destroy_context(chan); ++ priv->base.context_del(chan, engine); + return ret; + } + +-void +-nvc0_graph_destroy_context(struct nouveau_channel *chan) ++static void ++nvc0_graph_context_del(struct nouveau_channel *chan, int engine) + { +- struct nvc0_graph_chan *grch; +- +- grch = chan->pgraph_ctx; +- chan->pgraph_ctx = NULL; +- if (!grch) +- return; ++ struct nvc0_graph_chan *grch = chan->engctx[engine]; + + nouveau_gpuobj_ref(NULL, &grch->mmio); + nouveau_gpuobj_ref(NULL, &grch->unk418810); + nouveau_gpuobj_ref(NULL, &grch->unk40800c); + nouveau_gpuobj_ref(NULL, &grch->unk408004); + nouveau_gpuobj_ref(NULL, &grch->grctx); +- chan->ramin_grctx = NULL; ++ chan->engctx[engine] = NULL; + } + +-int +-nvc0_graph_load_context(struct nouveau_channel *chan) ++static int ++nvc0_graph_object_new(struct nouveau_channel *chan, int engine, ++ u32 handle, u16 class) + { +- struct drm_device *dev = chan->dev; +- +- nv_wr32(dev, 0x409840, 0x00000030); +- nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12); +- nv_wr32(dev, 0x409504, 0x00000003); +- if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010)) +- NV_ERROR(dev, "PGRAPH: load_ctx timeout\n"); +- + return 0; + } + + static int +-nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan) ++nvc0_graph_fini(struct drm_device *dev, int engine) + { +- nv_wr32(dev, 0x409840, 0x00000003); +- nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12); +- nv_wr32(dev, 0x409504, 0x00000009); +- if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n"); +- return -EBUSY; +- } +- + return 0; + } + +-int +-nvc0_graph_unload_context(struct drm_device *dev) +-{ +- u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12; +- return nvc0_graph_unload_context_to(dev, inst); +-} +- +-static void +-nvc0_graph_destroy(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct nvc0_graph_priv *priv; +- +- priv = pgraph->priv; +- if (!priv) +- return; +- +- nouveau_irq_unregister(dev, 12); +- nouveau_irq_unregister(dev, 25); +- +- nouveau_gpuobj_ref(NULL, &priv->unk4188b8); +- nouveau_gpuobj_ref(NULL, &priv->unk4188b4); +- +- if (priv->grctx_vals) +- kfree(priv->grctx_vals); +- kfree(priv); +-} +- +-void +-nvc0_graph_takedown(struct drm_device *dev) +-{ +- nvc0_graph_destroy(dev); +-} +- + static int + nvc0_graph_mthd_page_flip(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) +@@ -306,119 +261,10 @@ + return 0; + } + +-static int +-nvc0_graph_create(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct nvc0_graph_priv *priv; +- int ret, gpc, i; +- +- priv = kzalloc(sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- pgraph->priv = priv; +- +- ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4); +- if (ret) +- goto error; +- +- ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8); +- if (ret) +- goto error; +- +- for (i = 0; i < 0x1000; i += 4) { +- nv_wo32(priv->unk4188b4, i, 0x00000010); +- nv_wo32(priv->unk4188b8, i, 0x00000010); +- } +- +- priv->gpc_nr = nv_rd32(dev, 0x409604) & 0x0000001f; +- priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16; +- for (gpc = 0; gpc < priv->gpc_nr; gpc++) { +- priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608)); +- priv->tp_total += priv->tp_nr[gpc]; +- } +- +- /*XXX: these need figuring out... */ +- switch (dev_priv->chipset) { +- case 0xc0: +- if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */ +- priv->magic_not_rop_nr = 0x07; +- /* filled values up to tp_total, the rest 0 */ +- priv->magicgpc980[0] = 0x22111000; +- priv->magicgpc980[1] = 0x00000233; +- priv->magicgpc980[2] = 0x00000000; +- priv->magicgpc980[3] = 0x00000000; +- priv->magicgpc918 = 0x000ba2e9; +- } else +- if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */ +- priv->magic_not_rop_nr = 0x05; +- priv->magicgpc980[0] = 0x11110000; +- priv->magicgpc980[1] = 0x00233222; +- priv->magicgpc980[2] = 0x00000000; +- priv->magicgpc980[3] = 0x00000000; +- priv->magicgpc918 = 0x00092493; +- } else +- if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */ +- priv->magic_not_rop_nr = 0x06; +- priv->magicgpc980[0] = 0x11110000; +- priv->magicgpc980[1] = 0x03332222; +- priv->magicgpc980[2] = 0x00000000; +- priv->magicgpc980[3] = 0x00000000; +- priv->magicgpc918 = 0x00088889; +- } +- break; +- case 0xc3: /* 450, 4/0/0/0, 2 */ +- priv->magic_not_rop_nr = 0x03; +- priv->magicgpc980[0] = 0x00003210; +- priv->magicgpc980[1] = 0x00000000; +- priv->magicgpc980[2] = 0x00000000; +- priv->magicgpc980[3] = 0x00000000; +- priv->magicgpc918 = 0x00200000; +- break; +- case 0xc4: /* 460, 3/4/0/0, 4 */ +- priv->magic_not_rop_nr = 0x01; +- priv->magicgpc980[0] = 0x02321100; +- priv->magicgpc980[1] = 0x00000000; +- priv->magicgpc980[2] = 0x00000000; +- priv->magicgpc980[3] = 0x00000000; +- priv->magicgpc918 = 0x00124925; +- break; +- } +- +- if (!priv->magic_not_rop_nr) { +- NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n", +- priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2], +- priv->tp_nr[3], priv->rop_nr); +- /* use 0xc3's values... */ +- priv->magic_not_rop_nr = 0x03; +- priv->magicgpc980[0] = 0x00003210; +- priv->magicgpc980[1] = 0x00000000; +- priv->magicgpc980[2] = 0x00000000; +- priv->magicgpc980[3] = 0x00000000; +- priv->magicgpc918 = 0x00200000; +- } +- +- nouveau_irq_register(dev, 12, nvc0_graph_isr); +- nouveau_irq_register(dev, 25, nvc0_runk140_isr); +- NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */ +- NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */ +- NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip); +- NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */ +- NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */ +- return 0; +- +-error: +- nvc0_graph_destroy(dev); +- return ret; +-} +- + static void + nvc0_graph_init_obj418880(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct nvc0_graph_priv *priv = pgraph->priv; ++ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); + int i; + + nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000); +@@ -449,35 +295,42 @@ + static void + nvc0_graph_init_gpc_0(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; +- int gpc; +- +- // TP ROP UNKVAL(magic_not_rop_nr) +- // 450: 4/0/0/0 2 3 +- // 460: 3/4/0/0 4 1 +- // 465: 3/4/4/0 4 7 +- // 470: 3/3/4/4 5 5 +- // 480: 3/4/4/4 6 6 +- +- // magicgpc918 +- // 450: 00200000 00000000001000000000000000000000 +- // 460: 00124925 00000000000100100100100100100101 +- // 465: 000ba2e9 00000000000010111010001011101001 +- // 470: 00092493 00000000000010010010010010010011 +- // 480: 00088889 00000000000010001000100010001001 +- +- /* filled values up to tp_total, remainder 0 */ +- // 450: 00003210 00000000 00000000 00000000 +- // 460: 02321100 00000000 00000000 00000000 +- // 465: 22111000 00000233 00000000 00000000 +- // 470: 11110000 00233222 00000000 00000000 +- // 480: 11110000 03332222 00000000 00000000 +- +- nv_wr32(dev, GPC_BCAST(0x0980), priv->magicgpc980[0]); +- nv_wr32(dev, GPC_BCAST(0x0984), priv->magicgpc980[1]); +- nv_wr32(dev, GPC_BCAST(0x0988), priv->magicgpc980[2]); +- nv_wr32(dev, GPC_BCAST(0x098c), priv->magicgpc980[3]); ++ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); ++ u32 data[TP_MAX / 8]; ++ u8 tpnr[GPC_MAX]; ++ int i, gpc, tpc; ++ ++ /* ++ * TP ROP UNKVAL(magic_not_rop_nr) ++ * 450: 4/0/0/0 2 3 ++ * 460: 3/4/0/0 4 1 ++ * 465: 3/4/4/0 4 7 ++ * 470: 3/3/4/4 5 5 ++ * 480: 3/4/4/4 6 6 ++ * ++ * magicgpc918 ++ * 450: 00200000 00000000001000000000000000000000 ++ * 460: 00124925 00000000000100100100100100100101 ++ * 465: 000ba2e9 00000000000010111010001011101001 ++ * 470: 00092493 00000000000010010010010010010011 ++ * 480: 00088889 00000000000010001000100010001001 ++ */ ++ ++ memset(data, 0x00, sizeof(data)); ++ memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); ++ for (i = 0, gpc = -1; i < priv->tp_total; i++) { ++ do { ++ gpc = (gpc + 1) % priv->gpc_nr; ++ } while (!tpnr[gpc]); ++ tpc = priv->tp_nr[gpc] - tpnr[gpc]--; ++ ++ data[i / 8] |= tpc << ((i % 8) * 4); ++ } ++ ++ nv_wr32(dev, GPC_BCAST(0x0980), data[0]); ++ nv_wr32(dev, GPC_BCAST(0x0984), data[1]); ++ nv_wr32(dev, GPC_BCAST(0x0988), data[2]); ++ nv_wr32(dev, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 | +@@ -509,8 +362,7 @@ + static void + nvc0_graph_init_gpc_1(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; ++ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); + int gpc, tp; + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { +@@ -535,8 +387,7 @@ + static void + nvc0_graph_init_rop(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; ++ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); + int rop; + + for (rop = 0; rop < priv->rop_nr; rop++) { +@@ -547,62 +398,36 @@ + } + } + +-static int +-nvc0_fuc_load_fw(struct drm_device *dev, u32 fuc_base, +- const char *code_fw, const char *data_fw) ++static void ++nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base, ++ struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data) + { +- const struct firmware *fw; +- char name[32]; +- int ret, i; +- +- snprintf(name, sizeof(name), "nouveau/%s", data_fw); +- ret = request_firmware(&fw, name, &dev->pdev->dev); +- if (ret) { +- NV_ERROR(dev, "failed to load %s\n", data_fw); +- return ret; +- } ++ int i; + + nv_wr32(dev, fuc_base + 0x01c0, 0x01000000); +- for (i = 0; i < fw->size / 4; i++) +- nv_wr32(dev, fuc_base + 0x01c4, ((u32 *)fw->data)[i]); +- release_firmware(fw); +- +- snprintf(name, sizeof(name), "nouveau/%s", code_fw); +- ret = request_firmware(&fw, name, &dev->pdev->dev); +- if (ret) { +- NV_ERROR(dev, "failed to load %s\n", code_fw); +- return ret; +- } ++ for (i = 0; i < data->size / 4; i++) ++ nv_wr32(dev, fuc_base + 0x01c4, data->data[i]); + + nv_wr32(dev, fuc_base + 0x0180, 0x01000000); +- for (i = 0; i < fw->size / 4; i++) { ++ for (i = 0; i < code->size / 4; i++) { + if ((i & 0x3f) == 0) + nv_wr32(dev, fuc_base + 0x0188, i >> 6); +- nv_wr32(dev, fuc_base + 0x0184, ((u32 *)fw->data)[i]); ++ nv_wr32(dev, fuc_base + 0x0184, code->data[i]); + } +- release_firmware(fw); +- +- return 0; + } + + static int + nvc0_graph_init_ctxctl(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; ++ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); + u32 r000260; +- int ret; + + /* load fuc microcode */ + r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000); +- ret = nvc0_fuc_load_fw(dev, 0x409000, "fuc409c", "fuc409d"); +- if (ret == 0) +- ret = nvc0_fuc_load_fw(dev, 0x41a000, "fuc41ac", "fuc41ad"); ++ nvc0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, &priv->fuc409d); ++ nvc0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, &priv->fuc41ad); + nv_wr32(dev, 0x000260, r000260); + +- if (ret) +- return ret; +- + /* start both of them running */ + nv_wr32(dev, 0x409840, 0xffffffff); + nv_wr32(dev, 0x41a10c, 0x00000000); +@@ -644,41 +469,19 @@ + return 0; + } + +-int +-nvc0_graph_init(struct drm_device *dev) ++static int ++nvc0_graph_init(struct drm_device *dev, int engine) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + int ret; + +- dev_priv->engine.graph.accel_blocked = true; +- +- switch (dev_priv->chipset) { +- case 0xc0: +- case 0xc3: +- case 0xc4: +- break; +- default: +- NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n"); +- if (nouveau_noaccel != 0) +- return 0; +- break; +- } +- + nv_mask(dev, 0x000200, 0x18001000, 0x00000000); + nv_mask(dev, 0x000200, 0x18001000, 0x18001000); + +- if (!pgraph->priv) { +- ret = nvc0_graph_create(dev); +- if (ret) +- return ret; +- } +- + nvc0_graph_init_obj418880(dev); + nvc0_graph_init_regs(dev); +- //nvc0_graph_init_unitplemented_magics(dev); ++ /*nvc0_graph_init_unitplemented_magics(dev);*/ + nvc0_graph_init_gpc_0(dev); +- //nvc0_graph_init_unitplemented_c242(dev); ++ /*nvc0_graph_init_unitplemented_c242(dev);*/ + + nv_wr32(dev, 0x400500, 0x00010001); + nv_wr32(dev, 0x400100, 0xffffffff); +@@ -697,12 +500,13 @@ + nv_wr32(dev, 0x400054, 0x34ce3464); + + ret = nvc0_graph_init_ctxctl(dev); +- if (ret == 0) +- dev_priv->engine.graph.accel_blocked = false; ++ if (ret) ++ return ret; ++ + return 0; + } + +-static int ++int + nvc0_graph_isr_chid(struct drm_device *dev, u64 inst) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -806,3 +610,187 @@ + units &= ~(1 << unit); + } + } ++ ++static int ++nvc0_graph_create_fw(struct drm_device *dev, const char *fwname, ++ struct nvc0_graph_fuc *fuc) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ const struct firmware *fw; ++ char f[32]; ++ int ret; ++ ++ snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname); ++ ret = request_firmware(&fw, f, &dev->pdev->dev); ++ if (ret) { ++ snprintf(f, sizeof(f), "nouveau/%s", fwname); ++ ret = request_firmware(&fw, f, &dev->pdev->dev); ++ if (ret) { ++ NV_ERROR(dev, "failed to load %s\n", fwname); ++ return ret; ++ } ++ } ++ ++ fuc->size = fw->size; ++ fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL); ++ release_firmware(fw); ++ return (fuc->data != NULL) ? 0 : -ENOMEM; ++} ++ ++static void ++nvc0_graph_destroy_fw(struct nvc0_graph_fuc *fuc) ++{ ++ if (fuc->data) { ++ kfree(fuc->data); ++ fuc->data = NULL; ++ } ++} ++ ++static void ++nvc0_graph_destroy(struct drm_device *dev, int engine) ++{ ++ struct nvc0_graph_priv *priv = nv_engine(dev, engine); ++ ++ nvc0_graph_destroy_fw(&priv->fuc409c); ++ nvc0_graph_destroy_fw(&priv->fuc409d); ++ nvc0_graph_destroy_fw(&priv->fuc41ac); ++ nvc0_graph_destroy_fw(&priv->fuc41ad); ++ ++ nouveau_irq_unregister(dev, 12); ++ nouveau_irq_unregister(dev, 25); ++ ++ nouveau_gpuobj_ref(NULL, &priv->unk4188b8); ++ nouveau_gpuobj_ref(NULL, &priv->unk4188b4); ++ ++ if (priv->grctx_vals) ++ kfree(priv->grctx_vals); ++ ++ NVOBJ_ENGINE_DEL(dev, GR); ++ kfree(priv); ++} ++ ++int ++nvc0_graph_create(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nvc0_graph_priv *priv; ++ int ret, gpc, i; ++ ++ switch (dev_priv->chipset) { ++ case 0xc0: ++ case 0xc3: ++ case 0xc4: ++ break; ++ default: ++ NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n"); ++ return 0; ++ } ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->base.destroy = nvc0_graph_destroy; ++ priv->base.init = nvc0_graph_init; ++ priv->base.fini = nvc0_graph_fini; ++ priv->base.context_new = nvc0_graph_context_new; ++ priv->base.context_del = nvc0_graph_context_del; ++ priv->base.object_new = nvc0_graph_object_new; ++ ++ NVOBJ_ENGINE_ADD(dev, GR, &priv->base); ++ nouveau_irq_register(dev, 12, nvc0_graph_isr); ++ nouveau_irq_register(dev, 25, nvc0_runk140_isr); ++ ++ if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) || ++ nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) || ++ nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) || ++ nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) { ++ ret = 0; ++ goto error; ++ } ++ ++ ++ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4); ++ if (ret) ++ goto error; ++ ++ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8); ++ if (ret) ++ goto error; ++ ++ for (i = 0; i < 0x1000; i += 4) { ++ nv_wo32(priv->unk4188b4, i, 0x00000010); ++ nv_wo32(priv->unk4188b8, i, 0x00000010); ++ } ++ ++ priv->gpc_nr = nv_rd32(dev, 0x409604) & 0x0000001f; ++ priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16; ++ for (gpc = 0; gpc < priv->gpc_nr; gpc++) { ++ priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608)); ++ priv->tp_total += priv->tp_nr[gpc]; ++ } ++ ++ /*XXX: these need figuring out... */ ++ switch (dev_priv->chipset) { ++ case 0xc0: ++ if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */ ++ priv->magic_not_rop_nr = 0x07; ++ /* filled values up to tp_total, the rest 0 */ ++ priv->magicgpc918 = 0x000ba2e9; ++ } else ++ if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */ ++ priv->magic_not_rop_nr = 0x05; ++ priv->magicgpc918 = 0x00092493; ++ } else ++ if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */ ++ priv->magic_not_rop_nr = 0x06; ++ priv->magicgpc918 = 0x00088889; ++ } ++ break; ++ case 0xc3: /* 450, 4/0/0/0, 2 */ ++ priv->magic_not_rop_nr = 0x03; ++ priv->magicgpc918 = 0x00200000; ++ break; ++ case 0xc4: /* 460, 3/4/0/0, 4 */ ++ priv->magic_not_rop_nr = 0x01; ++ priv->magicgpc918 = 0x00124925; ++ break; ++ } ++ ++ if (!priv->magic_not_rop_nr) { ++ NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n", ++ priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2], ++ priv->tp_nr[3], priv->rop_nr); ++ /* use 0xc3's values... */ ++ priv->magic_not_rop_nr = 0x03; ++ priv->magicgpc918 = 0x00200000; ++ } ++ ++ NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */ ++ NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */ ++ NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip); ++ NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */ ++ NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */ ++ return 0; ++ ++error: ++ nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR); ++ return ret; ++} ++ ++MODULE_FIRMWARE("nouveau/nvc0_fuc409c"); ++MODULE_FIRMWARE("nouveau/nvc0_fuc409d"); ++MODULE_FIRMWARE("nouveau/nvc0_fuc41ac"); ++MODULE_FIRMWARE("nouveau/nvc0_fuc41ad"); ++MODULE_FIRMWARE("nouveau/nvc3_fuc409c"); ++MODULE_FIRMWARE("nouveau/nvc3_fuc409d"); ++MODULE_FIRMWARE("nouveau/nvc3_fuc41ac"); ++MODULE_FIRMWARE("nouveau/nvc3_fuc41ad"); ++MODULE_FIRMWARE("nouveau/nvc4_fuc409c"); ++MODULE_FIRMWARE("nouveau/nvc4_fuc409d"); ++MODULE_FIRMWARE("nouveau/nvc4_fuc41ac"); ++MODULE_FIRMWARE("nouveau/nvc4_fuc41ad"); ++MODULE_FIRMWARE("nouveau/fuc409c"); ++MODULE_FIRMWARE("nouveau/fuc409d"); ++MODULE_FIRMWARE("nouveau/fuc41ac"); ++MODULE_FIRMWARE("nouveau/fuc41ad"); +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nvc0_graph.h linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nvc0_graph.h +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nvc0_graph.h 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nvc0_graph.h 2011-05-09 00:36:22.000000000 +0200 +@@ -28,13 +28,25 @@ + #define GPC_MAX 4 + #define TP_MAX 32 + +-#define ROP_BCAST(r) (0x408800 + (r)) +-#define ROP_UNIT(u,r) (0x410000 + (u) * 0x400 + (r)) +-#define GPC_BCAST(r) (0x418000 + (r)) +-#define GPC_UNIT(t,r) (0x500000 + (t) * 0x8000 + (r)) +-#define TP_UNIT(t,m,r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r)) ++#define ROP_BCAST(r) (0x408800 + (r)) ++#define ROP_UNIT(u, r) (0x410000 + (u) * 0x400 + (r)) ++#define GPC_BCAST(r) (0x418000 + (r)) ++#define GPC_UNIT(t, r) (0x500000 + (t) * 0x8000 + (r)) ++#define TP_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r)) ++ ++struct nvc0_graph_fuc { ++ u32 *data; ++ u32 size; ++}; + + struct nvc0_graph_priv { ++ struct nouveau_exec_engine base; ++ ++ struct nvc0_graph_fuc fuc409c; ++ struct nvc0_graph_fuc fuc409d; ++ struct nvc0_graph_fuc fuc41ac; ++ struct nvc0_graph_fuc fuc41ad; ++ + u8 gpc_nr; + u8 rop_nr; + u8 tp_nr[GPC_MAX]; +@@ -46,15 +58,14 @@ + struct nouveau_gpuobj *unk4188b8; + + u8 magic_not_rop_nr; +- u32 magicgpc980[4]; + u32 magicgpc918; + }; + + struct nvc0_graph_chan { + struct nouveau_gpuobj *grctx; +- struct nouveau_gpuobj *unk408004; // 0x418810 too +- struct nouveau_gpuobj *unk40800c; // 0x419004 too +- struct nouveau_gpuobj *unk418810; // 0x419848 too ++ struct nouveau_gpuobj *unk408004; /* 0x418810 too */ ++ struct nouveau_gpuobj *unk40800c; /* 0x419004 too */ ++ struct nouveau_gpuobj *unk418810; /* 0x419848 too */ + struct nouveau_gpuobj *mmio; + int mmio_nr; + }; +diff -Naur linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nvc0_grctx.c linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nvc0_grctx.c +--- linux-2.6.39-rc6/drivers/gpu/drm/nouveau/nvc0_grctx.c 2011-05-04 04:59:13.000000000 +0200 ++++ linux-2.6.39-rc6.nouveau/drivers/gpu/drm/nouveau/nvc0_grctx.c 2011-05-09 00:36:22.000000000 +0200 +@@ -1623,7 +1623,7 @@ + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + +- // ROPC_BROADCAST ++ /* ROPC_BROADCAST */ + nv_wr32(dev, 0x408800, 0x02802a3c); + nv_wr32(dev, 0x408804, 0x00000040); + nv_wr32(dev, 0x408808, 0x0003e00d); +@@ -1647,7 +1647,7 @@ + { + int i; + +- // GPC_BROADCAST ++ /* GPC_BROADCAST */ + nv_wr32(dev, 0x418380, 0x00000016); + nv_wr32(dev, 0x418400, 0x38004e00); + nv_wr32(dev, 0x418404, 0x71e0ffff); +@@ -1728,7 +1728,7 @@ + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + +- // GPC_BROADCAST.TP_BROADCAST ++ /* GPC_BROADCAST.TP_BROADCAST */ + nv_wr32(dev, 0x419848, 0x00000000); + nv_wr32(dev, 0x419864, 0x0000012a); + nv_wr32(dev, 0x419888, 0x00000000); +@@ -1741,7 +1741,7 @@ + nv_wr32(dev, 0x419a1c, 0x00000000); + nv_wr32(dev, 0x419a20, 0x00000800); + if (dev_priv->chipset != 0xc0) +- nv_wr32(dev, 0x00419ac4, 0x0007f440); // 0xc3 ++ nv_wr32(dev, 0x00419ac4, 0x0007f440); /* 0xc3 */ + nv_wr32(dev, 0x419b00, 0x0a418820); + nv_wr32(dev, 0x419b04, 0x062080e6); + nv_wr32(dev, 0x419b08, 0x020398a4); +@@ -1797,8 +1797,8 @@ + nvc0_grctx_generate(struct nouveau_channel *chan) + { + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; +- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; +- struct nvc0_graph_chan *grch = chan->pgraph_ctx; ++ struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR); ++ struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR]; + struct drm_device *dev = chan->dev; + int i, gpc, tp, id; + u32 r000260, tmp; +@@ -1912,13 +1912,13 @@ + for (i = 1; i < 7; i++) + data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5); + +- // GPC_BROADCAST ++ /* GPC_BROADCAST */ + nv_wr32(dev, 0x418bb8, (priv->tp_total << 8) | + priv->magic_not_rop_nr); + for (i = 0; i < 6; i++) + nv_wr32(dev, 0x418b08 + (i * 4), data[i]); + +- // GPC_BROADCAST.TP_BROADCAST ++ /* GPC_BROADCAST.TP_BROADCAST */ + nv_wr32(dev, 0x419bd0, (priv->tp_total << 8) | + priv->magic_not_rop_nr | + data2[0]); +@@ -1926,7 +1926,7 @@ + for (i = 0; i < 6; i++) + nv_wr32(dev, 0x419b00 + (i * 4), data[i]); + +- // UNK78xx ++ /* UNK78xx */ + nv_wr32(dev, 0x4078bc, (priv->tp_total << 8) | + priv->magic_not_rop_nr); + for (i = 0; i < 6; i++) +@@ -1944,7 +1944,7 @@ + gpc = -1; + for (i = 0, gpc = -1; i < 32; i++) { + int ltp = i * (priv->tp_total - 1) / 32; +- ++ + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpnr[gpc]);