diff --git a/net-wireless/compat-wireless/Manifest b/net-wireless/compat-wireless/Manifest index 4bc8a9b79..eb237a6ab 100644 --- a/net-wireless/compat-wireless/Manifest +++ b/net-wireless/compat-wireless/Manifest @@ -41,6 +41,7 @@ AUX ubnt-wifi-station-ext2.patch 1006 RMD160 986218c0099e2ea95347391cd09c69ad51f AUX whynot-2.6.31.patch 4272 RMD160 74ec1c66cfb376cf2c83401aa3edcdbfdd019438 SHA1 18f5680625ad68ebba773c8f39a04edf6456e2f2 SHA256 a1839efde553fb6c78b7121f94a3dc5401c146f9ff3e017e61de1b0298f4b371 AUX whynot-2.6.32.patch 666 RMD160 fcca9ac8d2152bebe51643a4250dffed383aae68 SHA1 5d7261437f5c98758f13c6c3f8a5676769b05013 SHA256 07cfc03d0ad5c47bec08d320afa63c79c0e6be9109dcf42b9811aad10bdc9c63 AUX whynot.patch 4106 RMD160 ac38e8dbbe1a59607fe16b36f327a9ba73a001e7 SHA1 2208598c9f9811d368db099c863be2a2af11681e SHA256 956cf3a0a8b8e1f0f0e3df985e351799f325a44e4cddf042d677a9e8109b7c9e +AUX wl1251-inject-2.6.37.patch 47143 RMD160 35cfb086e93ce041fa6d9a698c7e630013ca666c SHA1 526dfe86d2002dd0a2868f5793fc982bd677a340 SHA256 04660a1f7fb241aafeb7fba3a7791cc31fd74efa75fa73616b3abe6b39f89b36 DIST compat-wireless-2.6.32.8.tar.bz2 2007299 RMD160 5afdf36753d78addc3dd9b94e3961506529d4fd5 SHA1 694b453db50cd22798b754d022aca1e5ba45c8f1 SHA256 d48a86e82fb314b96097d437215a8c85fe5072d00586a00ef9950d26ba1e673b DIST compat-wireless-2.6.33.tar.bz2 2266149 RMD160 599ab94e51179627407877b4c3c657175f44642d SHA1 03a148cf01bc92c8a4f2e0b61234f523a3f42d01 SHA256 740c8749808d82495c40a3139fc12e751463a82eb949804dfe96e166f0848200 DIST compat-wireless-2.6.34.tar.bz2 2370805 RMD160 a3e4635ccd100f95509783090458ceb646e97cba SHA1 84d99b0008785d91918a6b29575fc6de86552751 SHA256 4e4af0df6c74461571925bea8f315f86a6dee3f4a74bbafed7950fdf30fdddd4 @@ -57,6 +58,7 @@ EBUILD compat-wireless-2.6.34-r2.ebuild 3918 RMD160 48f91620cf68a993e63d3c9dfe56 EBUILD compat-wireless-2.6.35-r1.ebuild 5471 RMD160 dcc6f3666823faee305165a846cd37065ac9e2cb SHA1 74c3474682925c35629cffaad6a7ec522e31f5c9 SHA256 25c0b5e0db7fe4d1e9942acbe7f0325e1ef8d7e92488f0f554734bca2d0e86e0 EBUILD compat-wireless-2.6.36.ebuild 5332 RMD160 c4a19864f8703fce0b9369fc597f165290c56661 SHA1 efb406e9ab4ea21021f0e09edbfdb2e5d2a08f7e SHA256 52f02128f594db9950425aa03cd90cf9d5ff54d6475b25db696c58cd8c0a75d2 EBUILD compat-wireless-2.6.37-r7.ebuild 5443 RMD160 629fefa357220ebbad14d4f42979072a6ced87cc SHA1 7cd2e349de253e0f62abbe6c11bbfdc1558877e7 SHA256 f08fb77d9972331aae217e050e034e3bfd17d933c5eb22a272d05c7022f70462 +EBUILD compat-wireless-2.6.37-r8.ebuild 5665 RMD160 c4c93e64ff823ded6d960ac3fe13f14110afec70 SHA1 8698fc5a1268acfb62ba8f7d63522d66eccb60f8 SHA256 e772bd9a4c2c39332e0844476a7d9f3452576736f6c072562250644e787350d0 EBUILD compat-wireless-2.6.38.2-r1.ebuild 5641 RMD160 2a7056e079083a3cfd5ce42b8b48b51ccdfd6430 SHA1 ea2b0a1d8ce9298ead5cdca1ec5c0b43140aed32 SHA256 e226115a59b6c8b91585231ca007d8929dc5f3e4ea7e1e4807c81a2e788869a1 EBUILD compat-wireless-2.6.39-r1.ebuild 5452 RMD160 400562e5a513c9686ea30773d689cebcf8c4c4ef SHA1 144b17dd5de5113db1b1c7cc2a5811f9461d086e SHA256 f93936fa1e85242c8380d6c0ae045b8e7d25930490fe5111f33e7736d9e26aea EBUILD compat-wireless-3.0.ebuild 6461 RMD160 51e211bac46f5fedf4bf66d28fa84acf20793537 SHA1 6ff1ad045dd488334e2e84ddae5b4ceb67f2e71f SHA256 ed6bf245e9011e40296dac5f32f52f4166a9f684872509ef634f6aff78ba641e diff --git a/net-wireless/compat-wireless/compat-wireless-2.6.37-r8.ebuild b/net-wireless/compat-wireless/compat-wireless-2.6.37-r8.ebuild new file mode 100644 index 000000000..f0933d65f --- /dev/null +++ b/net-wireless/compat-wireless/compat-wireless-2.6.37-r8.ebuild @@ -0,0 +1,147 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI="2" +inherit linux-mod linux-info versionator eutils flag-o-matic + +##Stable + +MY_P=${P/_rc/-rc} + +MY_PV=v$(get_version_component_range 1-3) +DESCRIPTION="Stable kernel pre-release wifi subsystem backport" +HOMEPAGE="http://wireless.kernel.org/en/users/Download/stable" +CRAZY_VERSIONING="4-sn" +SRC_URI="http://www.orbit-lab.org/kernel/${PN}-2.6-stable/${MY_PV}/${MY_P}-${CRAZY_VERSIONING}.tar.bz2" + +LICENSE="GPL-2" +SLOT="0" +KEYWORDS="x86 amd64 arm" +IUSE="atheros_obey_crda debugfs debug-driver full-debug injection noleds tinyversionoverride n900" + +DEPEND="" +RDEPEND="!arm? ( =sys-kernel/linux-firmware-99999999 )" + +S="${WORKDIR}"/"${MY_P}"-${CRAZY_VERSIONING} +RESTRICT="strip" + +#CONFIG_CHECK="!DYNAMIC_FTRACE" + +pkg_setup() { + linux-mod_pkg_setup + kernel_is -lt 2 6 27 && die "kernel 2.6.27 or higher is required for compat wireless to be installed" + kernel_is -gt $(get_version_component_range 1) $(get_version_component_range 2) $(get_version_component_range 3) && die "The version of compat-wireless you are trying to install contains older modules than your kernel. Failing before downgrading your system." + if kernel_is -eq $(get_version_component_range 1) $(get_version_component_range 2) $(get_version_component_range 3); then + if use tinyversionoverride; then + ewarn "You have the tinyversionoverride use flag set which means you know for a fact that your" + ewarn "kernel is older than the compat-wireless you are installing." + ewarn "Most likely you have no clue what you are doing and should hit control-C now" + ewarn "before you downgrade your system. Ten seconds to think about it." + epause 10 + else + ewarn "Your kernel version is most likely newer than the compat-wireless release you are" + ewarn "trying to install. If you are certain that your kernel is older then you can set" + ewarn "the tinyversionoverride use flag to override this safety check." + epause 5 + die "Your kernel version is too close to the compat-wireless version to risk installation." + fi + fi + linux_chkconfig_module MAC80211 || die "CONFIG_MAC80211 must be built as a _module_ !" + linux_chkconfig_module CFG80211 || die "CONFIG_CFG80211 must be built as a _module_ !" +} + +src_prepare() { + #this patch fixes a trivial typo in the config.mk + epatch "${FILESDIR}"/fix-typos-2.6.36_rc5.patch + + #this patch is needed to forcibly enable new ralink chips because the shipped config.mk doesn't enable them + epatch "${FILESDIR}"/force-enable-new-ralink-pci-2.6.36-rc5.patch + + #this may or may not HELP the channel -1 issue. this is not a fix + # this breaks wl1251 patches + #epatch "${FILESDIR}"/channel-negative-one-maxim.patch + + #add support for ubiquiti toy for Ray + epatch "${FILESDIR}"/ubnt-wifi-station-ext2.patch + + #this patch ignores the regulatory settings of an atheros card and uses what CRDA thinks is right + if use atheros_obey_crda; then + ewarn "You have enabled atheros_obey_crda which doesn't do what you think." + ewarn "This use flag will cause the eeprom of the card to be ignored and force" + ewarn "world roaming on the device until crda provides a valid regdomain." + ewarn "Short version, this is not a way to break the law, this will automatically" + ewarn "make your card less functional unless you set a proper regdomain with iw/crda." + ewarn "Pausing for 10 secs..." + epause 10 + epatch "${FILESDIR}"/ath_ignore_eeprom.patch + fi + + if use injection; then + epatch "${FILESDIR}"/4002_mac80211-2.6.29-fix-tx-ctl-no-ack-retry-count.patch + epatch "${FILESDIR}"/4004_zd1211rw-2.6.28.patch + epatch "${FILESDIR}"/mac80211.compat08082009.wl_frag+ack_v1.patch + epatch "${FILESDIR}"/4013-runtime-enable-disable-of-mac80211-packet-injection.patch +# epatch "${FILESDIR}"/compat-chaos.patch + epatch "${FILESDIR}"/rtl8187-mac80211-injection-speed-2.6.30-rc3.patch +# epatch "${FILESDIR}"/super_secret_patch.diff + epatch "${FILESDIR}"/ipw2200-inject.2.6.36.patch + if use arm; then + epatch "${FILESDIR}"/wl1251-inject-2.6.37.patch + fi + fi + use noleds && epatch "${FILESDIR}"/leds-disable-strict.patch + use debug-driver && epatch "${FILESDIR}"/driver-debug.patch + use debugfs && sed -i '/DEBUGFS/s/^# *//' "${S}"/config.mk + if use full-debug; then + if use debug-driver ; then + sed -i '/CONFIG=/s/^# *//' "${S}"/config.mk + else + ewarn "Enabling full-debug includes debug-driver." + sed -i '/DEBUG=/s/^# *//' "${S}"/config.mk + fi + fi +} + +src_compile() { + export LDFLAGS=$(raw-ldflags) + addpredict "${KERNEL_DIR}" + set_arch_to_kernel + if use n900; then + ./scripts/driver-select wl1251 + fi + emake KLIB_BUILD="${DESTDIR}"/lib/modules/"${KV_FULL}"/build || die "emake failed" +} + +src_install() { + for file in $(find -name \*.ko); do + insinto "/lib/modules/${KV_FULL}/updates/$(dirname ${file})" + doins "${file}" || die "failed to install module ${file}" + done + dosbin scripts/athenable scripts/b43load scripts/iwl-enable \ + scripts/madwifi-unload scripts/athload scripts/iwl-load \ + scripts/b43enable scripts/unload.sh || die "script installation failed" + + dodir /usr/lib/compat-wireless + exeinto /usr/lib/compat-wireless + doexe scripts/modlib.sh || die + + dodoc README || die + dodir /$(get_libdir)/udev/rules.d/ + insinto /$(get_libdir)/udev/rules.d/ + doins udev/50-compat_firmware.rules + exeinto /$(get_libdir)/udev/ + doexe udev/compat_firmware.sh +} + +pkg_postinst() { + update_depmod + update_moduledb + einfo 'You may have problem if you do not run "depmod -ae" after this installation' + einfo 'To switch to the new drivers without reboot run unload.sh then load + your needed driver.' +} + +pkg_postrm() { + remove_moduledb +} diff --git a/net-wireless/compat-wireless/files/wl1251-inject-2.6.37.patch b/net-wireless/compat-wireless/files/wl1251-inject-2.6.37.patch new file mode 100644 index 000000000..14c320472 --- /dev/null +++ b/net-wireless/compat-wireless/files/wl1251-inject-2.6.37.patch @@ -0,0 +1,1685 @@ +diff -Naur compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/acx.c compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/acx.c +--- compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/acx.c 2011-01-13 02:06:39.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/acx.c 2011-08-23 17:07:28.000000000 +0200 +@@ -211,7 +211,7 @@ + return ret; + } + +-int wl1251_acx_feature_cfg(struct wl1251 *wl) ++int wl1251_acx_feature_cfg(struct wl1251 *wl, u32 data_flow_options) + { + struct acx_feature_config *feature; + int ret; +@@ -224,8 +224,8 @@ + goto out; + } + +- /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ +- feature->data_flow_options = 0; ++ /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE can be set */ ++ feature->data_flow_options = data_flow_options; + feature->options = 0; + + ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, +@@ -410,7 +410,8 @@ + return ret; + } + +-int wl1251_acx_group_address_tbl(struct wl1251 *wl) ++int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable, ++ void *mc_list, u32 mc_list_len) + { + struct acx_dot11_grp_addr_tbl *acx; + int ret; +@@ -424,9 +425,9 @@ + } + + /* MAC filtering */ +- acx->enabled = 0; +- acx->num_groups = 0; +- memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); ++ acx->enabled = enable; ++ acx->num_groups = mc_list_len; ++ memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); + + ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, + acx, sizeof(*acx)); +@@ -583,7 +584,7 @@ + return ret; + } + +-int wl1251_acx_sg_enable(struct wl1251 *wl) ++int wl1251_acx_sg_enable(struct wl1251 *wl, u8 mode) + { + struct acx_bt_wlan_coex *pta; + int ret; +@@ -596,7 +597,7 @@ + goto out; + } + +- pta->enable = SG_ENABLE; ++ pta->enable = mode; + + ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); + if (ret < 0) { +@@ -609,7 +610,7 @@ + return ret; + } + +-int wl1251_acx_sg_cfg(struct wl1251 *wl) ++int wl1251_acx_sg_cfg(struct wl1251 *wl, u16 wake_up_beacon) + { + struct acx_bt_wlan_coex_param *param; + int ret; +@@ -634,7 +635,7 @@ + param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; + param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; + param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; +- param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; ++ param->wake_up_beacon = wake_up_beacon; + param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; + param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; + param->antenna_type = PTA_ANTENNA_TYPE_DEF; +@@ -663,6 +664,41 @@ + return ret; + } + ++int wl1251_acx_sg_configure(struct wl1251 *wl, bool force) ++{ ++ int ret; ++ ++ if (wl->state == WL1251_STATE_OFF && !force) ++ return 0; ++ ++ switch (wl->bt_coex_mode) { ++ case WL1251_BT_COEX_OFF: ++ ret = wl1251_acx_sg_enable(wl, SG_DISABLE); ++ if (ret) ++ break; ++ ret = wl1251_acx_sg_cfg(wl, 0); ++ break; ++ case WL1251_BT_COEX_ENABLE: ++ ret = wl1251_acx_sg_enable(wl, SG_ENABLE); ++ if (ret) ++ break; ++ ret = wl1251_acx_sg_cfg(wl, PTA_TIME_BEFORE_BEACON_DEF); ++ break; ++ case WL1251_BT_COEX_MONOAUDIO: ++ ret = wl1251_acx_sg_enable(wl, SG_ENABLE); ++ if (ret) ++ break; ++ ret = wl1251_acx_sg_cfg(wl, PTA_TIME_BEFORE_BEACON_MONO_AUDIO); ++ break; ++ default: ++ wl1251_error("Invalid BT co-ex mode!"); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ return ret; ++} ++ + int wl1251_acx_cca_threshold(struct wl1251 *wl) + { + struct acx_energy_detection *detection; +@@ -776,6 +812,31 @@ + return ret; + } + ++int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight, ++ u8 depth, enum wl1251_acx_low_rssi_type type) ++{ ++ struct acx_low_rssi *rssi; ++ int ret; ++ ++ wl1251_debug(DEBUG_ACX, "acx low rssi"); ++ ++ rssi = kzalloc(sizeof(*rssi), GFP_KERNEL); ++ if (!rssi) ++ return -ENOMEM; ++ ++ rssi->threshold = threshold; ++ rssi->weight = weight; ++ rssi->depth = depth; ++ rssi->type = type; ++ ++ ret = wl1251_cmd_configure(wl, ACX_LOW_RSSI, rssi, sizeof(*rssi)); ++ if (ret < 0) ++ wl1251_warning("failed to set low rssi threshold: %d", ret); ++ ++ kfree(rssi); ++ return ret; ++} ++ + int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) + { + struct acx_preamble *acx; +@@ -886,12 +947,18 @@ + } + + /* configure one default (one-size-fits-all) rate class */ +- acx->rate_class_cnt = 1; ++ acx->rate_class_cnt = 2; + acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; + acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; + acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; + acx->rate_class[0].aflags = 0; + ++ /* no-retry rate class */ ++ acx->rate_class[1].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; ++ acx->rate_class[1].short_retry_limit = 0; ++ acx->rate_class[1].long_retry_limit = 0; ++ acx->rate_class[1].aflags = 0; ++ + ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("Setting of rate policies failed: %d", ret); +@@ -973,6 +1040,65 @@ + goto out; + } + ++out: ++ kfree(acx); ++ return ret; ++} ++ ++int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode, ++ u8 max_consecutive) ++{ ++ struct wl1251_acx_bet_enable *acx; ++ int ret; ++ ++ wl1251_debug(DEBUG_ACX, "acx bet enable"); ++ ++ acx = kzalloc(sizeof(*acx), GFP_KERNEL); ++ if (!acx) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ acx->enable = mode; ++ acx->max_consecutive = max_consecutive; ++ ++ ret = wl1251_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); ++ if (ret < 0) { ++ wl1251_warning("wl1251 acx bet enable failed: %d", ret); ++ goto out; ++ } ++ ++out: ++ kfree(acx); ++ return ret; ++} ++ ++int wl1251_acx_arp_ip_filter(struct wl1251 *wl, bool enable, __be32 address) ++{ ++ struct wl1251_acx_arp_filter *acx; ++ int ret; ++ ++ wl1251_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable); ++ ++ acx = kzalloc(sizeof(*acx), GFP_KERNEL); ++ if (!acx) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ acx->version = ACX_IPV4_VERSION; ++ acx->enable = enable; ++ ++ if (enable == true) ++ memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); ++ ++ ret = wl1251_cmd_configure(wl, ACX_ARP_IP_FILTER, ++ acx, sizeof(*acx)); ++ if (ret < 0) { ++ wl1251_warning("failed to set arp ip filter: %d", ret); ++ goto out; ++ } ++ + out: + kfree(acx); + return ret; +diff -Naur compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/acx.h compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/acx.h +--- compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/acx.h 2011-01-13 02:06:39.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/acx.h 2011-08-23 17:07:20.000000000 +0200 +@@ -350,8 +350,8 @@ + } __packed; + + +-#define ADDRESS_GROUP_MAX (8) +-#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) ++#define ACX_MC_ADDRESS_GROUP_MAX (8) ++#define ACX_MC_ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX) + + struct acx_dot11_grp_addr_tbl { + struct acx_header header; +@@ -359,7 +359,7 @@ + u8 enabled; + u8 num_groups; + u8 pad[2]; +- u8 mac_table[ADDRESS_GROUP_MAX_LEN]; ++ u8 mac_table[ACX_MC_ADDRESS_GROUP_MAX_LEN]; + } __packed; + + +@@ -399,6 +399,49 @@ + u8 pad[2]; + } __packed; + ++enum wl1251_acx_low_rssi_type { ++ /* ++ * The event is a "Level" indication which keeps triggering ++ * as long as the average RSSI is below the threshold. ++ */ ++ WL1251_ACX_LOW_RSSI_TYPE_LEVEL = 0, ++ ++ /* ++ * The event is an "Edge" indication which triggers ++ * only when the RSSI threshold is crossed from above. ++ */ ++ WL1251_ACX_LOW_RSSI_TYPE_EDGE = 1, ++}; ++ ++struct acx_low_rssi { ++ struct acx_header header; ++ ++ /* ++ * The threshold (in dBm) below (or above after low rssi ++ * indication) which the firmware generates an interrupt to the ++ * host. This parameter is signed. ++ */ ++ s8 threshold; ++ ++ /* ++ * The weight of the current RSSI sample, before adding the new ++ * sample, that is used to calculate the average RSSI. ++ */ ++ u8 weight; ++ ++ /* ++ * The number of Beacons/Probe response frames that will be ++ * received before issuing the Low or Regained RSSI event. ++ */ ++ u8 depth; ++ ++ /* ++ * Configures how the Low RSSI Event is triggered. Refer to ++ * enum wl1251_acx_low_rssi_type for more. ++ */ ++ u8 type; ++} __packed; ++ + struct acx_beacon_filter_option { + struct acx_header header; + +@@ -515,7 +558,8 @@ + #define PTA_ANTI_STARVE_PERIOD_DEF (500) + #define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) + #define PTA_ALLOW_PA_SD_DEF (1) +-#define PTA_TIME_BEFORE_BEACON_DEF (6300) ++#define PTA_TIME_BEFORE_BEACON_DEF (500) ++#define PTA_TIME_BEFORE_BEACON_MONO_AUDIO (6300) + #define PTA_HPDM_MAX_TIME_DEF (1600) + #define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) + #define PTA_AUTO_MODE_NO_CTS_DEF (0) +@@ -1164,6 +1208,45 @@ + u8 padding; + } __packed; + ++enum wl1251_acx_bet_mode { ++ WL1251_ACX_BET_DISABLE = 0, ++ WL1251_ACX_BET_ENABLE = 1, ++}; ++ ++struct wl1251_acx_bet_enable { ++ struct acx_header header; ++ ++ /* ++ * Specifies if beacon early termination procedure is enabled or ++ * disabled, see enum wl1251_acx_bet_mode. ++ */ ++ u8 enable; ++ ++ /* ++ * Specifies the maximum number of consecutive beacons that may be ++ * early terminated. After this number is reached at least one full ++ * beacon must be correctly received in FW before beacon ET ++ * resumes. Range 0 - 255. ++ */ ++ u8 max_consecutive; ++ ++ u8 padding[2]; ++} __attribute__ ((packed)); ++ ++#define ACX_IPV4_VERSION 4 ++#define ACX_IPV6_VERSION 6 ++#define ACX_IPV4_ADDR_SIZE 4 ++struct wl1251_acx_arp_filter { ++ struct acx_header header; ++ u8 version; /* The IP version: 4 - IPv4, 6 - IPv6.*/ ++ u8 enable; /* 1 - ARP filtering is enabled, 0 - disabled */ ++ u8 padding[2]; ++ u8 address[16]; /* The IP address used to filter ARP packets. ++ ARP packets that do not match this address are ++ dropped. When the IP Version is 4, the last 12 ++ bytes of the the address are ignored. */ ++} __attribute__((packed)); ++ + struct wl1251_acx_ac_cfg { + struct acx_header header; + +@@ -1372,7 +1455,7 @@ + int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth); + int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len); + int wl1251_acx_tx_power(struct wl1251 *wl, int power); +-int wl1251_acx_feature_cfg(struct wl1251 *wl); ++int wl1251_acx_feature_cfg(struct wl1251 *wl, u32 data_flow_options); + int wl1251_acx_mem_map(struct wl1251 *wl, + struct acx_header *mem_map, size_t len); + int wl1251_acx_data_path_params(struct wl1251 *wl, +@@ -1381,18 +1464,22 @@ + int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter); + int wl1251_acx_pd_threshold(struct wl1251 *wl); + int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); +-int wl1251_acx_group_address_tbl(struct wl1251 *wl); ++int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable, ++ void *mc_list, u32 mc_list_len); + int wl1251_acx_service_period_timeout(struct wl1251 *wl); + int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); + int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter); + int wl1251_acx_beacon_filter_table(struct wl1251 *wl); + int wl1251_acx_conn_monit_params(struct wl1251 *wl); +-int wl1251_acx_sg_enable(struct wl1251 *wl); +-int wl1251_acx_sg_cfg(struct wl1251 *wl); ++int wl1251_acx_sg_enable(struct wl1251 *wl, u8 mode); ++int wl1251_acx_sg_cfg(struct wl1251 *wl, u16 wake_up_beacon); ++int wl1251_acx_sg_configure(struct wl1251 *wl, bool force); + int wl1251_acx_cca_threshold(struct wl1251 *wl); + int wl1251_acx_bcn_dtim_options(struct wl1251 *wl); + int wl1251_acx_aid(struct wl1251 *wl, u16 aid); + int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask); ++int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight, ++ u8 depth, enum wl1251_acx_low_rssi_type type); + int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble); + int wl1251_acx_cts_protect(struct wl1251 *wl, + enum acx_ctsprotect_type ctsprotect); +@@ -1401,6 +1488,9 @@ + int wl1251_acx_rate_policies(struct wl1251 *wl); + int wl1251_acx_mem_cfg(struct wl1251 *wl); + int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); ++int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode, ++ u8 max_consecutive); ++int wl1251_acx_arp_ip_filter(struct wl1251 *wl, bool enable, __be32 address); + int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, + u8 aifs, u16 txop); + int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, +diff -Naur compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/cmd.c compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/cmd.c +--- compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/cmd.c 2011-01-13 02:06:39.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/cmd.c 2011-08-23 17:30:45.000000000 +0200 +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + + #include "wl1251.h" + #include "reg.h" +@@ -203,11 +204,11 @@ + return ret; + } + +-int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable) ++int wl1251_cmd_data_path_rx(struct wl1251 *wl, u8 channel, bool enable) + { + struct cmd_enabledisable_path *cmd; + int ret; +- u16 cmd_rx, cmd_tx; ++ u16 cmd_rx; + + wl1251_debug(DEBUG_CMD, "cmd data path"); + +@@ -219,13 +220,10 @@ + + cmd->channel = channel; + +- if (enable) { ++ if (enable) + cmd_rx = CMD_ENABLE_RX; +- cmd_tx = CMD_ENABLE_TX; +- } else { ++ else + cmd_rx = CMD_DISABLE_RX; +- cmd_tx = CMD_DISABLE_TX; +- } + + ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); + if (ret < 0) { +@@ -237,6 +235,32 @@ + wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d", + enable ? "start" : "stop", channel); + ++out: ++ kfree(cmd); ++ return ret; ++} ++ ++int wl1251_cmd_data_path_tx(struct wl1251 *wl, u8 channel, bool enable) ++{ ++ struct cmd_enabledisable_path *cmd; ++ int ret; ++ u16 cmd_tx; ++ ++ wl1251_debug(DEBUG_CMD, "cmd data path"); ++ ++ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); ++ if (!cmd) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ cmd->channel = channel; ++ ++ if (enable) ++ cmd_tx = CMD_ENABLE_TX; ++ else ++ cmd_tx = CMD_DISABLE_TX; ++ + ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1251_error("tx %s cmd for channel %d failed", +@@ -277,15 +301,6 @@ + join->rx_config_options = wl->rx_config; + join->rx_filter_options = wl->rx_filter; + +- /* +- * FIXME: disable temporarily all filters because after commit +- * 9cef8737 "mac80211: fix managed mode BSSID handling" broke +- * association. The filter logic needs to be implemented properly +- * and once that is done, this hack can be removed. +- */ +- join->rx_config_options = 0; +- join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; +- + join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | + RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; + +@@ -419,7 +434,10 @@ + struct wl1251_cmd_scan *cmd; + int i, ret = 0; + +- wl1251_debug(DEBUG_CMD, "cmd scan"); ++ wl1251_debug(DEBUG_CMD, "cmd scan channels %d ssid(%d) '%s'", ++ n_channels, ssid_len, ssid); ++ ++ WARN_ON(n_channels > SCAN_MAX_NUM_OF_CHANNELS); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) +@@ -430,6 +448,11 @@ + CFG_RX_MGMT_EN | + CFG_RX_BCN_EN); + cmd->params.scan_options = 0; ++ /* Use high priority scan when not associated to prevent fw issue ++ * causing never-ending scans (sometimes 20+ minutes). ++ * Note: This bug may be caused by the fw's DTIM handling. */ ++ if (is_zero_ether_addr(wl->bssid)) ++ cmd->params.scan_options |= WL1251_SCAN_OPT_PRIORITY_HIGH; + cmd->params.num_channels = n_channels; + cmd->params.num_probe_requests = n_probes; + cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ +diff -Naur compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/cmd.h compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/cmd.h +--- compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/cmd.h 2011-01-13 02:06:39.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/cmd.h 2011-08-23 17:07:12.000000000 +0200 +@@ -35,7 +35,8 @@ + int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); + int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, + void *bitmap, u16 bitmap_len, u8 bitmap_control); +-int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); ++int wl1251_cmd_data_path_rx(struct wl1251 *wl, u8 channel, bool enable); ++int wl1251_cmd_data_path_tx(struct wl1251 *wl, u8 channel, bool enable); + int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, + u16 beacon_interval, u8 dtim_interval); + int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); +@@ -167,6 +168,11 @@ + #define CMDMBOX_HEADER_LEN 4 + #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 + ++#define WL1251_SCAN_OPT_PASSIVE 1 ++#define WL1251_SCAN_OPT_5GHZ_BAND 2 ++#define WL1251_SCAN_OPT_TRIGGERD_SCAN 4 ++#define WL1251_SCAN_OPT_PRIORITY_HIGH 8 ++ + #define WL1251_SCAN_MIN_DURATION 30000 + #define WL1251_SCAN_MAX_DURATION 60000 + +diff -Naur compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/event.c compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/event.c +--- compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/event.c 2011-01-13 02:06:39.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/event.c 2011-08-23 17:07:05.000000000 +0200 +@@ -42,6 +42,43 @@ + return 0; + } + ++#define WL1251_PSM_ENTRY_RETRIES 3 ++static int wl1251_event_ps_report(struct wl1251 *wl, ++ struct event_mailbox *mbox) ++{ ++ int ret = 0; ++ ++ wl1251_debug(DEBUG_EVENT, "ps status: %x", mbox->ps_status); ++ ++ switch (mbox->ps_status) { ++ case EVENT_ENTER_POWER_SAVE_FAIL: ++ wl1251_debug(DEBUG_PSM, "PSM entry failed"); ++ ++ if (!wl->psm) { ++ /* remain in active mode */ ++ wl->psm_entry_retry = 0; ++ break; ++ } ++ ++ if (wl->psm_entry_retry < WL1251_PSM_ENTRY_RETRIES) { ++ wl->psm_entry_retry++; ++ ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); ++ } else { ++ wl1251_error("Power save entry failed, giving up"); ++ wl->psm_entry_retry = 0; ++ } ++ break; ++ case EVENT_ENTER_POWER_SAVE_SUCCESS: ++ case EVENT_EXIT_POWER_SAVE_FAIL: ++ case EVENT_EXIT_POWER_SAVE_SUCCESS: ++ default: ++ wl->psm_entry_retry = 0; ++ break; ++ } ++ ++ return 0; ++} ++ + static void wl1251_event_mbox_dump(struct event_mailbox *mbox) + { + wl1251_debug(DEBUG_EVENT, "MBOX DUMP:"); +@@ -75,6 +112,13 @@ + } + } + ++ if (vector & PS_REPORT_EVENT_ID) { ++ wl1251_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); ++ ret = wl1251_event_ps_report(wl, mbox); ++ if (ret < 0) ++ return ret; ++ } ++ + if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) { + wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); + +@@ -90,6 +134,24 @@ + } + } + ++ if (wl->vif && wl->rssi_thold) { ++ if (vector & ROAMING_TRIGGER_LOW_RSSI_EVENT_ID) { ++ wl1251_debug(DEBUG_EVENT, ++ "ROAMING_TRIGGER_LOW_RSSI_EVENT"); ++ ieee80211_cqm_rssi_notify(wl->vif, ++ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, ++ GFP_KERNEL); ++ } ++ ++ if (vector & ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID) { ++ wl1251_debug(DEBUG_EVENT, ++ "ROAMING_TRIGGER_REGAINED_RSSI_EVENT"); ++ ieee80211_cqm_rssi_notify(wl->vif, ++ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, ++ GFP_KERNEL); ++ } ++ } ++ + return 0; + } + +diff -Naur compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/event.h compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/event.h +--- compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/event.h 2011-01-13 02:06:39.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/event.h 2011-08-23 17:07:01.000000000 +0200 +@@ -112,6 +112,13 @@ + u8 padding[19]; + } __packed; + ++enum { ++ EVENT_ENTER_POWER_SAVE_FAIL = 0, ++ EVENT_ENTER_POWER_SAVE_SUCCESS, ++ EVENT_EXIT_POWER_SAVE_FAIL, ++ EVENT_EXIT_POWER_SAVE_SUCCESS, ++}; ++ + int wl1251_event_unmask(struct wl1251 *wl); + void wl1251_event_mbox_config(struct wl1251 *wl); + int wl1251_event_handle(struct wl1251 *wl, u8 mbox); +diff -Naur compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/init.c compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/init.c +--- compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/init.c 2011-01-13 02:06:39.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/init.c 2011-08-23 17:07:20.000000000 +0200 +@@ -33,7 +33,7 @@ + { + int ret; + +- ret = wl1251_acx_feature_cfg(wl); ++ ret = wl1251_acx_feature_cfg(wl, 0); + if (ret < 0) { + wl1251_warning("couldn't set feature config"); + return ret; +@@ -127,7 +127,7 @@ + if (ret < 0) + return ret; + +- ret = wl1251_acx_group_address_tbl(wl); ++ ret = wl1251_acx_group_address_tbl(wl, true, NULL, 0); + if (ret < 0) + return ret; + +@@ -162,11 +162,7 @@ + { + int ret; + +- ret = wl1251_acx_sg_enable(wl); +- if (ret < 0) +- return ret; +- +- ret = wl1251_acx_sg_cfg(wl); ++ ret = wl1251_acx_sg_configure(wl, true); + if (ret < 0) + return ret; + +@@ -394,8 +390,13 @@ + if (ret < 0) + goto out_free_data_path; + +- /* Enable data path */ +- ret = wl1251_cmd_data_path(wl, wl->channel, 1); ++ /* Enable rx data path */ ++ ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1); ++ if (ret < 0) ++ goto out_free_data_path; ++ ++ /* Enable tx data path */ ++ ret = wl1251_cmd_data_path_tx(wl, wl->channel, 1); + if (ret < 0) + goto out_free_data_path; + +diff -Naur compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/main.c compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/main.c +--- compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/main.c 2011-01-13 02:06:41.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/main.c 2011-08-23 17:07:29.000000000 +0200 +@@ -30,7 +30,9 @@ + #include + #include + #include ++#include + #include ++#include + + #include "wl1251.h" + #include "wl12xx_80211.h" +@@ -348,33 +350,6 @@ + return ret; + } + +-static void wl1251_filter_work(struct work_struct *work) +-{ +- struct wl1251 *wl = +- container_of(work, struct wl1251, filter_work); +- int ret; +- +- mutex_lock(&wl->mutex); +- +- if (wl->state == WL1251_STATE_OFF) +- goto out; +- +- ret = wl1251_ps_elp_wakeup(wl); +- if (ret < 0) +- goto out; +- +- ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, +- wl->dtim_period); +- if (ret < 0) +- goto out_sleep; +- +-out_sleep: +- wl1251_ps_elp_sleep(wl); +- +-out: +- mutex_unlock(&wl->mutex); +-} +- + static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) + { + struct wl1251 *wl = hw->priv; +@@ -480,7 +455,6 @@ + + cancel_work_sync(&wl->irq_work); + cancel_work_sync(&wl->tx_work); +- cancel_work_sync(&wl->filter_work); + + mutex_lock(&wl->mutex); + +@@ -500,9 +474,13 @@ + wl->next_tx_complete = 0; + wl->elp = false; + wl->psm = 0; ++ wl->psm_entry_retry = 0; + wl->tx_queue_stopped = false; + wl->power_level = WL1251_DEFAULT_POWER_LEVEL; ++ wl->rssi_thold = 0; + wl->channel = WL1251_DEFAULT_CHANNEL; ++ wl->monitor_present = false; ++ wl->joined = false; + + wl1251_debugfs_reset(wl); + +@@ -559,6 +537,7 @@ + mutex_lock(&wl->mutex); + wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface"); + wl->vif = NULL; ++ memset(wl->bssid, 0, ETH_ALEN); + mutex_unlock(&wl->mutex); + } + +@@ -591,8 +570,10 @@ + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + +- wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", ++ wl1251_debug(DEBUG_MAC80211, ++ "mac80211 config ch %d monitor %s psm %s power %d", + channel, ++ conf->flags & IEEE80211_CONF_MONITOR ? "on" : "off", + conf->flags & IEEE80211_CONF_PS ? "on" : "off", + conf->power_level); + +@@ -602,16 +583,55 @@ + if (ret < 0) + goto out; + ++ if (changed & IEEE80211_CONF_CHANGE_MONITOR) { ++ u32 mode; ++ ++ if (conf->flags & IEEE80211_CONF_MONITOR) { ++ wl->monitor_present = true; ++ mode = DF_SNIFF_MODE_ENABLE | DF_ENCRYPTION_DISABLE; ++ } else { ++ wl->monitor_present = false; ++ mode = 0; ++ } ++ ++ ret = wl1251_acx_feature_cfg(wl, mode); ++ if (ret < 0) ++ goto out_sleep; ++ ++ if (wl->monitor_present) ++ wl->rx_config |= CFG_RX_ALL_GOOD; ++ else ++ wl->rx_config &= ~CFG_RX_ALL_GOOD; ++ ++ /* update filters immediately */ ++ ret = wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter); ++ if (ret < 0) ++ goto out_sleep; ++ } ++ + if (channel != wl->channel) { + wl->channel = channel; + +- ret = wl1251_join(wl, wl->bss_type, wl->channel, +- wl->beacon_int, wl->dtim_period); ++ /* ++ * Use ENABLE_RX command for channel switching when no ++ * interface is present (monitor mode only). ++ * This leaves the tx path disabled in firmware, whereas ++ * the usual JOIN command seems to transmit some frames ++ * at firmware level. ++ */ ++ if (wl->vif == NULL) { ++ wl->joined = false; ++ ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1); ++ } else { ++ ret = wl1251_join(wl, wl->bss_type, wl->channel, ++ wl->beacon_int, wl->dtim_period); ++ } + if (ret < 0) + goto out_sleep; + } + +- if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { ++ if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested && ++ !wl->monitor_present) { + wl1251_debug(DEBUG_PSM, "psm enabled"); + + wl->psm_requested = true; +@@ -627,8 +647,8 @@ + ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + goto out_sleep; +- } else if (!(conf->flags & IEEE80211_CONF_PS) && +- wl->psm_requested) { ++ } else if ((!(conf->flags & IEEE80211_CONF_PS) || wl->monitor_present) ++ && wl->psm_requested) { + wl1251_debug(DEBUG_PSM, "psm disabled"); + + wl->psm_requested = false; +@@ -648,6 +668,16 @@ + wl->power_level = conf->power_level; + } + ++ /* ++ * Tell stack that connection is lost because hw encryption isn't ++ * supported in monitor mode. ++ * XXX This requires temporary enabling the hw connection monitor flag ++ */ ++ if ((changed & IEEE80211_CONF_CHANGE_MONITOR) && wl->vif) { ++ wl->hw->flags |= IEEE80211_HW_CONNECTION_MONITOR; ++ ieee80211_connection_loss(wl->vif); ++ } ++ + out_sleep: + wl1251_ps_elp_sleep(wl); + +@@ -657,6 +687,44 @@ + return ret; + } + ++struct wl1251_filter_params { ++ bool enabled; ++ int mc_list_length; ++ u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; ++}; ++ ++static u64 wl1251_op_prepare_multicast(struct ieee80211_hw *hw, ++ struct netdev_hw_addr_list *mc_list) ++{ ++ struct wl1251_filter_params *fp; ++ struct netdev_hw_addr *ha; ++ struct wl1251 *wl = hw->priv; ++ ++ if (unlikely(wl->state == WL1251_STATE_OFF)) ++ return 0; ++ ++ fp = kzalloc(sizeof(*fp), GFP_ATOMIC); ++ if (!fp) { ++ wl1251_error("Out of memory setting filters."); ++ return 0; ++ } ++ ++ /* update multicast filtering parameters */ ++ fp->mc_list_length = 0; ++ if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) { ++ fp->enabled = false; ++ } else { ++ fp->enabled = true; ++ netdev_hw_addr_list_for_each(ha, mc_list) { ++ memcpy(fp->mc_list[fp->mc_list_length], ++ ha->addr, ETH_ALEN); ++ fp->mc_list_length++; ++ } ++ } ++ ++ return (u64)(unsigned long)fp; ++} ++ + #define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ +@@ -666,27 +734,47 @@ + + static void wl1251_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, +- unsigned int *total,u64 multicast) ++ unsigned int *total, u64 multicast) + { ++ struct wl1251_filter_params *fp = (void *)(unsigned long)multicast; + struct wl1251 *wl = hw->priv; ++ int ret; + + wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter"); + + *total &= WL1251_SUPPORTED_FILTERS; + changed &= WL1251_SUPPORTED_FILTERS; + ++ mutex_lock(&wl->mutex); ++ ++ if (unlikely(wl->state == WL1251_STATE_OFF)) ++ goto out; ++ ++ ret = wl1251_ps_elp_wakeup(wl); ++ if (ret < 0) ++ goto out; ++ ++ if (*total & FIF_ALLMULTI || *total & FIF_PROMISC_IN_BSS) ++ ret = wl1251_acx_group_address_tbl(wl, false, NULL, 0); ++ else if (fp) ++ ret = wl1251_acx_group_address_tbl(wl, fp->enabled, ++ fp->mc_list, ++ fp->mc_list_length); ++ if (ret < 0) ++ goto out_sleep; ++ + if (changed == 0) + /* no filters which we support changed */ +- return; +- +- /* FIXME: wl->rx_config and wl->rx_filter are not protected */ ++ goto out_sleep; + + wl->rx_config = WL1251_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1251_DEFAULT_RX_FILTER; + +- if (*total & FIF_PROMISC_IN_BSS) { ++ if (!is_zero_ether_addr(wl->bssid)) + wl->rx_config |= CFG_BSSID_FILTER_EN; +- wl->rx_config |= CFG_RX_ALL_GOOD; ++ if (*total & FIF_PROMISC_IN_BSS) { ++ wl->rx_config &= ~CFG_UNI_FILTER_EN; ++ wl->rx_config &= ~CFG_MC_FILTER_EN; + } + if (*total & FIF_ALLMULTI) + /* +@@ -702,15 +790,28 @@ + } + if (*total & FIF_CONTROL) + wl->rx_filter |= CFG_RX_CTL_EN; +- if (*total & FIF_OTHER_BSS) +- wl->rx_filter &= ~CFG_BSSID_FILTER_EN; ++ if (*total & FIF_OTHER_BSS) { ++ wl->rx_config &= ~CFG_BSSID_FILTER_EN; ++ wl->rx_config &= ~CFG_SSID_FILTER_EN; ++ } ++ if (wl->monitor_present) ++ wl->rx_config |= CFG_RX_ALL_GOOD; + +- /* +- * FIXME: workqueues need to be properly cancelled on stop(), for +- * now let's just disable changing the filter settings. They will +- * be updated any on config(). +- */ +- /* schedule_work(&wl->filter_work); */ ++ wl1251_debug(DEBUG_MAC80211, "mac80211 filter total 0x%02x" ++ " changed 0x%02x rx_config 0x%02x rx_filter 0x%02x", ++ *total, changed, wl->rx_config, wl->rx_filter); ++ ++ /* apply configured filters */ ++ ret = wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter); ++ if (ret < 0) ++ goto out_sleep; ++ ++out_sleep: ++ wl1251_ps_elp_sleep(wl); ++ ++out: ++ mutex_unlock(&wl->mutex); ++ kfree(fp); + } + + /* HW encryption */ +@@ -790,12 +891,12 @@ + + mutex_lock(&wl->mutex); + +- ret = wl1251_ps_elp_wakeup(wl); +- if (ret < 0) +- goto out_unlock; +- + switch (cmd) { + case SET_KEY: ++ if (wl->monitor_present) { ++ ret = -EOPNOTSUPP; ++ goto out_unlock; ++ } + wl_cmd->key_action = KEY_ADD_OR_REPLACE; + break; + case DISABLE_KEY: +@@ -806,6 +907,10 @@ + break; + } + ++ ret = wl1251_ps_elp_wakeup(wl); ++ if (ret < 0) ++ goto out_unlock; ++ + ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr); + if (ret < 0) { + wl1251_error("Set KEY type failed"); +@@ -906,6 +1011,7 @@ + ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels, + req->n_channels, WL1251_SCAN_NUM_PROBES); + if (ret < 0) { ++ wl1251_debug(DEBUG_SCAN, "scan failed %d", ret); + wl->scanning = false; + goto out_sleep; + } +@@ -959,9 +1065,24 @@ + if (ret < 0) + goto out; + ++ if (changed & BSS_CHANGED_CQM) { ++ ret = wl1251_acx_low_rssi(wl, bss_conf->cqm_rssi_thold, ++ WL1251_DEFAULT_LOW_RSSI_WEIGHT, ++ WL1251_DEFAULT_LOW_RSSI_DEPTH, ++ WL1251_ACX_LOW_RSSI_TYPE_EDGE); ++ if (ret < 0) ++ goto out; ++ wl->rssi_thold = bss_conf->cqm_rssi_thold; ++ } ++ + if (changed & BSS_CHANGED_BSSID) { + memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); + ++ if (is_zero_ether_addr(wl->bssid)) ++ wl->rx_config &= ~CFG_BSSID_FILTER_EN; ++ else ++ wl->rx_config |= CFG_BSSID_FILTER_EN; ++ + skb = ieee80211_nullfunc_get(wl->hw, wl->vif); + if (!skb) + goto out_sleep; +@@ -985,6 +1106,9 @@ + } + + if (changed & BSS_CHANGED_ASSOC) { ++ /* XXX Disable temporary enabled hw connection monitor flag */ ++ wl->hw->flags &= ~IEEE80211_HW_CONNECTION_MONITOR; ++ + if (bss_conf->assoc) { + wl->beacon_int = bss_conf->beacon_int; + +@@ -1037,6 +1161,19 @@ + } + } + ++ if (changed & BSS_CHANGED_ARP_FILTER) { ++ __be32 addr = bss_conf->arp_addr_list[0]; ++ WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); ++ ++ if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled) ++ ret = wl1251_acx_arp_ip_filter(wl, true, addr); ++ else ++ ret = wl1251_acx_arp_ip_filter(wl, false, addr); ++ ++ if (ret < 0) ++ goto out_sleep; ++ } ++ + if (changed & BSS_CHANGED_BEACON) { + beacon = ieee80211_beacon_get(hw, vif); + ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data, +@@ -1203,6 +1340,7 @@ + .add_interface = wl1251_op_add_interface, + .remove_interface = wl1251_op_remove_interface, + .config = wl1251_op_config, ++ .prepare_multicast = wl1251_op_prepare_multicast, + .configure_filter = wl1251_op_configure_filter, + .tx = wl1251_op_tx, + .set_key = wl1251_op_set_key, +@@ -1213,6 +1351,94 @@ + .get_survey = wl1251_op_get_survey, + }; + ++static ssize_t wl1251_sysfs_show_bt_coex_mode(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct wl1251 *wl = dev_get_drvdata(dev); ++ ssize_t len; ++ ++ /* FIXME: what's the maximum length of buf? page size?*/ ++ len = 500; ++ ++ mutex_lock(&wl->mutex); ++ len = snprintf(buf, len, "%d\n\n%d - off\n%d - on\n%d - monoaudio\n", ++ wl->bt_coex_mode, ++ WL1251_BT_COEX_OFF, ++ WL1251_BT_COEX_ENABLE, ++ WL1251_BT_COEX_MONOAUDIO); ++ mutex_unlock(&wl->mutex); ++ ++ return len; ++ ++} ++ ++static ssize_t wl1251_sysfs_store_bt_coex_mode(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct wl1251 *wl = dev_get_drvdata(dev); ++ unsigned long res; ++ int ret; ++ ++ ret = strict_strtoul(buf, 10, &res); ++ ++ if (ret < 0) { ++ wl1251_warning("incorrect value written to bt_coex_mode"); ++ return count; ++ } ++ ++ mutex_lock(&wl->mutex); ++ ++ if (res == wl->bt_coex_mode) ++ goto out; ++ ++ switch (res) { ++ case WL1251_BT_COEX_OFF: ++ case WL1251_BT_COEX_ENABLE: ++ case WL1251_BT_COEX_MONOAUDIO: ++ wl->bt_coex_mode = res; ++ break; ++ default: ++ wl1251_warning("incorrect value written to bt_coex_mode"); ++ goto out; ++ } ++ ++ if (wl->state == WL1251_STATE_OFF) ++ goto out; ++ ++ ret = wl1251_ps_elp_wakeup(wl); ++ if (ret < 0) ++ goto out; ++ ++ wl1251_acx_sg_configure(wl, false); ++ wl1251_ps_elp_sleep(wl); ++ ++out: ++ mutex_unlock(&wl->mutex); ++ return count; ++} ++ ++static DEVICE_ATTR(bt_coex_mode, S_IRUGO | S_IWUSR, ++ wl1251_sysfs_show_bt_coex_mode, ++ wl1251_sysfs_store_bt_coex_mode); ++ ++static void wl1251_device_release(struct device *dev) ++{ ++ ++} ++ ++static struct platform_device wl1251_device = { ++ /* FIXME: use wl12xx name to not break the user space */ ++ .name = "wl12xx", ++ .id = -1, ++ ++ /* device model insists to have a release function */ ++ .dev = { ++ .release = wl1251_device_release, ++ }, ++}; ++ + static int wl1251_read_eeprom_byte(struct wl1251 *wl, off_t offset, u8 *data) + { + unsigned long timeout; +@@ -1310,9 +1536,11 @@ + wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_BEACON_FILTER | +- IEEE80211_HW_SUPPORTS_UAPSD; ++ IEEE80211_HW_SUPPORTS_UAPSD | ++ IEEE80211_HW_SUPPORTS_CQM_RSSI; + +- wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); ++ wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | ++ BIT(NL80211_IFTYPE_ADHOC); + wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; + +@@ -1325,6 +1553,22 @@ + if (ret) + goto out; + ++ /* Register platform device */ ++ ret = platform_device_register(&wl1251_device); ++ if (ret) { ++ wl1251_error("couldn't register platform device"); ++ goto out; ++ } ++ dev_set_drvdata(&wl1251_device.dev, wl); ++ ++ ++ /* Create sysfs file to control bt coex state */ ++ ret = device_create_file(&wl1251_device.dev, &dev_attr_bt_coex_mode); ++ if (ret < 0) { ++ wl1251_error("failed to create sysfs file bt_coex_mode"); ++ goto out; ++ } ++ + wl1251_debugfs_init(wl); + wl1251_notice("initialized"); + +@@ -1357,10 +1601,12 @@ + + skb_queue_head_init(&wl->tx_queue); + +- INIT_WORK(&wl->filter_work, wl1251_filter_work); + INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work); + wl->channel = WL1251_DEFAULT_CHANNEL; ++ wl->monitor_present = false; ++ wl->joined = false; + wl->scanning = false; ++ wl->bss_type = MAX_BSS_TYPE; + wl->default_key = 0; + wl->listen_int = 1; + wl->rx_counter = 0; +@@ -1372,11 +1618,14 @@ + wl->elp = false; + wl->psm = 0; + wl->psm_requested = false; ++ wl->psm_entry_retry = 0; + wl->tx_queue_stopped = false; + wl->power_level = WL1251_DEFAULT_POWER_LEVEL; ++ wl->rssi_thold = 0; + wl->beacon_int = WL1251_DEFAULT_BEACON_INT; + wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; + wl->vif = NULL; ++ wl->bt_coex_mode = WL1251_BT_COEX_OFF; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + wl->tx_frames[i] = NULL; +@@ -1416,6 +1665,8 @@ + + wl1251_debugfs_exit(wl); + ++ platform_device_unregister(&wl1251_device); ++ + kfree(wl->target_mem_map); + kfree(wl->data_path); + vfree(wl->fw); +diff -Naur compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/ps.c compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/ps.c +--- compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/ps.c 2011-01-13 02:06:39.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/ps.c 2011-08-23 17:07:03.000000000 +0200 +@@ -153,6 +153,11 @@ + if (ret < 0) + return ret; + ++ ret = wl1251_acx_bet_enable(wl, WL1251_ACX_BET_ENABLE, ++ WL1251_DEFAULT_BET_CONSECUTIVE); ++ if (ret < 0) ++ return ret; ++ + ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + return ret; +@@ -170,6 +175,12 @@ + if (ret < 0) + return ret; + ++ /* disable BET */ ++ ret = wl1251_acx_bet_enable(wl, WL1251_ACX_BET_DISABLE, ++ WL1251_DEFAULT_BET_CONSECUTIVE); ++ if (ret < 0) ++ return ret; ++ + /* disable beacon filtering */ + ret = wl1251_acx_beacon_filter_opt(wl, false); + if (ret < 0) +diff -Naur compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/rx.c compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/rx.c +--- compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/rx.c 2011-01-13 02:06:39.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/rx.c 2011-08-23 17:07:16.000000000 +0200 +@@ -82,7 +82,7 @@ + + status->flag |= RX_FLAG_TSFT; + +- if (desc->flags & RX_DESC_ENCRYPTION_MASK) { ++ if (!wl->monitor_present && (desc->flags & RX_DESC_ENCRYPTION_MASK)) { + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + + if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) +@@ -95,8 +95,54 @@ + if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + ++ switch (desc->rate) { ++ /* skip 1 and 12 Mbps because they have same value 0x0a */ ++ case RATE_2MBPS: ++ status->rate_idx = 1; ++ break; ++ case RATE_5_5MBPS: ++ status->rate_idx = 2; ++ break; ++ case RATE_11MBPS: ++ status->rate_idx = 3; ++ break; ++ case RATE_6MBPS: ++ status->rate_idx = 4; ++ break; ++ case RATE_9MBPS: ++ status->rate_idx = 5; ++ break; ++ case RATE_18MBPS: ++ status->rate_idx = 7; ++ break; ++ case RATE_24MBPS: ++ status->rate_idx = 8; ++ break; ++ case RATE_36MBPS: ++ status->rate_idx = 9; ++ break; ++ case RATE_48MBPS: ++ status->rate_idx = 10; ++ break; ++ case RATE_54MBPS: ++ status->rate_idx = 11; ++ break; ++ } ++ ++ /* for 1 and 12 Mbps we have to check the modulation */ ++ if (desc->rate == RATE_1MBPS) { ++ if (!(desc->mod_pre & OFDM_RATE_BIT)) { ++ /* CCK -> RATE_1MBPS */ ++ status->rate_idx = 0; ++ } else { ++ /* OFDM -> RATE_12MBPS */ ++ status->rate_idx = 6; ++ } ++ } + +- /* FIXME: set status->rate_idx */ ++ if (desc->mod_pre & SHORT_PREAMBLE_BIT) { ++ status->flag |= RX_FLAG_SHORTPRE; ++ } + } + + static void wl1251_rx_body(struct wl1251 *wl, +diff -Naur compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/tx.c compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/tx.c +--- compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/tx.c 2011-01-13 02:06:39.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/tx.c 2011-08-23 17:07:28.000000000 +0200 +@@ -28,6 +28,7 @@ + #include "tx.h" + #include "ps.h" + #include "io.h" ++#include "event.h" + + static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) + { +@@ -89,8 +90,12 @@ + /* 802.11 packets */ + tx_hdr->control.packet_type = 0; + +- if (control->flags & IEEE80211_TX_CTL_NO_ACK) ++ /* Also disable retry and ACK policy for injected packets */ ++ if ((control->flags & IEEE80211_TX_CTL_NO_ACK) || ++ (control->flags & IEEE80211_TX_CTL_INJECTED)) { ++ tx_hdr->control.rate_policy = 1; + tx_hdr->control.ack_policy = 1; ++ } + + tx_hdr->control.tx_complete = 1; + +@@ -213,16 +218,30 @@ + wl1251_debug(DEBUG_TX, "skb offset %d", offset); + + /* check whether the current skb can be used */ +- if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { +- unsigned char *src = skb->data; ++ if (skb_cloned(skb) || (skb_tailroom(skb) < offset)) { ++ struct sk_buff *newskb = skb_copy_expand(skb, 0, 3, ++ GFP_KERNEL); ++ ++ if (unlikely(newskb == NULL)) { ++ wl1251_error("Can't allocate skb!"); ++ return -EINVAL; ++ } ++ ++ tx_hdr = (struct tx_double_buffer_desc *) newskb->data; ++ ++ dev_kfree_skb_any(skb); ++ wl->tx_frames[tx_hdr->id] = skb = newskb; ++ ++ offset = (4 - (long)skb->data) & 0x03; ++ wl1251_debug(DEBUG_TX, "new skb offset %d", offset); ++ } + +- /* align the buffer on a 4-byte boundary */ ++ /* align the buffer on a 4-byte boundary */ ++ if (offset) { ++ unsigned char *src = skb->data; + skb_reserve(skb, offset); + memmove(skb->data, src, skb->len); + tx_hdr = (struct tx_double_buffer_desc *) skb->data; +- } else { +- wl1251_info("No handler, fixme!"); +- return -EINVAL; + } + } + +@@ -273,6 +292,9 @@ + info = IEEE80211_SKB_CB(skb); + + if (info->control.hw_key) { ++ if (unlikely(wl->monitor_present)) ++ return -1; ++ + idx = info->control.hw_key->hw_key_idx; + if (unlikely(wl->default_key != idx)) { + ret = wl1251_acx_default_key(wl, idx); +@@ -281,6 +303,22 @@ + } + } + ++ /* Enable tx path in monitor mode for packet injection */ ++ if ((wl->vif == NULL) && !wl->joined) { ++ ret = wl1251_cmd_join(wl, BSS_TYPE_STA_BSS, wl->channel, ++ wl->beacon_int, wl->dtim_period); ++ if (ret < 0) ++ wl1251_warning("join failed"); ++ else { ++ ret = wl1251_event_wait(wl, JOIN_EVENT_COMPLETE_ID, ++ 100); ++ if (ret < 0) ++ wl1251_warning("join timeout"); ++ else ++ wl->joined = true; ++ } ++ } ++ + ret = wl1251_tx_path_status(wl); + if (ret < 0) + return ret; +@@ -368,7 +406,7 @@ + { + struct ieee80211_tx_info *info; + struct sk_buff *skb; +- int hdrlen, ret; ++ int hdrlen; + u8 *frame; + + skb = wl->tx_frames[result->id]; +@@ -380,6 +418,7 @@ + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && ++ !(info->flags & IEEE80211_TX_CTL_INJECTED) && + (result->status == TX_SUCCESS)) + info->flags |= IEEE80211_TX_STAT_ACK; + +@@ -407,40 +446,12 @@ + ieee80211_tx_status(wl->hw, skb); + + wl->tx_frames[result->id] = NULL; +- +- if (wl->tx_queue_stopped) { +- wl1251_debug(DEBUG_TX, "cb: queue was stopped"); +- +- skb = skb_dequeue(&wl->tx_queue); +- +- /* The skb can be NULL because tx_work might have been +- scheduled before the queue was stopped making the +- queue empty */ +- +- if (skb) { +- ret = wl1251_tx_frame(wl, skb); +- if (ret == -EBUSY) { +- /* firmware buffer is still full */ +- wl1251_debug(DEBUG_TX, "cb: fw buffer " +- "still full"); +- skb_queue_head(&wl->tx_queue, skb); +- return; +- } else if (ret < 0) { +- dev_kfree_skb(skb); +- return; +- } +- } +- +- wl1251_debug(DEBUG_TX, "cb: waking queues"); +- ieee80211_wake_queues(wl->hw); +- wl->tx_queue_stopped = false; +- } + } + + /* Called upon reception of a TX complete interrupt */ + void wl1251_tx_complete(struct wl1251 *wl) + { +- int i, result_index, num_complete = 0; ++ int i, result_index, num_complete = 0, queue_len; + struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; + unsigned long flags; + +@@ -471,18 +482,22 @@ + } + } + +- if (wl->tx_queue_stopped +- && +- skb_queue_len(&wl->tx_queue) <= WL1251_TX_QUEUE_LOW_WATERMARK){ ++ queue_len = skb_queue_len(&wl->tx_queue); + +- /* firmware buffer has space, restart queues */ ++ if ((num_complete > 0) && (queue_len > 0)) { ++ /* firmware buffer has space, reschedule tx_work */ ++ wl1251_debug(DEBUG_TX, "tx_complete: reschedule tx_work"); ++ ieee80211_queue_work(wl->hw, &wl->tx_work); ++ } ++ ++ if (wl->tx_queue_stopped && ++ queue_len <= WL1251_TX_QUEUE_LOW_WATERMARK) { ++ /* tx_queue has space, restart queues */ + wl1251_debug(DEBUG_TX, "tx_complete: waking queues"); + spin_lock_irqsave(&wl->wl_lock, flags); + ieee80211_wake_queues(wl->hw); + wl->tx_queue_stopped = false; + spin_unlock_irqrestore(&wl->wl_lock, flags); +- ieee80211_queue_work(wl->hw, &wl->tx_work); +- + } + + /* Every completed frame needs to be acknowledged */ +diff -Naur compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/wl1251.h compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/wl1251.h +--- compat-wireless-2.6.37-4-sn.orig//drivers/net/wireless/wl1251/wl1251.h 2011-01-13 02:06:39.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/drivers/net/wireless/wl1251/wl1251.h 2011-08-23 17:07:26.000000000 +0200 +@@ -92,13 +92,12 @@ + true); \ + } while (0) + +-#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ +- CFG_BSSID_FILTER_EN) ++#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ ++ CFG_MC_FILTER_EN) + + #define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ + CFG_RX_MGMT_EN | \ + CFG_RX_DATA_EN | \ +- CFG_RX_CTL_EN | \ + CFG_RX_BCN_EN | \ + CFG_RX_AUTH_EN | \ + CFG_RX_ASSOC_EN) +@@ -251,6 +250,12 @@ + struct dentry *excessive_retries; + }; + ++enum wl1251_bt_coex_mode { ++ WL1251_BT_COEX_OFF, ++ WL1251_BT_COEX_ENABLE, ++ WL1251_BT_COEX_MONOAUDIO ++}; ++ + struct wl1251_if_operations { + void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); + void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); +@@ -296,6 +301,8 @@ + u8 bss_type; + u8 listen_int; + int channel; ++ bool monitor_present; ++ bool joined; + + void *target_mem_map; + struct acx_data_path_params_resp *data_path; +@@ -308,7 +315,6 @@ + bool tx_queue_stopped; + + struct work_struct tx_work; +- struct work_struct filter_work; + + /* Pending TX frames */ + struct sk_buff *tx_frames[16]; +@@ -363,12 +369,17 @@ + /* PSM mode requested */ + bool psm_requested; + ++ /* retry counter for PSM entries */ ++ u8 psm_entry_retry; ++ + u16 beacon_int; + u8 dtim_period; + + /* in dBm */ + int power_level; + ++ int rssi_thold; ++ + struct wl1251_stats stats; + struct wl1251_debugfs debugfs; + +@@ -379,6 +390,8 @@ + + struct ieee80211_vif *vif; + ++ enum wl1251_bt_coex_mode bt_coex_mode; ++ + u32 chip_id; + char fw_ver[21]; + +@@ -409,6 +422,8 @@ + + #define WL1251_DEFAULT_CHANNEL 0 + ++#define WL1251_DEFAULT_BET_CONSECUTIVE 10 ++ + #define CHIP_ID_1251_PG10 (0x7010101) + #define CHIP_ID_1251_PG11 (0x7020101) + #define CHIP_ID_1251_PG12 (0x7030101) +@@ -430,4 +445,7 @@ + #define WL1251_PART_WORK_REG_START REGISTERS_BASE + #define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE + ++#define WL1251_DEFAULT_LOW_RSSI_WEIGHT 10 ++#define WL1251_DEFAULT_LOW_RSSI_DEPTH 10 ++ + #endif +diff -Naur compat-wireless-2.6.37-4-sn.orig//net/wireless/chan.c compat-wireless-2.6.37-4-sn/net/wireless/chan.c +--- compat-wireless-2.6.37-4-sn.orig//net/wireless/chan.c 2011-01-13 02:06:38.000000000 +0100 ++++ compat-wireless-2.6.37-4-sn/net/wireless/chan.c 2011-08-23 17:07:37.000000000 +0200 +@@ -83,9 +83,6 @@ + struct ieee80211_channel *chan; + int result; + +- if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR) +- wdev = NULL; +- + if (wdev) { + ASSERT_WDEV_LOCK(wdev); + +@@ -123,7 +120,9 @@ + } + + result = rdev->ops->set_channel(&rdev->wiphy, +- wdev ? wdev->netdev : NULL, ++ wdev && wdev->iftype != ++ NL80211_IFTYPE_MONITOR ? ++ wdev->netdev : NULL, + chan, channel_type); + if (result) + return result;