Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Wed, 5 May 2010 20:14:16 +0000 (16:14 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 5 May 2010 20:14:16 +0000 (16:14 -0400)
Conflicts:
drivers/net/wireless/libertas_tf/cmd.c
drivers/net/wireless/libertas_tf/main.c

140 files changed:
MAINTAINERS
drivers/net/wireless/Kconfig
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/ar9170/main.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/ani.h
drivers/net/wireless/ath/ath9k/ar5008_initvals.h
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9002_initvals.h
drivers/net/wireless/ath/ath9k/ar9002_phy.c
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
drivers/net/wireless/ath/ath9k/ar9003_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/common.c
drivers/net/wireless/ath/ath9k/eeprom.h
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/hif_usb.h
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
drivers/net/wireless/ath/ath9k/htc_hst.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/wmi.c
drivers/net/wireless/ath/ath9k/wmi.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/b43legacy/xmit.c
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-3945.h
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwmc3200wifi/bus.h
drivers/net/wireless/iwmc3200wifi/debug.h
drivers/net/wireless/iwmc3200wifi/debugfs.c
drivers/net/wireless/iwmc3200wifi/sdio.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas_tf/cmd.c
drivers/net/wireless/libertas_tf/deb_defs.h [new file with mode: 0644]
drivers/net/wireless/libertas_tf/if_usb.c
drivers/net/wireless/libertas_tf/libertas_tf.h
drivers/net/wireless/libertas_tf/main.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/Kconfig
drivers/net/wireless/orinoco/Makefile
drivers/net/wireless/orinoco/airport.c
drivers/net/wireless/orinoco/cfg.c
drivers/net/wireless/orinoco/fw.c
drivers/net/wireless/orinoco/hermes.c
drivers/net/wireless/orinoco/hermes.h
drivers/net/wireless/orinoco/hermes_dld.c
drivers/net/wireless/orinoco/hw.c
drivers/net/wireless/orinoco/main.c
drivers/net/wireless/orinoco/orinoco.h
drivers/net/wireless/orinoco/orinoco_cs.c
drivers/net/wireless/orinoco/orinoco_nortel.c
drivers/net/wireless/orinoco/orinoco_pci.c
drivers/net/wireless/orinoco/orinoco_plx.c
drivers/net/wireless/orinoco/orinoco_tmd.c
drivers/net/wireless/orinoco/orinoco_usb.c [new file with mode: 0644]
drivers/net/wireless/orinoco/spectrum_cs.c
drivers/net/wireless/orinoco/wext.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180_dev.c
drivers/net/wireless/rtl818x/rtl8187_dev.c
drivers/net/wireless/wl12xx/wl1251_main.c
drivers/net/wireless/wl12xx/wl1251_rx.c
drivers/net/wireless/wl12xx/wl1271_acx.c
drivers/net/wireless/wl12xx/wl1271_boot.c
drivers/net/wireless/wl12xx/wl1271_cmd.c
drivers/net/wireless/wl12xx/wl1271_conf.h
drivers/net/wireless/wl12xx/wl1271_main.c
drivers/ssb/driver_chipcommon.c
drivers/ssb/main.c
drivers/ssb/pci.c
drivers/ssb/sprom.c
include/linux/nl80211.h
include/linux/ssb/ssb.h
include/linux/ssb/ssb_driver_chipcommon.h
include/linux/ssb/ssb_regs.h
include/net/cfg80211.h
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/debugfs_sta.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/work.c
net/wireless/core.c
net/wireless/nl80211.c

index 405aea02dfbfecdc6e7842ea45e7866ad83f710f..a73b9b3cffade8db9815d41a71063d154cac74c6 100644 (file)
@@ -3956,6 +3956,7 @@ F:        net/rfkill/
 F:     net/wireless/
 F:     include/net/ieee80211*
 F:     include/linux/wireless.h
+F:     include/linux/iw_handler.h
 F:     drivers/net/wireless/
 
 NETWORKING DRIVERS
index 77500cb7fd26a012ae804f87a7a81d60d3f774aa..2fbe9b4506c0fd19809fd3901cb7e717947aea6d 100644 (file)
@@ -38,6 +38,12 @@ config LIBERTAS_THINFIRM
        ---help---
          A library for Marvell Libertas 8xxx devices using thinfirm.
 
+config LIBERTAS_THINFIRM_DEBUG
+       bool "Enable full debugging output in the Libertas thin firmware module."
+       depends on LIBERTAS_THINFIRM
+       ---help---
+         Debugging support.
+
 config LIBERTAS_THINFIRM_USB
        tristate "Marvell Libertas 8388 USB 802.11b/g cards with thin firmware"
        depends on LIBERTAS_THINFIRM && USB
index 0fb419936dfff58e0b8780107c07c70d842d712b..7a626d4e100fe4e03944d0b4f324895f477aa1db 100644 (file)
@@ -1889,6 +1889,7 @@ static void at76_dwork_hw_scan(struct work_struct *work)
 }
 
 static int at76_hw_scan(struct ieee80211_hw *hw,
+                       struct ieee80211_vif *vif,
                        struct cfg80211_scan_request *req)
 {
        struct at76_priv *priv = hw->priv;
index 0312cee395703c38c34835aa0fa180877fbe9e62..2e9b330f64137c702a913e7ae8ca54a5f53c611c 100644 (file)
@@ -927,7 +927,6 @@ static void ar9170_rx_phy_status(struct ar9170 *ar,
 
        /* TODO: we could do something with phy_errors */
        status->signal = ar->noise[0] + phy->rssi_combined;
-       status->noise = ar->noise[0];
 }
 
 static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len)
@@ -2548,8 +2547,7 @@ void *ar9170_alloc(size_t priv_size)
                                         BIT(NL80211_IFTYPE_ADHOC);
        ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
                         IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-                        IEEE80211_HW_SIGNAL_DBM |
-                        IEEE80211_HW_NOISE_DBM;
+                        IEEE80211_HW_SIGNAL_DBM;
 
        if (modparam_ht) {
                ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
index c274979ada3a667a84bf82db49139830155686d0..7f5953fac434af1448ec06113fa1fb29e48e9a48 100644 (file)
@@ -548,8 +548,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
        SET_IEEE80211_DEV(hw, &pdev->dev);
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                    IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-                   IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_NOISE_DBM;
+                   IEEE80211_HW_SIGNAL_DBM;
 
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_AP) |
@@ -2030,8 +2029,7 @@ accept:
                rxs->freq = sc->curchan->center_freq;
                rxs->band = sc->curband->band;
 
-               rxs->noise = sc->ah->ah_noise_floor;
-               rxs->signal = rxs->noise + rs.rs_rssi;
+               rxs->signal = sc->ah->ah_noise_floor + rs.rs_rssi;
 
                rxs->antenna = rs.rs_antenna;
 
index cec62d311c78094c515b80d81712129ffd9ea4b0..ba8b20f01594a8908f135620dd10b392d1498227 100644 (file)
@@ -657,12 +657,3 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
        if (ah->config.enable_ani)
                ah->proc_phyerr |= HAL_PROCESS_ANI;
 }
-
-void ath9k_hw_ani_disable(struct ath_hw *ah)
-{
-       ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, "Disabling ANI\n");
-
-       ath9k_hw_disable_mib_counters(ah);
-       REG_WRITE(ah, AR_PHY_ERR_1, 0);
-       REG_WRITE(ah, AR_PHY_ERR_2, 0);
-}
index 4e1ab94a51536705b49979babf3d0296789ef66b..3356762ea384af7fc4f3dfd049d8f27cca576ff5 100644 (file)
@@ -118,6 +118,5 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
 void ath9k_hw_procmibevent(struct ath_hw *ah);
 void ath9k_hw_ani_setup(struct ath_hw *ah);
 void ath9k_hw_ani_init(struct ath_hw *ah);
-void ath9k_hw_ani_disable(struct ath_hw *ah);
 
 #endif /* ANI_H */
index cd953f6c46287d0a6cb917c4ac9e79c9489de080..025c31ac614697a5f12d1f04188291daaa2c6e31 100644 (file)
@@ -249,7 +249,7 @@ static const u32 ar5416Common[][2] = {
     { 0x00008258, 0x00000000 },
     { 0x0000825c, 0x400000ff },
     { 0x00008260, 0x00080922 },
-    { 0x00008264, 0xa8000010 },
+    { 0x00008264, 0x88000010 },
     { 0x00008270, 0x00000000 },
     { 0x00008274, 0x40000000 },
     { 0x00008278, 0x003e4180 },
index de8ce1291a4608eebbafd0a7a933a6a446dc1d59..b2c17c98bb386ca4c1cbe62a0b64d705ea496511 100644 (file)
@@ -850,7 +850,7 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
 
        REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites);
 
-       if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) {
+       if (IS_CHAN_A_FAST_CLOCK(ah, chan)) {
                REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex,
                                regWrites);
        }
@@ -892,8 +892,7 @@ static void ar5008_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan)
                rfMode |= (IS_CHAN_5GHZ(chan)) ?
                        AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ;
 
-       if ((AR_SREV_9280_20(ah) || AR_SREV_9300_20_OR_LATER(ah))
-           && IS_CHAN_A_5MHZ_SPACED(chan))
+       if (IS_CHAN_A_FAST_CLOCK(ah, chan))
                rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
 
        REG_WRITE(ah, AR_PHY_MODE, rfMode);
index adb33b34a56df27a0227dc3599f9fc2efe565030..a8a8cdc04afa1f445f499ed8501d3e90fc1ddf56 100644 (file)
@@ -408,6 +408,8 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
                        REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
 
                } else {
+                       ENABLE_REGWRITE_BUFFER(ah);
+
                        REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
                        REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
 
@@ -428,6 +430,9 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
 
                        /* Load the new settings */
                        REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+                       REGWRITE_BUFFER_FLUSH(ah);
+                       DISABLE_REGWRITE_BUFFER(ah);
                }
 
                udelay(1000);
index f06313d3bad6458076aedfec79f5c870a470ba7e..dae7f3304eb877610e2dca763aa904e491771756 100644 (file)
@@ -793,7 +793,7 @@ static const u32 ar9280Common_9280_2[][2] = {
     { 0x00008258, 0x00000000 },
     { 0x0000825c, 0x400000ff },
     { 0x00008260, 0x00080922 },
-    { 0x00008264, 0xa8a00010 },
+    { 0x00008264, 0x88a00010 },
     { 0x00008270, 0x00000000 },
     { 0x00008274, 0x40000000 },
     { 0x00008278, 0x003e4180 },
@@ -1963,7 +1963,7 @@ static const u32 ar9285Common_9285[][2] = {
     { 0x00008258, 0x00000000 },
     { 0x0000825c, 0x400000ff },
     { 0x00008260, 0x00080922 },
-    { 0x00008264, 0xa8a00010 },
+    { 0x00008264, 0x88a00010 },
     { 0x00008270, 0x00000000 },
     { 0x00008274, 0x40000000 },
     { 0x00008278, 0x003e4180 },
@@ -3185,7 +3185,7 @@ static const u32 ar9287Common_9287_1_0[][2] = {
     { 0x00008258, 0x00000000 },
     { 0x0000825c, 0x400000ff },
     { 0x00008260, 0x00080922 },
-    { 0x00008264, 0xa8a00010 },
+    { 0x00008264, 0x88a00010 },
     { 0x00008270, 0x00000000 },
     { 0x00008274, 0x40000000 },
     { 0x00008278, 0x003e4180 },
@@ -4973,7 +4973,7 @@ static const u32 ar9271Common_9271[][2] = {
     { 0x00008258, 0x00000000 },
     { 0x0000825c, 0x400000ff },
     { 0x00008260, 0x00080922 },
-    { 0x00008264, 0xa8a00010 },
+    { 0x00008264, 0x88a00010 },
     { 0x00008270, 0x00000000 },
     { 0x00008274, 0x40000000 },
     { 0x00008278, 0x003e4180 },
index 18cfe1a9781cd71b0db087b631a00ead59727635..ed314e89bfe177d65cc95c20fe4b4042f3749814 100644 (file)
@@ -455,16 +455,12 @@ static u32 ar9002_hw_compute_pll_control(struct ath_hw *ah,
                pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
 
        if (chan && IS_CHAN_5GHZ(chan)) {
-               pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
-
-
-               if (AR_SREV_9280_20(ah)) {
-                       if (((chan->channel % 20) == 0)
-                           || ((chan->channel % 10) == 0))
-                               pll = 0x2850;
-                       else
-                               pll = 0x142c;
-               }
+               if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+                       pll = 0x142c;
+               else if (AR_SREV_9280_20(ah))
+                       pll = 0x2850;
+               else
+                       pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
        } else {
                pll |= SM(0x2c, AR_RTC_9160_PLL_DIV);
        }
index 5e20b4860c7f045126ed09db0a1f2d1521a0f40e..5fcafb460877cee7f2bf60e7a6c88d553da2e75e 100644 (file)
@@ -755,7 +755,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
        }
 
        /* Do Tx IQ Calibration */
-       ar9003_hw_tx_iq_cal(ah);
+       if (ah->config.tx_iq_calibration)
+               ar9003_hw_tx_iq_cal(ah);
 
        /* Revert chainmasks to their original values before NF cal */
        ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
index 5d92be47c5a5cd2a2d0db060051412eeb8d65e32..8a79550dff71f3f085e5987964d814ddc059c14f 100644 (file)
@@ -659,6 +659,9 @@ static void ar9300_swap_eeprom(struct ar9300_eeprom *eep)
        word = swab16(eep->baseEepHeader.regDmn[1]);
        eep->baseEepHeader.regDmn[1] = word;
 
+       dword = swab32(eep->baseEepHeader.swreg);
+       eep->baseEepHeader.swreg = dword;
+
        dword = swab32(eep->modalHeader2G.antCtrlCommon);
        eep->modalHeader2G.antCtrlCommon = dword;
 
@@ -1200,7 +1203,7 @@ static u8 ar9003_hw_eeprom_get_tgt_pwr(struct ath_hw *ah,
        u8 *pFreqBin;
 
        if (is2GHz) {
-               numPiers = AR9300_NUM_5G_20_TARGET_POWERS;
+               numPiers = AR9300_NUM_2G_20_TARGET_POWERS;
                pEepromTargetPwr = eep->calTargetPower2G;
                pFreqBin = eep->calTarget_freqbin_2G;
        } else {
@@ -1236,7 +1239,7 @@ static u8 ar9003_hw_eeprom_get_ht20_tgt_pwr(struct ath_hw *ah,
        u8 *pFreqBin;
 
        if (is2GHz) {
-               numPiers = AR9300_NUM_5G_20_TARGET_POWERS;
+               numPiers = AR9300_NUM_2G_20_TARGET_POWERS;
                pEepromTargetPwr = eep->calTargetPower2GHT20;
                pFreqBin = eep->calTarget_freqbin_2GHT20;
        } else {
@@ -1817,6 +1820,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
                                        u8 twiceMaxRegulatoryPower,
                                        u8 powerLimit)
 {
+       ah->txpower_limit = powerLimit;
        ar9003_hw_set_target_power_eeprom(ah, chan->channel);
        ar9003_hw_calibration_apply(ah, chan->channel);
 }
index 5fe335e22c890c363850ace60ad5d649f1ddff86..d8c0318f416f02b916c7de66e1e3010850e538d8 100644 (file)
@@ -265,7 +265,7 @@ struct cal_ctl_edge_pwr {
 } __packed;
 
 struct cal_ctl_data_2g {
-       struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_5G];
+       struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_2G];
 } __packed;
 
 struct cal_ctl_data_5g {
index e0391b12e533048166286ad643e586de70273c67..a131cd10ef29cd258c3a0891f62e10f6778b5b02 100644 (file)
@@ -31,7 +31,7 @@ static const u32 ar9300_2p0_radio_postamble[][5] = {
 
 static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p0[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x0000a410, 0x000050da, 0x000050da, 0x000050da, 0x000050da},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
        {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
        {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
@@ -545,7 +545,7 @@ static const u32 ar9300_2p0_soc_postamble[][5] = {
 };
 
 static const u32 ar9200_merlin_2p0_radio_core[][2] = {
-       /* Addr      common    */
+       /* Addr      allmodes  */
        {0x00007800, 0x00040000},
        {0x00007804, 0xdb005012},
        {0x00007808, 0x04924914},
@@ -835,71 +835,71 @@ static const u32 ar9300_2p0_baseband_core[][2] = {
 
 static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050da, 0x000050da},
+       {0x0000a410, 0x000050db, 0x000050db, 0x000050d9, 0x000050d9},
        {0x0000a500, 0x00020220, 0x00020220, 0x00000000, 0x00000000},
        {0x0000a504, 0x06020223, 0x06020223, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0b022220, 0x0b022220, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x10022223, 0x10022223, 0x0b000200, 0x0b000200},
-       {0x0000a510, 0x17022620, 0x17022620, 0x0f000202, 0x0f000202},
-       {0x0000a514, 0x1b022622, 0x1b022622, 0x11000400, 0x11000400},
-       {0x0000a518, 0x1f022822, 0x1f022822, 0x15000402, 0x15000402},
-       {0x0000a51c, 0x24022842, 0x24022842, 0x19000404, 0x19000404},
-       {0x0000a520, 0x28042840, 0x28042840, 0x1b000603, 0x1b000603},
-       {0x0000a524, 0x2c042842, 0x2c042842, 0x1f000a02, 0x1f000a02},
-       {0x0000a528, 0x30042844, 0x30042844, 0x23000a04, 0x23000a04},
-       {0x0000a52c, 0x34042846, 0x34042846, 0x26000a20, 0x26000a20},
-       {0x0000a530, 0x39042869, 0x39042869, 0x2a000e20, 0x2a000e20},
-       {0x0000a534, 0x3d062869, 0x3d062869, 0x2e000e22, 0x2e000e22},
-       {0x0000a538, 0x44062c69, 0x44062c69, 0x31000e24, 0x31000e24},
-       {0x0000a53c, 0x48063069, 0x48063069, 0x34001640, 0x34001640},
-       {0x0000a540, 0x4c0a3065, 0x4c0a3065, 0x38001660, 0x38001660},
-       {0x0000a544, 0x500a3069, 0x500a3069, 0x3b001861, 0x3b001861},
-       {0x0000a548, 0x530a3469, 0x530a3469, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x590a7464, 0x590a7464, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x5e0a7865, 0x5e0a7865, 0x44001c84, 0x44001c84},
-       {0x0000a554, 0x630a7e66, 0x630a7e66, 0x48001ce3, 0x48001ce3},
-       {0x0000a558, 0x680a7e89, 0x680a7e89, 0x4c001ce5, 0x4c001ce5},
-       {0x0000a55c, 0x6e0a7e8c, 0x6e0a7e8c, 0x50001ce9, 0x50001ce9},
-       {0x0000a560, 0x730e7e8c, 0x730e7e8c, 0x54001ceb, 0x54001ceb},
-       {0x0000a564, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
-       {0x0000a568, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
-       {0x0000a56c, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
-       {0x0000a570, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
-       {0x0000a574, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
-       {0x0000a578, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
-       {0x0000a57c, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
+       {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
+       {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
+       {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
+       {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
+       {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
+       {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
+       {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
+       {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
+       {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
+       {0x0000a530, 0x34043643, 0x34043643, 0x2a000e20, 0x2a000e20},
+       {0x0000a534, 0x38043a44, 0x38043a44, 0x2e000e22, 0x2e000e22},
+       {0x0000a538, 0x3b043e45, 0x3b043e45, 0x31000e24, 0x31000e24},
+       {0x0000a53c, 0x40063e46, 0x40063e46, 0x34001640, 0x34001640},
+       {0x0000a540, 0x44083e46, 0x44083e46, 0x38001660, 0x38001660},
+       {0x0000a544, 0x46083e66, 0x46083e66, 0x3b001861, 0x3b001861},
+       {0x0000a548, 0x4b0a3e69, 0x4b0a3e69, 0x3e001a81, 0x3e001a81},
+       {0x0000a54c, 0x4f0a5e66, 0x4f0a5e66, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x540a7e66, 0x540a7e66, 0x44001c84, 0x44001c84},
+       {0x0000a554, 0x570a7e89, 0x570a7e89, 0x48001ce3, 0x48001ce3},
+       {0x0000a558, 0x5c0e7e8a, 0x5c0e7e8a, 0x4c001ce5, 0x4c001ce5},
+       {0x0000a55c, 0x60127e8b, 0x60127e8b, 0x50001ce9, 0x50001ce9},
+       {0x0000a560, 0x65127ecc, 0x65127ecc, 0x54001ceb, 0x54001ceb},
+       {0x0000a564, 0x6b169ecd, 0x6b169ecd, 0x56001eec, 0x56001eec},
+       {0x0000a568, 0x70169f0e, 0x70169f0e, 0x56001eec, 0x56001eec},
+       {0x0000a56c, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
+       {0x0000a570, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
+       {0x0000a574, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
+       {0x0000a578, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
+       {0x0000a57c, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
        {0x0000a580, 0x00820220, 0x00820220, 0x00800000, 0x00800000},
        {0x0000a584, 0x06820223, 0x06820223, 0x04800002, 0x04800002},
-       {0x0000a588, 0x0b822220, 0x0b822220, 0x08800004, 0x08800004},
-       {0x0000a58c, 0x10822223, 0x10822223, 0x0b800200, 0x0b800200},
-       {0x0000a590, 0x17822620, 0x17822620, 0x0f800202, 0x0f800202},
-       {0x0000a594, 0x1b822622, 0x1b822622, 0x11800400, 0x11800400},
-       {0x0000a598, 0x1f822822, 0x1f822822, 0x15800402, 0x15800402},
-       {0x0000a59c, 0x24822842, 0x24822842, 0x19800404, 0x19800404},
-       {0x0000a5a0, 0x28842840, 0x28842840, 0x1b800603, 0x1b800603},
-       {0x0000a5a4, 0x2c842842, 0x2c842842, 0x1f800a02, 0x1f800a02},
-       {0x0000a5a8, 0x30842844, 0x30842844, 0x23800a04, 0x23800a04},
-       {0x0000a5ac, 0x34842846, 0x34842846, 0x26800a20, 0x26800a20},
-       {0x0000a5b0, 0x39842869, 0x39842869, 0x2a800e20, 0x2a800e20},
-       {0x0000a5b4, 0x3d862869, 0x3d862869, 0x2e800e22, 0x2e800e22},
-       {0x0000a5b8, 0x44862c69, 0x44862c69, 0x31800e24, 0x31800e24},
-       {0x0000a5bc, 0x48863069, 0x48863069, 0x34801640, 0x34801640},
-       {0x0000a5c0, 0x4c8a3065, 0x4c8a3065, 0x38801660, 0x38801660},
-       {0x0000a5c4, 0x508a3069, 0x508a3069, 0x3b801861, 0x3b801861},
-       {0x0000a5c8, 0x538a3469, 0x538a3469, 0x3e801a81, 0x3e801a81},
-       {0x0000a5cc, 0x598a7464, 0x598a7464, 0x42801a83, 0x42801a83},
-       {0x0000a5d0, 0x5e8a7865, 0x5e8a7865, 0x44801c84, 0x44801c84},
-       {0x0000a5d4, 0x638a7e66, 0x638a7e66, 0x48801ce3, 0x48801ce3},
-       {0x0000a5d8, 0x688a7e89, 0x688a7e89, 0x4c801ce5, 0x4c801ce5},
-       {0x0000a5dc, 0x6e8a7e8c, 0x6e8a7e8c, 0x50801ce9, 0x50801ce9},
-       {0x0000a5e0, 0x738e7e8c, 0x738e7e8c, 0x54801ceb, 0x54801ceb},
-       {0x0000a5e4, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
-       {0x0000a5e8, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
-       {0x0000a5ec, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
-       {0x0000a5f0, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
-       {0x0000a5f4, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
-       {0x0000a5f8, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
-       {0x0000a5fc, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
+       {0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004},
+       {0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200},
+       {0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202},
+       {0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400},
+       {0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402},
+       {0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404},
+       {0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603},
+       {0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
+       {0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
+       {0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
+       {0x0000a5b0, 0x34843643, 0x34843643, 0x2a800e20, 0x2a800e20},
+       {0x0000a5b4, 0x38843a44, 0x38843a44, 0x2e800e22, 0x2e800e22},
+       {0x0000a5b8, 0x3b843e45, 0x3b843e45, 0x31800e24, 0x31800e24},
+       {0x0000a5bc, 0x40863e46, 0x40863e46, 0x34801640, 0x34801640},
+       {0x0000a5c0, 0x4c8a3065, 0x44883e46, 0x44883e46, 0x38801660},
+       {0x0000a5c4, 0x46883e66, 0x46883e66, 0x3b801861, 0x3b801861},
+       {0x0000a5c8, 0x4b8a3e69, 0x4b8a3e69, 0x3e801a81, 0x3e801a81},
+       {0x0000a5cc, 0x4f8a5e66, 0x4f8a5e66, 0x42801a83, 0x42801a83},
+       {0x0000a5d0, 0x548a7e66, 0x548a7e66, 0x44801c84, 0x44801c84},
+       {0x0000a5d4, 0x578a7e89, 0x578a7e89, 0x48801ce3, 0x48801ce3},
+       {0x0000a5d8, 0x5c8e7e8a, 0x5c8e7e8a, 0x4c801ce5, 0x4c801ce5},
+       {0x0000a5dc, 0x60927e8b, 0x60927e8b, 0x50801ce9, 0x50801ce9},
+       {0x0000a5e0, 0x65927ecc, 0x65927ecc, 0x54801ceb, 0x54801ceb},
+       {0x0000a5e4, 0x6b969ecd, 0x6b969ecd, 0x56801eec, 0x56801eec},
+       {0x0000a5e8, 0x70969f0e, 0x70969f0e, 0x56801eec, 0x56801eec},
+       {0x0000a5ec, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
+       {0x0000a5f0, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
+       {0x0000a5f4, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
+       {0x0000a5f8, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
+       {0x0000a5fc, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
        {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
        {0x00016048, 0xad241a61, 0xad241a61, 0xad241a61, 0xad241a61},
        {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
@@ -913,71 +913,71 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = {
 
 static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p0[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050da, 0x000050da},
+       {0x0000a410, 0x000050db, 0x000050db, 0x000050d9, 0x000050d9},
        {0x0000a500, 0x00020220, 0x00020220, 0x00000000, 0x00000000},
        {0x0000a504, 0x06020223, 0x06020223, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0b022220, 0x0b022220, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x10022223, 0x10022223, 0x0b000200, 0x0b000200},
-       {0x0000a510, 0x17022620, 0x17022620, 0x0f000202, 0x0f000202},
-       {0x0000a514, 0x1b022622, 0x1b022622, 0x11000400, 0x11000400},
-       {0x0000a518, 0x1f022822, 0x1f022822, 0x15000402, 0x15000402},
-       {0x0000a51c, 0x24022842, 0x24022842, 0x19000404, 0x19000404},
-       {0x0000a520, 0x28042840, 0x28042840, 0x1b000603, 0x1b000603},
-       {0x0000a524, 0x2c042842, 0x2c042842, 0x1f000a02, 0x1f000a02},
-       {0x0000a528, 0x30042844, 0x30042844, 0x23000a04, 0x23000a04},
-       {0x0000a52c, 0x34042846, 0x34042846, 0x26000a20, 0x26000a20},
-       {0x0000a530, 0x39042869, 0x39042869, 0x2a000e20, 0x2a000e20},
-       {0x0000a534, 0x3d062869, 0x3d062869, 0x2e000e22, 0x2e000e22},
-       {0x0000a538, 0x44062c69, 0x44062c69, 0x31000e24, 0x31000e24},
-       {0x0000a53c, 0x48063069, 0x48063069, 0x34001640, 0x34001640},
-       {0x0000a540, 0x4c0a3065, 0x4c0a3065, 0x38001660, 0x38001660},
-       {0x0000a544, 0x500a3069, 0x500a3069, 0x3b001861, 0x3b001861},
-       {0x0000a548, 0x530a3469, 0x530a3469, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x590a7464, 0x590a7464, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x5e0a7865, 0x5e0a7865, 0x44001c84, 0x44001c84},
-       {0x0000a554, 0x630a7e66, 0x630a7e66, 0x48001ce3, 0x48001ce3},
-       {0x0000a558, 0x680a7e89, 0x680a7e89, 0x4c001ce5, 0x4c001ce5},
-       {0x0000a55c, 0x6e0a7e8c, 0x6e0a7e8c, 0x50001ce9, 0x50001ce9},
-       {0x0000a560, 0x730e7e8c, 0x730e7e8c, 0x54001ceb, 0x54001ceb},
-       {0x0000a564, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
-       {0x0000a568, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
-       {0x0000a56c, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
-       {0x0000a570, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
-       {0x0000a574, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
-       {0x0000a578, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
-       {0x0000a57c, 0x730e7e8c, 0x730e7e8c, 0x56001eec, 0x56001eec},
+       {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
+       {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
+       {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
+       {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
+       {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
+       {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
+       {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
+       {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
+       {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
+       {0x0000a530, 0x34043643, 0x34043643, 0x2a000e20, 0x2a000e20},
+       {0x0000a534, 0x38043a44, 0x38043a44, 0x2e000e22, 0x2e000e22},
+       {0x0000a538, 0x3b043e45, 0x3b043e45, 0x31000e24, 0x31000e24},
+       {0x0000a53c, 0x40063e46, 0x40063e46, 0x34001640, 0x34001640},
+       {0x0000a540, 0x44083e46, 0x44083e46, 0x38001660, 0x38001660},
+       {0x0000a544, 0x46083e66, 0x46083e66, 0x3b001861, 0x3b001861},
+       {0x0000a548, 0x4b0a3e69, 0x4b0a3e69, 0x3e001a81, 0x3e001a81},
+       {0x0000a54c, 0x4f0a5e66, 0x4f0a5e66, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x540a7e66, 0x540a7e66, 0x44001c84, 0x44001c84},
+       {0x0000a554, 0x570a7e89, 0x570a7e89, 0x48001ce3, 0x48001ce3},
+       {0x0000a558, 0x5c0e7e8a, 0x5c0e7e8a, 0x4c001ce5, 0x4c001ce5},
+       {0x0000a55c, 0x60127e8b, 0x60127e8b, 0x50001ce9, 0x50001ce9},
+       {0x0000a560, 0x65127ecc, 0x65127ecc, 0x54001ceb, 0x54001ceb},
+       {0x0000a564, 0x6b169ecd, 0x6b169ecd, 0x56001eec, 0x56001eec},
+       {0x0000a568, 0x70169f0e, 0x70169f0e, 0x56001eec, 0x56001eec},
+       {0x0000a56c, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
+       {0x0000a570, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
+       {0x0000a574, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
+       {0x0000a578, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
+       {0x0000a57c, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
        {0x0000a580, 0x00820220, 0x00820220, 0x00800000, 0x00800000},
        {0x0000a584, 0x06820223, 0x06820223, 0x04800002, 0x04800002},
-       {0x0000a588, 0x0b822220, 0x0b822220, 0x08800004, 0x08800004},
-       {0x0000a58c, 0x10822223, 0x10822223, 0x0b800200, 0x0b800200},
-       {0x0000a590, 0x17822620, 0x17822620, 0x0f800202, 0x0f800202},
-       {0x0000a594, 0x1b822622, 0x1b822622, 0x11800400, 0x11800400},
-       {0x0000a598, 0x1f822822, 0x1f822822, 0x15800402, 0x15800402},
-       {0x0000a59c, 0x24822842, 0x24822842, 0x19800404, 0x19800404},
-       {0x0000a5a0, 0x28842840, 0x28842840, 0x1b800603, 0x1b800603},
-       {0x0000a5a4, 0x2c842842, 0x2c842842, 0x1f800a02, 0x1f800a02},
-       {0x0000a5a8, 0x30842844, 0x30842844, 0x23800a04, 0x23800a04},
-       {0x0000a5ac, 0x34842846, 0x34842846, 0x26800a20, 0x26800a20},
-       {0x0000a5b0, 0x39842869, 0x39842869, 0x2a800e20, 0x2a800e20},
-       {0x0000a5b4, 0x3d862869, 0x3d862869, 0x2e800e22, 0x2e800e22},
-       {0x0000a5b8, 0x44862c69, 0x44862c69, 0x31800e24, 0x31800e24},
-       {0x0000a5bc, 0x48863069, 0x48863069, 0x34801640, 0x34801640},
-       {0x0000a5c0, 0x4c8a3065, 0x4c8a3065, 0x38801660, 0x38801660},
-       {0x0000a5c4, 0x508a3069, 0x508a3069, 0x3b801861, 0x3b801861},
-       {0x0000a5c8, 0x538a3469, 0x538a3469, 0x3e801a81, 0x3e801a81},
-       {0x0000a5cc, 0x598a7464, 0x598a7464, 0x42801a83, 0x42801a83},
-       {0x0000a5d0, 0x5e8a7865, 0x5e8a7865, 0x44801c84, 0x44801c84},
-       {0x0000a5d4, 0x638a7e66, 0x638a7e66, 0x48801ce3, 0x48801ce3},
-       {0x0000a5d8, 0x688a7e89, 0x688a7e89, 0x4c801ce5, 0x4c801ce5},
-       {0x0000a5dc, 0x6e8a7e8c, 0x6e8a7e8c, 0x50801ce9, 0x50801ce9},
-       {0x0000a5e0, 0x738e7e8c, 0x738e7e8c, 0x54801ceb, 0x54801ceb},
-       {0x0000a5e4, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
-       {0x0000a5e8, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
-       {0x0000a5ec, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
-       {0x0000a5f0, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
-       {0x0000a5f4, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
-       {0x0000a5f8, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
-       {0x0000a5fc, 0x738e7e8c, 0x738e7e8c, 0x56801eec, 0x56801eec},
+       {0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004},
+       {0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200},
+       {0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202},
+       {0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400},
+       {0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402},
+       {0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404},
+       {0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603},
+       {0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
+       {0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
+       {0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
+       {0x0000a5b0, 0x34843643, 0x34843643, 0x2a800e20, 0x2a800e20},
+       {0x0000a5b4, 0x38843a44, 0x38843a44, 0x2e800e22, 0x2e800e22},
+       {0x0000a5b8, 0x3b843e45, 0x3b843e45, 0x31800e24, 0x31800e24},
+       {0x0000a5bc, 0x40863e46, 0x40863e46, 0x34801640, 0x34801640},
+       {0x0000a5c0, 0x44883e46, 0x44883e46, 0x38801660, 0x38801660},
+       {0x0000a5c4, 0x46883e66, 0x46883e66, 0x3b801861, 0x3b801861},
+       {0x0000a5c8, 0x4b8a3e69, 0x4b8a3e69, 0x3e801a81, 0x3e801a81},
+       {0x0000a5cc, 0x4f8a5e66, 0x4f8a5e66, 0x42801a83, 0x42801a83},
+       {0x0000a5d0, 0x548a7e66, 0x548a7e66, 0x44801c84, 0x44801c84},
+       {0x0000a5d4, 0x578a7e89, 0x578a7e89, 0x48801ce3, 0x48801ce3},
+       {0x0000a5d8, 0x5c8e7e8a, 0x5c8e7e8a, 0x4c801ce5, 0x4c801ce5},
+       {0x0000a5dc, 0x60927e8b, 0x60927e8b, 0x50801ce9, 0x50801ce9},
+       {0x0000a5e0, 0x65927ecc, 0x65927ecc, 0x54801ceb, 0x54801ceb},
+       {0x0000a5e4, 0x6b969ecd, 0x6b969ecd, 0x56801eec, 0x56801eec},
+       {0x0000a5e8, 0x70969f0e, 0x70969f0e, 0x56801eec, 0x56801eec},
+       {0x0000a5ec, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
+       {0x0000a5f0, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
+       {0x0000a5f4, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
+       {0x0000a5f8, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
+       {0x0000a5fc, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
        {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
        {0x00016048, 0x8c001a61, 0x8c001a61, 0x8c001a61, 0x8c001a61},
        {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -1251,7 +1251,7 @@ static const u32 ar9300Common_rx_gain_table_2p0[][2] = {
 
 static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p0[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x0000a410, 0x000050da, 0x000050da, 0x000050da, 0x000050da},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
        {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
        {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
@@ -1760,31 +1760,22 @@ static const u32 ar9300_2p0_soc_preamble[][2] = {
        {0x00007038, 0x000004c2},
 };
 
-/*
- * PCIE-PHY programming array, to be used prior to entering
- * full sleep (holding RTC in reset, PLL is ON in L1 mode)
- */
 static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p0[][2] = {
+       /* Addr      allmodes  */
        {0x00004040, 0x08212e5e},
        {0x00004040, 0x0008003b},
        {0x00004044, 0x00000000},
 };
 
-/*
- * PCIE-PHY programming array, to be used when not in
- * full sleep (holding RTC in reset)
- */
 static const u32 ar9300PciePhy_clkreq_enable_L1_2p0[][2] = {
+       /* Addr      allmodes  */
        {0x00004040, 0x08253e5e},
        {0x00004040, 0x0008003b},
        {0x00004044, 0x00000000},
 };
 
-/*
- * PCIE-PHY programming array, to be used prior to entering
- * full sleep (holding RTC in reset)
- */
 static const u32 ar9300PciePhy_clkreq_disable_L1_2p0[][2] = {
+       /* Addr      allmodes  */
        {0x00004040, 0x08213e5e},
        {0x00004040, 0x0008003b},
        {0x00004044, 0x00000000},
index 7d111fbf8bc54175de243a1dd383c0eabd6e3ec2..37ba37481a47eea72df41a631e3b6252423b334e 100644 (file)
@@ -311,6 +311,9 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
 {
        struct ar9003_txc *ads = (struct ar9003_txc *) ds;
 
+       if (txpower > ah->txpower_limit)
+               txpower = ah->txpower_limit;
+
        txpower += ah->txpower_indexoffset;
        if (txpower > 63)
                txpower = 63;
index 137543b2d7396c8692477b35011c8bfd0a7cf934..80431a2f6dc1d941ef2376637a7cf32133192ff9 100644 (file)
@@ -375,16 +375,7 @@ static u32 ar9003_hw_compute_pll_control(struct ath_hw *ah,
        else if (chan && IS_CHAN_QUARTER_RATE(chan))
                pll |= SM(0x2, AR_RTC_9300_PLL_CLKSEL);
 
-       if (chan && IS_CHAN_5GHZ(chan)) {
-               pll |= SM(0x28, AR_RTC_9300_PLL_DIV);
-
-               /*
-                * When doing fast clock, set PLL to 0x142c
-                */
-               if (IS_CHAN_A_5MHZ_SPACED(chan))
-                       pll = 0x142c;
-       } else
-               pll |= SM(0x2c, AR_RTC_9300_PLL_DIV);
+       pll |= SM(0x2c, AR_RTC_9300_PLL_DIV);
 
        return pll;
 }
@@ -592,7 +583,7 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
         * For 5GHz channels requiring Fast Clock, apply
         * different modal values.
         */
-       if (IS_CHAN_A_5MHZ_SPACED(chan))
+       if (IS_CHAN_A_FAST_CLOCK(ah, chan))
                REG_WRITE_ARRAY(&ah->iniModesAdditional,
                                modesIndex, regWrites);
 
@@ -622,7 +613,7 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah,
        rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
                ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
 
-       if (IS_CHAN_A_5MHZ_SPACED(chan))
+       if (IS_CHAN_A_FAST_CLOCK(ah, chan))
                rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
 
        REG_WRITE(ah, AR_PHY_MODE, rfMode);
@@ -1102,6 +1093,7 @@ static void ar9003_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
                ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
                          "to load: AR_PHY_AGC_CONTROL=0x%x\n",
                          REG_READ(ah, AR_PHY_AGC_CONTROL));
+               return;
        }
 
        /*
index 09effdedc8c085eb64d482d9147e0a9881d5386f..b4424a623cf5d2b0aa80019b906237183984c799 100644 (file)
@@ -212,7 +212,6 @@ int ath9k_cmn_rx_skb_preprocess(struct ath_common *common,
        rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp);
        rx_status->band = hw->conf.channel->band;
        rx_status->freq = hw->conf.channel->center_freq;
-       rx_status->noise = common->ani.noise_floor;
        rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
        rx_status->antenna = rx_stats->rs_antenna;
        rx_status->flag |= RX_FLAG_TSFT;
index fb9c8c92eabeb79fde04c928f977cb16de882aae..21354c15a9a9b1181fd2eaa6d7933c5706019b47 100644 (file)
@@ -300,7 +300,8 @@ struct base_eep_header {
        u32 binBuildNumber;
        u8 deviceType;
        u8 pwdclkind;
-       u8 futureBase_1[2];
+       u8 fastClk5g;
+       u8 divChain;
        u8 rxGainType;
        u8 dacHiPwrMode_5G;
        u8 openLoopPwrCntl;
index cf59799ef3073553673e938c96e80be22556a1ee..e591ad6016e58ad215f6c27dd2916a7a4e60bfaf 100644 (file)
@@ -274,6 +274,8 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
                return pBase->txMask;
        case EEP_RX_MASK:
                return pBase->rxMask;
+       case EEP_FSTCLK_5G:
+               return pBase->fastClk5g;
        case EEP_RXGAIN_TYPE:
                return pBase->rxGainType;
        case EEP_TXGAIN_TYPE:
index 3091bb3cef9be6c182cdd41131c6bfac3f3e6208..74872ca76f9a2c3a4cd679ac3fc4f120b6c7ce75 100644 (file)
@@ -93,14 +93,24 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
        return ret;
 }
 
+static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
+                                        struct sk_buff_head *list)
+{
+       struct sk_buff *skb;
+
+       while ((skb = __skb_dequeue(list)) != NULL) {
+               dev_kfree_skb_any(skb);
+               TX_STAT_INC(skb_dropped);
+       }
+}
+
 static void hif_usb_tx_cb(struct urb *urb)
 {
        struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
        struct hif_device_usb *hif_dev = tx_buf->hif_dev;
        struct sk_buff *skb;
-       bool drop, flush;
 
-       if (!hif_dev)
+       if (!hif_dev || !tx_buf)
                return;
 
        switch (urb->status) {
@@ -108,57 +118,47 @@ static void hif_usb_tx_cb(struct urb *urb)
                break;
        case -ENOENT:
        case -ECONNRESET:
-               break;
        case -ENODEV:
        case -ESHUTDOWN:
+               /*
+                * The URB has been killed, free the SKBs
+                * and return.
+                */
+               ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
                return;
        default:
                break;
        }
 
-       if (tx_buf) {
-               spin_lock(&hif_dev->tx.tx_lock);
-               drop = !!(hif_dev->tx.flags & HIF_USB_TX_STOP);
-               flush = !!(hif_dev->tx.flags & HIF_USB_TX_FLUSH);
-               spin_unlock(&hif_dev->tx.tx_lock);
-
-               while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) {
-                       if (!drop && !flush) {
-                               ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
-                                                         skb, 1);
-                               TX_STAT_INC(skb_completed);
-                       } else {
-                               dev_kfree_skb_any(skb);
-                               TX_STAT_INC(skb_dropped);
-                       }
-               }
-
-               if (flush)
-                       return;
-
-               tx_buf->len = tx_buf->offset = 0;
-               __skb_queue_head_init(&tx_buf->skb_queue);
-
-               spin_lock(&hif_dev->tx.tx_lock);
-               list_del(&tx_buf->list);
-               list_add_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
-               hif_dev->tx.tx_buf_cnt++;
-               if (!drop)
-                       __hif_usb_tx(hif_dev); /* Check for pending SKBs */
-               TX_STAT_INC(buf_completed);
+       /* Check if TX has been stopped */
+       spin_lock(&hif_dev->tx.tx_lock);
+       if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
                spin_unlock(&hif_dev->tx.tx_lock);
-       }
-}
-
-static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
-                                        struct sk_buff_head *list)
-{
-       struct sk_buff *skb;
-
-       while ((skb = __skb_dequeue(list)) != NULL) {
-               dev_kfree_skb_any(skb);
-               TX_STAT_INC(skb_dropped);
-       }
+               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);
+       }
+
+add_free:
+       /* Re-initialize the SKB queue */
+       tx_buf->len = tx_buf->offset = 0;
+       __skb_queue_head_init(&tx_buf->skb_queue);
+
+       /* Add this TX buffer to the free list */
+       spin_lock(&hif_dev->tx.tx_lock);
+       list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
+       hif_dev->tx.tx_buf_cnt++;
+       if (!(hif_dev->tx.flags & HIF_USB_TX_STOP))
+               __hif_usb_tx(hif_dev); /* Check for pending SKBs */
+       TX_STAT_INC(buf_completed);
+       spin_unlock(&hif_dev->tx.tx_lock);
 }
 
 /* TX lock has to be taken */
@@ -178,8 +178,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
                return 0;
 
        tx_buf = list_first_entry(&hif_dev->tx.tx_buf, struct tx_buf, list);
-       list_del(&tx_buf->list);
-       list_add_tail(&tx_buf->list, &hif_dev->tx.tx_pending);
+       list_move_tail(&tx_buf->list, &hif_dev->tx.tx_pending);
        hif_dev->tx.tx_buf_cnt--;
 
        tx_skb_cnt = min_t(u16, hif_dev->tx.tx_skb_cnt, MAX_TX_AGGR_NUM);
@@ -511,9 +510,18 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
        if (likely(urb->actual_length != 0)) {
                skb_put(skb, urb->actual_length);
 
+               /* Process the command first */
+               ath9k_htc_rx_msg(hif_dev->htc_handle, skb,
+                                skb->len, USB_REG_IN_PIPE);
+
+
                nskb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC);
-               if (!nskb)
-                       goto resubmit;
+               if (!nskb) {
+                       dev_err(&hif_dev->udev->dev,
+                               "ath9k_htc: REG_IN memory allocation failure\n");
+                       urb->context = NULL;
+                       return;
+               }
 
                usb_fill_int_urb(urb, hif_dev->udev,
                                 usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE),
@@ -523,12 +531,9 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
                ret = usb_submit_urb(urb, GFP_ATOMIC);
                if (ret) {
                        kfree_skb(nskb);
-                       goto free;
+                       urb->context = NULL;
                }
 
-               ath9k_htc_rx_msg(hif_dev->htc_handle, skb,
-                                skb->len, USB_REG_IN_PIPE);
-
                return;
        }
 
@@ -548,20 +553,17 @@ free:
 
 static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
 {
-       unsigned long flags;
        struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
 
-       list_for_each_entry_safe(tx_buf, tx_buf_tmp, &hif_dev->tx.tx_buf, list) {
+       list_for_each_entry_safe(tx_buf, tx_buf_tmp,
+                                &hif_dev->tx.tx_buf, list) {
+               usb_kill_urb(tx_buf->urb);
                list_del(&tx_buf->list);
                usb_free_urb(tx_buf->urb);
                kfree(tx_buf->buf);
                kfree(tx_buf);
        }
 
-       spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
-       hif_dev->tx.flags |= HIF_USB_TX_FLUSH;
-       spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
-
        list_for_each_entry_safe(tx_buf, tx_buf_tmp,
                                 &hif_dev->tx.tx_pending, list) {
                usb_kill_urb(tx_buf->urb);
@@ -570,10 +572,6 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
                kfree(tx_buf->buf);
                kfree(tx_buf);
        }
-
-       spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
-       hif_dev->tx.flags &= ~HIF_USB_TX_FLUSH;
-       spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 }
 
 static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
@@ -897,6 +895,26 @@ err_alloc:
        return ret;
 }
 
+static void ath9k_hif_usb_reboot(struct usb_device *udev)
+{
+       u32 reboot_cmd = 0xffffffff;
+       void *buf;
+       int ret;
+
+       buf = kmalloc(4, GFP_KERNEL);
+       if (!buf)
+               return;
+
+       memcpy(buf, &reboot_cmd, 4);
+
+       ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, USB_REG_OUT_PIPE),
+                          buf, 4, NULL, HZ);
+       if (ret)
+               dev_err(&udev->dev, "ath9k_htc: USB reboot failed\n");
+
+       kfree(buf);
+}
+
 static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
 {
        struct usb_device *udev = interface_to_usbdev(interface);
@@ -904,14 +922,15 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
                (struct hif_device_usb *) usb_get_intfdata(interface);
 
        if (hif_dev) {
-               ath9k_htc_hw_deinit(hif_dev->htc_handle, true);
+               ath9k_htc_hw_deinit(hif_dev->htc_handle,
+                   (udev->state == USB_STATE_NOTATTACHED) ? true : false);
                ath9k_htc_hw_free(hif_dev->htc_handle);
                ath9k_hif_usb_dev_deinit(hif_dev);
                usb_set_intfdata(interface, NULL);
        }
 
        if (hif_dev->flags & HIF_USB_START)
-               usb_reset_device(udev);
+               ath9k_hif_usb_reboot(udev);
 
        kfree(hif_dev);
        dev_info(&udev->dev, "ath9k_htc: USB layer deinitialized\n");
index 7d49a8af420ebdffae103eb4899660a83b306c24..0aca49b6fcb68d33745dfeb3edcba3333c381b4d 100644 (file)
@@ -61,7 +61,6 @@ struct tx_buf {
 };
 
 #define HIF_USB_TX_STOP  BIT(0)
-#define HIF_USB_TX_FLUSH BIT(1)
 
 struct hif_usb_tx {
        u8 flags;
index c765ff4a505c54ea265b423c83d3dc1b752ddb3d..1ae18bbc4d9e54afe33109b786cbf6ed193fc5e2 100644 (file)
@@ -329,6 +329,7 @@ struct htc_beacon_config {
 #define OP_ASSOCIATED     BIT(8)
 #define OP_ENABLE_BEACON  BIT(9)
 #define OP_LED_DEINIT     BIT(10)
+#define OP_UNPLUGGED      BIT(11)
 
 struct ath9k_htc_priv {
        struct device *dev;
@@ -378,6 +379,7 @@ struct ath9k_htc_priv {
        struct mutex htc_pm_lock;
        unsigned long ps_usecount;
        bool ps_enabled;
+       bool ps_idle;
 
        struct ath_led radio_led;
        struct ath_led assoc_led;
index a86189629d92bd41f310803270ff4ecb2f6066e9..701f2ef5a440724f21a43b85e49600b302941030 100644 (file)
@@ -744,6 +744,9 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
        if (ret)
                goto err_init;
 
+       /* The device may have been unplugged earlier. */
+       priv->op_flags &= ~OP_UNPLUGGED;
+
        ret = ath9k_init_device(priv, devid);
        if (ret)
                goto err_init;
@@ -760,6 +763,11 @@ err_free:
 void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug)
 {
        if (htc_handle->drv_priv) {
+
+               /* Check if the device has been yanked out. */
+               if (hotunplug)
+                       htc_handle->drv_priv->op_flags |= OP_UNPLUGGED;
+
                ath9k_deinit_device(htc_handle->drv_priv);
                ath9k_deinit_wmi(htc_handle->drv_priv);
                ieee80211_free_hw(htc_handle->drv_priv->hw);
index ec7bcc8696ecf257f420085b16f75c8560be75ef..ca7f3a78eb112392b75e9111da28b9f4a3fe1330 100644 (file)
@@ -94,8 +94,11 @@ void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv)
        if (--priv->ps_usecount != 0)
                goto unlock;
 
-       if (priv->ps_enabled)
+       if (priv->ps_idle)
+               ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP);
+       else if (priv->ps_enabled)
                ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP);
+
 unlock:
        mutex_unlock(&priv->htc_pm_lock);
 }
@@ -153,7 +156,6 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
                ath_print(common, ATH_DBG_FATAL,
                          "Unable to reset channel (%u Mhz) "
                          "reset status %d\n", channel->center_freq, ret);
-               ath9k_htc_ps_restore(priv);
                goto err;
        }
 
@@ -1097,7 +1099,7 @@ fail_tx:
        return 0;
 }
 
-static int ath9k_htc_start(struct ieee80211_hw *hw)
+static int ath9k_htc_radio_enable(struct ieee80211_hw *hw)
 {
        struct ath9k_htc_priv *priv = hw->priv;
        struct ath_hw *ah = priv->ah;
@@ -1113,8 +1115,6 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
                  "Starting driver with initial channel: %d MHz\n",
                  curchan->center_freq);
 
-       mutex_lock(&priv->mutex);
-
        /* setup initial channel */
        init_channel = ath9k_cmn_get_curchannel(hw, ah);
 
@@ -1127,7 +1127,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
                ath_print(common, ATH_DBG_FATAL,
                          "Unable to reset hardware; reset status %d "
                          "(freq %u MHz)\n", ret, curchan->center_freq);
-               goto mutex_unlock;
+               return ret;
        }
 
        ath_update_txpow(priv);
@@ -1135,16 +1135,8 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
        mode = ath9k_htc_get_curmode(priv, init_channel);
        htc_mode = cpu_to_be16(mode);
        WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
-       if (ret)
-               goto mutex_unlock;
-
        WMI_CMD(WMI_ATH_INIT_CMDID);
-       if (ret)
-               goto mutex_unlock;
-
        WMI_CMD(WMI_START_RECV_CMDID);
-       if (ret)
-               goto mutex_unlock;
 
        ath9k_host_rx_init(priv);
 
@@ -1157,12 +1149,22 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
 
        ieee80211_wake_queues(hw);
 
-mutex_unlock:
+       return ret;
+}
+
+static int ath9k_htc_start(struct ieee80211_hw *hw)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       int ret = 0;
+
+       mutex_lock(&priv->mutex);
+       ret = ath9k_htc_radio_enable(hw);
        mutex_unlock(&priv->mutex);
+
        return ret;
 }
 
-static void ath9k_htc_stop(struct ieee80211_hw *hw)
+static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
 {
        struct ath9k_htc_priv *priv = hw->priv;
        struct ath_hw *ah = priv->ah;
@@ -1170,14 +1172,18 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
        int ret = 0;
        u8 cmd_rsp;
 
-       mutex_lock(&priv->mutex);
-
        if (priv->op_flags & OP_INVALID) {
                ath_print(common, ATH_DBG_ANY, "Device not present\n");
-               mutex_unlock(&priv->mutex);
                return;
        }
 
+       /* Cancel all the running timers/work .. */
+       cancel_work_sync(&priv->ps_work);
+       cancel_delayed_work_sync(&priv->ath9k_ani_work);
+       cancel_delayed_work_sync(&priv->ath9k_aggr_work);
+       cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
+       ath9k_led_stop_brightness(priv);
+
        ath9k_htc_ps_wakeup(priv);
        htc_stop(priv->htc);
        WMI_CMD(WMI_DISABLE_INTR_CMDID);
@@ -1189,11 +1195,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
        ath9k_htc_ps_restore(priv);
        ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
 
-       cancel_work_sync(&priv->ps_work);
-       cancel_delayed_work_sync(&priv->ath9k_ani_work);
-       cancel_delayed_work_sync(&priv->ath9k_aggr_work);
-       cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
-       ath9k_led_stop_brightness(priv);
        skb_queue_purge(&priv->tx_queue);
 
        /* Remove monitor interface here */
@@ -1207,11 +1208,20 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
        }
 
        priv->op_flags |= OP_INVALID;
-       mutex_unlock(&priv->mutex);
 
        ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
 }
 
+static void ath9k_htc_stop(struct ieee80211_hw *hw)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+
+       mutex_lock(&priv->mutex);
+       ath9k_htc_radio_disable(hw);
+       mutex_unlock(&priv->mutex);
+}
+
+
 static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif)
 {
@@ -1325,6 +1335,23 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
 
        mutex_lock(&priv->mutex);
 
+       if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+               bool enable_radio = false;
+               bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
+
+               if (!idle && priv->ps_idle)
+                       enable_radio = true;
+
+               priv->ps_idle = idle;
+
+               if (enable_radio) {
+                       ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+                       ath9k_htc_radio_enable(hw);
+                       ath_print(common, ATH_DBG_CONFIG,
+                                 "not-idle: enabling radio\n");
+               }
+       }
+
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
                struct ieee80211_channel *curchan = hw->conf.channel;
                int pos = curchan->hw_value;
@@ -1368,6 +1395,13 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
                }
        }
 
+       if (priv->ps_idle) {
+               ath_print(common, ATH_DBG_CONFIG,
+                         "idle: disabling radio\n");
+               ath9k_htc_radio_disable(hw);
+       }
+
+
        mutex_unlock(&priv->mutex);
 
        return 0;
index 2c3c51007dd362908ac8e0ec60191ef718c67277..28abc7d5e90970532ebaf02523026d1d74aaaed5 100644 (file)
@@ -244,16 +244,25 @@ 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;
 
        if (!skb)
                return;
 
-       if (ep_id == priv->mgmt_ep)
+       if (ep_id == priv->mgmt_ep) {
                skb_pull(skb, sizeof(struct tx_mgmt_hdr));
-       else
-               /* TODO: Check for cab/uapsd/data */
+       } 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_print(common, ATH_DBG_FATAL,
+                         "Unsupported TX EPID: %d\n", ep_id);
+               dev_kfree_skb_any(skb);
+               return;
+       }
 
        tx_info = IEEE80211_SKB_CB(skb);
 
@@ -439,10 +448,32 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
        struct ieee80211_hw *hw = priv->hw;
        struct sk_buff *skb = rxbuf->skb;
        struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath_htc_rx_status *rxstatus;
        int hdrlen, padpos, padsize;
        int last_rssi = ATH_RSSI_DUMMY_MARKER;
        __le16 fc;
 
+       if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Corrupted RX frame, dropping\n");
+               goto rx_next;
+       }
+
+       rxstatus = (struct ath_htc_rx_status *)skb->data;
+
+       if (be16_to_cpu(rxstatus->rs_datalen) -
+           (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Corrupted RX data len, dropping "
+                         "(dlen: %d, skblen: %d)\n",
+                         rxstatus->rs_datalen, skb->len);
+               goto rx_next;
+       }
+
+       /* Get the RX status information */
+       memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
+       skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
+
        hdr = (struct ieee80211_hdr *)skb->data;
        fc = hdr->frame_control;
        hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -607,8 +638,6 @@ void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb,
        struct ath_hw *ah = priv->ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL;
-       struct ath_htc_rx_status *rxstatus;
-       u32 len = 0;
 
        spin_lock(&priv->rx.rxbuflock);
        list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) {
@@ -625,27 +654,7 @@ void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb,
                goto err;
        }
 
-       len = skb->len;
-       if (len <= HTC_RX_FRAME_HEADER_SIZE) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Corrupted RX frame, dropping\n");
-               goto err;
-       }
-
-       rxstatus = (struct ath_htc_rx_status *)skb->data;
-
-       if (be16_to_cpu(rxstatus->rs_datalen) -
-           (len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Corrupted RX data len, dropping "
-                         "(epid: %d, dlen: %d, skblen: %d)\n",
-                         ep_id, rxstatus->rs_datalen, len);
-               goto err;
-       }
-
        spin_lock(&priv->rx.rxbuflock);
-       memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
-       skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
        rxbuf->skb = skb;
        rxbuf->in_process = true;
        spin_unlock(&priv->rx.rxbuflock);
index f2dca258bdc2b520b8aedd66e87a15f0baf556f5..7bf6ce1e7e2e6d9e7593d31c9982e92aeb6ebef4 100644 (file)
@@ -341,8 +341,9 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
                skb_pull(skb, sizeof(struct htc_frame_hdr));
 
                if (endpoint->ep_callbacks.tx) {
-                       endpoint->ep_callbacks.tx(htc_handle->drv_priv, skb,
-                                                 htc_hdr->endpoint_id, txok);
+                       endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv,
+                                                 skb, htc_hdr->endpoint_id,
+                                                 txok);
                }
        }
 
index 5a29048db3b192c496d3a5507961fe2ed7e5be94..559019262d30202efd274a806f777a88132e703f 100644 (file)
@@ -26,6 +26,7 @@
 #define ATH9K_CLOCK_RATE_CCK           22
 #define ATH9K_CLOCK_RATE_5GHZ_OFDM     40
 #define ATH9K_CLOCK_RATE_2GHZ_OFDM     44
+#define ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM 44
 
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
 
@@ -91,7 +92,11 @@ static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs)
                return usecs *ATH9K_CLOCK_RATE_CCK;
        if (conf->channel->band == IEEE80211_BAND_2GHZ)
                return usecs *ATH9K_CLOCK_RATE_2GHZ_OFDM;
-       return usecs *ATH9K_CLOCK_RATE_5GHZ_OFDM;
+
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)
+               return usecs * ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;
+       else
+               return usecs * ATH9K_CLOCK_RATE_5GHZ_OFDM;
 }
 
 static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
@@ -386,6 +391,12 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
 
        ah->config.rx_intr_mitigation = true;
 
+       /*
+        * Tx IQ Calibration (ah->config.tx_iq_calibration) is only
+        * used by AR9003, but it is showing reliability issues.
+        * It will take a while to fix so this is currently disabled.
+        */
+
        /*
         * We need this for PCI devices only (Cardbus, PCI, miniPCI)
         * _and_ if on non-uniprocessor systems (Multiprocessor/HT).
@@ -819,9 +830,6 @@ void ath9k_hw_deinit(struct ath_hw *ah)
        if (common->state < ATH_HW_INITIALIZED)
                goto free_hw;
 
-       if (!AR_SREV_9100(ah))
-               ath9k_hw_ani_disable(ah);
-
        ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
 
 free_hw:
@@ -1221,8 +1229,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
            (chan->channel != ah->curchan->channel) &&
            ((chan->channelFlags & CHANNEL_ALL) ==
             (ah->curchan->channelFlags & CHANNEL_ALL)) &&
-            !(AR_SREV_9280(ah) || IS_CHAN_A_5MHZ_SPACED(chan) ||
-            IS_CHAN_A_5MHZ_SPACED(ah->curchan))) {
+           !AR_SREV_9280(ah)) {
 
                if (ath9k_hw_channel_change(ah, chan)) {
                        ath9k_hw_loadnf(ah, ah->curchan);
@@ -2186,7 +2193,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
        }
 
        if (AR_SREV_9300_20_OR_LATER(ah)) {
-               pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_LDPC;
+               pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_LDPC |
+                                ATH9K_HW_CAP_FASTCLOCK;
                pCap->rx_hp_qdepth = ATH9K_HW_RX_HP_QDEPTH;
                pCap->rx_lp_qdepth = ATH9K_HW_RX_LP_QDEPTH;
                pCap->rx_status_len = sizeof(struct ar9003_rxs);
@@ -2194,6 +2202,11 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                pCap->txs_len = sizeof(struct ar9003_txs);
        } else {
                pCap->tx_desc_len = sizeof(struct ath_desc);
+               if (AR_SREV_9280_20(ah) &&
+                   ((ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) <=
+                     AR5416_EEP_MINOR_VER_16) ||
+                    ah->eep_ops->get_eeprom(ah, EEP_FSTCLK_5G)))
+                       pCap->hw_caps |= ATH9K_HW_CAP_FASTCLOCK;
        }
 
        if (AR_SREV_9300_20_OR_LATER(ah))
index a78e09bab431225bd438db738d95dc34e979a8e1..77245dff599358e5070c92293df0dc97d2f1bd1f 100644 (file)
@@ -198,6 +198,7 @@ enum ath9k_hw_caps {
        ATH9K_HW_CAP_EDMA                       = BIT(17),
        ATH9K_HW_CAP_RAC_SUPPORTED              = BIT(18),
        ATH9K_HW_CAP_LDPC                       = BIT(19),
+       ATH9K_HW_CAP_FASTCLOCK                  = BIT(20),
 };
 
 enum ath9k_capability_type {
@@ -261,6 +262,7 @@ struct ath9k_ops_config {
 #define AR_BASE_FREQ_5GHZ      4900
 #define AR_SPUR_FEEQ_BOUND_HT40 19
 #define AR_SPUR_FEEQ_BOUND_HT20 10
+       bool tx_iq_calibration; /* Only available for >= AR9003 */
        int spurmode;
        u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
        u8 max_txtrig_level;
@@ -367,10 +369,9 @@ struct ath9k_channel {
 #define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
 #define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0)
 #define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
-#define IS_CHAN_A_5MHZ_SPACED(_c)                      \
+#define IS_CHAN_A_FAST_CLOCK(_ah, _c)                  \
        ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) &&  \
-        (((_c)->channel % 20) != 0) &&                 \
-        (((_c)->channel % 10) != 0))
+        ((_ah)->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK))
 
 /* These macros check chanmode and not channelFlags */
 #define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B)
@@ -718,6 +719,7 @@ struct ath_hw {
        u32 *addac5416_21;
        u32 *bank6Temp;
 
+       u8 txpower_limit;
        int16_t txpower_indexoffset;
        int coverage_class;
        u32 beacon_interval;
index 7bbf502563bc046e7863ad26613d435d054d0c05..0e425cb4bbb1b9b8fb189d17792c9758babb1bd1 100644 (file)
@@ -878,10 +878,12 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah,
        if (ints & ATH9K_INT_TX) {
                if (ah->config.tx_intr_mitigation)
                        mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM;
-               if (ah->txok_interrupt_mask)
-                       mask |= AR_IMR_TXOK;
-               if (ah->txdesc_interrupt_mask)
-                       mask |= AR_IMR_TXDESC;
+               else {
+                       if (ah->txok_interrupt_mask)
+                               mask |= AR_IMR_TXOK;
+                       if (ah->txdesc_interrupt_mask)
+                               mask |= AR_IMR_TXDESC;
+               }
                if (ah->txerr_interrupt_mask)
                        mask |= AR_IMR_TXERR;
                if (ah->txeol_interrupt_mask)
index aad370a7f95b782049fc11b05277c48538ea0944..893b552981a07494413288064dd9601be1e3373e 100644 (file)
@@ -2044,6 +2044,25 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
        return ret;
 }
 
+static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
+                            struct survey_info *survey)
+{
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ieee80211_conf *conf = &hw->conf;
+
+        if (idx != 0)
+               return -ENOENT;
+
+       survey->channel = conf->channel;
+       survey->filled = SURVEY_INFO_NOISE_DBM;
+       survey->noise = common->ani.noise_floor;
+
+       return 0;
+}
+
 static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 {
        struct ath_wiphy *aphy = hw->priv;
@@ -2115,6 +2134,7 @@ struct ieee80211_ops ath9k_ops = {
        .set_tsf            = ath9k_set_tsf,
        .reset_tsf          = ath9k_reset_tsf,
        .ampdu_action       = ath9k_ampdu_action,
+       .get_survey         = ath9k_get_survey,
        .sw_scan_start      = ath9k_sw_scan_start,
        .sw_scan_complete   = ath9k_sw_scan_complete,
        .rfkill_poll        = ath9k_rfkill_poll_state,
index dc6c6fc2e095bcdf8d01a3eaaf55b5957ecb5e97..e23172c9caaf1e038a2ee0b91556c008062030cc 100644 (file)
@@ -276,6 +276,9 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
        int time_left, ret = 0;
        unsigned long flags;
 
+       if (wmi->drv_priv->op_flags & OP_UNPLUGGED)
+               return 0;
+
        if (!wmi)
                return -EINVAL;
 
@@ -302,14 +305,14 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
        wmi->cmd_rsp_buf = rsp_buf;
        wmi->cmd_rsp_len = rsp_len;
 
-       ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len);
-       if (ret)
-               goto out;
-
        spin_lock_irqsave(&wmi->wmi_lock, flags);
        wmi->last_cmd_id = cmd_id;
        spin_unlock_irqrestore(&wmi->wmi_lock, flags);
 
+       ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len);
+       if (ret)
+               goto out;
+
        time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout);
        if (!time_left) {
                ath_print(common, ATH_DBG_WMI,
index 167e15c500627426ff46d21752c9dae8e30a2104..765db5faa2d3d01291f790680bb87ca76bc8736d 100644 (file)
@@ -126,14 +126,14 @@ void ath9k_wmi_tasklet(unsigned long data);
        do {                                                            \
                ret = ath9k_wmi_cmd(priv->wmi, _wmi_cmd, NULL, 0,       \
                                    (u8 *) &cmd_rsp,                    \
-                                   sizeof(cmd_rsp), HZ);               \
+                                   sizeof(cmd_rsp), HZ*2);             \
        } while (0)
 
 #define WMI_CMD_BUF(_wmi_cmd, _buf)                                    \
        do {                                                            \
                ret = ath9k_wmi_cmd(priv->wmi, _wmi_cmd,                \
                                    (u8 *) _buf, sizeof(*_buf),         \
-                                   &cmd_rsp, sizeof(cmd_rsp), HZ);     \
+                                   &cmd_rsp, sizeof(cmd_rsp), HZ*2);   \
        } while (0)
 
 #endif /* WMI_H */
index b0d345a675fe6f23f5e150c6c97f85e767197ba9..3db19172b43b7a1aa165e68463fabaf71dd4d278 100644 (file)
@@ -2290,6 +2290,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
                        ath_tx_complete_buf(sc, bf, txq, &bf_head,
                                            &txs, txok, 0);
 
+               ath_wake_mac80211_queue(sc, txq);
+
                spin_lock_bh(&txq->axq_lock);
                if (!list_empty(&txq->txq_fifo_pending)) {
                        INIT_LIST_HEAD(&bf_head);
index 997303bcf4ae81dd441f2f49750a10bedff4af6a..7965b70efbab5de2d1149eda5eba68f0bd871a9b 100644 (file)
@@ -4571,6 +4571,23 @@ static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw)
        mutex_unlock(&wl->mutex);
 }
 
+static int b43_op_get_survey(struct ieee80211_hw *hw, int idx,
+                            struct survey_info *survey)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct b43_wldev *dev = wl->current_dev;
+       struct ieee80211_conf *conf = &hw->conf;
+
+       if (idx != 0)
+               return -ENOENT;
+
+       survey->channel = conf->channel;
+       survey->filled = SURVEY_INFO_NOISE_DBM;
+       survey->noise = dev->stats.link_noise;
+
+       return 0;
+}
+
 static const struct ieee80211_ops b43_hw_ops = {
        .tx                     = b43_op_tx,
        .conf_tx                = b43_op_conf_tx,
@@ -4590,6 +4607,7 @@ static const struct ieee80211_ops b43_hw_ops = {
        .sta_notify             = b43_op_sta_notify,
        .sw_scan_start          = b43_op_sw_scan_start_notifier,
        .sw_scan_complete       = b43_op_sw_scan_complete_notifier,
+       .get_survey             = b43_op_get_survey,
        .rfkill_poll            = b43_rfkill_poll,
 };
 
@@ -4905,8 +4923,7 @@ static int b43_wireless_init(struct ssb_device *dev)
 
        /* fill hw info */
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-                   IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_NOISE_DBM;
+                   IEEE80211_HW_SIGNAL_DBM;
 
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_AP) |
index eda06529ef5f493384179272216af98b8e420ab5..e6b0528f3b52a31d38fb2c93e3a609f1eae14d2e 100644 (file)
@@ -610,7 +610,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
        }
 
        /* Link quality statistics */
-       status.noise = dev->stats.link_noise;
        if ((chanstat & B43_RX_CHAN_PHYTYPE) == B43_PHYTYPE_N) {
 //             s8 rssi = max(rxhdr->power0, rxhdr->power1);
                //TODO: Find out what the rssi value is (dBm or percentage?)
index bb2dd9329aa0fd88ff7f7b2dc85d841e1a193209..1713f5f7a58b0571c57876cdee4ac6b4f4b63019 100644 (file)
@@ -3482,6 +3482,23 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
        return 0;
 }
 
+static int b43legacy_op_get_survey(struct ieee80211_hw *hw, int idx,
+                                  struct survey_info *survey)
+{
+       struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+       struct b43legacy_wldev *dev = wl->current_dev;
+       struct ieee80211_conf *conf = &hw->conf;
+
+       if (idx != 0)
+               return -ENOENT;
+
+       survey->channel = conf->channel;
+       survey->filled = SURVEY_INFO_NOISE_DBM;
+       survey->noise = dev->stats.link_noise;
+
+       return 0;
+}
+
 static const struct ieee80211_ops b43legacy_hw_ops = {
        .tx                     = b43legacy_op_tx,
        .conf_tx                = b43legacy_op_conf_tx,
@@ -3494,6 +3511,7 @@ static const struct ieee80211_ops b43legacy_hw_ops = {
        .start                  = b43legacy_op_start,
        .stop                   = b43legacy_op_stop,
        .set_tim                = b43legacy_op_beacon_set_tim,
+       .get_survey             = b43legacy_op_get_survey,
        .rfkill_poll            = b43legacy_rfkill_poll,
 };
 
@@ -3769,8 +3787,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
 
        /* fill hw info */
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-                   IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_NOISE_DBM;
+                   IEEE80211_HW_SIGNAL_DBM;
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_AP) |
                BIT(NL80211_IFTYPE_STATION) |
index 9c8882d9275edf203ee11a4c975d9c6d815d4ee1..7d177d97f1f7ff82803ed6dbbeabd4ce3bdb594f 100644 (file)
@@ -548,7 +548,6 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
                                      (phystat0 & B43legacy_RX_PHYST0_OFDM),
                                      (phystat0 & B43legacy_RX_PHYST0_GAINCTL),
                                      (phystat3 & B43legacy_RX_PHYST3_TRSTATE));
-       status.noise = dev->stats.link_noise;
        /* change to support A PHY */
        if (phystat0 & B43legacy_RX_PHYST0_OFDM)
                status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false);
index 5ed2dcbe6d01bbb0dc4c87b9d34a04b185dddf4f..7c7235385513b8464c22aca463f76ab549bb9b25 100644 (file)
@@ -22,5 +22,6 @@ iwlagn-$(CONFIG_IWL5000) += iwl-1000.o
 # 3945
 obj-$(CONFIG_IWL3945)  += iwl3945.o
 iwl3945-objs           := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o
+iwl3945-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-3945-debugfs.o
 
 ccflags-y += -D__CHECK_ENDIAN__
index 8431ffce37d3e8cea51bf24df3aeeb4e0d56f324..fb59af2d41c68c435c14109da5b96d09f9c19f9e 100644 (file)
@@ -282,7 +282,6 @@ struct iwl_cfg iwl1000_bg_cfg = {
        .use_bsm = false,
        .max_ll_items = OTP_MAX_LL_ITEMS_1000,
        .shadow_ram_support = false,
-       .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .support_ct_kill_exit = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
new file mode 100644 (file)
index 0000000..6a9c64a
--- /dev/null
@@ -0,0 +1,500 @@
+/******************************************************************************
+ *
+ * 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 <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+#include "iwl-3945-debugfs.h"
+
+ssize_t iwl3945_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 iwl39_statistics_rx_phy) * 40 +
+                   sizeof(struct iwl39_statistics_rx_non_phy) * 40 + 400;
+       ssize_t ret;
+       struct iwl39_statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
+       struct iwl39_statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
+       struct iwl39_statistics_rx_non_phy *general, *accum_general;
+       struct iwl39_statistics_rx_non_phy *delta_general, *max_general;
+
+       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->_3945.statistics.rx.ofdm;
+       cck = &priv->_3945.statistics.rx.cck;
+       general = &priv->_3945.statistics.rx.general;
+       accum_ofdm = &priv->_3945.accum_statistics.rx.ofdm;
+       accum_cck = &priv->_3945.accum_statistics.rx.cck;
+       accum_general = &priv->_3945.accum_statistics.rx.general;
+       delta_ofdm = &priv->_3945.delta_statistics.rx.ofdm;
+       delta_cck = &priv->_3945.delta_statistics.rx.cck;
+       delta_general = &priv->_3945.delta_statistics.rx.general;
+       max_ofdm = &priv->_3945.max_delta.rx.ofdm;
+       max_cck = &priv->_3945.max_delta.rx.cck;
+       max_general = &priv->_3945.max_delta.rx.general;
+
+       pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Rx - OFDM:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",  "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Rx - CCK:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Rx - GENERAL:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+ssize_t iwl3945_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 iwl39_statistics_tx) * 48) + 250;
+       ssize_t ret;
+       struct iwl39_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->_3945.statistics.tx;
+       accum_tx = &priv->_3945.accum_statistics.tx;
+       delta_tx = &priv->_3945.delta_statistics.tx;
+       max_tx = &priv->_3945.max_delta.tx;
+       pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Tx:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+ssize_t iwl3945_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 iwl39_statistics_general) * 10 + 300;
+       ssize_t ret;
+       struct iwl39_statistics_general *general, *accum_general;
+       struct iwl39_statistics_general *delta_general, *max_general;
+       struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
+       struct iwl39_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->_3945.statistics.general;
+       dbg = &priv->_3945.statistics.general.dbg;
+       div = &priv->_3945.statistics.general.div;
+       accum_general = &priv->_3945.accum_statistics.general;
+       delta_general = &priv->_3945.delta_statistics.general;
+       max_general = &priv->_3945.max_delta.general;
+       accum_dbg = &priv->_3945.accum_statistics.general.dbg;
+       delta_dbg = &priv->_3945.delta_statistics.general.dbg;
+       max_dbg = &priv->_3945.max_delta.general.dbg;
+       accum_div = &priv->_3945.accum_statistics.general.div;
+       delta_div = &priv->_3945.delta_statistics.general.div;
+       max_div = &priv->_3945.max_delta.general.div;
+       pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_General:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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, "ttl_timestamp:\t\t\t%u\n",
+                        le32_to_cpu(general->ttl_timestamp));
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "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,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "probe_time:",
+                        le32_to_cpu(div->probe_time), accum_div->probe_time,
+                        delta_div->probe_time, max_div->probe_time);
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h
new file mode 100644 (file)
index 0000000..70809c5
--- /dev/null
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * 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 <ilw@linux.intel.com>
+ * 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 iwl3945_ucode_rx_stats_read(struct file *file, char __user *user_buf,
+                                   size_t count, loff_t *ppos);
+ssize_t iwl3945_ucode_tx_stats_read(struct file *file, char __user *user_buf,
+                                   size_t count, loff_t *ppos);
+ssize_t iwl3945_ucode_general_stats_read(struct file *file,
+                                        char __user *user_buf, size_t count,
+                                        loff_t *ppos);
+#else
+static ssize_t iwl3945_ucode_rx_stats_read(struct file *file,
+                                          char __user *user_buf, size_t count,
+                                          loff_t *ppos)
+{
+       return 0;
+}
+static ssize_t iwl3945_ucode_tx_stats_read(struct file *file,
+                                          char __user *user_buf, size_t count,
+                                          loff_t *ppos)
+{
+       return 0;
+}
+static ssize_t iwl3945_ucode_general_stats_read(struct file *file,
+                                               char __user *user_buf,
+                                               size_t count, loff_t *ppos)
+{
+       return 0;
+}
+#endif
index 59af2594c9c5a5e1842643c26a838e0b17beba4a..17197a78d894949407b2c76ef1b9897c76756aef 100644 (file)
@@ -50,6 +50,7 @@
 #include "iwl-helpers.h"
 #include "iwl-led.h"
 #include "iwl-3945-led.h"
+#include "iwl-3945-debugfs.h"
 
 #define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \
        [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,   \
@@ -293,7 +294,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
  * iwl3945_rx_reply_tx - Handle Tx response
  */
 static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
-                           struct iwl_rx_mem_buffer *rxb)
+                               struct iwl_rx_mem_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
@@ -351,18 +352,81 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
  *  RX handler implementations
  *
  *****************************************************************************/
+#ifdef CONFIG_IWLWIFI_DEBUG
+/*
+ *  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 iwl3945_accumulative_statistics(struct iwl_priv *priv,
+                                           __le32 *stats)
+{
+       int i;
+       __le32 *prev_stats;
+       u32 *accum_stats;
+       u32 *delta, *max_delta;
+
+       prev_stats = (__le32 *)&priv->_3945.statistics;
+       accum_stats = (u32 *)&priv->_3945.accum_statistics;
+       delta = (u32 *)&priv->_3945.delta_statistics;
+       max_delta = (u32 *)&priv->_3945.max_delta;
+
+       for (i = sizeof(__le32); i < sizeof(struct iwl3945_notif_statistics);
+            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)
+                               *max_delta = *delta;
+               }
+       }
+
+       /* reset accumulative statistics for "no-counter" type statistics */
+       priv->_3945.accum_statistics.general.temperature =
+               priv->_3945.statistics.general.temperature;
+       priv->_3945.accum_statistics.general.ttl_timestamp =
+               priv->_3945.statistics.general.ttl_timestamp;
+}
+#endif
 
 void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
                struct iwl_rx_mem_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
        IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
                     (int)sizeof(struct iwl3945_notif_statistics),
                     le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
+#ifdef CONFIG_IWLWIFI_DEBUG
+       iwl3945_accumulative_statistics(priv, (__le32 *)&pkt->u.raw);
+#endif
 
        memcpy(&priv->_3945.statistics, pkt->u.raw, sizeof(priv->_3945.statistics));
 }
 
+void iwl3945_reply_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       __le32 *flag = (__le32 *)&pkt->u.raw;
+
+       if (le32_to_cpu(*flag) & UCODE_STATISTICS_CLEAR_MSK) {
+#ifdef CONFIG_IWLWIFI_DEBUG
+               memset(&priv->_3945.accum_statistics, 0,
+                       sizeof(struct iwl3945_notif_statistics));
+               memset(&priv->_3945.delta_statistics, 0,
+                       sizeof(struct iwl3945_notif_statistics));
+               memset(&priv->_3945.max_delta, 0,
+                       sizeof(struct iwl3945_notif_statistics));
+#endif
+               IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
+       }
+       iwl3945_hw_rx_statistics(priv, rxb);
+}
+
+
 /******************************************************************************
  *
  * Misc. internal state and helper functions
@@ -2736,6 +2800,12 @@ static struct iwl_lib_ops iwl3945_lib = {
        .isr = iwl_isr_legacy,
        .config_ap = iwl3945_config_ap,
        .add_bcast_station = iwl3945_add_bcast_station,
+
+       .debugfs_ops = {
+               .rx_stats_read = iwl3945_ucode_rx_stats_read,
+               .tx_stats_read = iwl3945_ucode_tx_stats_read,
+               .general_stats_read = iwl3945_ucode_general_stats_read,
+       },
 };
 
 static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
index e9674f0a1e949c379b043d4ee5da6c31ee2ccd2e..643adb644bb8a8378723994a21b042f2c43788ef 100644 (file)
@@ -264,6 +264,8 @@ extern int iwl3945_hw_reg_send_txpower(struct iwl_priv *priv);
 extern int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
 extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
                                 struct iwl_rx_mem_buffer *rxb);
+void iwl3945_reply_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb);
 extern void iwl3945_disable_events(struct iwl_priv *priv);
 extern int iwl4965_get_temperature(const struct iwl_priv *priv);
 extern void iwl3945_post_associate(struct iwl_priv *priv);
index e434936852714599d9eee6c67fb082cc5ad97d06..115d3ea1142f364d79865dc9fa22c012bc29662a 100644 (file)
@@ -200,26 +200,57 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 
        /* Set initial sensitivity parameters */
        /* Set initial calibration set */
-       switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
-       case CSR_HW_REV_TYPE_5150:
-               priv->hw_params.sens = &iwl5150_sensitivity;
-               priv->hw_params.calib_init_cfg =
-                       BIT(IWL_CALIB_DC)               |
-                       BIT(IWL_CALIB_LO)               |
-                       BIT(IWL_CALIB_TX_IQ)            |
-                       BIT(IWL_CALIB_BASE_BAND);
-
-               break;
-       default:
-               priv->hw_params.sens = &iwl5000_sensitivity;
-               priv->hw_params.calib_init_cfg =
-                       BIT(IWL_CALIB_XTAL)             |
-                       BIT(IWL_CALIB_LO)               |
-                       BIT(IWL_CALIB_TX_IQ)            |
-                       BIT(IWL_CALIB_TX_IQ_PERD)       |
-                       BIT(IWL_CALIB_BASE_BAND);
-               break;
-       }
+       priv->hw_params.sens = &iwl5000_sensitivity;
+       priv->hw_params.calib_init_cfg =
+               BIT(IWL_CALIB_XTAL)             |
+               BIT(IWL_CALIB_LO)               |
+               BIT(IWL_CALIB_TX_IQ)            |
+               BIT(IWL_CALIB_TX_IQ_PERD)       |
+               BIT(IWL_CALIB_BASE_BAND);
+
+       return 0;
+}
+
+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)
+               priv->cfg->num_of_queues =
+                       priv->cfg->mod_params->num_of_queues;
+
+       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+       priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
+       priv->hw_params.scd_bc_tbls_size =
+                       priv->cfg->num_of_queues *
+                       sizeof(struct iwlagn_scd_bc_tbl);
+       priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
+       priv->hw_params.max_stations = IWL5000_STATION_COUNT;
+       priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+
+       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;
+
+       priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+       priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+       priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
+       priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
+
+       if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
+               priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+
+       /* Set initial sensitivity parameters */
+       /* Set initial calibration set */
+       priv->hw_params.sens = &iwl5150_sensitivity;
+       priv->hw_params.calib_init_cfg =
+               BIT(IWL_CALIB_DC)               |
+               BIT(IWL_CALIB_LO)               |
+               BIT(IWL_CALIB_TX_IQ)            |
+               BIT(IWL_CALIB_BASE_BAND);
 
        return 0;
 }
@@ -332,7 +363,7 @@ static struct iwl_lib_ops iwl5000_lib = {
 };
 
 static struct iwl_lib_ops iwl5150_lib = {
-       .set_hw_params = iwl5000_hw_set_hw_params,
+       .set_hw_params = iwl5150_hw_set_hw_params,
        .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,
index 7da23d3ff7b65efbf6e4b6563f1fc60a3e5b4959..7acef703253a53ddc33d02a493d02817c63f31b9 100644 (file)
@@ -176,24 +176,56 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
        /* Set initial sensitivity parameters */
        /* Set initial calibration set */
        priv->hw_params.sens = &iwl6000_sensitivity;
-       switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
-       case CSR_HW_REV_TYPE_6x50:
-               priv->hw_params.calib_init_cfg =
-                       BIT(IWL_CALIB_XTAL)             |
-                       BIT(IWL_CALIB_DC)               |
-                       BIT(IWL_CALIB_LO)               |
-                       BIT(IWL_CALIB_TX_IQ)            |
-                       BIT(IWL_CALIB_BASE_BAND);
-
-               break;
-       default:
-               priv->hw_params.calib_init_cfg =
-                       BIT(IWL_CALIB_XTAL)             |
-                       BIT(IWL_CALIB_LO)               |
-                       BIT(IWL_CALIB_TX_IQ)            |
-                       BIT(IWL_CALIB_BASE_BAND);
-               break;
-       }
+       priv->hw_params.calib_init_cfg =
+               BIT(IWL_CALIB_XTAL)             |
+               BIT(IWL_CALIB_LO)               |
+               BIT(IWL_CALIB_TX_IQ)            |
+               BIT(IWL_CALIB_BASE_BAND);
+
+       return 0;
+}
+
+static int iwl6050_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)
+               priv->cfg->num_of_queues =
+                       priv->cfg->mod_params->num_of_queues;
+
+       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+       priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
+       priv->hw_params.scd_bc_tbls_size =
+                       priv->cfg->num_of_queues *
+                       sizeof(struct iwlagn_scd_bc_tbl);
+       priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
+       priv->hw_params.max_stations = IWL5000_STATION_COUNT;
+       priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+
+       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;
+
+       priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+       priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+       priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
+       priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
+
+       if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
+               priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+
+       /* Set initial sensitivity parameters */
+       /* Set initial calibration set */
+       priv->hw_params.sens = &iwl6000_sensitivity;
+       priv->hw_params.calib_init_cfg =
+               BIT(IWL_CALIB_XTAL)             |
+               BIT(IWL_CALIB_DC)               |
+               BIT(IWL_CALIB_LO)               |
+               BIT(IWL_CALIB_TX_IQ)            |
+               BIT(IWL_CALIB_BASE_BAND);
 
        return 0;
 }
@@ -304,7 +336,7 @@ static const struct iwl_ops iwl6000_ops = {
 };
 
 static struct iwl_lib_ops iwl6050_lib = {
-       .set_hw_params = iwl6000_hw_set_hw_params,
+       .set_hw_params = iwl6050_hw_set_hw_params,
        .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,
@@ -468,7 +500,6 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
        .pa_type = IWL_PA_INTERNAL,
        .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
        .shadow_ram_support = true,
-       .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .supports_idle = true,
@@ -501,7 +532,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .pa_type = IWL_PA_INTERNAL,
        .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
        .shadow_ram_support = true,
-       .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .supports_idle = true,
@@ -568,7 +598,6 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .pa_type = IWL_PA_SYSTEM,
        .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
        .shadow_ram_support = true,
-       .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .supports_idle = true,
index 4bd0aecc7713164656db82044df1804323c67666..a27347425968a2de955f5af8694f45f18c676edf 100644 (file)
@@ -1395,16 +1395,29 @@ void iwlagn_request_scan(struct iwl_priv *priv)
                        rate = IWL_RATE_1M_PLCP;
                        rate_flags = RATE_MCS_CCK_MSK;
                }
-               scan->good_CRC_th = 0;
+               scan->good_CRC_th = IWL_GOOD_CRC_TH_DISABLED;
                break;
        case IEEE80211_BAND_5GHZ:
                rate = IWL_RATE_6M_PLCP;
                /*
-                * If active scaning is requested but a certain channel
-                * is marked passive, we can do active scanning if we
-                * detect transmissions.
+                * If active scanning is requested but a certain channel is
+                * marked passive, we can do active scanning if we detect
+                * transmissions.
+                *
+                * There is an issue with some firmware versions that triggers
+                * a sysassert on a "good CRC threshold" of zero (== disabled),
+                * on a radar channel even though this means that we should NOT
+                * send probes.
+                *
+                * The "good CRC threshold" is the number of frames that we
+                * need to receive during our dwell time on a channel before
+                * sending out probes -- setting this to a huge value will
+                * 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.
                 */
-               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH : 0;
+               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+                                               IWL_GOOD_CRC_TH_NEVER;
                break;
        default:
                IWL_WARN(priv, "Invalid scan band count\n");
index 0e6161d7c764e470a8a2cea287c6fb97db0b57a7..bfcac5608d87c9b920da6a76e9ccfa0bef0cffca 100644 (file)
@@ -868,14 +868,14 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
                rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type,
                                &rs_index);
                rs_collect_tx_data(curr_tbl, rs_index,
-                                  info->status.ampdu_ack_len,
-                                  info->status.ampdu_ack_map);
+                                  info->status.ampdu_len,
+                                  info->status.ampdu_ack_len);
 
                /* Update success/fail counts if not searching for new mode */
                if (lq_sta->stay_in_tbl) {
-                       lq_sta->total_success += info->status.ampdu_ack_map;
-                       lq_sta->total_failed += (info->status.ampdu_ack_len -
-                                       info->status.ampdu_ack_map);
+                       lq_sta->total_success += info->status.ampdu_ack_len;
+                       lq_sta->total_failed += (info->status.ampdu_len -
+                                       info->status.ampdu_ack_len);
                }
        } else {
        /*
@@ -2078,10 +2078,12 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        }
        /* Else we have enough samples; calculate estimate of
         * actual average throughput */
-
-       /* Sanity-check TPT calculations */
-       BUG_ON(window->average_tpt != ((window->success_ratio *
-                       tbl->expected_tpt[index] + 64) / 128));
+       if (window->average_tpt != ((window->success_ratio *
+                       tbl->expected_tpt[index] + 64) / 128)) {
+               IWL_ERR(priv, "expected_tpt should have been calculated by now\n");
+               window->average_tpt = ((window->success_ratio *
+                                       tbl->expected_tpt[index] + 64) / 128);
+       }
 
        /* If we are searching for better modulation mode, check success. */
        if (lq_sta->search_better_tbl &&
index 11661fa28f219be6ab34422fbe9dbaafef2a9cac..c2a5c85542bfaf25a2d493f7e5a7da4bc1640086 100644 (file)
@@ -83,6 +83,15 @@ static inline int get_fifo_from_ac(u8 ac)
        return ac_to_fifo[ac];
 }
 
+static inline int get_ac_from_tid(u16 tid)
+{
+       if (likely(tid < ARRAY_SIZE(tid_to_ac)))
+               return tid_to_ac[tid];
+
+       /* no support for TIDs 8-15 yet */
+       return -EINVAL;
+}
+
 static inline int get_fifo_from_tid(u16 tid)
 {
        if (likely(tid < ARRAY_SIZE(tid_to_ac)))
@@ -991,7 +1000,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
        tid_data = &priv->stations[sta_id].tid[tid];
        *ssn = SEQ_TO_SN(tid_data->seq_number);
        tid_data->agg.txq_id = txq_id;
-       priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(tx_fifo, txq_id);
+       priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(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,
@@ -1224,8 +1233,9 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
        memset(&info->status, 0, sizeof(info->status));
        info->flags |= IEEE80211_TX_STAT_ACK;
        info->flags |= IEEE80211_TX_STAT_AMPDU;
-       info->status.ampdu_ack_map = successes;
-       info->status.ampdu_ack_len = agg->frame_count;
+       info->status.ampdu_ack_len = successes;
+       info->status.ampdu_ack_map = bitmap;
+       info->status.ampdu_len = agg->frame_count;
        iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
 
        IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", (unsigned long long)bitmap);
index 00344d64635c580146762ba25f179fe323106cf1..a672d3379cfdf5130f05f5e22a5e69715912308e 100644 (file)
@@ -2654,7 +2654,6 @@ static int iwl_mac_setup_register(struct iwl_priv *priv)
 
        /* Tell mac80211 our characteristics */
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_NOISE_DBM |
                    IEEE80211_HW_AMPDU_AGGREGATION |
                    IEEE80211_HW_SPECTRUM_MGMT;
 
@@ -3002,18 +3001,6 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
        return 0;
 }
 
-static int iwl_mac_get_stats(struct ieee80211_hw *hw,
-                            struct ieee80211_low_level_stats *stats)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       priv = hw->priv;
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return 0;
-}
-
 static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif,
                               enum sta_notify_cmd cmd,
@@ -3391,7 +3378,6 @@ static struct ieee80211_ops iwl_hw_ops = {
        .configure_filter = iwl_configure_filter,
        .set_key = iwl_mac_set_key,
        .update_tkip_key = iwl_mac_update_tkip_key,
-       .get_stats = iwl_mac_get_stats,
        .conf_tx = iwl_mac_conf_tx,
        .reset_tsf = iwl_mac_reset_tsf,
        .bss_info_changed = iwl_bss_info_changed,
index 67c723cc32d276b1b310f701d98adfc4c3274241..0086019b7a15067111b67a14dfca7b2864aaef6d 100644 (file)
@@ -2663,7 +2663,9 @@ struct iwl_ssid_ie {
 #define PROBE_OPTION_MAX_3945          4
 #define PROBE_OPTION_MAX               20
 #define TX_CMD_LIFE_TIME_INFINITE      cpu_to_le32(0xFFFFFFFF)
-#define IWL_GOOD_CRC_TH                        cpu_to_le16(1)
+#define IWL_GOOD_CRC_TH_DISABLED       0
+#define IWL_GOOD_CRC_TH_DEFAULT                cpu_to_le16(1)
+#define IWL_GOOD_CRC_TH_NEVER          cpu_to_le16(0xffff)
 #define IWL_MAX_SCAN_SIZE 1024
 #define IWL_MAX_CMD_SIZE 4096
 #define IWL_MAX_PROBE_REQUEST          200
index 56a9f1741419b581bbcb23bbf083319bdb05b16c..4cdf4d3a9ddb1074348928ec55155885ed0dfe2d 100644 (file)
@@ -2117,10 +2117,6 @@ EXPORT_SYMBOL(iwl_mac_remove_interface);
 
 /**
  * iwl_mac_config - mac80211 config callback
- *
- * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
- * be set inappropriately and the driver currently sets the hardware up to
- * use it whenever needed.
  */
 int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
 {
@@ -2935,6 +2931,12 @@ int iwl_pci_resume(struct pci_dev *pdev)
        struct iwl_priv *priv = pci_get_drvdata(pdev);
        int ret;
 
+       /*
+        * 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);
+
        pci_set_power_state(pdev, PCI_D0);
        ret = pci_enable_device(pdev);
        if (ret)
index a0cc11ecbe939322450a00072e65403d6ff308c9..7273609448595fba3c4029db1c78def2287388fd 100644 (file)
@@ -512,7 +512,9 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
 void iwl_init_scan_params(struct iwl_priv *priv);
 int iwl_scan_cancel(struct iwl_priv *priv);
 int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
-int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
+int iwl_mac_hw_scan(struct ieee80211_hw *hw,
+                   struct ieee80211_vif *vif,
+                   struct cfg80211_scan_request *req);
 void iwl_internal_short_hw_scan(struct iwl_priv *priv);
 int iwl_force_reset(struct iwl_priv *priv, int mode);
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
index 61faf2dd7fbe95df7571919ff8b008f6dde68c32..4aabb542fcbea1a6bc1efad5797464f532ed21c8 100644 (file)
@@ -1059,10 +1059,8 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
                                        size_t count, loff_t *ppos)
 {
        struct iwl_priv *priv = file->private_data;
-       if (priv->cfg->ops->lib->debugfs_ops.rx_stats_read)
-               return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
-                                               user_buf, count, ppos);
-       return 0;
+       return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
+                       user_buf, count, ppos);
 }
 
 static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
@@ -1070,10 +1068,8 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
                                        size_t count, loff_t *ppos)
 {
        struct iwl_priv *priv = file->private_data;
-       if (priv->cfg->ops->lib->debugfs_ops.tx_stats_read)
-               return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
-                                               user_buf, count, ppos);
-       return 0;
+       return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
+                       user_buf, count, ppos);
 }
 
 static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
@@ -1081,10 +1077,8 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
                                        size_t count, loff_t *ppos)
 {
        struct iwl_priv *priv = file->private_data;
-       if (priv->cfg->ops->lib->debugfs_ops.general_stats_read)
-               return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
-                                               user_buf, count, ppos);
-       return 0;
+       return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
+                       user_buf, count, ppos);
 }
 
 static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
index bdc60aae75ec6862c9ec70471a563b001629fc93..58c69a5798d4e5b94b0d61b9c753fbc18997028d 100644 (file)
@@ -1202,6 +1202,11 @@ struct iwl_priv {
                        struct delayed_work rfkill_poll;
 
                        struct iwl3945_notif_statistics statistics;
+#ifdef CONFIG_IWLWIFI_DEBUG
+                       struct iwl3945_notif_statistics accum_statistics;
+                       struct iwl3945_notif_statistics delta_statistics;
+                       struct iwl3945_notif_statistics max_delta;
+#endif
 
                        u32 sta_supp_rates;
                        int last_rx_rssi;       /* From Rx packet statistics */
index f4b897804a8072bc8b3b8e5e8e462b594a49c2d4..d12fd5553846749a9612edaff77b0ae0b3fccdc9 100644 (file)
@@ -313,7 +313,8 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
 }
 
 int iwl_mac_hw_scan(struct ieee80211_hw *hw,
-                    struct cfg80211_scan_request *req)
+                   struct ieee80211_vif *vif,
+                   struct cfg80211_scan_request *req)
 {
        struct iwl_priv *priv = hw->priv;
        int ret;
index a41ba72ceb007da8a283df9c60ed84425badc3a4..c7e1d7d09e021b6231927f7b23782a64c7837d2d 100644 (file)
@@ -957,7 +957,7 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv)
         * statistics request from the host as well as for the periodic
         * statistics notifications (after received beacons) from the uCode.
         */
-       priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics;
+       priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_reply_statistics;
        priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics;
 
        iwl_setup_rx_scan_handlers(priv);
@@ -2939,7 +2939,8 @@ void iwl3945_request_scan(struct iwl_priv *priv)
                 * is marked passive, we can do active scanning if we
                 * detect transmissions.
                 */
-               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH : 0;
+               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+                                               IWL_GOOD_CRC_TH_DISABLED;
                band = IEEE80211_BAND_5GHZ;
                break;
        default:
@@ -3873,7 +3874,6 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
 
        /* Tell mac80211 our characteristics */
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_NOISE_DBM |
                    IEEE80211_HW_SPECTRUM_MGMT;
 
        if (!priv->cfg->broken_powersave)
index 836663eec257c61e0ee8a0041e0c7723f2b56313..62edd5888a7b34fa6dc2353d4adef8ad7dc14eda 100644 (file)
@@ -31,7 +31,7 @@ struct iwm_if_ops {
        int (*disable)(struct iwm_priv *iwm);
        int (*send_chunk)(struct iwm_priv *iwm, u8* buf, int count);
 
-       int (*debugfs_init)(struct iwm_priv *iwm, struct dentry *parent_dir);
+       void (*debugfs_init)(struct iwm_priv *iwm, struct dentry *parent_dir);
        void (*debugfs_exit)(struct iwm_priv *iwm);
 
        const char *umac_name;
index e35c9b693d1fde1a06a5dcf4eaa3aa7c7ac016b2..a0c13a49ab3ca095be4a042963fb52776bcce1f7 100644 (file)
@@ -113,13 +113,10 @@ struct iwm_debugfs {
 };
 
 #ifdef CONFIG_IWM_DEBUG
-int iwm_debugfs_init(struct iwm_priv *iwm);
+void iwm_debugfs_init(struct iwm_priv *iwm);
 void iwm_debugfs_exit(struct iwm_priv *iwm);
 #else
-static inline int iwm_debugfs_init(struct iwm_priv *iwm)
-{
-       return 0;
-}
+static inline void iwm_debugfs_init(struct iwm_priv *iwm) {}
 static inline void iwm_debugfs_exit(struct iwm_priv *iwm) {}
 #endif
 
index 724441368a18e468338e46f5ff7cd0fd1bd31d46..53b0b7711f02a4c595d95fd0a92ef62753b33f65 100644 (file)
@@ -48,12 +48,11 @@ static struct {
 
 #define add_dbg_module(dbg, name, id, initlevel)       \
 do {                                                   \
-       struct dentry *d;                               \
        dbg.dbg_module[id] = (initlevel);               \
-       d = debugfs_create_x8(name, 0600, dbg.dbgdir,   \
-                            &(dbg.dbg_module[id]));    \
-       if (!IS_ERR(d))                                 \
-               dbg.dbg_module_dentries[id] = d;        \
+       dbg.dbg_module_dentries[id] =                   \
+               debugfs_create_x8(name, 0600,           \
+                               dbg.dbgdir,             \
+                               &(dbg.dbg_module[id])); \
 } while (0)
 
 static int iwm_debugfs_u32_read(void *data, u64 *val)
@@ -423,89 +422,29 @@ static const struct file_operations iwm_debugfs_fw_err_fops = {
        .read =         iwm_debugfs_fw_err_read,
 };
 
-int iwm_debugfs_init(struct iwm_priv *iwm)
+void iwm_debugfs_init(struct iwm_priv *iwm)
 {
-       int i, result;
-       char devdir[16];
+       int i;
 
        iwm->dbg.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
-       result = PTR_ERR(iwm->dbg.rootdir);
-       if (!result || IS_ERR(iwm->dbg.rootdir)) {
-               if (result == -ENODEV) {
-                       IWM_ERR(iwm, "DebugFS (CONFIG_DEBUG_FS) not "
-                               "enabled in kernel config\n");
-                       result = 0;     /* No debugfs support */
-               }
-               IWM_ERR(iwm, "Couldn't create rootdir: %d\n", result);
-               goto error;
-       }
-
-       snprintf(devdir, sizeof(devdir), "%s", wiphy_name(iwm_to_wiphy(iwm)));
-
-       iwm->dbg.devdir = debugfs_create_dir(devdir, iwm->dbg.rootdir);
-       result = PTR_ERR(iwm->dbg.devdir);
-       if (IS_ERR(iwm->dbg.devdir) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create devdir: %d\n", result);
-               goto error;
-       }
-
+       iwm->dbg.devdir = debugfs_create_dir(wiphy_name(iwm_to_wiphy(iwm)),
+                                            iwm->dbg.rootdir);
        iwm->dbg.dbgdir = debugfs_create_dir("debug", iwm->dbg.devdir);
-       result = PTR_ERR(iwm->dbg.dbgdir);
-       if (IS_ERR(iwm->dbg.dbgdir) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create dbgdir: %d\n", result);
-               goto error;
-       }
-
        iwm->dbg.rxdir = debugfs_create_dir("rx", iwm->dbg.devdir);
-       result = PTR_ERR(iwm->dbg.rxdir);
-       if (IS_ERR(iwm->dbg.rxdir) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create rx dir: %d\n", result);
-               goto error;
-       }
-
        iwm->dbg.txdir = debugfs_create_dir("tx", iwm->dbg.devdir);
-       result = PTR_ERR(iwm->dbg.txdir);
-       if (IS_ERR(iwm->dbg.txdir) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create tx dir: %d\n", result);
-               goto error;
-       }
-
        iwm->dbg.busdir = debugfs_create_dir("bus", iwm->dbg.devdir);
-       result = PTR_ERR(iwm->dbg.busdir);
-       if (IS_ERR(iwm->dbg.busdir) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create bus dir: %d\n", result);
-               goto error;
-       }
-
-       if (iwm->bus_ops->debugfs_init) {
-               result = iwm->bus_ops->debugfs_init(iwm, iwm->dbg.busdir);
-               if (result < 0) {
-                       IWM_ERR(iwm, "Couldn't create bus entry: %d\n", result);
-                       goto error;
-               }
-       }
-
+       if (iwm->bus_ops->debugfs_init)
+               iwm->bus_ops->debugfs_init(iwm, iwm->dbg.busdir);
 
        iwm->dbg.dbg_level = IWM_DL_NONE;
        iwm->dbg.dbg_level_dentry =
                debugfs_create_file("level", 0200, iwm->dbg.dbgdir, iwm,
                                    &fops_iwm_dbg_level);
-       result = PTR_ERR(iwm->dbg.dbg_level_dentry);
-       if (IS_ERR(iwm->dbg.dbg_level_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create dbg_level: %d\n", result);
-               goto error;
-       }
-
 
        iwm->dbg.dbg_modules = IWM_DM_DEFAULT;
        iwm->dbg.dbg_modules_dentry =
                debugfs_create_file("modules", 0200, iwm->dbg.dbgdir, iwm,
                                    &fops_iwm_dbg_modules);
-       result = PTR_ERR(iwm->dbg.dbg_modules_dentry);
-       if (IS_ERR(iwm->dbg.dbg_modules_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create dbg_modules: %d\n", result);
-               goto error;
-       }
 
        for (i = 0; i < __IWM_DM_NR; i++)
                add_dbg_module(iwm->dbg, iwm_debug_module[i].name,
@@ -514,44 +453,15 @@ int iwm_debugfs_init(struct iwm_priv *iwm)
        iwm->dbg.txq_dentry = debugfs_create_file("queues", 0200,
                                                  iwm->dbg.txdir, iwm,
                                                  &iwm_debugfs_txq_fops);
-       result = PTR_ERR(iwm->dbg.txq_dentry);
-       if (IS_ERR(iwm->dbg.txq_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create tx queue: %d\n", result);
-               goto error;
-       }
-
        iwm->dbg.tx_credit_dentry = debugfs_create_file("credits", 0200,
                                                   iwm->dbg.txdir, iwm,
                                                   &iwm_debugfs_tx_credit_fops);
-       result = PTR_ERR(iwm->dbg.tx_credit_dentry);
-       if (IS_ERR(iwm->dbg.tx_credit_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create tx credit: %d\n", result);
-               goto error;
-       }
-
        iwm->dbg.rx_ticket_dentry = debugfs_create_file("tickets", 0200,
                                                  iwm->dbg.rxdir, iwm,
                                                  &iwm_debugfs_rx_ticket_fops);
-       result = PTR_ERR(iwm->dbg.rx_ticket_dentry);
-       if (IS_ERR(iwm->dbg.rx_ticket_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create rx ticket: %d\n", result);
-               goto error;
-       }
-
        iwm->dbg.fw_err_dentry = debugfs_create_file("last_fw_err", 0200,
                                                     iwm->dbg.dbgdir, iwm,
                                                     &iwm_debugfs_fw_err_fops);
-       result = PTR_ERR(iwm->dbg.fw_err_dentry);
-       if (IS_ERR(iwm->dbg.fw_err_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create last FW err: %d\n", result);
-               goto error;
-       }
-
-
-       return 0;
-
- error:
-       return result;
 }
 
 void iwm_debugfs_exit(struct iwm_priv *iwm)
index 1eafd6dec3fd1536766983f8c5a67ef994cbb0a2..1acea37f39f807b1112fa0dac5bc258abb551e08 100644 (file)
@@ -366,21 +366,13 @@ static const struct file_operations iwm_debugfs_sdio_fops = {
        .read =         iwm_debugfs_sdio_read,
 };
 
-static int if_sdio_debugfs_init(struct iwm_priv *iwm, struct dentry *parent_dir)
+static void if_sdio_debugfs_init(struct iwm_priv *iwm, struct dentry *parent_dir)
 {
-       int result;
        struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
 
        hw->cccr_dentry = debugfs_create_file("cccr", 0200,
                                              parent_dir, iwm,
                                              &iwm_debugfs_sdio_fops);
-       result = PTR_ERR(hw->cccr_dentry);
-       if (IS_ERR(hw->cccr_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create CCCR entry: %d\n", result);
-               return result;
-       }
-
-       return 0;
 }
 
 static void if_sdio_debugfs_exit(struct iwm_priv *iwm)
@@ -440,11 +432,7 @@ static int iwm_sdio_probe(struct sdio_func *func,
        hw = iwm_private(iwm);
        hw->iwm = iwm;
 
-       ret = iwm_debugfs_init(iwm);
-       if (ret < 0) {
-               IWM_ERR(iwm, "Debugfs registration failed\n");
-               goto if_free;
-       }
+       iwm_debugfs_init(iwm);
 
        sdio_set_drvdata(func, hw);
 
@@ -473,7 +461,6 @@ static int iwm_sdio_probe(struct sdio_func *func,
        destroy_workqueue(hw->isr_wq);
  debugfs_exit:
        iwm_debugfs_exit(iwm);
- if_free:
        iwm_if_free(iwm);
        return ret;
 }
index 13dfeda742bcb4a3ffe45a3848d27cf35383530e..64dd345d30f526f2c10ff0b4c0b03998798e0fc0 100644 (file)
@@ -324,7 +324,9 @@ static int if_sdio_wait_status(struct if_sdio_card *card, const u8 condition)
        timeout = jiffies + HZ;
        while (1) {
                status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
-               if (ret || (status & condition))
+               if (ret)
+                       return ret;
+               if ((status & condition) == condition)
                        break;
                if (time_after(jiffies, timeout))
                        return -ETIMEDOUT;
index b620daf59ef7fa3927c3e323779d70d3ec4e49bd..8945afd6ce3ef7e88e182709020660e3183f27d2 100644 (file)
@@ -7,6 +7,8 @@
  *  the Free Software Foundation; either version 2 of the License, or (at
  *  your option) any later version.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/slab.h>
 
 #include "libertas_tf.h"
@@ -82,6 +84,8 @@ int lbtf_update_hw_spec(struct lbtf_private *priv)
        int ret = -1;
        u32 i;
 
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        memset(&cmd, 0, sizeof(cmd));
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
@@ -104,6 +108,8 @@ int lbtf_update_hw_spec(struct lbtf_private *priv)
                priv->fwrelease >>  8 & 0xff,
                priv->fwrelease       & 0xff,
                priv->fwcapinfo);
+       lbtf_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
+                   cmd.hwifversion, cmd.version);
 
        /* Clamp region code to 8-bit since FW spec indicates that it should
         * only ever be 8-bit, even though the field size is 16-bit.  Some
@@ -118,8 +124,10 @@ int lbtf_update_hw_spec(struct lbtf_private *priv)
        }
 
        /* if it's unidentified region code, use the default (USA) */
-       if (i >= MRVDRV_MAX_REGION_CODE)
+       if (i >= MRVDRV_MAX_REGION_CODE) {
                priv->regioncode = 0x10;
+               pr_info("unidentified region code; using the default (USA)\n");
+       }
 
        if (priv->current_addr[0] == 0xff)
                memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
@@ -128,6 +136,7 @@ int lbtf_update_hw_spec(struct lbtf_private *priv)
 
        lbtf_geo_init(priv);
 out:
+       lbtf_deb_leave(LBTF_DEB_CMD);
        return ret;
 }
 
@@ -141,13 +150,18 @@ out:
  */
 int lbtf_set_channel(struct lbtf_private *priv, u8 channel)
 {
+       int ret = 0;
        struct cmd_ds_802_11_rf_channel cmd;
 
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
        cmd.channel = cpu_to_le16(channel);
 
-       return lbtf_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
+       ret = lbtf_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
+       lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", ret);
+       return ret;
 }
 
 int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon)
@@ -155,20 +169,28 @@ int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon)
        struct cmd_ds_802_11_beacon_set cmd;
        int size;
 
-       if (beacon->len > MRVL_MAX_BCN_SIZE)
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
+       if (beacon->len > MRVL_MAX_BCN_SIZE) {
+               lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", -1);
                return -1;
+       }
        size =  sizeof(cmd) - sizeof(cmd.beacon) + beacon->len;
        cmd.hdr.size = cpu_to_le16(size);
        cmd.len = cpu_to_le16(beacon->len);
        memcpy(cmd.beacon, (u8 *) beacon->data, beacon->len);
 
        lbtf_cmd_async(priv, CMD_802_11_BEACON_SET, &cmd.hdr, size);
+
+       lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", 0);
        return 0;
 }
 
 int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable,
-                    int beacon_int) {
+                    int beacon_int)
+{
        struct cmd_ds_802_11_beacon_control cmd;
+       lbtf_deb_enter(LBTF_DEB_CMD);
 
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_ACT_SET);
@@ -176,6 +198,8 @@ int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable,
        cmd.beacon_period = cpu_to_le16(beacon_int);
 
        lbtf_cmd_async(priv, CMD_802_11_BEACON_CTRL, &cmd.hdr, sizeof(cmd));
+
+       lbtf_deb_leave(LBTF_DEB_CMD);
        return 0;
 }
 
@@ -183,17 +207,28 @@ static void lbtf_queue_cmd(struct lbtf_private *priv,
                          struct cmd_ctrl_node *cmdnode)
 {
        unsigned long flags;
+       lbtf_deb_enter(LBTF_DEB_HOST);
 
-       if (!cmdnode)
-               return;
+       if (!cmdnode) {
+               lbtf_deb_host("QUEUE_CMD: cmdnode is NULL\n");
+               goto qcmd_done;
+       }
 
-       if (!cmdnode->cmdbuf->size)
-               return;
+       if (!cmdnode->cmdbuf->size) {
+               lbtf_deb_host("DNLD_CMD: cmd size is zero\n");
+               goto qcmd_done;
+       }
 
        cmdnode->result = 0;
        spin_lock_irqsave(&priv->driver_lock, flags);
        list_add_tail(&cmdnode->list, &priv->cmdpendingq);
        spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+       lbtf_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
+                    le16_to_cpu(cmdnode->cmdbuf->command));
+
+qcmd_done:
+       lbtf_deb_leave(LBTF_DEB_HOST);
 }
 
 static void lbtf_submit_command(struct lbtf_private *priv,
@@ -206,22 +241,33 @@ static void lbtf_submit_command(struct lbtf_private *priv,
        int timeo = 5 * HZ;
        int ret;
 
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
        cmd = cmdnode->cmdbuf;
 
        spin_lock_irqsave(&priv->driver_lock, flags);
        priv->cur_cmd = cmdnode;
        cmdsize = le16_to_cpu(cmd->size);
        command = le16_to_cpu(cmd->command);
+
+       lbtf_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
+                    command, le16_to_cpu(cmd->seqnum), cmdsize);
+       lbtf_deb_hex(LBTF_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
+
        ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
-       if (ret)
+       if (ret) {
+               pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
                /* Let the timer kick in and retry, and potentially reset
                   the whole thing if the condition persists */
                timeo = HZ;
+       }
 
        /* Setup the timer after transmit command */
        mod_timer(&priv->command_timer, jiffies + timeo);
+
+       lbtf_deb_leave(LBTF_DEB_HOST);
 }
 
 /**
@@ -231,8 +277,10 @@ static void lbtf_submit_command(struct lbtf_private *priv,
 static void __lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
                                         struct cmd_ctrl_node *cmdnode)
 {
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
        if (!cmdnode)
-               return;
+               goto cl_ins_out;
 
        cmdnode->callback = NULL;
        cmdnode->callback_arg = 0;
@@ -240,6 +288,9 @@ static void __lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
        memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
 
        list_add_tail(&cmdnode->list, &priv->cmdfreeq);
+
+cl_ins_out:
+       lbtf_deb_leave(LBTF_DEB_HOST);
 }
 
 static void lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
@@ -268,29 +319,41 @@ int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv)
 {
        struct cmd_ds_mac_multicast_addr cmd;
 
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_ACT_SET);
 
        cmd.nr_of_adrs = cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
+
+       lbtf_deb_cmd("MULTICAST_ADR: setting %d addresses\n", cmd.nr_of_adrs);
+
        memcpy(cmd.maclist, priv->multicastlist,
               priv->nr_of_multicastmacaddr * ETH_ALEN);
 
        lbtf_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &cmd.hdr, sizeof(cmd));
+
+       lbtf_deb_leave(LBTF_DEB_CMD);
        return 0;
 }
 
 void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode)
 {
        struct cmd_ds_set_mode cmd;
+       lbtf_deb_enter(LBTF_DEB_WEXT);
 
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.mode = cpu_to_le16(mode);
+       lbtf_deb_wext("Switching to mode: 0x%x\n", mode);
        lbtf_cmd_async(priv, CMD_802_11_SET_MODE, &cmd.hdr, sizeof(cmd));
+
+       lbtf_deb_leave(LBTF_DEB_WEXT);
 }
 
 void lbtf_set_bssid(struct lbtf_private *priv, bool activate, const u8 *bssid)
 {
        struct cmd_ds_set_bssid cmd;
+       lbtf_deb_enter(LBTF_DEB_CMD);
 
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.activate = activate ? 1 : 0;
@@ -298,11 +361,13 @@ void lbtf_set_bssid(struct lbtf_private *priv, bool activate, const u8 *bssid)
                memcpy(cmd.bssid, bssid, ETH_ALEN);
 
        lbtf_cmd_async(priv, CMD_802_11_SET_BSSID, &cmd.hdr, sizeof(cmd));
+       lbtf_deb_leave(LBTF_DEB_CMD);
 }
 
 int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr)
 {
        struct cmd_ds_802_11_mac_address cmd;
+       lbtf_deb_enter(LBTF_DEB_CMD);
 
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_ACT_SET);
@@ -310,6 +375,7 @@ int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr)
        memcpy(cmd.macadd, mac_addr, ETH_ALEN);
 
        lbtf_cmd_async(priv, CMD_802_11_MAC_ADDRESS, &cmd.hdr, sizeof(cmd));
+       lbtf_deb_leave(LBTF_DEB_CMD);
        return 0;
 }
 
@@ -318,6 +384,8 @@ int lbtf_set_radio_control(struct lbtf_private *priv)
        int ret = 0;
        struct cmd_ds_802_11_radio_control cmd;
 
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_ACT_SET);
 
@@ -341,19 +409,28 @@ int lbtf_set_radio_control(struct lbtf_private *priv)
        else
                cmd.control &= cpu_to_le16(~TURN_ON_RF);
 
+       lbtf_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon,
+                   priv->preamble);
+
        ret = lbtf_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
+
+       lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", ret);
        return ret;
 }
 
 void lbtf_set_mac_control(struct lbtf_private *priv)
 {
        struct cmd_ds_mac_control cmd;
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(priv->mac_control);
        cmd.reserved = 0;
 
        lbtf_cmd_async(priv, CMD_MAC_CONTROL,
                &cmd.hdr, sizeof(cmd));
+
+       lbtf_deb_leave(LBTF_DEB_CMD);
 }
 
 /**
@@ -365,29 +442,43 @@ void lbtf_set_mac_control(struct lbtf_private *priv)
  */
 int lbtf_allocate_cmd_buffer(struct lbtf_private *priv)
 {
+       int ret = 0;
        u32 bufsize;
        u32 i;
        struct cmd_ctrl_node *cmdarray;
 
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
        /* Allocate and initialize the command array */
        bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
        cmdarray = kzalloc(bufsize, GFP_KERNEL);
-       if (!cmdarray)
-               return -1;
+       if (!cmdarray) {
+               lbtf_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
+               ret = -1;
+               goto done;
+       }
        priv->cmd_array = cmdarray;
 
        /* Allocate and initialize each command buffer in the command array */
        for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
                cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
-               if (!cmdarray[i].cmdbuf)
-                       return -1;
+               if (!cmdarray[i].cmdbuf) {
+                       lbtf_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
+                       ret = -1;
+                       goto done;
+               }
        }
 
        for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
                init_waitqueue_head(&cmdarray[i].cmdwait_q);
                lbtf_cleanup_and_insert_cmd(priv, &cmdarray[i]);
        }
-       return 0;
+
+       ret = 0;
+
+done:
+       lbtf_deb_leave_args(LBTF_DEB_HOST, "ret %d", ret);
+       return ret;
 }
 
 /**
@@ -402,9 +493,13 @@ int lbtf_free_cmd_buffer(struct lbtf_private *priv)
        struct cmd_ctrl_node *cmdarray;
        unsigned int i;
 
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
        /* need to check if cmd array is allocated or not */
-       if (priv->cmd_array == NULL)
-               return 0;
+       if (priv->cmd_array == NULL) {
+               lbtf_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
+               goto done;
+       }
 
        cmdarray = priv->cmd_array;
 
@@ -418,6 +513,8 @@ int lbtf_free_cmd_buffer(struct lbtf_private *priv)
        kfree(priv->cmd_array);
        priv->cmd_array = NULL;
 
+done:
+       lbtf_deb_leave(LBTF_DEB_HOST);
        return 0;
 }
 
@@ -433,6 +530,8 @@ static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv)
        struct cmd_ctrl_node *tempnode;
        unsigned long flags;
 
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
        if (!priv)
                return NULL;
 
@@ -442,11 +541,14 @@ static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv)
                tempnode = list_first_entry(&priv->cmdfreeq,
                                            struct cmd_ctrl_node, list);
                list_del(&tempnode->list);
-       } else
+       } else {
+               lbtf_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
                tempnode = NULL;
+       }
 
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
+       lbtf_deb_leave(LBTF_DEB_HOST);
        return tempnode;
 }
 
@@ -462,16 +564,20 @@ int lbtf_execute_next_command(struct lbtf_private *priv)
        struct cmd_ctrl_node *cmdnode = NULL;
        struct cmd_header *cmd;
        unsigned long flags;
+       int ret = 0;
 
-       /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
+       /* Debug group is lbtf_deb_THREAD and not lbtf_deb_HOST, because the
         * only caller to us is lbtf_thread() and we get even when a
         * data packet is received */
+       lbtf_deb_enter(LBTF_DEB_THREAD);
 
        spin_lock_irqsave(&priv->driver_lock, flags);
 
        if (priv->cur_cmd) {
+               pr_alert("EXEC_NEXT_CMD: already processing command!\n");
                spin_unlock_irqrestore(&priv->driver_lock, flags);
-               return -1;
+               ret = -1;
+               goto done;
        }
 
        if (!list_empty(&priv->cmdpendingq)) {
@@ -483,11 +589,17 @@ int lbtf_execute_next_command(struct lbtf_private *priv)
                cmd = cmdnode->cmdbuf;
 
                list_del(&cmdnode->list);
+               lbtf_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
+                           le16_to_cpu(cmd->command));
                spin_unlock_irqrestore(&priv->driver_lock, flags);
                lbtf_submit_command(priv, cmdnode);
        } else
                spin_unlock_irqrestore(&priv->driver_lock, flags);
-       return 0;
+
+       ret = 0;
+done:
+       lbtf_deb_leave(LBTF_DEB_THREAD);
+       return ret;
 }
 
 static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv,
@@ -498,14 +610,22 @@ static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv,
 {
        struct cmd_ctrl_node *cmdnode;
 
-       if (priv->surpriseremoved)
-               return ERR_PTR(-ENOENT);
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
+       if (priv->surpriseremoved) {
+               lbtf_deb_host("PREP_CMD: card removed\n");
+               cmdnode = ERR_PTR(-ENOENT);
+               goto done;
+       }
 
        cmdnode = lbtf_get_cmd_ctrl_node(priv);
        if (cmdnode == NULL) {
+               lbtf_deb_host("PREP_CMD: cmdnode is NULL\n");
+
                /* Wake up main thread to execute next command */
                queue_work(lbtf_wq, &priv->cmd_work);
-               return ERR_PTR(-ENOBUFS);
+               cmdnode = ERR_PTR(-ENOBUFS);
+               goto done;
        }
 
        cmdnode->callback = callback;
@@ -520,17 +640,24 @@ static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv,
        cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
        cmdnode->cmdbuf->seqnum  = cpu_to_le16(priv->seqnum);
        cmdnode->cmdbuf->result  = 0;
+
+       lbtf_deb_host("PREP_CMD: command 0x%04x\n", command);
+
        cmdnode->cmdwaitqwoken = 0;
        lbtf_queue_cmd(priv, cmdnode);
        queue_work(lbtf_wq, &priv->cmd_work);
 
+ done:
+       lbtf_deb_leave_args(LBTF_DEB_HOST, "ret %p", cmdnode);
        return cmdnode;
 }
 
 void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command,
        struct cmd_header *in_cmd, int in_cmd_size)
 {
+       lbtf_deb_enter(LBTF_DEB_CMD);
        __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size, NULL, 0);
+       lbtf_deb_leave(LBTF_DEB_CMD);
 }
 
 int __lbtf_cmd(struct lbtf_private *priv, uint16_t command,
@@ -543,30 +670,35 @@ int __lbtf_cmd(struct lbtf_private *priv, uint16_t command,
        unsigned long flags;
        int ret = 0;
 
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
        cmdnode = __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size,
                                  callback, callback_arg);
-       if (IS_ERR(cmdnode))
-               return PTR_ERR(cmdnode);
+       if (IS_ERR(cmdnode)) {
+               ret = PTR_ERR(cmdnode);
+               goto done;
+       }
 
        might_sleep();
        ret = wait_event_interruptible(cmdnode->cmdwait_q,
                                       cmdnode->cmdwaitqwoken);
-       if (ret)        {
-               printk(KERN_DEBUG
-                      "libertastf: command 0x%04x interrupted by signal",
-                      command);
-               return ret;
+       if (ret) {
+               pr_info("PREP_CMD: command 0x%04x interrupted by signal: %d\n",
+                           command, ret);
+               goto done;
        }
 
        spin_lock_irqsave(&priv->driver_lock, flags);
        ret = cmdnode->result;
        if (ret)
-               printk(KERN_DEBUG "libertastf: command 0x%04x failed: %d\n",
+               pr_info("PREP_CMD: command 0x%04x failed: %d\n",
                            command, ret);
 
        __lbtf_cleanup_and_insert_cmd(priv, cmdnode);
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
+done:
+       lbtf_deb_leave_args(LBTF_DEB_HOST, "ret %d", ret);
        return ret;
 }
 EXPORT_SYMBOL_GPL(__lbtf_cmd);
@@ -587,6 +719,8 @@ int lbtf_process_rx_command(struct lbtf_private *priv)
        unsigned long flags;
        uint16_t result;
 
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        mutex_lock(&priv->lock);
        spin_lock_irqsave(&priv->driver_lock, flags);
 
@@ -602,7 +736,7 @@ int lbtf_process_rx_command(struct lbtf_private *priv)
        result = le16_to_cpu(resp->result);
 
        if (net_ratelimit())
-               printk(KERN_DEBUG "libertastf: cmd response 0x%04x, seq %d, size %d\n",
+               pr_info("libertastf: cmd response 0x%04x, seq %d, size %d\n",
                        respcmd, le16_to_cpu(resp->seqnum),
                        le16_to_cpu(resp->size));
 
@@ -639,7 +773,7 @@ int lbtf_process_rx_command(struct lbtf_private *priv)
                switch (respcmd) {
                case CMD_RET(CMD_GET_HW_SPEC):
                case CMD_RET(CMD_802_11_RESET):
-                       printk(KERN_DEBUG "libertastf: reset failed\n");
+                       pr_info("libertastf: reset failed\n");
                        break;
 
                }
@@ -666,5 +800,6 @@ int lbtf_process_rx_command(struct lbtf_private *priv)
 
 done:
        mutex_unlock(&priv->lock);
+       lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", ret);
        return ret;
 }
diff --git a/drivers/net/wireless/libertas_tf/deb_defs.h b/drivers/net/wireless/libertas_tf/deb_defs.h
new file mode 100644 (file)
index 0000000..ae75396
--- /dev/null
@@ -0,0 +1,104 @@
+/**
+  * This header file contains global constant/enum definitions,
+  * global variable declaration.
+  */
+#ifndef _LBS_DEB_DEFS_H_
+#define _LBS_DEB_EFS_H_
+
+#ifndef DRV_NAME
+#define DRV_NAME "libertas_tf"
+#endif
+
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_LIBERTAS_THINFIRM_DEBUG
+#define DEBUG
+#define PROC_DEBUG
+#endif
+
+#define LBTF_DEB_ENTER 0x00000001
+#define LBTF_DEB_LEAVE 0x00000002
+#define LBTF_DEB_MAIN  0x00000004
+#define LBTF_DEB_NET   0x00000008
+#define LBTF_DEB_MESH  0x00000010
+#define LBTF_DEB_WEXT  0x00000020
+#define LBTF_DEB_IOCTL 0x00000040
+#define LBTF_DEB_SCAN  0x00000080
+#define LBTF_DEB_ASSOC 0x00000100
+#define LBTF_DEB_JOIN  0x00000200
+#define LBTF_DEB_11D   0x00000400
+#define LBTF_DEB_DEBUGFS       0x00000800
+#define LBTF_DEB_ETHTOOL       0x00001000
+#define LBTF_DEB_HOST  0x00002000
+#define LBTF_DEB_CMD   0x00004000
+#define LBTF_DEB_RX    0x00008000
+#define LBTF_DEB_TX    0x00010000
+#define LBTF_DEB_USB   0x00020000
+#define LBTF_DEB_CS    0x00040000
+#define LBTF_DEB_FW    0x00080000
+#define LBTF_DEB_THREAD        0x00100000
+#define LBTF_DEB_HEX   0x00200000
+#define LBTF_DEB_SDIO  0x00400000
+#define LBTF_DEB_MACOPS        0x00800000
+
+extern unsigned int lbtf_debug;
+
+
+#ifdef DEBUG
+#define LBTF_DEB_LL(grp, grpnam, fmt, args...) \
+do { if ((lbtf_debug & (grp)) == (grp)) \
+  printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \
+         in_interrupt() ? " (INT)" : "", ## args); } while (0)
+#else
+#define LBTF_DEB_LL(grp, grpnam, fmt, args...) do {} while (0)
+#endif
+
+#define lbtf_deb_enter(grp) \
+  LBTF_DEB_LL(grp | LBTF_DEB_ENTER, " enter", "%s()\n", __func__);
+#define lbtf_deb_enter_args(grp, fmt, args...) \
+  LBTF_DEB_LL(grp | LBTF_DEB_ENTER, " enter", "%s(" fmt ")\n", __func__, ## args);
+#define lbtf_deb_leave(grp) \
+  LBTF_DEB_LL(grp | LBTF_DEB_LEAVE, " leave", "%s()\n", __func__);
+#define lbtf_deb_leave_args(grp, fmt, args...) \
+  LBTF_DEB_LL(grp | LBTF_DEB_LEAVE, " leave", "%s(), " fmt "\n", \
+  __func__, ##args);
+#define lbtf_deb_main(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_MAIN, " main", fmt, ##args)
+#define lbtf_deb_net(fmt, args...)       LBTF_DEB_LL(LBTF_DEB_NET, " net", fmt, ##args)
+#define lbtf_deb_mesh(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_MESH, " mesh", fmt, ##args)
+#define lbtf_deb_wext(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_WEXT, " wext", fmt, ##args)
+#define lbtf_deb_ioctl(fmt, args...)     LBTF_DEB_LL(LBTF_DEB_IOCTL, " ioctl", fmt, ##args)
+#define lbtf_deb_scan(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_SCAN, " scan", fmt, ##args)
+#define lbtf_deb_assoc(fmt, args...)     LBTF_DEB_LL(LBTF_DEB_ASSOC, " assoc", fmt, ##args)
+#define lbtf_deb_join(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_JOIN, " join", fmt, ##args)
+#define lbtf_deb_11d(fmt, args...)       LBTF_DEB_LL(LBTF_DEB_11D, " 11d", fmt, ##args)
+#define lbtf_deb_debugfs(fmt, args...)   LBTF_DEB_LL(LBTF_DEB_DEBUGFS, " debugfs", fmt, ##args)
+#define lbtf_deb_ethtool(fmt, args...)   LBTF_DEB_LL(LBTF_DEB_ETHTOOL, " ethtool", fmt, ##args)
+#define lbtf_deb_host(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_HOST, " host", fmt, ##args)
+#define lbtf_deb_cmd(fmt, args...)       LBTF_DEB_LL(LBTF_DEB_CMD, " cmd", fmt, ##args)
+#define lbtf_deb_rx(fmt, args...)        LBTF_DEB_LL(LBTF_DEB_RX, " rx", fmt, ##args)
+#define lbtf_deb_tx(fmt, args...)        LBTF_DEB_LL(LBTF_DEB_TX, " tx", fmt, ##args)
+#define lbtf_deb_fw(fmt, args...)        LBTF_DEB_LL(LBTF_DEB_FW, " fw", fmt, ##args)
+#define lbtf_deb_usb(fmt, args...)       LBTF_DEB_LL(LBTF_DEB_USB, " usb", fmt, ##args)
+#define lbtf_deb_usbd(dev, fmt, args...) LBTF_DEB_LL(LBTF_DEB_USB, " usbd", "%s:" fmt, dev_name(dev), ##args)
+#define lbtf_deb_cs(fmt, args...)        LBTF_DEB_LL(LBTF_DEB_CS, " cs", fmt, ##args)
+#define lbtf_deb_thread(fmt, args...)    LBTF_DEB_LL(LBTF_DEB_THREAD, " thread", fmt, ##args)
+#define lbtf_deb_sdio(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_SDIO, " thread", fmt, ##args)
+#define lbtf_deb_macops(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_MACOPS, " thread", fmt, ##args)
+
+#ifdef DEBUG
+static inline void lbtf_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
+{
+       char newprompt[32];
+
+       if (len &&
+           (lbtf_debug & LBTF_DEB_HEX) &&
+           (lbtf_debug & grp)) {
+               snprintf(newprompt, sizeof(newprompt), DRV_NAME " %s: ", prompt);
+               print_hex_dump_bytes(prompt, DUMP_PREFIX_NONE, buf, len);
+       }
+}
+#else
+#define lbtf_deb_hex(grp, prompt, buf, len)    do {} while (0)
+#endif
+
+#endif
index 8cc9db60c14b5c8e52fe8183feac773406cdcbc1..4412c279ca947c58790d5a118dcdb6829af87526 100644 (file)
@@ -7,6 +7,13 @@
  *  the Free Software Foundation; either version 2 of the License, or (at
  *  your option) any later version.
  */
+#define DRV_NAME "lbtf_usb"
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "libertas_tf.h"
+#include "if_usb.h"
+
 #include <linux/delay.h>
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
 #include <linux/usb.h>
 
-#define DRV_NAME "lbtf_usb"
-
-#include "libertas_tf.h"
-#include "if_usb.h"
+#define INSANEDEBUG    0
+#define lbtf_deb_usb2(...) do { if (INSANEDEBUG) lbtf_deb_usbd(__VA_ARGS__); } while (0)
 
 #define MESSAGE_HEADER_LEN     4
 
@@ -53,9 +58,14 @@ static int if_usb_reset_device(struct if_usb_card *cardp);
  */
 static void if_usb_write_bulk_callback(struct urb *urb)
 {
-       if (urb->status != 0)
-               printk(KERN_INFO "libertastf: URB in failure status: %d\n",
-                      urb->status);
+       if (urb->status != 0) {
+               /* print the failure status number for debug */
+               pr_info("URB in failure status: %d\n", urb->status);
+       } else {
+               lbtf_deb_usb2(&urb->dev->dev, "URB status is successful\n");
+               lbtf_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n",
+                            urb->actual_length);
+       }
 }
 
 /**
@@ -65,6 +75,8 @@ static void if_usb_write_bulk_callback(struct urb *urb)
  */
 static void if_usb_free(struct if_usb_card *cardp)
 {
+       lbtf_deb_enter(LBTF_DEB_USB);
+
        /* Unlink tx & rx urb */
        usb_kill_urb(cardp->tx_urb);
        usb_kill_urb(cardp->rx_urb);
@@ -81,6 +93,8 @@ static void if_usb_free(struct if_usb_card *cardp)
 
        kfree(cardp->ep_out_buf);
        cardp->ep_out_buf = NULL;
+
+       lbtf_deb_leave(LBTF_DEB_USB);
 }
 
 static void if_usb_setup_firmware(struct lbtf_private *priv)
@@ -88,23 +102,33 @@ static void if_usb_setup_firmware(struct lbtf_private *priv)
        struct if_usb_card *cardp = priv->card;
        struct cmd_ds_set_boot2_ver b2_cmd;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
+
        if_usb_submit_rx_urb(cardp);
        b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
        b2_cmd.action = 0;
        b2_cmd.version = cardp->boot2_version;
 
        if (lbtf_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd))
-               printk(KERN_INFO "libertastf: setting boot2 version failed\n");
+               lbtf_deb_usb("Setting boot2 version failed\n");
+
+       lbtf_deb_leave(LBTF_DEB_USB);
 }
 
 static void if_usb_fw_timeo(unsigned long priv)
 {
        struct if_usb_card *cardp = (void *)priv;
 
-       if (!cardp->fwdnldover)
+       lbtf_deb_enter(LBTF_DEB_USB);
+       if (!cardp->fwdnldover) {
                /* Download timed out */
                cardp->priv->surpriseremoved = 1;
+               pr_err("Download timed out\n");
+       } else {
+               lbtf_deb_usb("Download complete, no event. Assuming success\n");
+       }
        wake_up(&cardp->fw_wq);
+       lbtf_deb_leave(LBTF_DEB_USB);
 }
 
 /**
@@ -125,11 +149,14 @@ static int if_usb_probe(struct usb_interface *intf,
        struct if_usb_card *cardp;
        int i;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
        udev = interface_to_usbdev(intf);
 
        cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
-       if (!cardp)
+       if (!cardp) {
+               pr_err("Out of memory allocating private data.\n");
                goto error;
+       }
 
        setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp);
        init_waitqueue_head(&cardp->fw_wq);
@@ -137,38 +164,62 @@ static int if_usb_probe(struct usb_interface *intf,
        cardp->udev = udev;
        iface_desc = intf->cur_altsetting;
 
+       lbtf_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
+                    " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
+                    le16_to_cpu(udev->descriptor.bcdUSB),
+                    udev->descriptor.bDeviceClass,
+                    udev->descriptor.bDeviceSubClass,
+                    udev->descriptor.bDeviceProtocol);
+
        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
                endpoint = &iface_desc->endpoint[i].desc;
                if (usb_endpoint_is_bulk_in(endpoint)) {
                        cardp->ep_in_size =
                                le16_to_cpu(endpoint->wMaxPacketSize);
                        cardp->ep_in = usb_endpoint_num(endpoint);
+
+                       lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
+                       lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
                } else if (usb_endpoint_is_bulk_out(endpoint)) {
                        cardp->ep_out_size =
                                le16_to_cpu(endpoint->wMaxPacketSize);
                        cardp->ep_out = usb_endpoint_num(endpoint);
+
+                       lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
+                       lbtf_deb_usbd(&udev->dev, "Bulk out size is %d\n",
+                                     cardp->ep_out_size);
                }
        }
-       if (!cardp->ep_out_size || !cardp->ep_in_size)
+       if (!cardp->ep_out_size || !cardp->ep_in_size) {
+               lbtf_deb_usbd(&udev->dev, "Endpoints not found\n");
                /* Endpoints not found */
                goto dealloc;
+       }
 
        cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!cardp->rx_urb)
+       if (!cardp->rx_urb) {
+               lbtf_deb_usbd(&udev->dev, "Rx URB allocation failed\n");
                goto dealloc;
+       }
 
        cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!cardp->tx_urb)
+       if (!cardp->tx_urb) {
+               lbtf_deb_usbd(&udev->dev, "Tx URB allocation failed\n");
                goto dealloc;
+       }
 
        cardp->cmd_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!cardp->cmd_urb)
+       if (!cardp->cmd_urb) {
+               lbtf_deb_usbd(&udev->dev, "Cmd URB allocation failed\n");
                goto dealloc;
+       }
 
        cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
                                    GFP_KERNEL);
-       if (!cardp->ep_out_buf)
+       if (!cardp->ep_out_buf) {
+               lbtf_deb_usbd(&udev->dev, "Could not allocate buffer\n");
                goto dealloc;
+       }
 
        priv = lbtf_add_card(cardp, &udev->dev);
        if (!priv)
@@ -189,6 +240,7 @@ static int if_usb_probe(struct usb_interface *intf,
 dealloc:
        if_usb_free(cardp);
 error:
+lbtf_deb_leave(LBTF_DEB_MAIN);
        return -ENOMEM;
 }
 
@@ -202,6 +254,8 @@ static void if_usb_disconnect(struct usb_interface *intf)
        struct if_usb_card *cardp = usb_get_intfdata(intf);
        struct lbtf_private *priv = (struct lbtf_private *) cardp->priv;
 
+       lbtf_deb_enter(LBTF_DEB_MAIN);
+
        if_usb_reset_device(cardp);
 
        if (priv)
@@ -212,6 +266,8 @@ static void if_usb_disconnect(struct usb_interface *intf)
 
        usb_set_intfdata(intf, NULL);
        usb_put_dev(interface_to_usbdev(intf));
+
+       lbtf_deb_leave(LBTF_DEB_MAIN);
 }
 
 /**
@@ -226,6 +282,8 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
        struct fwdata *fwdata = cardp->ep_out_buf;
        u8 *firmware = (u8 *) cardp->fw->data;
 
+       lbtf_deb_enter(LBTF_DEB_FW);
+
        /* If we got a CRC failure on the last block, back
           up and retry it */
        if (!cardp->CRC_OK) {
@@ -233,6 +291,9 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
                cardp->fwseqnum--;
        }
 
+       lbtf_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n",
+                    cardp->totalbytes);
+
        /* struct fwdata (which we sent to the card) has an
           extra __le32 field in between the header and the data,
           which is not in the struct fwheader in the actual
@@ -246,18 +307,33 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
        memcpy(fwdata->data, &firmware[cardp->totalbytes],
               le32_to_cpu(fwdata->hdr.datalength));
 
+       lbtf_deb_usb2(&cardp->udev->dev, "Data length = %d\n",
+                    le32_to_cpu(fwdata->hdr.datalength));
+
        fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
        cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
 
        usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
                     le32_to_cpu(fwdata->hdr.datalength), 0);
 
-       if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK))
+       if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
+               lbtf_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
+               lbtf_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
+                            cardp->fwseqnum, cardp->totalbytes);
+       } else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
+               lbtf_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
+               lbtf_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
+
                /* Host has finished FW downloading
                 * Donwloading FW JUMP BLOCK
                 */
                cardp->fwfinalblk = 1;
+       }
 
+       lbtf_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n",
+                    cardp->totalbytes);
+
+       lbtf_deb_leave(LBTF_DEB_FW);
        return 0;
 }
 
@@ -266,6 +342,8 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
        struct cmd_ds_802_11_reset *cmd = cardp->ep_out_buf + 4;
        int ret;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
+
        *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
 
        cmd->hdr.command = cpu_to_le16(CMD_802_11_RESET);
@@ -280,6 +358,8 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
        ret = usb_reset_device(cardp->udev);
        msleep(100);
 
+       lbtf_deb_leave_args(LBTF_DEB_USB, "ret %d", ret);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(if_usb_reset_device);
@@ -297,11 +377,15 @@ EXPORT_SYMBOL_GPL(if_usb_reset_device);
 static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
                        uint16_t nb, u8 data)
 {
+       int ret = -1;
        struct urb *urb;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
        /* check if device is removed */
-       if (cardp->priv->surpriseremoved)
-               return -1;
+       if (cardp->priv->surpriseremoved) {
+               lbtf_deb_usbd(&cardp->udev->dev, "Device removed\n");
+               goto tx_ret;
+       }
 
        if (data)
                urb = cardp->tx_urb;
@@ -315,19 +399,34 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
 
        urb->transfer_flags |= URB_ZERO_PACKET;
 
-       if (usb_submit_urb(urb, GFP_ATOMIC))
-               return -1;
-       return 0;
+       if (usb_submit_urb(urb, GFP_ATOMIC)) {
+               lbtf_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
+               goto tx_ret;
+       }
+
+       lbtf_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
+
+       ret = 0;
+
+tx_ret:
+       lbtf_deb_leave(LBTF_DEB_USB);
+       return ret;
 }
 
 static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
                                  void (*callbackfn)(struct urb *urb))
 {
        struct sk_buff *skb;
+       int ret = -1;
+
+       lbtf_deb_enter(LBTF_DEB_USB);
 
        skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
-       if (!skb)
+       if (!skb) {
+               pr_err("No free skb\n");
+               lbtf_deb_leave(LBTF_DEB_USB);
                return -1;
+       }
 
        cardp->rx_skb = skb;
 
@@ -339,12 +438,19 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
 
        cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
 
-       if (usb_submit_urb(cardp->rx_urb, GFP_ATOMIC)) {
+       lbtf_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
+       ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC);
+       if (ret) {
+               lbtf_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
                kfree_skb(skb);
                cardp->rx_skb = NULL;
+               lbtf_deb_leave(LBTF_DEB_USB);
                return -1;
-       } else
+       } else {
+               lbtf_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n");
+               lbtf_deb_leave(LBTF_DEB_USB);
                return 0;
+       }
 }
 
 static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp)
@@ -364,8 +470,12 @@ static void if_usb_receive_fwload(struct urb *urb)
        struct fwsyncheader *syncfwheader;
        struct bootcmdresp bcmdresp;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
        if (urb->status) {
+               lbtf_deb_usbd(&cardp->udev->dev,
+                            "URB status is failed during fw load\n");
                kfree_skb(skb);
+               lbtf_deb_leave(LBTF_DEB_USB);
                return;
        }
 
@@ -373,12 +483,17 @@ static void if_usb_receive_fwload(struct urb *urb)
                __le32 *tmp = (__le32 *)(skb->data);
 
                if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
-                   tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY))
+                   tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
                        /* Firmware ready event received */
+                       pr_info("Firmware ready event received\n");
                        wake_up(&cardp->fw_wq);
-               else
+               } else {
+                       lbtf_deb_usb("Waiting for confirmation; got %x %x\n",
+                                   le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1]));
                        if_usb_submit_rx_urb_fwload(cardp);
+               }
                kfree_skb(skb);
+               lbtf_deb_leave(LBTF_DEB_USB);
                return;
        }
        if (cardp->bootcmdresp <= 0) {
@@ -389,34 +504,60 @@ static void if_usb_receive_fwload(struct urb *urb)
                        if_usb_submit_rx_urb_fwload(cardp);
                        cardp->bootcmdresp = 1;
                        /* Received valid boot command response */
+                       lbtf_deb_usbd(&cardp->udev->dev,
+                                    "Received valid boot command response\n");
+                       lbtf_deb_leave(LBTF_DEB_USB);
                        return;
                }
                if (bcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
                        if (bcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) ||
                            bcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
-                           bcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION))
+                           bcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
+                               if (!cardp->bootcmdresp)
+                                       pr_info("Firmware already seems alive; resetting\n");
                                cardp->bootcmdresp = -1;
-               } else if (bcmdresp.cmd == BOOT_CMD_FW_BY_USB &&
-                          bcmdresp.result == BOOT_CMD_RESP_OK)
+                       } else {
+                               pr_info("boot cmd response wrong magic number (0x%x)\n",
+                                           le32_to_cpu(bcmdresp.magic));
+                       }
+               } else if (bcmdresp.cmd != BOOT_CMD_FW_BY_USB) {
+                       pr_info("boot cmd response cmd_tag error (%d)\n",
+                                   bcmdresp.cmd);
+               } else if (bcmdresp.result != BOOT_CMD_RESP_OK) {
+                       pr_info("boot cmd response result error (%d)\n",
+                                   bcmdresp.result);
+               } else {
                        cardp->bootcmdresp = 1;
+                       lbtf_deb_usbd(&cardp->udev->dev,
+                                    "Received valid boot command response\n");
+               }
 
                kfree_skb(skb);
                if_usb_submit_rx_urb_fwload(cardp);
+               lbtf_deb_leave(LBTF_DEB_USB);
                return;
        }
 
        syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
        if (!syncfwheader) {
+               lbtf_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
                kfree_skb(skb);
+               lbtf_deb_leave(LBTF_DEB_USB);
                return;
        }
 
        memcpy(syncfwheader, skb->data, sizeof(struct fwsyncheader));
 
-       if (!syncfwheader->cmd)
+       if (!syncfwheader->cmd) {
+               lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
+               lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
+                            le32_to_cpu(syncfwheader->seqnum));
                cardp->CRC_OK = 1;
-       else
+       } else {
+               lbtf_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
                cardp->CRC_OK = 0;
+       }
+
        kfree_skb(skb);
 
        /* reschedule timer for 200ms hence */
@@ -434,6 +575,7 @@ static void if_usb_receive_fwload(struct urb *urb)
 
        kfree(syncfwheader);
 
+       lbtf_deb_leave(LBTF_DEB_USB);
        return;
 }
 
@@ -445,6 +587,7 @@ static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
 {
        if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
            || recvlength < MRVDRV_MIN_PKT_LEN) {
+               lbtf_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n");
                kfree_skb(skb);
                return;
        }
@@ -460,6 +603,8 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
                                      struct lbtf_private *priv)
 {
        if (recvlength > LBS_CMD_BUFFER_SIZE) {
+               lbtf_deb_usbd(&cardp->udev->dev,
+                            "The receive buffer is too large\n");
                kfree_skb(skb);
                return;
        }
@@ -489,16 +634,24 @@ static void if_usb_receive(struct urb *urb)
        uint32_t recvtype = 0;
        __le32 *pkt = (__le32 *) skb->data;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
+
        if (recvlength) {
                if (urb->status) {
+                       lbtf_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n",
+                                    urb->status);
                        kfree_skb(skb);
                        goto setup_for_next;
                }
 
                recvbuff = skb->data;
                recvtype = le32_to_cpu(pkt[0]);
+               lbtf_deb_usbd(&cardp->udev->dev,
+                           "Recv length = 0x%x, Recv type = 0x%X\n",
+                           recvlength, recvtype);
        } else if (urb->status) {
                kfree_skb(skb);
+               lbtf_deb_leave(LBTF_DEB_USB);
                return;
        }
 
@@ -515,6 +668,7 @@ static void if_usb_receive(struct urb *urb)
        {
                /* Event cause handling */
                u32 event_cause = le32_to_cpu(pkt[1]);
+               lbtf_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event_cause);
 
                /* Icky undocumented magic special case */
                if (event_cause & 0xffff0000) {
@@ -529,21 +683,22 @@ static void if_usb_receive(struct urb *urb)
                } else if (event_cause == LBTF_EVENT_BCN_SENT)
                        lbtf_bcn_sent(priv);
                else
-                       printk(KERN_DEBUG
+                       lbtf_deb_usbd(&cardp->udev->dev,
                               "Unsupported notification %d received\n",
                               event_cause);
                kfree_skb(skb);
                break;
        }
        default:
-               printk(KERN_DEBUG "libertastf: unknown command type 0x%X\n",
-                            recvtype);
+               lbtf_deb_usbd(&cardp->udev->dev,
+                        "libertastf: unknown command type 0x%X\n", recvtype);
                kfree_skb(skb);
                break;
        }
 
 setup_for_next:
        if_usb_submit_rx_urb(cardp);
+       lbtf_deb_leave(LBTF_DEB_USB);
 }
 
 /**
@@ -562,6 +717,9 @@ static int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type,
        struct if_usb_card *cardp = priv->card;
        u8 data = 0;
 
+       lbtf_deb_usbd(&cardp->udev->dev, "*** type = %u\n", type);
+       lbtf_deb_usbd(&cardp->udev->dev, "size after = %d\n", nb);
+
        if (type == MVMS_CMD) {
                *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
        } else {
@@ -639,8 +797,10 @@ static int check_fwfile_format(const u8 *data, u32 totlen)
        } while (!exit);
 
        if (ret)
-               printk(KERN_INFO
-                      "libertastf: firmware file format check failed\n");
+               pr_err("firmware file format check FAIL\n");
+       else
+               lbtf_deb_fw("firmware file format check PASS\n");
+
        return ret;
 }
 
@@ -651,10 +811,12 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp)
        static int reset_count = 10;
        int ret = 0;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
+
        ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev);
        if (ret < 0) {
-               printk(KERN_INFO "libertastf: firmware %s not found\n",
-                      lbtf_fw_name);
+               pr_err("request_firmware() failed with %#x\n", ret);
+               pr_err("firmware %s not found\n", lbtf_fw_name);
                goto done;
        }
 
@@ -663,6 +825,7 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp)
 
 restart:
        if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
+               lbtf_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
                ret = -1;
                goto release_fw;
        }
@@ -709,14 +872,13 @@ restart:
        usb_kill_urb(cardp->rx_urb);
 
        if (!cardp->fwdnldover) {
-               printk(KERN_INFO "libertastf: failed to load fw,"
-                                " resetting device!\n");
+               pr_info("failed to load fw, resetting device!\n");
                if (--reset_count >= 0) {
                        if_usb_reset_device(cardp);
                        goto restart;
                }
 
-               printk(KERN_INFO "libertastf: fw download failure\n");
+               pr_info("FW download failure, time = %d ms\n", i * 100);
                ret = -1;
                goto release_fw;
        }
@@ -730,6 +892,7 @@ restart:
        if_usb_setup_firmware(cardp->priv);
 
  done:
+       lbtf_deb_leave_args(LBTF_DEB_USB, "ret %d", ret);
        return ret;
 }
 EXPORT_SYMBOL_GPL(if_usb_prog_firmware);
@@ -751,13 +914,19 @@ static int __init if_usb_init_module(void)
 {
        int ret = 0;
 
+       lbtf_deb_enter(LBTF_DEB_MAIN);
+
        ret = usb_register(&if_usb_driver);
+
+       lbtf_deb_leave_args(LBTF_DEB_MAIN, "ret %d", ret);
        return ret;
 }
 
 static void __exit if_usb_exit_module(void)
 {
+       lbtf_deb_enter(LBTF_DEB_MAIN);
        usb_deregister(&if_usb_driver);
+       lbtf_deb_leave(LBTF_DEB_MAIN);
 }
 
 module_init(if_usb_init_module);
index 4cc42dd5a005258f10055bcaae3e61617e3bb2e9..fbbaaae7a1aefe4274c5ec0d31d58c2d0acdbe83 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/kthread.h>
 #include <net/mac80211.h>
 
+#include "deb_defs.h"
+
 #ifndef DRV_NAME
 #define DRV_NAME "libertas_tf"
 #endif
index 7533a23e0500f709368a160d64a3111515d12a56..60787de56f3a9b5865448da2527e34e8751b0924 100644 (file)
@@ -7,10 +7,12 @@
  *  the Free Software Foundation; either version 2 of the License, or (at
  *  your option) any later version.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/slab.h>
 
+#include <linux/etherdevice.h>
 #include "libertas_tf.h"
-#include "linux/etherdevice.h"
 
 #define DRIVER_RELEASE_VERSION "004.p0"
 /* thinfirm version: 5.132.X.pX */
 #define LBTF_FW_VER_MAX                0x0584ffff
 #define QOS_CONTROL_LEN                2
 
-static const char lbtf_driver_version[] = "THINFIRM-USB8388-" DRIVER_RELEASE_VERSION;
+/* Module parameters */
+unsigned int lbtf_debug;
+EXPORT_SYMBOL_GPL(lbtf_debug);
+module_param_named(libertas_tf_debug, lbtf_debug, int, 0644);
+
+static const char lbtf_driver_version[] = "THINFIRM-USB8388-" DRIVER_RELEASE_VERSION
+#ifdef DEBUG
+       "-dbg"
+#endif
+       "";
+
 struct workqueue_struct *lbtf_wq;
 
 static const struct ieee80211_channel lbtf_channels[] = {
@@ -81,6 +93,9 @@ static void lbtf_cmd_work(struct work_struct *work)
 {
        struct lbtf_private *priv = container_of(work, struct lbtf_private,
                                         cmd_work);
+
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        spin_lock_irq(&priv->driver_lock);
        /* command response? */
        if (priv->cmd_response_rxed) {
@@ -108,11 +123,16 @@ static void lbtf_cmd_work(struct work_struct *work)
        priv->cmd_timed_out = 0;
        spin_unlock_irq(&priv->driver_lock);
 
-       if (!priv->fw_ready)
+       if (!priv->fw_ready) {
+               lbtf_deb_leave_args(LBTF_DEB_CMD, "fw not ready");
                return;
+       }
+
        /* Execute the next command */
        if (!priv->cur_cmd)
                lbtf_execute_next_command(priv);
+
+       lbtf_deb_leave(LBTF_DEB_CMD);
 }
 
 /**
@@ -126,6 +146,7 @@ static int lbtf_setup_firmware(struct lbtf_private *priv)
 {
        int ret = -1;
 
+       lbtf_deb_enter(LBTF_DEB_FW);
        /*
         * Read priv address from HW
         */
@@ -141,6 +162,7 @@ static int lbtf_setup_firmware(struct lbtf_private *priv)
 
        ret = 0;
 done:
+       lbtf_deb_leave_args(LBTF_DEB_FW, "ret: %d", ret);
        return ret;
 }
 
@@ -152,6 +174,7 @@ static void command_timer_fn(unsigned long data)
 {
        struct lbtf_private *priv = (struct lbtf_private *)data;
        unsigned long flags;
+       lbtf_deb_enter(LBTF_DEB_CMD);
 
        spin_lock_irqsave(&priv->driver_lock, flags);
 
@@ -168,10 +191,12 @@ static void command_timer_fn(unsigned long data)
        queue_work(lbtf_wq, &priv->cmd_work);
 out:
        spin_unlock_irqrestore(&priv->driver_lock, flags);
+       lbtf_deb_leave(LBTF_DEB_CMD);
 }
 
 static int lbtf_init_adapter(struct lbtf_private *priv)
 {
+       lbtf_deb_enter(LBTF_DEB_MAIN);
        memset(priv->current_addr, 0xff, ETH_ALEN);
        mutex_init(&priv->lock);
 
@@ -188,13 +213,16 @@ static int lbtf_init_adapter(struct lbtf_private *priv)
        if (lbtf_allocate_cmd_buffer(priv))
                return -1;
 
+       lbtf_deb_leave(LBTF_DEB_MAIN);
        return 0;
 }
 
 static void lbtf_free_adapter(struct lbtf_private *priv)
 {
+       lbtf_deb_enter(LBTF_DEB_MAIN);
        lbtf_free_cmd_buffer(priv);
        del_timer(&priv->command_timer);
+       lbtf_deb_leave(LBTF_DEB_MAIN);
 }
 
 static int lbtf_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
@@ -221,14 +249,18 @@ static void lbtf_tx_work(struct work_struct *work)
        struct sk_buff *skb = NULL;
        int err;
 
+       lbtf_deb_enter(LBTF_DEB_MACOPS | LBTF_DEB_TX);
+
        if ((priv->vif->type == NL80211_IFTYPE_AP) &&
            (!skb_queue_empty(&priv->bc_ps_buf)))
                skb = skb_dequeue(&priv->bc_ps_buf);
        else if (priv->skb_to_tx) {
                skb = priv->skb_to_tx;
                priv->skb_to_tx = NULL;
-       } else
+       } else {
+               lbtf_deb_leave(LBTF_DEB_MACOPS | LBTF_DEB_TX);
                return;
+       }
 
        len = skb->len;
        info  = IEEE80211_SKB_CB(skb);
@@ -236,6 +268,7 @@ static void lbtf_tx_work(struct work_struct *work)
 
        if (priv->surpriseremoved) {
                dev_kfree_skb_any(skb);
+               lbtf_deb_leave(LBTF_DEB_MACOPS | LBTF_DEB_TX);
                return;
        }
 
@@ -249,6 +282,7 @@ static void lbtf_tx_work(struct work_struct *work)
                ETH_ALEN);
        txpd->tx_packet_length = cpu_to_le16(len);
        txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
+       lbtf_deb_hex(LBTF_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
        BUG_ON(priv->tx_skb);
        spin_lock_irq(&priv->driver_lock);
        priv->tx_skb = skb;
@@ -257,7 +291,9 @@ static void lbtf_tx_work(struct work_struct *work)
        if (err) {
                dev_kfree_skb_any(skb);
                priv->tx_skb = NULL;
+               pr_err("TX error: %d", err);
        }
+       lbtf_deb_leave(LBTF_DEB_MACOPS | LBTF_DEB_TX);
 }
 
 static int lbtf_op_start(struct ieee80211_hw *hw)
@@ -266,6 +302,8 @@ static int lbtf_op_start(struct ieee80211_hw *hw)
        void *card = priv->card;
        int ret = -1;
 
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
+
        if (!priv->fw_ready)
                /* Upload firmware */
                if (priv->hw_prog_firmware(card))
@@ -286,10 +324,12 @@ static int lbtf_op_start(struct ieee80211_hw *hw)
        }
 
        printk(KERN_INFO "libertastf: Marvell WLAN 802.11 thinfirm adapter\n");
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
        return 0;
 
 err_prog_firmware:
        priv->hw_reset_device(card);
+       lbtf_deb_leave_args(LBTF_DEB_MACOPS, "error programing fw; ret=%d", ret);
        return ret;
 }
 
@@ -300,6 +340,9 @@ static void lbtf_op_stop(struct ieee80211_hw *hw)
        struct sk_buff *skb;
 
        struct cmd_ctrl_node *cmdnode;
+
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
+
        /* Flush pending command nodes */
        spin_lock_irqsave(&priv->driver_lock, flags);
        list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
@@ -316,6 +359,7 @@ static void lbtf_op_stop(struct ieee80211_hw *hw)
        priv->radioon = RADIO_OFF;
        lbtf_set_radio_control(priv);
 
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
        return;
 }
 
@@ -323,6 +367,7 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
                        struct ieee80211_vif *vif)
 {
        struct lbtf_private *priv = hw->priv;
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
        if (priv->vif != NULL)
                return -EOPNOTSUPP;
 
@@ -340,6 +385,7 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
                return -EOPNOTSUPP;
        }
        lbtf_set_mac_address(priv, (u8 *) vif->addr);
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
        return 0;
 }
 
@@ -347,6 +393,7 @@ static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
                        struct ieee80211_vif *vif)
 {
        struct lbtf_private *priv = hw->priv;
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
 
        if (priv->vif->type == NL80211_IFTYPE_AP ||
            priv->vif->type == NL80211_IFTYPE_MESH_POINT)
@@ -354,17 +401,20 @@ static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
        lbtf_set_mode(priv, LBTF_PASSIVE_MODE);
        lbtf_set_bssid(priv, 0, NULL);
        priv->vif = NULL;
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
 }
 
 static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct lbtf_private *priv = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
 
        if (conf->channel->center_freq != priv->cur_freq) {
                priv->cur_freq = conf->channel->center_freq;
                lbtf_set_channel(priv, conf->channel->hw_value);
        }
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
        return 0;
 }
 
@@ -395,11 +445,16 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
 {
        struct lbtf_private *priv = hw->priv;
        int old_mac_control = priv->mac_control;
+
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
+
        changed_flags &= SUPPORTED_FIF_FLAGS;
        *new_flags &= SUPPORTED_FIF_FLAGS;
 
-       if (!changed_flags)
+       if (!changed_flags) {
+               lbtf_deb_leave(LBTF_DEB_MACOPS);
                return;
+       }
 
        if (*new_flags & (FIF_PROMISC_IN_BSS))
                priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
@@ -425,6 +480,8 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
 
        if (priv->mac_control != old_mac_control)
                lbtf_set_mac_control(priv);
+
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
 }
 
 static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw,
@@ -434,6 +491,7 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw,
 {
        struct lbtf_private *priv = hw->priv;
        struct sk_buff *beacon;
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
 
        if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_INT)) {
                switch (priv->vif->type) {
@@ -464,6 +522,8 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw,
                        priv->preamble = CMD_TYPE_LONG_PREAMBLE;
                lbtf_set_radio_control(priv);
        }
+
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
 }
 
 static const struct ieee80211_ops lbtf_ops = {
@@ -486,6 +546,8 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
        unsigned int flags;
        struct ieee80211_hdr *hdr;
 
+       lbtf_deb_enter(LBTF_DEB_RX);
+
        prxpd = (struct rxpd *) skb->data;
 
        stats.flag = 0;
@@ -494,7 +556,6 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
        stats.freq = priv->cur_freq;
        stats.band = IEEE80211_BAND_2GHZ;
        stats.signal = prxpd->snr;
-       stats.noise = prxpd->nf;
        /* Marvell rate index has a hole at value 4 */
        if (prxpd->rx_rate > 4)
                --prxpd->rx_rate;
@@ -516,7 +577,15 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
        }
 
        memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
+
+       lbtf_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
+              skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+       lbtf_deb_hex(LBTF_DEB_RX, "RX Data", skb->data,
+                    min_t(unsigned int, skb->len, 100));
+
        ieee80211_rx_irqsafe(priv->hw, skb);
+
+       lbtf_deb_leave(LBTF_DEB_RX);
        return 0;
 }
 EXPORT_SYMBOL_GPL(lbtf_rx);
@@ -533,6 +602,8 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev)
        struct ieee80211_hw *hw;
        struct lbtf_private *priv = NULL;
 
+       lbtf_deb_enter(LBTF_DEB_MAIN);
+
        hw = ieee80211_alloc_hw(sizeof(struct lbtf_private), &lbtf_ops);
        if (!hw)
                goto done;
@@ -575,6 +646,7 @@ err_init_adapter:
        priv = NULL;
 
 done:
+       lbtf_deb_leave_args(LBTF_DEB_MAIN, "priv %p", priv);
        return priv;
 }
 EXPORT_SYMBOL_GPL(lbtf_add_card);
@@ -584,6 +656,8 @@ int lbtf_remove_card(struct lbtf_private *priv)
 {
        struct ieee80211_hw *hw = priv->hw;
 
+       lbtf_deb_enter(LBTF_DEB_MAIN);
+
        priv->surpriseremoved = 1;
        del_timer(&priv->command_timer);
        lbtf_free_adapter(priv);
@@ -591,6 +665,7 @@ int lbtf_remove_card(struct lbtf_private *priv)
        ieee80211_unregister_hw(hw);
        ieee80211_free_hw(hw);
 
+    lbtf_deb_leave(LBTF_DEB_MAIN);
        return 0;
 }
 EXPORT_SYMBOL_GPL(lbtf_remove_card);
@@ -649,17 +724,21 @@ EXPORT_SYMBOL_GPL(lbtf_bcn_sent);
 
 static int __init lbtf_init_module(void)
 {
+       lbtf_deb_enter(LBTF_DEB_MAIN);
        lbtf_wq = create_workqueue("libertastf");
        if (lbtf_wq == NULL) {
                printk(KERN_ERR "libertastf: couldn't create workqueue\n");
                return -ENOMEM;
        }
+       lbtf_deb_leave(LBTF_DEB_MAIN);
        return 0;
 }
 
 static void __exit lbtf_exit_module(void)
 {
+       lbtf_deb_enter(LBTF_DEB_MAIN);
        destroy_workqueue(lbtf_wq);
+       lbtf_deb_leave(LBTF_DEB_MAIN);
 }
 
 module_init(lbtf_init_module);
index 6f0d8c9fa933d4f2e533ea9a08f940a6fd973bc0..9fd2beadb6f566214053b8912b9d0788e4562937 100644 (file)
@@ -974,6 +974,7 @@ static void hw_scan_done(struct work_struct *work)
 }
 
 static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif,
                                  struct cfg80211_scan_request *req)
 {
        struct hw_scan_done *hsd = kzalloc(sizeof(*hsd), GFP_KERNEL);
@@ -1020,7 +1021,7 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw)
        mutex_lock(&hwsim->mutex);
 
        printk(KERN_DEBUG "hwsim sw_scan_complete\n");
-       hwsim->scanning = true;
+       hwsim->scanning = false;
 
        mutex_unlock(&hwsim->mutex);
 }
@@ -1299,7 +1300,8 @@ static int __init init_mac80211_hwsim(void)
                hw->flags = IEEE80211_HW_MFP_CAPABLE |
                            IEEE80211_HW_SIGNAL_DBM |
                            IEEE80211_HW_SUPPORTS_STATIC_SMPS |
-                           IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
+                           IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
+                           IEEE80211_HW_AMPDU_AGGREGATION;
 
                /* ask mac80211 to reserve space for magic */
                hw->vif_data_size = sizeof(struct hwsim_vif_priv);
index 73bbd080c6e7b3ef2ce3f58a07e11fede10fc8dd..808adb9090952347feeaafe03b801bb8ae681b62 100644 (file)
@@ -750,7 +750,6 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
        memset(status, 0, sizeof(*status));
 
        status->signal = -rxd->rssi;
-       status->noise = -rxd->noise_floor;
 
        if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) {
                status->flag |= RX_FLAG_HT;
@@ -852,7 +851,6 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status,
        memset(status, 0, sizeof(*status));
 
        status->signal = -rxd->rssi;
-       status->noise = -rxd->noise_level;
        status->antenna = MWL8K_STA_RATE_INFO_ANTSELECT(rate_info);
        status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info);
 
@@ -3984,8 +3982,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 
        hw->queues = MWL8K_TX_QUEUES;
 
-       /* Set rssi and noise values to dBm */
-       hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM;
+       /* Set rssi values to dBm */
+       hw->flags |= IEEE80211_HW_SIGNAL_DBM;
        hw->vif_data_size = sizeof(struct mwl8k_vif);
        hw->sta_data_size = sizeof(struct mwl8k_sta);
 
index 6116b546861d80c8174342c4672b5ca1eb43c1aa..60819bcf437735fd43a7f03d14ba988623e8e9e6 100644 (file)
@@ -132,3 +132,10 @@ config PCMCIA_SPECTRUM
          This driver requires firmware download on startup.  Utilities
          for downloading Symbol firmware are available at
          <http://sourceforge.net/projects/orinoco/>
+
+config ORINOCO_USB
+       tristate "Agere Orinoco USB support"
+       depends on USB && HERMES
+       select FW_LOADER
+       ---help---
+         This driver is for USB versions of the Agere Orinoco card.
index e6452698eba9bc6bd150bedb19880e63ecf66176..bfdefb85abcdf1bffebc0e130ef81bd5546241fe 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_PCI_HERMES)      += orinoco_pci.o
 obj-$(CONFIG_TMD_HERMES)       += orinoco_tmd.o
 obj-$(CONFIG_NORTEL_HERMES)    += orinoco_nortel.o
 obj-$(CONFIG_PCMCIA_SPECTRUM)  += spectrum_cs.o
+obj-$(CONFIG_ORINOCO_USB)      += orinoco_usb.o
 
 # Orinoco should be endian clean.
 ccflags-y += -D__CHECK_ENDIAN__
index c60df2c1aca305166313aa5f3fc0e60fd201f9ba..9bcee10c9308f861089843ccfe7c9b3009907e6d 100644 (file)
@@ -77,9 +77,9 @@ airport_resume(struct macio_dev *mdev)
 
        enable_irq(card->irq);
 
-       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, &flags);
        err = orinoco_up(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
        return err;
 }
@@ -195,7 +195,7 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
        ssleep(1);
 
        /* Reset it before we get the interrupt */
-       hermes_init(hw);
+       hw->ops->init(hw);
 
        if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) {
                printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq);
@@ -210,7 +210,7 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
        }
 
        /* Register an interface with the stack */
-       if (orinoco_if_add(priv, phys_addr, card->irq) != 0) {
+       if (orinoco_if_add(priv, phys_addr, card->irq, NULL) != 0) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto failed;
        }
index 90dd4d0595c33b544894beb0b8eef9f56ed6f574..81d228de9e5dc855a26e8f582123c8ea1624bc3f 100644 (file)
@@ -189,7 +189,7 @@ static int orinoco_set_channel(struct wiphy *wiphy,
        if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
                /* Fast channel change - no commit if successful */
                hermes_t *hw = &priv->hw;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+               err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
                                            HERMES_TEST_SET_CHANNEL,
                                        channel, NULL);
        }
index 5ea0f7cf85b1d2f8653eb0941f2a50eeaf7861dc..3e1947d097ca83faf849b8de051eb506247f9cb3 100644 (file)
@@ -122,7 +122,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
        dev_dbg(dev, "Attempting to download firmware %s\n", firmware);
 
        /* Read current plug data */
-       err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
+       err = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
        dev_dbg(dev, "Read PDA returned %d\n", err);
        if (err)
                goto free;
@@ -149,7 +149,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
        }
 
        /* Enable aux port to allow programming */
-       err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
+       err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point));
        dev_dbg(dev, "Program init returned %d\n", err);
        if (err != 0)
                goto abort;
@@ -177,7 +177,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
                goto abort;
 
        /* Tell card we've finished */
-       err = hermesi_program_end(hw);
+       err = hw->ops->program_end(hw);
        dev_dbg(dev, "Program end returned %d\n", err);
        if (err != 0)
                goto abort;
@@ -224,7 +224,7 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
                if (!pda)
                        return -ENOMEM;
 
-               ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1);
+               ret = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
                if (ret)
                        goto free;
        }
@@ -260,7 +260,7 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
        }
 
        /* Reset hermes chip and make sure it responds */
-       ret = hermes_init(hw);
+       ret = hw->ops->init(hw);
 
        /* hermes_reset() should return 0 with the secondary firmware */
        if (secondary && ret != 0)
index 1a2fca76fd3c87b87aef781dab91f1d9c8bb1ac4..6c6a23e08df652a8db97da4310cb2d4ca6e617f4 100644 (file)
 #define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
 #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
 
+/*
+ * AUX port access.  To unlock the AUX port write the access keys to the
+ * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
+ * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
+ */
+#define HERMES_AUX_ENABLE      0x8000  /* Enable auxiliary port access */
+#define HERMES_AUX_DISABLE     0x4000  /* Disable to auxiliary port access */
+#define HERMES_AUX_ENABLED     0xC000  /* Auxiliary port is open */
+#define HERMES_AUX_DISABLED    0x0000  /* Auxiliary port is closed */
+
+#define HERMES_AUX_PW0 0xFE01
+#define HERMES_AUX_PW1 0xDC23
+#define HERMES_AUX_PW2 0xBA45
+
+/* HERMES_CMD_DOWNLD */
+#define HERMES_PROGRAM_DISABLE             (0x0000 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_ENABLE_VOLATILE     (0x0100 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_NON_VOLATILE        (0x0300 | HERMES_CMD_DOWNLD)
+
 /*
  * Debugging helpers
  */
@@ -70,6 +90,7 @@
 
 #endif /* ! HERMES_DEBUG */
 
+static const struct hermes_ops hermes_ops_local;
 
 /*
  * Internal functions
@@ -111,9 +132,9 @@ static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0,
  */
 
 /* For doing cmds that wipe the magic constant in SWSUPPORT0 */
-int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
-                      u16 parm0, u16 parm1, u16 parm2,
-                      struct hermes_response *resp)
+static int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
+                             u16 parm0, u16 parm1, u16 parm2,
+                             struct hermes_response *resp)
 {
        int err = 0;
        int k;
@@ -163,17 +184,18 @@ int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
 out:
        return err;
 }
-EXPORT_SYMBOL(hermes_doicmd_wait);
 
 void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
 {
        hw->iobase = address;
        hw->reg_spacing = reg_spacing;
        hw->inten = 0x0;
+       hw->eeprom_pda = false;
+       hw->ops = &hermes_ops_local;
 }
 EXPORT_SYMBOL(hermes_struct_init);
 
-int hermes_init(hermes_t *hw)
+static int hermes_init(hermes_t *hw)
 {
        u16 reg;
        int err = 0;
@@ -217,7 +239,6 @@ int hermes_init(hermes_t *hw)
 
        return err;
 }
-EXPORT_SYMBOL(hermes_init);
 
 /* Issue a command to the chip, and (busy!) wait for it to
  * complete.
@@ -228,8 +249,8 @@ EXPORT_SYMBOL(hermes_init);
  *     > 0 on error returned by the firmware
  *
  * Callable from any context, but locking is your problem. */
-int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
-                     struct hermes_response *resp)
+static int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
+                            struct hermes_response *resp)
 {
        int err;
        int k;
@@ -291,9 +312,8 @@ int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
  out:
        return err;
 }
-EXPORT_SYMBOL(hermes_docmd_wait);
 
-int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
+static int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
 {
        int err = 0;
        int k;
@@ -333,7 +353,6 @@ int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
 
        return 0;
 }
-EXPORT_SYMBOL(hermes_allocate);
 
 /* Set up a BAP to read a particular chunk of data from card's internal buffer.
  *
@@ -403,8 +422,8 @@ static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
  *       0 on success
  *     > 0 on error from firmware
  */
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
-                    u16 id, u16 offset)
+static int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
+                           u16 id, u16 offset)
 {
        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
        int err = 0;
@@ -422,7 +441,6 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
  out:
        return err;
 }
-EXPORT_SYMBOL(hermes_bap_pread);
 
 /* Write a block of data to the chip's buffer, via the
  * BAP. Synchronization/serialization is the caller's problem.
@@ -432,8 +450,8 @@ EXPORT_SYMBOL(hermes_bap_pread);
  *       0 on success
  *     > 0 on error from firmware
  */
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
-                     u16 id, u16 offset)
+static int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
+                            u16 id, u16 offset)
 {
        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
        int err = 0;
@@ -451,7 +469,6 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
  out:
        return err;
 }
-EXPORT_SYMBOL(hermes_bap_pwrite);
 
 /* Read a Length-Type-Value record from the card.
  *
@@ -461,8 +478,8 @@ EXPORT_SYMBOL(hermes_bap_pwrite);
  * practice.
  *
  * Callable from user or bh context.  */
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
-                   u16 *length, void *buf)
+static int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
+                          u16 *length, void *buf)
 {
        int err = 0;
        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
@@ -505,10 +522,9 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
 
        return 0;
 }
-EXPORT_SYMBOL(hermes_read_ltv);
 
-int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
-                    u16 length, const void *value)
+static int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
+                           u16 length, const void *value)
 {
        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
        int err = 0;
@@ -533,4 +549,228 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
 
        return err;
 }
-EXPORT_SYMBOL(hermes_write_ltv);
+
+/*** Hermes AUX control ***/
+
+static inline void
+hermes_aux_setaddr(hermes_t *hw, u32 addr)
+{
+       hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
+       hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
+}
+
+static inline int
+hermes_aux_control(hermes_t *hw, int enabled)
+{
+       int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
+       int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
+       int i;
+
+       /* Already open? */
+       if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
+               return 0;
+
+       hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
+       hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
+       hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
+       hermes_write_reg(hw, HERMES_CONTROL, action);
+
+       for (i = 0; i < 20; i++) {
+               udelay(10);
+               if (hermes_read_reg(hw, HERMES_CONTROL) ==
+                   desired_state)
+                       return 0;
+       }
+
+       return -EBUSY;
+}
+
+/*** Hermes programming ***/
+
+/* About to start programming data (Hermes I)
+ * offset is the entry point
+ *
+ * Spectrum_cs' Symbol fw does not require this
+ * wl_lkm Agere fw does
+ * Don't know about intersil
+ */
+static int hermesi_program_init(hermes_t *hw, u32 offset)
+{
+       int err;
+
+       /* Disable interrupts?*/
+       /*hw->inten = 0x0;*/
+       /*hermes_write_regn(hw, INTEN, 0);*/
+       /*hermes_set_irqmask(hw, 0);*/
+
+       /* Acknowledge any outstanding command */
+       hermes_write_regn(hw, EVACK, 0xFFFF);
+
+       /* Using init_cmd_wait rather than cmd_wait */
+       err = hw->ops->init_cmd_wait(hw,
+                                    0x0100 | HERMES_CMD_INIT,
+                                    0, 0, 0, NULL);
+       if (err)
+               return err;
+
+       err = hw->ops->init_cmd_wait(hw,
+                                    0x0000 | HERMES_CMD_INIT,
+                                    0, 0, 0, NULL);
+       if (err)
+               return err;
+
+       err = hermes_aux_control(hw, 1);
+       pr_debug("AUX enable returned %d\n", err);
+
+       if (err)
+               return err;
+
+       pr_debug("Enabling volatile, EP 0x%08x\n", offset);
+       err = hw->ops->init_cmd_wait(hw,
+                                    HERMES_PROGRAM_ENABLE_VOLATILE,
+                                    offset & 0xFFFFu,
+                                    offset >> 16,
+                                    0,
+                                    NULL);
+       pr_debug("PROGRAM_ENABLE returned %d\n", err);
+
+       return err;
+}
+
+/* Done programming data (Hermes I)
+ *
+ * Spectrum_cs' Symbol fw does not require this
+ * wl_lkm Agere fw does
+ * Don't know about intersil
+ */
+static int hermesi_program_end(hermes_t *hw)
+{
+       struct hermes_response resp;
+       int rc = 0;
+       int err;
+
+       rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
+
+       pr_debug("PROGRAM_DISABLE returned %d, "
+                "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
+                rc, resp.resp0, resp.resp1, resp.resp2);
+
+       if ((rc == 0) &&
+           ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
+               rc = -EIO;
+
+       err = hermes_aux_control(hw, 0);
+       pr_debug("AUX disable returned %d\n", err);
+
+       /* Acknowledge any outstanding command */
+       hermes_write_regn(hw, EVACK, 0xFFFF);
+
+       /* Reinitialise, ignoring return */
+       (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
+                                     0, 0, 0, NULL);
+
+       return rc ? rc : err;
+}
+
+static int hermes_program_bytes(struct hermes *hw, const char *data,
+                               u32 addr, u32 len)
+{
+       /* wl lkm splits the programming into chunks of 2000 bytes.
+        * This restriction appears to come from USB. The PCMCIA
+        * adapters can program the whole lot in one go */
+       hermes_aux_setaddr(hw, addr);
+       hermes_write_bytes(hw, HERMES_AUXDATA, data, len);
+       return 0;
+}
+
+/* Read PDA from the adapter */
+static int hermes_read_pda(hermes_t *hw, __le16 *pda, u32 pda_addr, u16 pda_len)
+{
+       int ret;
+       u16 pda_size;
+       u16 data_len = pda_len;
+       __le16 *data = pda;
+
+       if (hw->eeprom_pda) {
+               /* PDA of spectrum symbol is in eeprom */
+
+               /* Issue command to read EEPROM */
+               ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
+               if (ret)
+                       return ret;
+       } else {
+               /* wl_lkm does not include PDA size in the PDA area.
+                * We will pad the information into pda, so other routines
+                * don't have to be modified */
+               pda[0] = cpu_to_le16(pda_len - 2);
+                       /* Includes CFG_PROD_DATA but not itself */
+               pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
+               data_len = pda_len - 4;
+               data = pda + 2;
+       }
+
+       /* Open auxiliary port */
+       ret = hermes_aux_control(hw, 1);
+       pr_debug("AUX enable returned %d\n", ret);
+       if (ret)
+               return ret;
+
+       /* Read PDA */
+       hermes_aux_setaddr(hw, pda_addr);
+       hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
+
+       /* Close aux port */
+       ret = hermes_aux_control(hw, 0);
+       pr_debug("AUX disable returned %d\n", ret);
+
+       /* Check PDA length */
+       pda_size = le16_to_cpu(pda[0]);
+       pr_debug("Actual PDA length %d, Max allowed %d\n",
+                pda_size, pda_len);
+       if (pda_size > pda_len)
+               return -EINVAL;
+
+       return 0;
+}
+
+static void hermes_lock_irqsave(spinlock_t *lock,
+                               unsigned long *flags) __acquires(lock)
+{
+       spin_lock_irqsave(lock, *flags);
+}
+
+static void hermes_unlock_irqrestore(spinlock_t *lock,
+                                    unsigned long *flags) __releases(lock)
+{
+       spin_unlock_irqrestore(lock, *flags);
+}
+
+static void hermes_lock_irq(spinlock_t *lock) __acquires(lock)
+{
+       spin_lock_irq(lock);
+}
+
+static void hermes_unlock_irq(spinlock_t *lock) __releases(lock)
+{
+       spin_unlock_irq(lock);
+}
+
+/* Hermes operations for local buses */
+static const struct hermes_ops hermes_ops_local = {
+       .init = hermes_init,
+       .cmd_wait = hermes_docmd_wait,
+       .init_cmd_wait = hermes_doicmd_wait,
+       .allocate = hermes_allocate,
+       .read_ltv = hermes_read_ltv,
+       .write_ltv = hermes_write_ltv,
+       .bap_pread = hermes_bap_pread,
+       .bap_pwrite = hermes_bap_pwrite,
+       .read_pda = hermes_read_pda,
+       .program_init = hermesi_program_init,
+       .program_end = hermesi_program_end,
+       .program = hermes_program_bytes,
+       .lock_irqsave = hermes_lock_irqsave,
+       .unlock_irqrestore = hermes_unlock_irqrestore,
+       .lock_irq = hermes_lock_irq,
+       .unlock_irq = hermes_unlock_irq,
+};
index 2dddbb597c4d26715dba1303b407038505182501..9ca34e722b45fc0d335b42ad339f40d25305c65e 100644 (file)
@@ -374,6 +374,37 @@ struct hermes_multicast {
 /* Timeouts */
 #define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
 
+struct hermes;
+
+/* Functions to access hardware */
+struct hermes_ops {
+       int (*init)(struct hermes *hw);
+       int (*cmd_wait)(struct hermes *hw, u16 cmd, u16 parm0,
+                       struct hermes_response *resp);
+       int (*init_cmd_wait)(struct hermes *hw, u16 cmd,
+                            u16 parm0, u16 parm1, u16 parm2,
+                            struct hermes_response *resp);
+       int (*allocate)(struct hermes *hw, u16 size, u16 *fid);
+       int (*read_ltv)(struct hermes *hw, int bap, u16 rid, unsigned buflen,
+                       u16 *length, void *buf);
+       int (*write_ltv)(struct hermes *hw, int bap, u16 rid,
+                        u16 length, const void *value);
+       int (*bap_pread)(struct hermes *hw, int bap, void *buf, int len,
+                        u16 id, u16 offset);
+       int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf,
+                         int len, u16 id, u16 offset);
+       int (*read_pda)(struct hermes *hw, __le16 *pda,
+                       u32 pda_addr, u16 pda_len);
+       int (*program_init)(struct hermes *hw, u32 entry_point);
+       int (*program_end)(struct hermes *hw);
+       int (*program)(struct hermes *hw, const char *buf,
+                      u32 addr, u32 len);
+       void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags);
+       void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags);
+       void (*lock_irq)(spinlock_t *lock);
+       void (*unlock_irq)(spinlock_t *lock);
+};
+
 /* Basic control structure */
 typedef struct hermes {
        void __iomem *iobase;
@@ -381,6 +412,9 @@ typedef struct hermes {
 #define HERMES_16BIT_REGSPACING        0
 #define HERMES_32BIT_REGSPACING        1
        u16 inten; /* Which interrupts should be enabled? */
+       bool eeprom_pda;
+       const struct hermes_ops *ops;
+       void *priv;
 } hermes_t;
 
 /* Register access convenience macros */
@@ -394,22 +428,6 @@ typedef struct hermes {
 
 /* Function prototypes */
 void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing);
-int hermes_init(hermes_t *hw);
-int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
-                     struct hermes_response *resp);
-int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
-                      u16 parm0, u16 parm1, u16 parm2,
-                      struct hermes_response *resp);
-int hermes_allocate(hermes_t *hw, u16 size, u16 *fid);
-
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
-                      u16 id, u16 offset);
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
-                       u16 id, u16 offset);
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen,
-                   u16 *length, void *buf);
-int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
-                     u16 length, const void *value);
 
 /* Inline functions */
 
@@ -426,13 +444,13 @@ static inline void hermes_set_irqmask(hermes_t *hw, u16 events)
 
 static inline int hermes_enable_port(hermes_t *hw, int port)
 {
-       return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
+       return hw->ops->cmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
                                 0, NULL);
 }
 
 static inline int hermes_disable_port(hermes_t *hw, int port)
 {
-       return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8),
+       return hw->ops->cmd_wait(hw, HERMES_CMD_DISABLE | (port << 8),
                                 0, NULL);
 }
 
@@ -440,7 +458,7 @@ static inline int hermes_disable_port(hermes_t *hw, int port)
  * information frame in __orinoco_ev_info() */
 static inline int hermes_inquire(hermes_t *hw, u16 rid)
 {
-       return hermes_docmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
+       return hw->ops->cmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
 }
 
 #define HERMES_BYTES_TO_RECLEN(n) ((((n)+1)/2) + 1)
@@ -475,10 +493,10 @@ static inline void hermes_clear_words(struct hermes *hw, int off,
 }
 
 #define HERMES_READ_RECORD(hw, bap, rid, buf) \
-       (hermes_read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
+       (hw->ops->read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
 #define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
-       (hermes_write_ltv((hw), (bap), (rid), \
-                         HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf)))
+       (hw->ops->write_ltv((hw), (bap), (rid), \
+                           HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf)))
 
 static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word)
 {
index fb157eb889ca19f20d507e7933b471ba8c564385..6da85e75fce071e2205a1a95767e8ee891af3dbc 100644 (file)
 
 #define PFX "hermes_dld: "
 
-/*
- * AUX port access.  To unlock the AUX port write the access keys to the
- * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
- * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
- */
-#define HERMES_AUX_ENABLE      0x8000  /* Enable auxiliary port access */
-#define HERMES_AUX_DISABLE     0x4000  /* Disable to auxiliary port access */
-#define HERMES_AUX_ENABLED     0xC000  /* Auxiliary port is open */
-#define HERMES_AUX_DISABLED    0x0000  /* Auxiliary port is closed */
-
-#define HERMES_AUX_PW0 0xFE01
-#define HERMES_AUX_PW1 0xDC23
-#define HERMES_AUX_PW2 0xBA45
-
-/* HERMES_CMD_DOWNLD */
-#define HERMES_PROGRAM_DISABLE             (0x0000 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_VOLATILE     (0x0100 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_NON_VOLATILE        (0x0300 | HERMES_CMD_DOWNLD)
-
 /* End markers used in dblocks */
 #define PDI_END                0x00000000      /* End of PDA */
 #define BLOCK_END      0xFFFFFFFF      /* Last image block */
 #define TEXT_END       0x1A            /* End of text header */
 
-/* Limit the amout we try to download in a single shot.
- * Size is in bytes.
- */
-#define MAX_DL_SIZE 1024
-#define LIMIT_PROGRAM_SIZE 0
-
 /*
  * The following structures have little-endian fields denoted by
  * the leading underscore.  Don't access them directly - use inline
@@ -165,41 +139,6 @@ pdi_len(const struct pdi *pdi)
        return 2 * (le16_to_cpu(pdi->len) - 1);
 }
 
-/*** Hermes AUX control ***/
-
-static inline void
-hermes_aux_setaddr(hermes_t *hw, u32 addr)
-{
-       hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
-       hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
-}
-
-static inline int
-hermes_aux_control(hermes_t *hw, int enabled)
-{
-       int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
-       int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
-       int i;
-
-       /* Already open? */
-       if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
-               return 0;
-
-       hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
-       hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
-       hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
-       hermes_write_reg(hw, HERMES_CONTROL, action);
-
-       for (i = 0; i < 20; i++) {
-               udelay(10);
-               if (hermes_read_reg(hw, HERMES_CONTROL) ==
-                   desired_state)
-                       return 0;
-       }
-
-       return -EBUSY;
-}
-
 /*** Plug Data Functions ***/
 
 /*
@@ -271,62 +210,7 @@ hermes_plug_pdi(hermes_t *hw, const struct pdr *first_pdr,
                return -EINVAL;
 
        /* do the actual plugging */
-       hermes_aux_setaddr(hw, pdr_addr(pdr));
-       hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
-
-       return 0;
-}
-
-/* Read PDA from the adapter */
-int hermes_read_pda(hermes_t *hw,
-                   __le16 *pda,
-                   u32 pda_addr,
-                   u16 pda_len,
-                   int use_eeprom) /* can we get this into hw? */
-{
-       int ret;
-       u16 pda_size;
-       u16 data_len = pda_len;
-       __le16 *data = pda;
-
-       if (use_eeprom) {
-               /* PDA of spectrum symbol is in eeprom */
-
-               /* Issue command to read EEPROM */
-               ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
-               if (ret)
-                       return ret;
-       } else {
-               /* wl_lkm does not include PDA size in the PDA area.
-                * We will pad the information into pda, so other routines
-                * don't have to be modified */
-               pda[0] = cpu_to_le16(pda_len - 2);
-                       /* Includes CFG_PROD_DATA but not itself */
-               pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
-               data_len = pda_len - 4;
-               data = pda + 2;
-       }
-
-       /* Open auxiliary port */
-       ret = hermes_aux_control(hw, 1);
-       pr_debug(PFX "AUX enable returned %d\n", ret);
-       if (ret)
-               return ret;
-
-       /* read PDA from EEPROM */
-       hermes_aux_setaddr(hw, pda_addr);
-       hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
-
-       /* Close aux port */
-       ret = hermes_aux_control(hw, 0);
-       pr_debug(PFX "AUX disable returned %d\n", ret);
-
-       /* Check PDA length */
-       pda_size = le16_to_cpu(pda[0]);
-       pr_debug(PFX "Actual PDA length %d, Max allowed %d\n",
-                pda_size, pda_len);
-       if (pda_size > pda_len)
-               return -EINVAL;
+       hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi));
 
        return 0;
 }
@@ -389,101 +273,13 @@ hermes_blocks_length(const char *first_block, const void *end)
 
 /*** Hermes programming ***/
 
-/* About to start programming data (Hermes I)
- * offset is the entry point
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-int hermesi_program_init(hermes_t *hw, u32 offset)
-{
-       int err;
-
-       /* Disable interrupts?*/
-       /*hw->inten = 0x0;*/
-       /*hermes_write_regn(hw, INTEN, 0);*/
-       /*hermes_set_irqmask(hw, 0);*/
-
-       /* Acknowledge any outstanding command */
-       hermes_write_regn(hw, EVACK, 0xFFFF);
-
-       /* Using doicmd_wait rather than docmd_wait */
-       err = hermes_doicmd_wait(hw,
-                                0x0100 | HERMES_CMD_INIT,
-                                0, 0, 0, NULL);
-       if (err)
-               return err;
-
-       err = hermes_doicmd_wait(hw,
-                                0x0000 | HERMES_CMD_INIT,
-                                0, 0, 0, NULL);
-       if (err)
-               return err;
-
-       err = hermes_aux_control(hw, 1);
-       pr_debug(PFX "AUX enable returned %d\n", err);
-
-       if (err)
-               return err;
-
-       pr_debug(PFX "Enabling volatile, EP 0x%08x\n", offset);
-       err = hermes_doicmd_wait(hw,
-                                HERMES_PROGRAM_ENABLE_VOLATILE,
-                                offset & 0xFFFFu,
-                                offset >> 16,
-                                0,
-                                NULL);
-       pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err);
-
-       return err;
-}
-
-/* Done programming data (Hermes I)
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-int hermesi_program_end(hermes_t *hw)
-{
-       struct hermes_response resp;
-       int rc = 0;
-       int err;
-
-       rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
-
-       pr_debug(PFX "PROGRAM_DISABLE returned %d, "
-                "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
-                rc, resp.resp0, resp.resp1, resp.resp2);
-
-       if ((rc == 0) &&
-           ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
-               rc = -EIO;
-
-       err = hermes_aux_control(hw, 0);
-       pr_debug(PFX "AUX disable returned %d\n", err);
-
-       /* Acknowledge any outstanding command */
-       hermes_write_regn(hw, EVACK, 0xFFFF);
-
-       /* Reinitialise, ignoring return */
-       (void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
-                                 0, 0, 0, NULL);
-
-       return rc ? rc : err;
-}
-
 /* Program the data blocks */
 int hermes_program(hermes_t *hw, const char *first_block, const void *end)
 {
        const struct dblock *blk;
        u32 blkaddr;
        u32 blklen;
-#if LIMIT_PROGRAM_SIZE
-       u32 addr;
-       u32 len;
-#endif
+       int err = 0;
 
        blk = (const struct dblock *) first_block;
 
@@ -498,30 +294,10 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
                pr_debug(PFX "Programming block of length %d "
                         "to address 0x%08x\n", blklen, blkaddr);
 
-#if !LIMIT_PROGRAM_SIZE
-               /* wl_lkm driver splits this into writes of 2000 bytes */
-               hermes_aux_setaddr(hw, blkaddr);
-               hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
-                                  blklen);
-#else
-               len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE;
-               addr = blkaddr;
-
-               while (addr < (blkaddr + blklen)) {
-                       pr_debug(PFX "Programming subblock of length %d "
-                                "to address 0x%08x. Data @ %p\n",
-                                len, addr, &blk->data[addr - blkaddr]);
-
-                       hermes_aux_setaddr(hw, addr);
-                       hermes_write_bytes(hw, HERMES_AUXDATA,
-                                          &blk->data[addr - blkaddr],
-                                          len);
-
-                       addr += len;
-                       len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ?
-                               (blkaddr + blklen - addr) : MAX_DL_SIZE;
-               }
-#endif
+               err = hw->ops->program(hw, blk->data, blkaddr, blklen);
+               if (err)
+                       break;
+
                blk = (const struct dblock *) &blk->data[blklen];
 
                if ((void *) blk > (end - sizeof(*blk)))
@@ -530,7 +306,7 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
                blkaddr = dblock_addr(blk);
                blklen = dblock_len(blk);
        }
-       return 0;
+       return err;
 }
 
 /*** Default plugging data for Hermes I ***/
@@ -690,9 +466,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
                        if ((pdi_len(pdi) == pdr_len(pdr)) &&
                            ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
                                /* do the actual plugging */
-                               hermes_aux_setaddr(hw, pdr_addr(pdr));
-                               hermes_write_bytes(hw, HERMES_AUXDATA,
-                                                  pdi->data, pdi_len(pdi));
+                               hw->ops->program(hw, pdi->data, pdr_addr(pdr),
+                                                pdi_len(pdi));
                        }
                }
 
index 741f8cea95b9230f4088167af7ed27822c989ca1..6fbd78850123fe100737f5bfec9d69005857d254 100644 (file)
@@ -177,9 +177,9 @@ int determine_fw_capabilities(struct orinoco_private *priv,
                /* 3Com MAC : 00:50:DA:* */
                memset(tmp, 0, sizeof(tmp));
                /* Get the Symbol firmware version */
-               err = hermes_read_ltv(hw, USER_BAP,
-                                     HERMES_RID_SECONDARYVERSION_SYMBOL,
-                                     SYMBOL_MAX_VER_LEN, NULL, &tmp);
+               err = hw->ops->read_ltv(hw, USER_BAP,
+                                       HERMES_RID_SECONDARYVERSION_SYMBOL,
+                                       SYMBOL_MAX_VER_LEN, NULL, &tmp);
                if (err) {
                        dev_warn(dev, "Error %d reading Symbol firmware info. "
                                 "Wildly guessing capabilities...\n", err);
@@ -286,8 +286,8 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
        u16 reclen;
 
        /* Get the MAC address */
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
-                             ETH_ALEN, NULL, dev_addr);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+                               ETH_ALEN, NULL, dev_addr);
        if (err) {
                dev_warn(dev, "Failed to read MAC address!\n");
                goto out;
@@ -296,8 +296,8 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
        dev_dbg(dev, "MAC address %pM\n", dev_addr);
 
        /* Get the station name */
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
-                             sizeof(nickbuf), &reclen, &nickbuf);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+                               sizeof(nickbuf), &reclen, &nickbuf);
        if (err) {
                dev_err(dev, "failed to read station name\n");
                goto out;
@@ -413,11 +413,11 @@ int orinoco_hw_allocate_fid(struct orinoco_private *priv)
        struct hermes *hw = &priv->hw;
        int err;
 
-       err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+       err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
        if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
                /* Try workaround for old Symbol firmware bug */
                priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
-               err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+               err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
 
                dev_warn(dev, "Firmware ALLOC bug detected "
                         "(old Symbol firmware?). Work around %s\n",
@@ -463,8 +463,9 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
        struct hermes_idstring idbuf;
 
        /* Set the MAC address */
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
-                              HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
+       err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+                                HERMES_BYTES_TO_RECLEN(ETH_ALEN),
+                                dev->dev_addr);
        if (err) {
                printk(KERN_ERR "%s: Error %d setting MAC address\n",
                       dev->name, err);
@@ -527,7 +528,7 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
        idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
        memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
        /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
+       err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
                        HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
                        &idbuf);
        if (err) {
@@ -535,7 +536,7 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
                       dev->name, err);
                return err;
        }
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
+       err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
                        HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
                        &idbuf);
        if (err) {
@@ -547,9 +548,9 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
        /* Set the station name */
        idbuf.len = cpu_to_le16(strlen(priv->nick));
        memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
-                              HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
-                              &idbuf);
+       err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+                                HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
+                                &idbuf);
        if (err) {
                printk(KERN_ERR "%s: Error %d setting nickname\n",
                       dev->name, err);
@@ -664,12 +665,12 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
        if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
                /* Enable monitor mode */
                dev->type = ARPHRD_IEEE80211;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+               err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
                                            HERMES_TEST_MONITOR, 0, NULL);
        } else {
                /* Disable monitor mode */
                dev->type = ARPHRD_ETHER;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+               err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
                                            HERMES_TEST_STOP, 0, NULL);
        }
        if (err)
@@ -695,8 +696,8 @@ int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
        if ((key < 0) || (key >= 4))
                return -EINVAL;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
-                             sizeof(tsc_arr), NULL, &tsc_arr);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
+                               sizeof(tsc_arr), NULL, &tsc_arr);
        if (!err)
                memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
 
@@ -875,7 +876,7 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
                                memcpy(key, priv->keys[i].key,
                                       priv->keys[i].key_len);
 
-                               err = hermes_write_ltv(hw, USER_BAP,
+                               err = hw->ops->write_ltv(hw, USER_BAP,
                                                HERMES_RID_CNFDEFAULTKEY0 + i,
                                                HERMES_BYTES_TO_RECLEN(keylen),
                                                key);
@@ -1092,7 +1093,7 @@ int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
                        memcpy(mclist.addr[i++], ha->addr, ETH_ALEN);
                }
 
-               err = hermes_write_ltv(hw, USER_BAP,
+               err = hw->ops->write_ltv(hw, USER_BAP,
                                   HERMES_RID_CNFGROUPADDRESSES,
                                   HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
                                   &mclist);
@@ -1134,15 +1135,15 @@ int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
                rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
                        HERMES_RID_CNFDESIREDSSID;
 
-               err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
-                                     NULL, &essidbuf);
+               err = hw->ops->read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
+                                       NULL, &essidbuf);
                if (err)
                        goto fail_unlock;
        } else {
                *active = 0;
 
-               err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
-                                     sizeof(essidbuf), NULL, &essidbuf);
+               err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
+                                       sizeof(essidbuf), NULL, &essidbuf);
                if (err)
                        goto fail_unlock;
        }
@@ -1213,8 +1214,8 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
-                             sizeof(list), NULL, &list);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
+                               sizeof(list), NULL, &list);
        orinoco_unlock(priv, &flags);
 
        if (err)
@@ -1281,7 +1282,7 @@ int orinoco_hw_trigger_scan(struct orinoco_private *priv,
                                idbuf.len = cpu_to_le16(len);
                                memcpy(idbuf.val, ssid->ssid, len);
 
-                               err = hermes_write_ltv(hw, USER_BAP,
+                               err = hw->ops->write_ltv(hw, USER_BAP,
                                               HERMES_RID_CNFSCANSSID_AGERE,
                                               HERMES_BYTES_TO_RECLEN(len + 2),
                                               &idbuf);
@@ -1345,8 +1346,8 @@ int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
        hermes_t *hw = &priv->hw;
        int err;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-                             ETH_ALEN, NULL, addr);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+                               ETH_ALEN, NULL, addr);
 
        return err;
 }
index 413e9ab6cab3bb1fb70782f85c07066ec55eac31..1d60c7e4392a2ffa86cbf0c977c04f2999fc9522 100644 (file)
@@ -254,7 +254,7 @@ void set_port_type(struct orinoco_private *priv)
 /* Device methods                                                   */
 /********************************************************************/
 
-static int orinoco_open(struct net_device *dev)
+int orinoco_open(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
@@ -272,8 +272,9 @@ static int orinoco_open(struct net_device *dev)
 
        return err;
 }
+EXPORT_SYMBOL(orinoco_open);
 
-static int orinoco_stop(struct net_device *dev)
+int orinoco_stop(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        int err = 0;
@@ -281,25 +282,27 @@ static int orinoco_stop(struct net_device *dev)
        /* We mustn't use orinoco_lock() here, because we need to be
           able to close the interface even if hw_unavailable is set
           (e.g. as we're released after a PC Card removal) */
-       spin_lock_irq(&priv->lock);
+       orinoco_lock_irq(priv);
 
        priv->open = 0;
 
        err = __orinoco_down(priv);
 
-       spin_unlock_irq(&priv->lock);
+       orinoco_unlock_irq(priv);
 
        return err;
 }
+EXPORT_SYMBOL(orinoco_stop);
 
-static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
+struct net_device_stats *orinoco_get_stats(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
 
        return &priv->stats;
 }
+EXPORT_SYMBOL(orinoco_get_stats);
 
-static void orinoco_set_multicast_list(struct net_device *dev)
+void orinoco_set_multicast_list(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
@@ -313,8 +316,9 @@ static void orinoco_set_multicast_list(struct net_device *dev)
        __orinoco_set_multicast_list(dev);
        orinoco_unlock(priv, &flags);
 }
+EXPORT_SYMBOL(orinoco_set_multicast_list);
 
-static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
+int orinoco_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct orinoco_private *priv = ndev_priv(dev);
 
@@ -330,6 +334,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
 
        return 0;
 }
+EXPORT_SYMBOL(orinoco_change_mtu);
 
 /********************************************************************/
 /* Tx path                                                          */
@@ -400,8 +405,8 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                memset(&desc, 0, sizeof(desc));
 
                *txcntl = cpu_to_le16(tx_control);
-               err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
-                                       txfid, 0);
+               err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+                                         txfid, 0);
                if (err) {
                        if (net_ratelimit())
                                printk(KERN_ERR "%s: Error %d writing Tx "
@@ -414,8 +419,8 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                memset(&desc, 0, sizeof(desc));
 
                desc.tx_control = cpu_to_le16(tx_control);
-               err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
-                                       txfid, 0);
+               err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+                                         txfid, 0);
                if (err) {
                        if (net_ratelimit())
                                printk(KERN_ERR "%s: Error %d writing Tx "
@@ -458,8 +463,8 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                memcpy(eh, &hdr, sizeof(hdr));
        }
 
-       err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len,
-                               txfid, HERMES_802_3_OFFSET);
+       err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len,
+                                 txfid, HERMES_802_3_OFFSET);
        if (err) {
                printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
                       dev->name, err);
@@ -490,8 +495,8 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                            skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
 
                /* Write the MIC */
-               err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
-                                       txfid, HERMES_802_3_OFFSET + offset);
+               err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
+                                         txfid, HERMES_802_3_OFFSET + offset);
                if (err) {
                        printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
                               dev->name, err);
@@ -502,7 +507,7 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Finally, we actually initiate the send */
        netif_stop_queue(dev);
 
-       err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
+       err = hw->ops->cmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
                                txfid, NULL);
        if (err) {
                netif_start_queue(dev);
@@ -572,9 +577,9 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
                return; /* Nothing's really happened */
 
        /* Read part of the frame header - we need status and addr1 */
-       err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
-                              sizeof(struct hermes_txexc_data),
-                              fid, 0);
+       err = hw->ops->bap_pread(hw, IRQ_BAP, &hdr,
+                                sizeof(struct hermes_txexc_data),
+                                fid, 0);
 
        hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
        stats->tx_errors++;
@@ -615,7 +620,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
        netif_wake_queue(dev);
 }
 
-static void orinoco_tx_timeout(struct net_device *dev)
+void orinoco_tx_timeout(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
@@ -630,6 +635,7 @@ static void orinoco_tx_timeout(struct net_device *dev)
 
        schedule_work(&priv->reset_work);
 }
+EXPORT_SYMBOL(orinoco_tx_timeout);
 
 /********************************************************************/
 /* Rx path (data frames)                                            */
@@ -764,9 +770,9 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
 
        /* If any, copy the data from the card to the skb */
        if (datalen > 0) {
-               err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
-                                      ALIGN(datalen, 2), rxfid,
-                                      HERMES_802_2_OFFSET);
+               err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+                                        ALIGN(datalen, 2), rxfid,
+                                        HERMES_802_2_OFFSET);
                if (err) {
                        printk(KERN_ERR "%s: error %d reading monitor frame\n",
                               dev->name, err);
@@ -792,7 +798,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
        stats->rx_dropped++;
 }
 
-static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
+void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
@@ -814,8 +820,8 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 
        rxfid = hermes_read_regn(hw, RXFID);
 
-       err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
-                              rxfid, 0);
+       err = hw->ops->bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
+                                rxfid, 0);
        if (err) {
                printk(KERN_ERR "%s: error %d reading Rx descriptor. "
                       "Frame dropped.\n", dev->name, err);
@@ -882,9 +888,9 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
           nothing is removed.  2 is for aligning the IP header.  */
        skb_reserve(skb, ETH_HLEN + 2);
 
-       err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
-                              ALIGN(length, 2), rxfid,
-                              HERMES_802_2_OFFSET);
+       err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, length),
+                                ALIGN(length, 2), rxfid,
+                                HERMES_802_2_OFFSET);
        if (err) {
                printk(KERN_ERR "%s: error %d reading frame. "
                       "Frame dropped.\n", dev->name, err);
@@ -913,6 +919,7 @@ update_stats:
 out:
        kfree(desc);
 }
+EXPORT_SYMBOL(__orinoco_ev_rx);
 
 static void orinoco_rx(struct net_device *dev,
                       struct hermes_rx_descriptor *desc,
@@ -1145,9 +1152,9 @@ static void orinoco_join_ap(struct work_struct *work)
                goto out;
 
        /* Read scan results from the firmware */
-       err = hermes_read_ltv(hw, USER_BAP,
-                             HERMES_RID_SCANRESULTSTABLE,
-                             MAX_SCAN_LEN, &len, buf);
+       err = hw->ops->read_ltv(hw, USER_BAP,
+                               HERMES_RID_SCANRESULTSTABLE,
+                               MAX_SCAN_LEN, &len, buf);
        if (err) {
                printk(KERN_ERR "%s: Cannot read scan results\n",
                       dev->name);
@@ -1194,8 +1201,8 @@ static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
        union iwreq_data wrqu;
        int err;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-                             ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+                               ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
        if (err != 0)
                return;
 
@@ -1217,8 +1224,8 @@ static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
        if (!priv->has_wpa)
                return;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
-                             sizeof(buf), NULL, &buf);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
+                               sizeof(buf), NULL, &buf);
        if (err != 0)
                return;
 
@@ -1247,8 +1254,9 @@ static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
        if (!priv->has_wpa)
                return;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
-                             sizeof(buf), NULL, &buf);
+       err = hw->ops->read_ltv(hw, USER_BAP,
+                               HERMES_RID_CURRENT_ASSOC_RESP_INFO,
+                               sizeof(buf), NULL, &buf);
        if (err != 0)
                return;
 
@@ -1353,7 +1361,7 @@ static void orinoco_process_scan_results(struct work_struct *work)
        spin_unlock_irqrestore(&priv->scan_lock, flags);
 }
 
-static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
+void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        u16 infofid;
@@ -1371,8 +1379,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
        infofid = hermes_read_regn(hw, INFOFID);
 
        /* Read the info frame header - don't try too hard */
-       err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),
-                              infofid, 0);
+       err = hw->ops->bap_pread(hw, IRQ_BAP, &info, sizeof(info),
+                                infofid, 0);
        if (err) {
                printk(KERN_ERR "%s: error %d reading info frame. "
                       "Frame dropped.\n", dev->name, err);
@@ -1393,8 +1401,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                        len = sizeof(tallies);
                }
 
-               err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len,
-                                      infofid, sizeof(info));
+               err = hw->ops->bap_pread(hw, IRQ_BAP, &tallies, len,
+                                        infofid, sizeof(info));
                if (err)
                        break;
 
@@ -1429,8 +1437,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                        break;
                }
 
-               err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len,
-                                      infofid, sizeof(info));
+               err = hw->ops->bap_pread(hw, IRQ_BAP, &linkstatus, len,
+                                        infofid, sizeof(info));
                if (err)
                        break;
                newstatus = le16_to_cpu(linkstatus.linkstatus);
@@ -1494,8 +1502,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                }
 
                /* Read scan data */
-               err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
-                                      infofid, sizeof(info));
+               err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) buf, len,
+                                        infofid, sizeof(info));
                if (err) {
                        kfree(buf);
                        qabort_scan(priv);
@@ -1547,8 +1555,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                        break;
 
                /* Read scan data */
-               err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
-                                      infofid, sizeof(info));
+               err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) bss, len,
+                                        infofid, sizeof(info));
                if (err)
                        kfree(bss);
                else
@@ -1571,6 +1579,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 
        return;
 }
+EXPORT_SYMBOL(__orinoco_ev_info);
 
 static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
 {
@@ -1647,7 +1656,7 @@ static int orinoco_reinit_firmware(struct orinoco_private *priv)
        struct hermes *hw = &priv->hw;
        int err;
 
-       err = hermes_init(hw);
+       err = hw->ops->init(hw);
        if (priv->do_fw_download && !err) {
                err = orinoco_download(priv);
                if (err)
@@ -1735,7 +1744,7 @@ void orinoco_reset(struct work_struct *work)
        }
 
        /* This has to be called from user context */
-       spin_lock_irq(&priv->lock);
+       orinoco_lock_irq(priv);
 
        priv->hw_unavailable--;
 
@@ -1750,7 +1759,7 @@ void orinoco_reset(struct work_struct *work)
                        dev->trans_start = jiffies;
        }
 
-       spin_unlock_irq(&priv->lock);
+       orinoco_unlock_irq(priv);
 
        return;
  disable:
@@ -1984,7 +1993,7 @@ int orinoco_init(struct orinoco_private *priv)
        priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
 
        /* Initialize the firmware */
-       err = hermes_init(hw);
+       err = hw->ops->init(hw);
        if (err != 0) {
                dev_err(dev, "Failed to initialize firmware (err = %d)\n",
                        err);
@@ -2067,9 +2076,9 @@ int orinoco_init(struct orinoco_private *priv)
 
        /* Make the hardware available, as long as it hasn't been
         * removed elsewhere (e.g. by PCMCIA hot unplug) */
-       spin_lock_irq(&priv->lock);
+       orinoco_lock_irq(priv);
        priv->hw_unavailable--;
-       spin_unlock_irq(&priv->lock);
+       orinoco_unlock_irq(priv);
 
        dev_dbg(dev, "Ready\n");
 
@@ -2192,7 +2201,8 @@ EXPORT_SYMBOL(alloc_orinocodev);
  */
 int orinoco_if_add(struct orinoco_private *priv,
                   unsigned long base_addr,
-                  unsigned int irq)
+                  unsigned int irq,
+                  const struct net_device_ops *ops)
 {
        struct wiphy *wiphy = priv_to_wiphy(priv);
        struct wireless_dev *wdev;
@@ -2211,12 +2221,17 @@ int orinoco_if_add(struct orinoco_private *priv,
 
        /* Setup / override net_device fields */
        dev->ieee80211_ptr = wdev;
-       dev->netdev_ops = &orinoco_netdev_ops;
        dev->watchdog_timeo = HZ; /* 1 second timeout */
        dev->wireless_handlers = &orinoco_handler_def;
 #ifdef WIRELESS_SPY
        dev->wireless_data = &priv->wireless_data;
 #endif
+       /* Default to standard ops if not set */
+       if (ops)
+               dev->netdev_ops = ops;
+       else
+               dev->netdev_ops = &orinoco_netdev_ops;
+
        /* we use the default eth_mac_addr for setting the MAC addr */
 
        /* Reserve space in skb for the SNAP header */
@@ -2305,7 +2320,7 @@ int orinoco_up(struct orinoco_private *priv)
        unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, &flags);
 
        err = orinoco_reinit_firmware(priv);
        if (err) {
@@ -2325,7 +2340,7 @@ int orinoco_up(struct orinoco_private *priv)
        }
 
 exit:
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
        return 0;
 }
@@ -2337,7 +2352,7 @@ void orinoco_down(struct orinoco_private *priv)
        unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, &flags);
        err = __orinoco_down(priv);
        if (err)
                printk(KERN_WARNING "%s: Error %d downing interface\n",
@@ -2345,7 +2360,7 @@ void orinoco_down(struct orinoco_private *priv)
 
        netif_device_detach(dev);
        priv->hw_unavailable++;
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 }
 EXPORT_SYMBOL(orinoco_down);
 
index ff6b7b1d421d10fe72c758a812e09d1e67ebbfbd..e9f415a56d4d6cd271c7a408568de42ea6bc93e9 100644 (file)
@@ -190,12 +190,24 @@ extern void free_orinocodev(struct orinoco_private *priv);
 extern int orinoco_init(struct orinoco_private *priv);
 extern int orinoco_if_add(struct orinoco_private *priv,
                          unsigned long base_addr,
-                         unsigned int irq);
+                         unsigned int irq,
+                         const struct net_device_ops *ops);
 extern void orinoco_if_del(struct orinoco_private *priv);
 extern int orinoco_up(struct orinoco_private *priv);
 extern void orinoco_down(struct orinoco_private *priv);
 extern irqreturn_t orinoco_interrupt(int irq, void *dev_id);
 
+extern void __orinoco_ev_info(struct net_device *dev, hermes_t *hw);
+extern void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw);
+
+/* Common ndo functions exported for reuse by orinoco_usb */
+int orinoco_open(struct net_device *dev);
+int orinoco_stop(struct net_device *dev);
+struct net_device_stats *orinoco_get_stats(struct net_device *dev);
+void orinoco_set_multicast_list(struct net_device *dev);
+int orinoco_change_mtu(struct net_device *dev, int new_mtu);
+void orinoco_tx_timeout(struct net_device *dev);
+
 /********************************************************************/
 /* Locking and synchronization functions                            */
 /********************************************************************/
@@ -203,11 +215,11 @@ extern irqreturn_t orinoco_interrupt(int irq, void *dev_id);
 static inline int orinoco_lock(struct orinoco_private *priv,
                               unsigned long *flags)
 {
-       spin_lock_irqsave(&priv->lock, *flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, flags);
        if (priv->hw_unavailable) {
                DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n",
                       priv->ndev);
-               spin_unlock_irqrestore(&priv->lock, *flags);
+               priv->hw.ops->unlock_irqrestore(&priv->lock, flags);
                return -EBUSY;
        }
        return 0;
@@ -216,7 +228,17 @@ static inline int orinoco_lock(struct orinoco_private *priv,
 static inline void orinoco_unlock(struct orinoco_private *priv,
                                  unsigned long *flags)
 {
-       spin_unlock_irqrestore(&priv->lock, *flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, flags);
+}
+
+static inline void orinoco_lock_irq(struct orinoco_private *priv)
+{
+       priv->hw.ops->lock_irq(&priv->lock);
+}
+
+static inline void orinoco_unlock_irq(struct orinoco_private *priv)
+{
+       priv->hw.ops->unlock_irq(&priv->lock);
 }
 
 /*** Navigate from net_device to orinoco_private ***/
index fdc961379170b30b4a5571ee422a16b00cf9c74b..f99b13ba92b36bb536bda9787f4f3a223da555c1 100644 (file)
@@ -296,7 +296,7 @@ orinoco_cs_config(struct pcmcia_device *link)
 
        /* Register an interface with the stack */
        if (orinoco_if_add(priv, link->io.BasePort1,
-                          link->irq.AssignedIRQ) != 0) {
+                          link->irq.AssignedIRQ, NULL) != 0) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto failed;
        }
@@ -327,9 +327,9 @@ orinoco_cs_release(struct pcmcia_device *link)
 
        /* We're committed to taking the device away now, so mark the
         * hardware as unavailable */
-       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, &flags);
        priv->hw_unavailable++;
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
        pcmcia_disable_device(link);
        if (priv->hw.iobase)
index 075f446b3139269cd0e492dd17fcba6c65fe19c8..bc3ea0b67a4f8ec83eb62f283455bdf4b05034af 100644 (file)
@@ -220,7 +220,7 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
                goto fail;
        }
 
-       err = orinoco_if_add(priv, 0, 0);
+       err = orinoco_if_add(priv, 0, 0, NULL);
        if (err) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto fail;
index bda5317cc596038c91f2e966c94c69185c9a1ac6..468197f86673e3b0569e993218d96ac257f44c04 100644 (file)
@@ -170,7 +170,7 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
                goto fail;
        }
 
-       err = orinoco_if_add(priv, 0, 0);
+       err = orinoco_if_add(priv, 0, 0, NULL);
        if (err) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto fail;
index e0d5874ab42fb9090ccaad1fa3e39e882ce4acef..9358f4d2307bb19265f462227bc3c8dd81ace14e 100644 (file)
@@ -259,7 +259,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
                goto fail;
        }
 
-       err = orinoco_if_add(priv, 0, 0);
+       err = orinoco_if_add(priv, 0, 0, NULL);
        if (err) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto fail;
index 88cbc7902aa0a1e5c31de5a6b66534babbed8561..784605f0af157e193c6f99e5eab5d0ce2afa3d29 100644 (file)
@@ -156,7 +156,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
                goto fail;
        }
 
-       err = orinoco_if_add(priv, 0, 0);
+       err = orinoco_if_add(priv, 0, 0, NULL);
        if (err) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto fail;
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
new file mode 100644 (file)
index 0000000..e220933
--- /dev/null
@@ -0,0 +1,1800 @@
+/*
+ * USB Orinoco driver
+ *
+ * Copyright (c) 2003 Manuel Estrada Sainz
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ *
+ * Queueing code based on linux-wlan-ng 0.2.1-pre5
+ *
+ * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+ *
+ *     The license is the same as above.
+ *
+ * Initialy based on USB Skeleton driver - 0.7
+ *
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ * NOTE: The original USB Skeleton driver is GPL, but all that code is
+ * gone so MPL/GPL applies.
+ */
+
+#define DRIVER_NAME "orinoco_usb"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/timer.h>
+
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+
+#include "orinoco.h"
+
+#ifndef URB_ASYNC_UNLINK
+#define URB_ASYNC_UNLINK 0
+#endif
+
+/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
+static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+#define ENCAPS_OVERHEAD                (sizeof(encaps_hdr) + 2)
+
+struct header_struct {
+       /* 802.3 */
+       u8 dest[ETH_ALEN];
+       u8 src[ETH_ALEN];
+       __be16 len;
+       /* 802.2 */
+       u8 dsap;
+       u8 ssap;
+       u8 ctrl;
+       /* SNAP */
+       u8 oui[3];
+       __be16 ethertype;
+} __attribute__ ((packed));
+
+struct ez_usb_fw {
+       u16 size;
+       const u8 *code;
+};
+
+static struct ez_usb_fw firmware = {
+       .size = 0,
+       .code = NULL,
+};
+
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+/* Debugging macros */
+#undef dbg
+#define dbg(format, arg...) \
+       do { if (debug) printk(KERN_DEBUG PFX "%s: " format "\n", \
+                              __func__ , ## arg); } while (0)
+#undef err
+#define err(format, arg...) \
+       do { printk(KERN_ERR PFX format "\n", ## arg); } while (0)
+
+/* Module paramaters */
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+MODULE_FIRMWARE("orinoco_ezusb_fw");
+
+/*
+ * Under some conditions, the card gets stuck and stops paying attention
+ * to the world (i.e. data communication stalls) until we do something to
+ * it.  Sending an INQ_TALLIES command seems to be enough and should be
+ * harmless otherwise.  This behaviour has been observed when using the
+ * driver on a systemimager client during installation.  In the past a
+ * timer was used to send INQ_TALLIES commands when there was no other
+ * activity, but it was troublesome and was removed.
+ */
+
+#define USB_COMPAQ_VENDOR_ID     0x049f /* Compaq Computer Corp. */
+#define USB_COMPAQ_WL215_ID      0x001f /* Compaq WL215 USB Adapter */
+#define USB_COMPAQ_W200_ID       0x0076 /* Compaq W200 USB Adapter */
+#define USB_HP_WL215_ID          0x0082 /* Compaq WL215 USB Adapter */
+
+#define USB_MELCO_VENDOR_ID      0x0411
+#define USB_BUFFALO_L11_ID       0x0006 /* BUFFALO WLI-USB-L11 */
+#define USB_BUFFALO_L11G_WR_ID   0x000B /* BUFFALO WLI-USB-L11G-WR */
+#define USB_BUFFALO_L11G_ID      0x000D /* BUFFALO WLI-USB-L11G */
+
+#define USB_LUCENT_VENDOR_ID     0x047E /* Lucent Technologies */
+#define USB_LUCENT_ORINOCO_ID    0x0300 /* Lucent/Agere Orinoco USB Client */
+
+#define USB_AVAYA8_VENDOR_ID     0x0D98
+#define USB_AVAYAE_VENDOR_ID     0x0D9E
+#define USB_AVAYA_WIRELESS_ID    0x0300 /* Avaya Wireless USB Card */
+
+#define USB_AGERE_VENDOR_ID      0x0D4E /* Agere Systems */
+#define USB_AGERE_MODEL0801_ID   0x1000 /* Wireless USB Card Model 0801 */
+#define USB_AGERE_MODEL0802_ID   0x1001 /* Wireless USB Card Model 0802 */
+#define USB_AGERE_REBRANDED_ID   0x047A /* WLAN USB Card */
+
+#define USB_ELSA_VENDOR_ID       0x05CC
+#define USB_ELSA_AIRLANCER_ID    0x3100 /* ELSA AirLancer USB-11 */
+
+#define USB_LEGEND_VENDOR_ID     0x0E7C
+#define USB_LEGEND_JOYNET_ID     0x0300 /* Joynet WLAN USB Card */
+
+#define USB_SAMSUNG_VENDOR_ID    0x04E8
+#define USB_SAMSUNG_SEW2001U1_ID 0x5002 /* Samsung SEW-2001u Card */
+#define USB_SAMSUNG_SEW2001U2_ID 0x5B11 /* Samsung SEW-2001u Card */
+#define USB_SAMSUNG_SEW2003U_ID  0x7011 /* Samsung SEW-2003U Card */
+
+#define USB_IGATE_VENDOR_ID      0x0681
+#define USB_IGATE_IGATE_11M_ID   0x0012 /* I-GATE 11M USB Card */
+
+#define USB_FUJITSU_VENDOR_ID    0x0BF8
+#define USB_FUJITSU_E1100_ID     0x1002 /* connect2AIR WLAN E-1100 USB */
+
+#define USB_2WIRE_VENDOR_ID      0x1630
+#define USB_2WIRE_WIRELESS_ID    0xff81 /* 2Wire Wireless USB adapter */
+
+
+#define EZUSB_REQUEST_FW_TRANS         0xA0
+#define EZUSB_REQUEST_TRIGER           0xAA
+#define EZUSB_REQUEST_TRIG_AC          0xAC
+#define EZUSB_CPUCS_REG                        0x7F92
+
+#define EZUSB_RID_TX                   0x0700
+#define EZUSB_RID_RX                   0x0701
+#define EZUSB_RID_INIT1                        0x0702
+#define EZUSB_RID_ACK                  0x0710
+#define EZUSB_RID_READ_PDA             0x0800
+#define EZUSB_RID_PROG_INIT            0x0852
+#define EZUSB_RID_PROG_SET_ADDR                0x0853
+#define EZUSB_RID_PROG_BYTES           0x0854
+#define EZUSB_RID_PROG_END             0x0855
+#define EZUSB_RID_DOCMD                        0x0860
+
+/* Recognize info frames */
+#define EZUSB_IS_INFO(id)              ((id >= 0xF000) && (id <= 0xF2FF))
+
+#define EZUSB_MAGIC                    0x0210
+
+#define EZUSB_FRAME_DATA               1
+#define EZUSB_FRAME_CONTROL            2
+
+#define DEF_TIMEOUT                    (3*HZ)
+
+#define BULK_BUF_SIZE                  2048
+
+#define MAX_DL_SIZE (BULK_BUF_SIZE - sizeof(struct ezusb_packet))
+
+#define FW_BUF_SIZE                    64
+#define FW_VAR_OFFSET_PTR              0x359
+#define FW_VAR_VALUE                   0
+#define FW_HOLE_START                  0x100
+#define FW_HOLE_END                    0x300
+
+struct ezusb_packet {
+       __le16 magic;           /* 0x0210 */
+       u8 req_reply_count;
+       u8 ans_reply_count;
+       __le16 frame_type;      /* 0x01 for data frames, 0x02 otherwise */
+       __le16 size;            /* transport size */
+       __le16 crc;             /* CRC up to here */
+       __le16 hermes_len;
+       __le16 hermes_rid;
+       u8 data[0];
+} __attribute__ ((packed));
+
+/* Table of devices that work or may work with this driver */
+static struct usb_device_id ezusb_table[] = {
+       {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_WL215_ID)},
+       {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_HP_WL215_ID)},
+       {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_W200_ID)},
+       {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11_ID)},
+       {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_WR_ID)},
+       {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_ID)},
+       {USB_DEVICE(USB_LUCENT_VENDOR_ID, USB_LUCENT_ORINOCO_ID)},
+       {USB_DEVICE(USB_AVAYA8_VENDOR_ID, USB_AVAYA_WIRELESS_ID)},
+       {USB_DEVICE(USB_AVAYAE_VENDOR_ID, USB_AVAYA_WIRELESS_ID)},
+       {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0801_ID)},
+       {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0802_ID)},
+       {USB_DEVICE(USB_ELSA_VENDOR_ID, USB_ELSA_AIRLANCER_ID)},
+       {USB_DEVICE(USB_LEGEND_VENDOR_ID, USB_LEGEND_JOYNET_ID)},
+       {USB_DEVICE_VER(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U1_ID,
+                       0, 0)},
+       {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U2_ID)},
+       {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2003U_ID)},
+       {USB_DEVICE(USB_IGATE_VENDOR_ID, USB_IGATE_IGATE_11M_ID)},
+       {USB_DEVICE(USB_FUJITSU_VENDOR_ID, USB_FUJITSU_E1100_ID)},
+       {USB_DEVICE(USB_2WIRE_VENDOR_ID, USB_2WIRE_WIRELESS_ID)},
+       {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_REBRANDED_ID)},
+       {}                      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, ezusb_table);
+
+/* Structure to hold all of our device specific stuff */
+struct ezusb_priv {
+       struct usb_device *udev;
+       struct net_device *dev;
+       struct mutex mtx;
+       spinlock_t req_lock;
+       struct list_head req_pending;
+       struct list_head req_active;
+       spinlock_t reply_count_lock;
+       u16 hermes_reg_fake[0x40];
+       u8 *bap_buf;
+       struct urb *read_urb;
+       int read_pipe;
+       int write_pipe;
+       u8 reply_count;
+};
+
+enum ezusb_state {
+       EZUSB_CTX_START,
+       EZUSB_CTX_QUEUED,
+       EZUSB_CTX_REQ_SUBMITTED,
+       EZUSB_CTX_REQ_COMPLETE,
+       EZUSB_CTX_RESP_RECEIVED,
+       EZUSB_CTX_REQ_TIMEOUT,
+       EZUSB_CTX_REQ_FAILED,
+       EZUSB_CTX_RESP_TIMEOUT,
+       EZUSB_CTX_REQSUBMIT_FAIL,
+       EZUSB_CTX_COMPLETE,
+};
+
+struct request_context {
+       struct list_head list;
+       atomic_t refcount;
+       struct completion done; /* Signals that CTX is dead */
+       int killed;
+       struct urb *outurb;     /* OUT for req pkt */
+       struct ezusb_priv *upriv;
+       struct ezusb_packet *buf;
+       int buf_length;
+       struct timer_list timer;        /* Timeout handling */
+       enum ezusb_state state; /* Current state */
+       /* the RID that we will wait for */
+       u16 out_rid;
+       u16 in_rid;
+};
+
+
+/* Forward declarations */
+static void ezusb_ctx_complete(struct request_context *ctx);
+static void ezusb_req_queue_run(struct ezusb_priv *upriv);
+static void ezusb_bulk_in_callback(struct urb *urb);
+
+static inline u8 ezusb_reply_inc(u8 count)
+{
+       if (count < 0x7F)
+               return count + 1;
+       else
+               return 1;
+}
+
+static void ezusb_request_context_put(struct request_context *ctx)
+{
+       if (!atomic_dec_and_test(&ctx->refcount))
+               return;
+
+       WARN_ON(!ctx->done.done);
+       BUG_ON(ctx->outurb->status == -EINPROGRESS);
+       BUG_ON(timer_pending(&ctx->timer));
+       usb_free_urb(ctx->outurb);
+       kfree(ctx->buf);
+       kfree(ctx);
+}
+
+static inline void ezusb_mod_timer(struct ezusb_priv *upriv,
+                                  struct timer_list *timer,
+                                  unsigned long expire)
+{
+       if (!upriv->udev)
+               return;
+       mod_timer(timer, expire);
+}
+
+static void ezusb_request_timerfn(u_long _ctx)
+{
+       struct request_context *ctx = (void *) _ctx;
+
+       ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
+       if (usb_unlink_urb(ctx->outurb) == -EINPROGRESS) {
+               ctx->state = EZUSB_CTX_REQ_TIMEOUT;
+       } else {
+               ctx->state = EZUSB_CTX_RESP_TIMEOUT;
+               dbg("couldn't unlink");
+               atomic_inc(&ctx->refcount);
+               ctx->killed = 1;
+               ezusb_ctx_complete(ctx);
+               ezusb_request_context_put(ctx);
+       }
+};
+
+static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv,
+                                              u16 out_rid, u16 in_rid)
+{
+       struct request_context *ctx;
+
+       ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
+       if (!ctx)
+               return NULL;
+
+       memset(ctx, 0, sizeof(*ctx));
+
+       ctx->buf = kmalloc(BULK_BUF_SIZE, GFP_ATOMIC);
+       if (!ctx->buf) {
+               kfree(ctx);
+               return NULL;
+       }
+       ctx->outurb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!ctx->outurb) {
+               kfree(ctx->buf);
+               kfree(ctx);
+               return NULL;
+       }
+
+       ctx->upriv = upriv;
+       ctx->state = EZUSB_CTX_START;
+       ctx->out_rid = out_rid;
+       ctx->in_rid = in_rid;
+
+       atomic_set(&ctx->refcount, 1);
+       init_completion(&ctx->done);
+
+       init_timer(&ctx->timer);
+       ctx->timer.function = ezusb_request_timerfn;
+       ctx->timer.data = (u_long) ctx;
+       return ctx;
+}
+
+
+/* Hopefully the real complete_all will soon be exported, in the mean
+ * while this should work. */
+static inline void ezusb_complete_all(struct completion *comp)
+{
+       complete(comp);
+       complete(comp);
+       complete(comp);
+       complete(comp);
+}
+
+static void ezusb_ctx_complete(struct request_context *ctx)
+{
+       struct ezusb_priv *upriv = ctx->upriv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&upriv->req_lock, flags);
+
+       list_del_init(&ctx->list);
+       if (upriv->udev) {
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+               ezusb_req_queue_run(upriv);
+               spin_lock_irqsave(&upriv->req_lock, flags);
+       }
+
+       switch (ctx->state) {
+       case EZUSB_CTX_COMPLETE:
+       case EZUSB_CTX_REQSUBMIT_FAIL:
+       case EZUSB_CTX_REQ_FAILED:
+       case EZUSB_CTX_REQ_TIMEOUT:
+       case EZUSB_CTX_RESP_TIMEOUT:
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+               if ((ctx->out_rid == EZUSB_RID_TX) && upriv->dev) {
+                       struct net_device *dev = upriv->dev;
+                       struct orinoco_private *priv = ndev_priv(dev);
+                       struct net_device_stats *stats = &priv->stats;
+
+                       if (ctx->state != EZUSB_CTX_COMPLETE)
+                               stats->tx_errors++;
+                       else
+                               stats->tx_packets++;
+
+                       netif_wake_queue(dev);
+               }
+               ezusb_complete_all(&ctx->done);
+               ezusb_request_context_put(ctx);
+               break;
+
+       default:
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+               if (!upriv->udev) {
+                       /* This is normal, as all request contexts get flushed
+                        * when the device is disconnected */
+                       err("Called, CTX not terminating, but device gone");
+                       ezusb_complete_all(&ctx->done);
+                       ezusb_request_context_put(ctx);
+                       break;
+               }
+
+               err("Called, CTX not in terminating state.");
+               /* Things are really bad if this happens. Just leak
+                * the CTX because it may still be linked to the
+                * queue or the OUT urb may still be active.
+                * Just leaking at least prevents an Oops or Panic.
+                */
+               break;
+       }
+}
+
+/**
+ * ezusb_req_queue_run:
+ * Description:
+ *     Note: Only one active CTX at any one time, because there's no
+ *     other (reliable) way to match the response URB to the correct
+ *     CTX.
+ **/
+static void ezusb_req_queue_run(struct ezusb_priv *upriv)
+{
+       unsigned long flags;
+       struct request_context *ctx;
+       int result;
+
+       spin_lock_irqsave(&upriv->req_lock, flags);
+
+       if (!list_empty(&upriv->req_active))
+               goto unlock;
+
+       if (list_empty(&upriv->req_pending))
+               goto unlock;
+
+       ctx =
+           list_entry(upriv->req_pending.next, struct request_context,
+                      list);
+
+       if (!ctx->upriv->udev)
+               goto unlock;
+
+       /* We need to split this off to avoid a race condition */
+       list_move_tail(&ctx->list, &upriv->req_active);
+
+       if (ctx->state == EZUSB_CTX_QUEUED) {
+               atomic_inc(&ctx->refcount);
+               result = usb_submit_urb(ctx->outurb, GFP_ATOMIC);
+               if (result) {
+                       ctx->state = EZUSB_CTX_REQSUBMIT_FAIL;
+
+                       spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+                       err("Fatal, failed to submit command urb."
+                           " error=%d\n", result);
+
+                       ezusb_ctx_complete(ctx);
+                       ezusb_request_context_put(ctx);
+                       goto done;
+               }
+
+               ctx->state = EZUSB_CTX_REQ_SUBMITTED;
+               ezusb_mod_timer(ctx->upriv, &ctx->timer,
+                               jiffies + DEF_TIMEOUT);
+       }
+
+ unlock:
+       spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+ done:
+       return;
+}
+
+static void ezusb_req_enqueue_run(struct ezusb_priv *upriv,
+                                 struct request_context *ctx)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&upriv->req_lock, flags);
+
+       if (!ctx->upriv->udev) {
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+               goto done;
+       }
+       atomic_inc(&ctx->refcount);
+       list_add_tail(&ctx->list, &upriv->req_pending);
+       spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+       ctx->state = EZUSB_CTX_QUEUED;
+       ezusb_req_queue_run(upriv);
+
+ done:
+       return;
+}
+
+static void ezusb_request_out_callback(struct urb *urb)
+{
+       unsigned long flags;
+       enum ezusb_state state;
+       struct request_context *ctx = urb->context;
+       struct ezusb_priv *upriv = ctx->upriv;
+
+       spin_lock_irqsave(&upriv->req_lock, flags);
+
+       del_timer(&ctx->timer);
+
+       if (ctx->killed) {
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+               pr_warning("interrupt called with dead ctx");
+               goto out;
+       }
+
+       state = ctx->state;
+
+       if (urb->status == 0) {
+               switch (state) {
+               case EZUSB_CTX_REQ_SUBMITTED:
+                       if (ctx->in_rid) {
+                               ctx->state = EZUSB_CTX_REQ_COMPLETE;
+                               /* reply URB still pending */
+                               ezusb_mod_timer(upriv, &ctx->timer,
+                                               jiffies + DEF_TIMEOUT);
+                               spin_unlock_irqrestore(&upriv->req_lock,
+                                                      flags);
+                               break;
+                       }
+                       /* fall through */
+               case EZUSB_CTX_RESP_RECEIVED:
+                       /* IN already received before this OUT-ACK */
+                       ctx->state = EZUSB_CTX_COMPLETE;
+                       spin_unlock_irqrestore(&upriv->req_lock, flags);
+                       ezusb_ctx_complete(ctx);
+                       break;
+
+               default:
+                       spin_unlock_irqrestore(&upriv->req_lock, flags);
+                       err("Unexpected state(0x%x, %d) in OUT URB",
+                           state, urb->status);
+                       break;
+               }
+       } else {
+               /* If someone cancels the OUT URB then its status
+                * should be either -ECONNRESET or -ENOENT.
+                */
+               switch (state) {
+               case EZUSB_CTX_REQ_SUBMITTED:
+               case EZUSB_CTX_RESP_RECEIVED:
+                       ctx->state = EZUSB_CTX_REQ_FAILED;
+                       /* fall through */
+
+               case EZUSB_CTX_REQ_FAILED:
+               case EZUSB_CTX_REQ_TIMEOUT:
+                       spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+                       ezusb_ctx_complete(ctx);
+                       break;
+
+               default:
+                       spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+                       err("Unexpected state(0x%x, %d) in OUT URB",
+                           state, urb->status);
+                       break;
+               }
+       }
+ out:
+       ezusb_request_context_put(ctx);
+}
+
+static void ezusb_request_in_callback(struct ezusb_priv *upriv,
+                                     struct urb *urb)
+{
+       struct ezusb_packet *ans = urb->transfer_buffer;
+       struct request_context *ctx = NULL;
+       enum ezusb_state state;
+       unsigned long flags;
+
+       /* Find the CTX on the active queue that requested this URB */
+       spin_lock_irqsave(&upriv->req_lock, flags);
+       if (upriv->udev) {
+               struct list_head *item;
+
+               list_for_each(item, &upriv->req_active) {
+                       struct request_context *c;
+                       int reply_count;
+
+                       c = list_entry(item, struct request_context, list);
+                       reply_count =
+                           ezusb_reply_inc(c->buf->req_reply_count);
+                       if ((ans->ans_reply_count == reply_count)
+                           && (le16_to_cpu(ans->hermes_rid) == c->in_rid)) {
+                               ctx = c;
+                               break;
+                       }
+                       dbg("Skipped (0x%x/0x%x) (%d/%d)",
+                           le16_to_cpu(ans->hermes_rid),
+                           c->in_rid, ans->ans_reply_count, reply_count);
+               }
+       }
+
+       if (ctx == NULL) {
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+               err("%s: got unexpected RID: 0x%04X", __func__,
+                   le16_to_cpu(ans->hermes_rid));
+               ezusb_req_queue_run(upriv);
+               return;
+       }
+
+       /* The data we want is in the in buffer, exchange */
+       urb->transfer_buffer = ctx->buf;
+       ctx->buf = (void *) ans;
+       ctx->buf_length = urb->actual_length;
+
+       state = ctx->state;
+       switch (state) {
+       case EZUSB_CTX_REQ_SUBMITTED:
+               /* We have received our response URB before
+                * our request has been acknowledged. Do NOT
+                * destroy our CTX yet, because our OUT URB
+                * is still alive ...
+                */
+               ctx->state = EZUSB_CTX_RESP_RECEIVED;
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+               /* Let the machine continue running. */
+               break;
+
+       case EZUSB_CTX_REQ_COMPLETE:
+               /* This is the usual path: our request
+                * has already been acknowledged, and
+                * we have now received the reply.
+                */
+               ctx->state = EZUSB_CTX_COMPLETE;
+
+               /* Stop the intimer */
+               del_timer(&ctx->timer);
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+               /* Call the completion handler */
+               ezusb_ctx_complete(ctx);
+               break;
+
+       default:
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+               pr_warning("Matched IN URB, unexpected context state(0x%x)",
+                    state);
+               /* Throw this CTX away and try submitting another */
+               del_timer(&ctx->timer);
+               ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
+               usb_unlink_urb(ctx->outurb);
+               ezusb_req_queue_run(upriv);
+               break;
+       }                       /* switch */
+}
+
+
+static void ezusb_req_ctx_wait(struct ezusb_priv *upriv,
+                              struct request_context *ctx)
+{
+       switch (ctx->state) {
+       case EZUSB_CTX_QUEUED:
+       case EZUSB_CTX_REQ_SUBMITTED:
+       case EZUSB_CTX_REQ_COMPLETE:
+       case EZUSB_CTX_RESP_RECEIVED:
+               if (in_softirq()) {
+                       /* If we get called from a timer, timeout timers don't
+                        * get the chance to run themselves. So we make sure
+                        * that we don't sleep for ever */
+                       int msecs = DEF_TIMEOUT * (1000 / HZ);
+                       while (!ctx->done.done && msecs--)
+                               udelay(1000);
+               } else {
+                       wait_event_interruptible(ctx->done.wait,
+                                                ctx->done.done);
+               }
+               break;
+       default:
+               /* Done or failed - nothing to wait for */
+               break;
+       }
+}
+
+static inline u16 build_crc(struct ezusb_packet *data)
+{
+       u16 crc = 0;
+       u8 *bytes = (u8 *)data;
+       int i;
+
+       for (i = 0; i < 8; i++)
+               crc = (crc << 1) + bytes[i];
+
+       return crc;
+}
+
+/**
+ * ezusb_fill_req:
+ *
+ * if data == NULL and length > 0 the data is assumed to be already in
+ * the target buffer and only the header is filled.
+ *
+ */
+static int ezusb_fill_req(struct ezusb_packet *req, u16 length, u16 rid,
+                         const void *data, u16 frame_type, u8 reply_count)
+{
+       int total_size = sizeof(*req) + length;
+
+       BUG_ON(total_size > BULK_BUF_SIZE);
+
+       req->magic = cpu_to_le16(EZUSB_MAGIC);
+       req->req_reply_count = reply_count;
+       req->ans_reply_count = 0;
+       req->frame_type = cpu_to_le16(frame_type);
+       req->size = cpu_to_le16(length + 4);
+       req->crc = cpu_to_le16(build_crc(req));
+       req->hermes_len = cpu_to_le16(HERMES_BYTES_TO_RECLEN(length));
+       req->hermes_rid = cpu_to_le16(rid);
+       if (data)
+               memcpy(req->data, data, length);
+       return total_size;
+}
+
+static int ezusb_submit_in_urb(struct ezusb_priv *upriv)
+{
+       int retval = 0;
+       void *cur_buf = upriv->read_urb->transfer_buffer;
+
+       if (upriv->read_urb->status == -EINPROGRESS) {
+               dbg("urb busy, not resubmiting");
+               retval = -EBUSY;
+               goto exit;
+       }
+       usb_fill_bulk_urb(upriv->read_urb, upriv->udev, upriv->read_pipe,
+                         cur_buf, BULK_BUF_SIZE,
+                         ezusb_bulk_in_callback, upriv);
+       upriv->read_urb->transfer_flags = 0;
+       retval = usb_submit_urb(upriv->read_urb, GFP_ATOMIC);
+       if (retval)
+               err("%s submit failed %d", __func__, retval);
+
+ exit:
+       return retval;
+}
+
+static inline int ezusb_8051_cpucs(struct ezusb_priv *upriv, int reset)
+{
+       u8 res_val = reset;     /* avoid argument promotion */
+
+       if (!upriv->udev) {
+               err("%s: !upriv->udev", __func__);
+               return -EFAULT;
+       }
+       return usb_control_msg(upriv->udev,
+                              usb_sndctrlpipe(upriv->udev, 0),
+                              EZUSB_REQUEST_FW_TRANS,
+                              USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+                              USB_DIR_OUT, EZUSB_CPUCS_REG, 0, &res_val,
+                              sizeof(res_val), DEF_TIMEOUT);
+}
+
+static int ezusb_firmware_download(struct ezusb_priv *upriv,
+                                  struct ez_usb_fw *fw)
+{
+       u8 fw_buffer[FW_BUF_SIZE];
+       int retval, addr;
+       int variant_offset;
+
+       /*
+        * This byte is 1 and should be replaced with 0.  The offset is
+        * 0x10AD in version 0.0.6.  The byte in question should follow
+        * the end of the code pointed to by the jump in the beginning
+        * of the firmware.  Also, it is read by code located at 0x358.
+        */
+       variant_offset = be16_to_cpup((__be16 *) &fw->code[FW_VAR_OFFSET_PTR]);
+       if (variant_offset >= fw->size) {
+               printk(KERN_ERR PFX "Invalid firmware variant offset: "
+                      "0x%04x\n", variant_offset);
+               retval = -EINVAL;
+               goto fail;
+       }
+
+       retval = ezusb_8051_cpucs(upriv, 1);
+       if (retval < 0)
+               goto fail;
+       for (addr = 0; addr < fw->size; addr += FW_BUF_SIZE) {
+               /* 0x100-0x300 should be left alone, it contains card
+                * specific data, like USB enumeration information */
+               if ((addr >= FW_HOLE_START) && (addr < FW_HOLE_END))
+                       continue;
+
+               memcpy(fw_buffer, &fw->code[addr], FW_BUF_SIZE);
+               if (variant_offset >= addr &&
+                   variant_offset < addr + FW_BUF_SIZE) {
+                       dbg("Patching card_variant byte at 0x%04X",
+                           variant_offset);
+                       fw_buffer[variant_offset - addr] = FW_VAR_VALUE;
+               }
+               retval = usb_control_msg(upriv->udev,
+                                        usb_sndctrlpipe(upriv->udev, 0),
+                                        EZUSB_REQUEST_FW_TRANS,
+                                        USB_TYPE_VENDOR | USB_RECIP_DEVICE
+                                        | USB_DIR_OUT,
+                                        addr, 0x0,
+                                        fw_buffer, FW_BUF_SIZE,
+                                        DEF_TIMEOUT);
+
+               if (retval < 0)
+                       goto fail;
+       }
+       retval = ezusb_8051_cpucs(upriv, 0);
+       if (retval < 0)
+               goto fail;
+
+       goto exit;
+ fail:
+       printk(KERN_ERR PFX "Firmware download failed, error %d\n",
+              retval);
+ exit:
+       return retval;
+}
+
+static int ezusb_access_ltv(struct ezusb_priv *upriv,
+                           struct request_context *ctx,
+                           u16 length, const void *data, u16 frame_type,
+                           void *ans_buff, int ans_size, u16 *ans_length)
+{
+       int req_size;
+       int retval = 0;
+       enum ezusb_state state;
+
+       BUG_ON(in_irq());
+
+       if (!upriv->udev) {
+               dbg("Device disconnected");
+               return -ENODEV;
+       }
+
+       if (upriv->read_urb->status != -EINPROGRESS)
+               err("%s: in urb not pending", __func__);
+
+       /* protect upriv->reply_count, guarantee sequential numbers */
+       spin_lock_bh(&upriv->reply_count_lock);
+       req_size = ezusb_fill_req(ctx->buf, length, ctx->out_rid, data,
+                                 frame_type, upriv->reply_count);
+       usb_fill_bulk_urb(ctx->outurb, upriv->udev, upriv->write_pipe,
+                         ctx->buf, req_size,
+                         ezusb_request_out_callback, ctx);
+
+       if (ctx->in_rid)
+               upriv->reply_count = ezusb_reply_inc(upriv->reply_count);
+
+       ezusb_req_enqueue_run(upriv, ctx);
+
+       spin_unlock_bh(&upriv->reply_count_lock);
+
+       if (ctx->in_rid)
+               ezusb_req_ctx_wait(upriv, ctx);
+
+       state = ctx->state;
+       switch (state) {
+       case EZUSB_CTX_COMPLETE:
+               retval = ctx->outurb->status;
+               break;
+
+       case EZUSB_CTX_QUEUED:
+       case EZUSB_CTX_REQ_SUBMITTED:
+               if (!ctx->in_rid)
+                       break;
+       default:
+               err("%s: Unexpected context state %d", __func__,
+                   state);
+               /* fall though */
+       case EZUSB_CTX_REQ_TIMEOUT:
+       case EZUSB_CTX_REQ_FAILED:
+       case EZUSB_CTX_RESP_TIMEOUT:
+       case EZUSB_CTX_REQSUBMIT_FAIL:
+               printk(KERN_ERR PFX "Access failed, resetting (state %d,"
+                      " reply_count %d)\n", state, upriv->reply_count);
+               upriv->reply_count = 0;
+               if (state == EZUSB_CTX_REQ_TIMEOUT
+                   || state == EZUSB_CTX_RESP_TIMEOUT) {
+                       printk(KERN_ERR PFX "ctx timed out\n");
+                       retval = -ETIMEDOUT;
+               } else {
+                       printk(KERN_ERR PFX "ctx failed\n");
+                       retval = -EFAULT;
+               }
+               goto exit;
+               break;
+       }
+       if (ctx->in_rid) {
+               struct ezusb_packet *ans = ctx->buf;
+               int exp_len;
+
+               if (ans->hermes_len != 0)
+                       exp_len = le16_to_cpu(ans->hermes_len) * 2 + 12;
+               else
+                       exp_len = 14;
+
+               if (exp_len != ctx->buf_length) {
+                       err("%s: length mismatch for RID 0x%04x: "
+                           "expected %d, got %d", __func__,
+                           ctx->in_rid, exp_len, ctx->buf_length);
+                       retval = -EIO;
+                       goto exit;
+               }
+
+               if (ans_buff)
+                       memcpy(ans_buff, ans->data,
+                              min_t(int, exp_len, ans_size));
+               if (ans_length)
+                       *ans_length = le16_to_cpu(ans->hermes_len);
+       }
+ exit:
+       ezusb_request_context_put(ctx);
+       return retval;
+}
+
+static int ezusb_write_ltv(hermes_t *hw, int bap, u16 rid,
+                          u16 length, const void *data)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       u16 frame_type;
+       struct request_context *ctx;
+
+       if (length == 0)
+               return -EINVAL;
+
+       length = HERMES_RECLEN_TO_BYTES(length);
+
+       /* On memory mapped devices HERMES_RID_CNFGROUPADDRESSES can be
+        * set to be empty, but the USB bridge doesn't like it */
+       if (length == 0)
+               return 0;
+
+       ctx = ezusb_alloc_ctx(upriv, rid, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       if (rid == EZUSB_RID_TX)
+               frame_type = EZUSB_FRAME_DATA;
+       else
+               frame_type = EZUSB_FRAME_CONTROL;
+
+       return ezusb_access_ltv(upriv, ctx, length, data, frame_type,
+                               NULL, 0, NULL);
+}
+
+static int ezusb_read_ltv(hermes_t *hw, int bap, u16 rid,
+                         unsigned bufsize, u16 *length, void *buf)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+
+       if ((bufsize < 0) || (bufsize % 2))
+               return -EINVAL;
+
+       ctx = ezusb_alloc_ctx(upriv, rid, rid);
+       if (!ctx)
+               return -ENOMEM;
+
+       return ezusb_access_ltv(upriv, ctx, 0, NULL, EZUSB_FRAME_CONTROL,
+                               buf, bufsize, length);
+}
+
+static int ezusb_doicmd_wait(hermes_t *hw, u16 cmd, u16 parm0, u16 parm1,
+                            u16 parm2, struct hermes_response *resp)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+
+       __le16 data[4] = {
+               cpu_to_le16(cmd),
+               cpu_to_le16(parm0),
+               cpu_to_le16(parm1),
+               cpu_to_le16(parm2),
+       };
+       dbg("0x%04X, parm0 0x%04X, parm1 0x%04X, parm2 0x%04X",
+           cmd, parm0, parm1, parm2);
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
+                           struct hermes_response *resp)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+
+       __le16 data[4] = {
+               cpu_to_le16(cmd),
+               cpu_to_le16(parm0),
+               0,
+               0,
+       };
+       dbg("0x%04X, parm0 0x%04X", cmd, parm0);
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_bap_pread(struct hermes *hw, int bap,
+                          void *buf, int len, u16 id, u16 offset)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct ezusb_packet *ans = (void *) upriv->read_urb->transfer_buffer;
+       int actual_length = upriv->read_urb->actual_length;
+
+       if (id == EZUSB_RID_RX) {
+               if ((sizeof(*ans) + offset + len) > actual_length) {
+                       printk(KERN_ERR PFX "BAP read beyond buffer end "
+                              "in rx frame\n");
+                       return -EINVAL;
+               }
+               memcpy(buf, ans->data + offset, len);
+               return 0;
+       }
+
+       if (EZUSB_IS_INFO(id)) {
+               /* Include 4 bytes for length/type */
+               if ((sizeof(*ans) + offset + len - 4) > actual_length) {
+                       printk(KERN_ERR PFX "BAP read beyond buffer end "
+                              "in info frame\n");
+                       return -EFAULT;
+               }
+               memcpy(buf, ans->data + offset - 4, len);
+       } else {
+               printk(KERN_ERR PFX "Unexpected fid 0x%04x\n", id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ezusb_read_pda(struct hermes *hw, __le16 *pda,
+                         u32 pda_addr, u16 pda_len)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+       __le16 data[] = {
+               cpu_to_le16(pda_addr & 0xffff),
+               cpu_to_le16(pda_len - 4)
+       };
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_READ_PDA, EZUSB_RID_READ_PDA);
+       if (!ctx)
+               return -ENOMEM;
+
+       /* wl_lkm does not include PDA size in the PDA area.
+        * We will pad the information into pda, so other routines
+        * don't have to be modified */
+       pda[0] = cpu_to_le16(pda_len - 2);
+       /* Includes CFG_PROD_DATA but not itself */
+       pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
+
+       return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+                               EZUSB_FRAME_CONTROL, &pda[2], pda_len - 4,
+                               NULL);
+}
+
+static int ezusb_program_init(struct hermes *hw, u32 entry_point)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+       __le32 data = cpu_to_le32(entry_point);
+
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_INIT, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_program_end(struct hermes *hw)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_END, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       return ezusb_access_ltv(upriv, ctx, 0, NULL,
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_program_bytes(struct hermes *hw, const char *buf,
+                              u32 addr, u32 len)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+       __le32 data = cpu_to_le32(addr);
+       int err;
+
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_SET_ADDR, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       err = ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+                              EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+       if (err)
+               return err;
+
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_BYTES, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       return ezusb_access_ltv(upriv, ctx, len, buf,
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_program(struct hermes *hw, const char *buf,
+                        u32 addr, u32 len)
+{
+       u32 ch_addr;
+       u32 ch_len;
+       int err = 0;
+
+       /* We can only send 2048 bytes out of the bulk xmit at a time,
+        * so we have to split any programming into chunks of <2048
+        * bytes. */
+
+       ch_len = (len < MAX_DL_SIZE) ? len : MAX_DL_SIZE;
+       ch_addr = addr;
+
+       while (ch_addr < (addr + len)) {
+               pr_debug("Programming subblock of length %d "
+                        "to address 0x%08x. Data @ %p\n",
+                        ch_len, ch_addr, &buf[ch_addr - addr]);
+
+               err = ezusb_program_bytes(hw, &buf[ch_addr - addr],
+                                         ch_addr, ch_len);
+               if (err)
+                       break;
+
+               ch_addr += ch_len;
+               ch_len = ((addr + len - ch_addr) < MAX_DL_SIZE) ?
+                       (addr + len - ch_addr) : MAX_DL_SIZE;
+       }
+
+       return err;
+}
+
+static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct orinoco_private *priv = ndev_priv(dev);
+       struct net_device_stats *stats = &priv->stats;
+       struct ezusb_priv *upriv = priv->card;
+       int err = 0;
+       char *p;
+       struct ethhdr *eh;
+       int len, data_len, data_off;
+       __le16 tx_control;
+       unsigned long flags;
+       struct request_context *ctx;
+       u8 *buf;
+       int tx_size;
+
+       if (!netif_running(dev)) {
+               printk(KERN_ERR "%s: Tx on stopped device!\n",
+                      dev->name);
+               return NETDEV_TX_BUSY;
+       }
+
+       if (netif_queue_stopped(dev)) {
+               printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
+                      dev->name);
+               return NETDEV_TX_BUSY;
+       }
+
+       if (orinoco_lock(priv, &flags) != 0) {
+               printk(KERN_ERR
+                      "%s: orinoco_xmit() called while hw_unavailable\n",
+                      dev->name);
+               return NETDEV_TX_BUSY;
+       }
+
+       if (!netif_carrier_ok(dev) ||
+           (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
+               /* Oops, the firmware hasn't established a connection,
+                  silently drop the packet (this seems to be the
+                  safest approach). */
+               stats->tx_errors++;
+               orinoco_unlock(priv, &flags);
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0);
+       if (!ctx)
+               goto fail;
+
+       memset(ctx->buf, 0, BULK_BUF_SIZE);
+       buf = ctx->buf->data;
+
+       /* Length of the packet body */
+       /* FIXME: what if the skb is smaller than this? */
+       len = max_t(int, skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN);
+
+       eh = (struct ethhdr *) skb->data;
+
+       tx_control = cpu_to_le16(0);
+       memcpy(buf, &tx_control, sizeof(tx_control));
+       buf += sizeof(tx_control);
+       /* Encapsulate Ethernet-II frames */
+       if (ntohs(eh->h_proto) > ETH_DATA_LEN) {        /* Ethernet-II frame */
+               struct header_struct *hdr = (void *) buf;
+               buf += sizeof(*hdr);
+               data_len = len;
+               data_off = sizeof(tx_control) + sizeof(*hdr);
+               p = skb->data + ETH_HLEN;
+
+               /* 802.3 header */
+               memcpy(hdr->dest, eh->h_dest, ETH_ALEN);
+               memcpy(hdr->src, eh->h_source, ETH_ALEN);
+               hdr->len = htons(data_len + ENCAPS_OVERHEAD);
+
+               /* 802.2 header */
+               memcpy(&hdr->dsap, &encaps_hdr, sizeof(encaps_hdr));
+
+               hdr->ethertype = eh->h_proto;
+       } else {                /* IEEE 802.3 frame */
+               data_len = len + ETH_HLEN;
+               data_off = sizeof(tx_control);
+               p = skb->data;
+       }
+
+       memcpy(buf, p, data_len);
+       buf += data_len;
+
+       /* Finally, we actually initiate the send */
+       netif_stop_queue(dev);
+
+       /* The card may behave better if we send evenly sized usb transfers */
+       tx_size = ALIGN(buf - ctx->buf->data, 2);
+
+       err = ezusb_access_ltv(upriv, ctx, tx_size, NULL,
+                              EZUSB_FRAME_DATA, NULL, 0, NULL);
+
+       if (err) {
+               netif_start_queue(dev);
+               if (net_ratelimit())
+                       printk(KERN_ERR "%s: Error %d transmitting packet\n",
+                               dev->name, err);
+               stats->tx_errors++;
+               goto fail;
+       }
+
+       dev->trans_start = jiffies;
+       stats->tx_bytes += data_off + data_len;
+
+       orinoco_unlock(priv, &flags);
+
+       dev_kfree_skb(skb);
+
+       return NETDEV_TX_OK;
+
+ fail:
+       orinoco_unlock(priv, &flags);
+       return NETDEV_TX_BUSY;
+}
+
+static int ezusb_allocate(struct hermes *hw, u16 size, u16 *fid)
+{
+       *fid = EZUSB_RID_TX;
+       return 0;
+}
+
+
+static int ezusb_hard_reset(struct orinoco_private *priv)
+{
+       struct ezusb_priv *upriv = priv->card;
+       int retval = ezusb_8051_cpucs(upriv, 1);
+
+       if (retval < 0) {
+               err("Failed to reset");
+               return retval;
+       }
+
+       retval = ezusb_8051_cpucs(upriv, 0);
+       if (retval < 0) {
+               err("Failed to unreset");
+               return retval;
+       }
+
+       dbg("sending control message");
+       retval = usb_control_msg(upriv->udev,
+                                usb_sndctrlpipe(upriv->udev, 0),
+                                EZUSB_REQUEST_TRIGER,
+                                USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+                                USB_DIR_OUT, 0x0, 0x0, NULL, 0,
+                                DEF_TIMEOUT);
+       if (retval < 0) {
+               err("EZUSB_REQUEST_TRIGER failed retval %d", retval);
+               return retval;
+       }
+#if 0
+       dbg("Sending EZUSB_REQUEST_TRIG_AC");
+       retval = usb_control_msg(upriv->udev,
+                                usb_sndctrlpipe(upriv->udev, 0),
+                                EZUSB_REQUEST_TRIG_AC,
+                                USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+                                USB_DIR_OUT, 0x00FA, 0x0, NULL, 0,
+                                DEF_TIMEOUT);
+       if (retval < 0) {
+               err("EZUSB_REQUEST_TRIG_AC failed retval %d", retval);
+               return retval;
+       }
+#endif
+
+       return 0;
+}
+
+
+static int ezusb_init(hermes_t *hw)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       int retval;
+
+       BUG_ON(in_interrupt());
+       BUG_ON(!upriv);
+
+       upriv->reply_count = 0;
+       /* Write the MAGIC number on the simulated registers to keep
+        * orinoco.c happy */
+       hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
+       hermes_write_regn(hw, RXFID, EZUSB_RID_RX);
+
+       usb_kill_urb(upriv->read_urb);
+       ezusb_submit_in_urb(upriv);
+
+       retval = ezusb_write_ltv(hw, 0, EZUSB_RID_INIT1,
+                                HERMES_BYTES_TO_RECLEN(2), "\x10\x00");
+       if (retval < 0) {
+               printk(KERN_ERR PFX "EZUSB_RID_INIT1 error %d\n", retval);
+               return retval;
+       }
+
+       retval = ezusb_docmd_wait(hw, HERMES_CMD_INIT, 0, NULL);
+       if (retval < 0) {
+               printk(KERN_ERR PFX "HERMES_CMD_INIT error %d\n", retval);
+               return retval;
+       }
+
+       return 0;
+}
+
+static void ezusb_bulk_in_callback(struct urb *urb)
+{
+       struct ezusb_priv *upriv = (struct ezusb_priv *) urb->context;
+       struct ezusb_packet *ans = urb->transfer_buffer;
+       u16 crc;
+       u16 hermes_rid;
+
+       if (upriv->udev == NULL) {
+               dbg("disconnected");
+               return;
+       }
+
+       if (urb->status == -ETIMEDOUT) {
+               /* When a device gets unplugged we get this every time
+                * we resubmit, flooding the logs.  Since we don't use
+                * USB timeouts, it shouldn't happen any other time*/
+               pr_warning("%s: urb timed out, not resubmiting", __func__);
+               return;
+       }
+       if (urb->status == -ECONNABORTED) {
+               pr_warning("%s: connection abort, resubmiting urb",
+                    __func__);
+               goto resubmit;
+       }
+       if ((urb->status == -EILSEQ)
+           || (urb->status == -ENOENT)
+           || (urb->status == -ECONNRESET)) {
+               dbg("status %d, not resubmiting", urb->status);
+               return;
+       }
+       if (urb->status)
+               dbg("status: %d length: %d",
+                   urb->status, urb->actual_length);
+       if (urb->actual_length < sizeof(*ans)) {
+               err("%s: short read, ignoring", __func__);
+               goto resubmit;
+       }
+       crc = build_crc(ans);
+       if (le16_to_cpu(ans->crc) != crc) {
+               err("CRC error, ignoring packet");
+               goto resubmit;
+       }
+
+       hermes_rid = le16_to_cpu(ans->hermes_rid);
+       if ((hermes_rid != EZUSB_RID_RX) && !EZUSB_IS_INFO(hermes_rid)) {
+               ezusb_request_in_callback(upriv, urb);
+       } else if (upriv->dev) {
+               struct net_device *dev = upriv->dev;
+               struct orinoco_private *priv = ndev_priv(dev);
+               hermes_t *hw = &priv->hw;
+
+               if (hermes_rid == EZUSB_RID_RX) {
+                       __orinoco_ev_rx(dev, hw);
+               } else {
+                       hermes_write_regn(hw, INFOFID,
+                                         le16_to_cpu(ans->hermes_rid));
+                       __orinoco_ev_info(dev, hw);
+               }
+       }
+
+ resubmit:
+       if (upriv->udev)
+               ezusb_submit_in_urb(upriv);
+}
+
+static inline void ezusb_delete(struct ezusb_priv *upriv)
+{
+       struct net_device *dev;
+       struct list_head *item;
+       struct list_head *tmp_item;
+       unsigned long flags;
+
+       BUG_ON(in_interrupt());
+       BUG_ON(!upriv);
+
+       dev = upriv->dev;
+       mutex_lock(&upriv->mtx);
+
+       upriv->udev = NULL;     /* No timer will be rearmed from here */
+
+       usb_kill_urb(upriv->read_urb);
+
+       spin_lock_irqsave(&upriv->req_lock, flags);
+       list_for_each_safe(item, tmp_item, &upriv->req_active) {
+               struct request_context *ctx;
+               int err;
+
+               ctx = list_entry(item, struct request_context, list);
+               atomic_inc(&ctx->refcount);
+
+               ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
+               err = usb_unlink_urb(ctx->outurb);
+
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+               if (err == -EINPROGRESS)
+                       wait_for_completion(&ctx->done);
+
+               del_timer_sync(&ctx->timer);
+               /* FIXME: there is an slight chance for the irq handler to
+                * be running */
+               if (!list_empty(&ctx->list))
+                       ezusb_ctx_complete(ctx);
+
+               ezusb_request_context_put(ctx);
+               spin_lock_irqsave(&upriv->req_lock, flags);
+       }
+       spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+       list_for_each_safe(item, tmp_item, &upriv->req_pending)
+           ezusb_ctx_complete(list_entry(item,
+                                         struct request_context, list));
+
+       if (upriv->read_urb->status == -EINPROGRESS)
+               printk(KERN_ERR PFX "Some URB in progress\n");
+
+       mutex_unlock(&upriv->mtx);
+
+       kfree(upriv->read_urb->transfer_buffer);
+       if (upriv->bap_buf != NULL)
+               kfree(upriv->bap_buf);
+       if (upriv->read_urb != NULL)
+               usb_free_urb(upriv->read_urb);
+       if (upriv->dev) {
+               struct orinoco_private *priv = ndev_priv(upriv->dev);
+               orinoco_if_del(priv);
+               free_orinocodev(priv);
+       }
+}
+
+static void ezusb_lock_irqsave(spinlock_t *lock,
+                              unsigned long *flags) __acquires(lock)
+{
+       spin_lock_bh(lock);
+}
+
+static void ezusb_unlock_irqrestore(spinlock_t *lock,
+                                   unsigned long *flags) __releases(lock)
+{
+       spin_unlock_bh(lock);
+}
+
+static void ezusb_lock_irq(spinlock_t *lock) __acquires(lock)
+{
+       spin_lock_bh(lock);
+}
+
+static void ezusb_unlock_irq(spinlock_t *lock) __releases(lock)
+{
+       spin_unlock_bh(lock);
+}
+
+static const struct hermes_ops ezusb_ops = {
+       .init = ezusb_init,
+       .cmd_wait = ezusb_docmd_wait,
+       .init_cmd_wait = ezusb_doicmd_wait,
+       .allocate = ezusb_allocate,
+       .read_ltv = ezusb_read_ltv,
+       .write_ltv = ezusb_write_ltv,
+       .bap_pread = ezusb_bap_pread,
+       .read_pda = ezusb_read_pda,
+       .program_init = ezusb_program_init,
+       .program_end = ezusb_program_end,
+       .program = ezusb_program,
+       .lock_irqsave = ezusb_lock_irqsave,
+       .unlock_irqrestore = ezusb_unlock_irqrestore,
+       .lock_irq = ezusb_lock_irq,
+       .unlock_irq = ezusb_unlock_irq,
+};
+
+static const struct net_device_ops ezusb_netdev_ops = {
+       .ndo_open               = orinoco_open,
+       .ndo_stop               = orinoco_stop,
+       .ndo_start_xmit         = ezusb_xmit,
+       .ndo_set_multicast_list = orinoco_set_multicast_list,
+       .ndo_change_mtu         = orinoco_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_tx_timeout         = orinoco_tx_timeout,
+       .ndo_get_stats          = orinoco_get_stats,
+};
+
+static int ezusb_probe(struct usb_interface *interface,
+                      const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct orinoco_private *priv;
+       hermes_t *hw;
+       struct ezusb_priv *upriv = NULL;
+       struct usb_interface_descriptor *iface_desc;
+       struct usb_endpoint_descriptor *ep;
+       const struct firmware *fw_entry;
+       int retval = 0;
+       int i;
+
+       priv = alloc_orinocodev(sizeof(*upriv), &udev->dev,
+                               ezusb_hard_reset, NULL);
+       if (!priv) {
+               err("Couldn't allocate orinocodev");
+               goto exit;
+       }
+
+       hw = &priv->hw;
+
+       upriv = priv->card;
+
+       mutex_init(&upriv->mtx);
+       spin_lock_init(&upriv->reply_count_lock);
+
+       spin_lock_init(&upriv->req_lock);
+       INIT_LIST_HEAD(&upriv->req_pending);
+       INIT_LIST_HEAD(&upriv->req_active);
+
+       upriv->udev = udev;
+
+       hw->iobase = (void __force __iomem *) &upriv->hermes_reg_fake;
+       hw->reg_spacing = HERMES_16BIT_REGSPACING;
+       hw->priv = upriv;
+       hw->ops = &ezusb_ops;
+
+       /* set up the endpoint information */
+       /* check out the endpoints */
+
+       iface_desc = &interface->altsetting[0].desc;
+       for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
+               ep = &interface->altsetting[0].endpoint[i].desc;
+
+               if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                    == USB_DIR_IN) &&
+                   ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                    == USB_ENDPOINT_XFER_BULK)) {
+                       /* we found a bulk in endpoint */
+                       if (upriv->read_urb != NULL) {
+                               pr_warning("Found a second bulk in ep, ignored");
+                               continue;
+                       }
+
+                       upriv->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+                       if (!upriv->read_urb) {
+                               err("No free urbs available");
+                               goto error;
+                       }
+                       if (le16_to_cpu(ep->wMaxPacketSize) != 64)
+                               pr_warning("bulk in: wMaxPacketSize!= 64");
+                       if (ep->bEndpointAddress != (2 | USB_DIR_IN))
+                               pr_warning("bulk in: bEndpointAddress: %d",
+                                    ep->bEndpointAddress);
+                       upriv->read_pipe = usb_rcvbulkpipe(udev,
+                                                        ep->
+                                                        bEndpointAddress);
+                       upriv->read_urb->transfer_buffer =
+                           kmalloc(BULK_BUF_SIZE, GFP_KERNEL);
+                       if (!upriv->read_urb->transfer_buffer) {
+                               err("Couldn't allocate IN buffer");
+                               goto error;
+                       }
+               }
+
+               if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                    == USB_DIR_OUT) &&
+                   ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                    == USB_ENDPOINT_XFER_BULK)) {
+                       /* we found a bulk out endpoint */
+                       if (upriv->bap_buf != NULL) {
+                               pr_warning("Found a second bulk out ep, ignored");
+                               continue;
+                       }
+
+                       if (le16_to_cpu(ep->wMaxPacketSize) != 64)
+                               pr_warning("bulk out: wMaxPacketSize != 64");
+                       if (ep->bEndpointAddress != 2)
+                               pr_warning("bulk out: bEndpointAddress: %d",
+                                    ep->bEndpointAddress);
+                       upriv->write_pipe = usb_sndbulkpipe(udev,
+                                                         ep->
+                                                         bEndpointAddress);
+                       upriv->bap_buf = kmalloc(BULK_BUF_SIZE, GFP_KERNEL);
+                       if (!upriv->bap_buf) {
+                               err("Couldn't allocate bulk_out_buffer");
+                               goto error;
+                       }
+               }
+       }
+       if (!upriv->bap_buf || !upriv->read_urb) {
+               err("Didn't find the required bulk endpoints");
+               goto error;
+       }
+
+       if (request_firmware(&fw_entry, "orinoco_ezusb_fw",
+                            &interface->dev) == 0) {
+               firmware.size = fw_entry->size;
+               firmware.code = fw_entry->data;
+       }
+       if (firmware.size && firmware.code) {
+               ezusb_firmware_download(upriv, &firmware);
+       } else {
+               err("No firmware to download");
+               goto error;
+       }
+
+       if (ezusb_hard_reset(priv) < 0) {
+               err("Cannot reset the device");
+               goto error;
+       }
+
+       /* If the firmware is already downloaded orinoco.c will call
+        * ezusb_init but if the firmware is not already there, that will make
+        * the kernel very unstable, so we try initializing here and quit in
+        * case of error */
+       if (ezusb_init(hw) < 0) {
+               err("Couldn't initialize the device");
+               err("Firmware may not be downloaded or may be wrong.");
+               goto error;
+       }
+
+       /* Initialise the main driver */
+       if (orinoco_init(priv) != 0) {
+               err("orinoco_init() failed\n");
+               goto error;
+       }
+
+       if (orinoco_if_add(priv, 0, 0, &ezusb_netdev_ops) != 0) {
+               upriv->dev = NULL;
+               err("%s: orinoco_if_add() failed", __func__);
+               goto error;
+       }
+       upriv->dev = priv->ndev;
+
+       goto exit;
+
+ error:
+       ezusb_delete(upriv);
+       if (upriv->dev) {
+               /* upriv->dev was 0, so ezusb_delete() didn't free it */
+               free_orinocodev(priv);
+       }
+       upriv = NULL;
+       retval = -EFAULT;
+ exit:
+       if (fw_entry) {
+               firmware.code = NULL;
+               firmware.size = 0;
+               release_firmware(fw_entry);
+       }
+       usb_set_intfdata(interface, upriv);
+       return retval;
+}
+
+
+static void ezusb_disconnect(struct usb_interface *intf)
+{
+       struct ezusb_priv *upriv = usb_get_intfdata(intf);
+       usb_set_intfdata(intf, NULL);
+       ezusb_delete(upriv);
+       printk(KERN_INFO PFX "Disconnected\n");
+}
+
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver orinoco_driver = {
+       .name = DRIVER_NAME,
+       .probe = ezusb_probe,
+       .disconnect = ezusb_disconnect,
+       .id_table = ezusb_table,
+};
+
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+    " (Manuel Estrada Sainz)";
+
+static int __init ezusb_module_init(void)
+{
+       int err;
+
+       printk(KERN_DEBUG "%s\n", version);
+
+       /* register this driver with the USB subsystem */
+       err = usb_register(&orinoco_driver);
+       if (err < 0) {
+               printk(KERN_ERR PFX "usb_register failed, error %d\n",
+                      err);
+               return err;
+       }
+
+       return 0;
+}
+
+static void __exit ezusb_module_exit(void)
+{
+       /* deregister this driver with the USB subsystem */
+       usb_deregister(&orinoco_driver);
+}
+
+
+module_init(ezusb_module_init);
+module_exit(ezusb_module_exit);
+
+MODULE_AUTHOR("Manuel Estrada Sainz");
+MODULE_DESCRIPTION
+    ("Driver for Orinoco wireless LAN cards using EZUSB bridge");
+MODULE_LICENSE("Dual MPL/GPL");
index 59bda240fdc228712490e6dfe7a0bea1d0b4c3f4..9b1af4976bf55c2fb5b7952794a3b6d6e24e76b2 100644 (file)
@@ -349,6 +349,7 @@ spectrum_cs_config(struct pcmcia_device *link)
                goto failed;
 
        hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
+       hw->eeprom_pda = true;
 
        /*
         * This actually configures the PCMCIA socket -- setting up
@@ -374,7 +375,7 @@ spectrum_cs_config(struct pcmcia_device *link)
 
        /* Register an interface with the stack */
        if (orinoco_if_add(priv, link->io.BasePort1,
-                          link->irq.AssignedIRQ) != 0) {
+                          link->irq.AssignedIRQ, NULL) != 0) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto failed;
        }
@@ -405,9 +406,9 @@ spectrum_cs_release(struct pcmcia_device *link)
 
        /* We're committed to taking the device away now, so mark the
         * hardware as unavailable */
-       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, &flags);
        priv->hw_unavailable++;
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
        pcmcia_disable_device(link);
        if (priv->hw.iobase)
index a1006bf430cc661240a710af9a466559e9acb51a..5775124e2aeefd57215324cb1c778ad983f8b024 100644 (file)
@@ -458,7 +458,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
        if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
                /* Fast channel change - no commit if successful */
                hermes_t *hw = &priv->hw;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+               err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
                                            HERMES_TEST_SET_CHANNEL,
                                        chan, NULL);
        }
@@ -1273,8 +1273,8 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
-                             extra);
+       err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
+                               extra);
        if (err)
                goto out;
 
index 7bbd9d3bba60026ce75bbd5e72ca9d3064ff1ba9..c072f41747cac9cf1e0c6c9c37c4c01e53c41a7c 100644 (file)
@@ -546,8 +546,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
                     IEEE80211_HW_SUPPORTS_PS |
                     IEEE80211_HW_PS_NULLFUNC_STACK |
                     IEEE80211_HW_BEACON_FILTER |
-                    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
-                    IEEE80211_HW_NOISE_DBM;
+                    IEEE80211_HW_REPORTS_TX_ACK_STATUS;
 
        dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                                      BIT(NL80211_IFTYPE_ADHOC) |
index ca42ccb23d766ac4204f75cda33aed63915b350f..07c4528f6e6b895d59e2cddc3fd30edcf80cb000 100644 (file)
@@ -277,6 +277,14 @@ static void p54p_tasklet(unsigned long dev_id)
        struct p54p_priv *priv = dev->priv;
        struct p54p_ring_control *ring_control = priv->ring_control;
 
+       p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, 3, ring_control->tx_mgmt,
+                          ARRAY_SIZE(ring_control->tx_mgmt),
+                          priv->tx_buf_mgmt);
+
+       p54p_check_tx_ring(dev, &priv->tx_idx_data, 1, ring_control->tx_data,
+                          ARRAY_SIZE(ring_control->tx_data),
+                          priv->tx_buf_data);
+
        p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt,
                ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt);
 
@@ -285,14 +293,6 @@ static void p54p_tasklet(unsigned long dev_id)
 
        wmb();
        P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
-
-       p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, 3, ring_control->tx_mgmt,
-                          ARRAY_SIZE(ring_control->tx_mgmt),
-                          priv->tx_buf_mgmt);
-
-       p54p_check_tx_ring(dev, &priv->tx_idx_data, 1, ring_control->tx_data,
-                          ARRAY_SIZE(ring_control->tx_data),
-                          priv->tx_buf_data);
 }
 
 static irqreturn_t p54p_interrupt(int irq, void *dev_id)
index 2ceff5480355aa3c351ba328ecc7ce55b2071d15..4e6891099d43d98d960619004e41d953cba3c1b1 100644 (file)
@@ -350,7 +350,6 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
                rx_status->flag |= RX_FLAG_MMIC_ERROR;
 
        rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi);
-       rx_status->noise = priv->noise;
        if (hdr->rate & 0x10)
                rx_status->flag |= RX_FLAG_SHORTPRE;
        if (priv->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
index 5239e082cd0f51b75c6978167a3b6782510c864a..eea1ef2f502bd3c926599b2308901277e35250ef 100644 (file)
@@ -87,7 +87,7 @@ if RT2800PCI
 
 config RT2800PCI_RT30XX
        bool "rt2800pci - Include support for rt30xx (PCI/PCIe/PCMCIA) devices"
-       default n
+       default y
        ---help---
          This adds support for rt30xx wireless chipset family to the
          rt2800pci driver.
@@ -156,7 +156,7 @@ if RT2800USB
 
 config RT2800USB_RT30XX
        bool "rt2800usb - Include support for rt30xx (USB) devices"
-       default n
+       default y
        ---help---
          This adds support for rt30xx wireless chipset family to the
          rt2800usb driver.
index cdbf59108ef9bd878d16ccb0b613ab9a80152745..06b92f8b7a55b957c58b1d04ffe61d21d3b4e022 100644 (file)
@@ -1018,8 +1018,8 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_desc_write(entry_priv->desc, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
-       rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, skb->len);
-       rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skb->len);
+       rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, txdesc->length);
+       rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, txdesc->length);
        rt2x00_desc_write(txd, 2, word);
 
        rt2x00_desc_read(txd, 3, &word);
index 89e986f449da51f091e806d6b87107ae7f2bdc48..ae8e205df26996a366caacc38ead707fce9d61d2 100644 (file)
@@ -1209,7 +1209,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
        rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
                           test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
        rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
        rt2x00_desc_write(txd, 0, word);
 }
index 7185cb05f257f2ef127284aec0da1087853938bc..41d9996c80e6004ad6cfadcbd1cbf9737be39a52 100644 (file)
@@ -1072,7 +1072,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
                           test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
-       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
        rt2x00_set_field32(&word, TXD_W0_CIPHER, !!txdesc->cipher);
        rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx);
        rt2x00_desc_write(txd, 0, word);
index ec893721cc80c6ff6133c1119f093be9247d21b9..2aa03751c341d18848f668beb26868bdc252abb5 100644 (file)
 /*
  * INT_SOURCE_CSR: Interrupt source register.
  * Write one to clear corresponding bit.
- * TX_FIFO_STATUS: FIFO Statistics is full, sw should read 0x171c
+ * TX_FIFO_STATUS: FIFO Statistics is full, sw should read TX_STA_FIFO
  */
 #define INT_SOURCE_CSR                 0x0200
 #define INT_SOURCE_CSR_RXDELAYINT      FIELD32(0x00000001)
  * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz
  */
 #define TX_BAND_CFG                    0x132c
-#define TX_BAND_CFG_HT40_PLUS          FIELD32(0x00000001)
+#define TX_BAND_CFG_HT40_MINUS         FIELD32(0x00000001)
 #define TX_BAND_CFG_A                  FIELD32(0x00000002)
 #define TX_BAND_CFG_BG                 FIELD32(0x00000004)
 
@@ -1519,7 +1519,7 @@ struct mac_iveiv_entry {
  * BBP 3: RX Antenna
  */
 #define BBP3_RX_ANTENNA                        FIELD8(0x18)
-#define BBP3_HT40_PLUS                 FIELD8(0x20)
+#define BBP3_HT40_MINUS                        FIELD8(0x20)
 
 /*
  * BBP 4: Bandwidth
@@ -1565,6 +1565,11 @@ struct mac_iveiv_entry {
  */
 #define RFCSR12_TX_POWER               FIELD8(0x1f)
 
+/*
+ * RFCSR 13:
+ */
+#define RFCSR13_TX_POWER               FIELD8(0x1f)
+
 /*
  * RFCSR 15:
  */
index 2648f315a93420b2a78acbede1d673a6c963d9e4..e37bbeab923399cffc891f530959dc6bf3c3c5f3 100644 (file)
@@ -41,9 +41,6 @@
 #if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
 #include "rt2x00usb.h"
 #endif
-#if defined(CONFIG_RT2X00_LIB_PCI) || defined(CONFIG_RT2X00_LIB_PCI_MODULE)
-#include "rt2x00pci.h"
-#endif
 #include "rt2800lib.h"
 #include "rt2800.h"
 #include "rt2800usb.h"
@@ -76,6 +73,23 @@ MODULE_LICENSE("GPL");
        rt2800_regbusy_read((__dev), H2M_MAILBOX_CSR, \
                            H2M_MAILBOX_CSR_OWNER, (__reg))
 
+static inline bool rt2800_is_305x_soc(struct rt2x00_dev *rt2x00dev)
+{
+       /* check for rt2872 on SoC */
+       if (!rt2x00_is_soc(rt2x00dev) ||
+           !rt2x00_rt(rt2x00dev, RT2872))
+               return false;
+
+       /* we know for sure that these rf chipsets are used on rt305x boards */
+       if (rt2x00_rf(rt2x00dev, RF3020) ||
+           rt2x00_rf(rt2x00dev, RF3021) ||
+           rt2x00_rf(rt2x00dev, RF3022))
+               return true;
+
+       NOTICE(rt2x00dev, "Unknown RF chipset on rt305x\n");
+       return false;
+}
+
 static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev,
                             const unsigned int word, const u8 value)
 {
@@ -794,6 +808,11 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev,
                          TXPOWER_G_TO_DEV(info->tx_power1));
        rt2800_rfcsr_write(rt2x00dev, 12, rfcsr);
 
+       rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER,
+                         TXPOWER_G_TO_DEV(info->tx_power2));
+       rt2800_rfcsr_write(rt2x00dev, 13, rfcsr);
+
        rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr);
        rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset);
        rt2800_rfcsr_write(rt2x00dev, 23, rfcsr);
@@ -849,7 +868,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        }
 
        rt2800_register_read(rt2x00dev, TX_BAND_CFG, &reg);
-       rt2x00_set_field32(&reg, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf));
+       rt2x00_set_field32(&reg, TX_BAND_CFG_HT40_MINUS, conf_is_ht40_minus(conf));
        rt2x00_set_field32(&reg, TX_BAND_CFG_A, rf->channel > 14);
        rt2x00_set_field32(&reg, TX_BAND_CFG_BG, rf->channel <= 14);
        rt2800_register_write(rt2x00dev, TX_BAND_CFG, reg);
@@ -882,7 +901,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        rt2800_bbp_write(rt2x00dev, 4, bbp);
 
        rt2800_bbp_read(rt2x00dev, 3, &bbp);
-       rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf));
+       rt2x00_set_field8(&bbp, BBP3_HT40_MINUS, conf_is_ht40_minus(conf));
        rt2800_bbp_write(rt2x00dev, 3, bbp);
 
        if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) {
@@ -1551,6 +1570,9 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
                     rt2800_wait_bbp_ready(rt2x00dev)))
                return -EACCES;
 
+       if (rt2800_is_305x_soc(rt2x00dev))
+               rt2800_bbp_write(rt2x00dev, 31, 0x08);
+
        rt2800_bbp_write(rt2x00dev, 65, 0x2c);
        rt2800_bbp_write(rt2x00dev, 66, 0x38);
 
@@ -1571,6 +1593,9 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
                rt2800_bbp_write(rt2x00dev, 79, 0x13);
                rt2800_bbp_write(rt2x00dev, 80, 0x05);
                rt2800_bbp_write(rt2x00dev, 81, 0x33);
+       } else if (rt2800_is_305x_soc(rt2x00dev)) {
+               rt2800_bbp_write(rt2x00dev, 78, 0x0e);
+               rt2800_bbp_write(rt2x00dev, 80, 0x08);
        } else {
                rt2800_bbp_write(rt2x00dev, 81, 0x37);
        }
@@ -1591,12 +1616,16 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
        if (rt2x00_rt_rev_gte(rt2x00dev, RT3070, REV_RT3070F) ||
            rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) ||
            rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) ||
-           rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E))
+           rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E) ||
+           rt2800_is_305x_soc(rt2x00dev))
                rt2800_bbp_write(rt2x00dev, 103, 0xc0);
        else
                rt2800_bbp_write(rt2x00dev, 103, 0x00);
 
-       rt2800_bbp_write(rt2x00dev, 105, 0x05);
+       if (rt2800_is_305x_soc(rt2x00dev))
+               rt2800_bbp_write(rt2x00dev, 105, 0x01);
+       else
+               rt2800_bbp_write(rt2x00dev, 105, 0x05);
        rt2800_bbp_write(rt2x00dev, 106, 0x35);
 
        if (rt2x00_rt(rt2x00dev, RT3071) ||
@@ -1613,11 +1642,6 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
                rt2800_bbp_write(rt2x00dev, 138, value);
        }
 
-       if (rt2x00_rt(rt2x00dev, RT2872)) {
-               rt2800_bbp_write(rt2x00dev, 31, 0x08);
-               rt2800_bbp_write(rt2x00dev, 78, 0x0e);
-               rt2800_bbp_write(rt2x00dev, 80, 0x08);
-       }
 
        for (i = 0; i < EEPROM_BBP_SIZE; i++) {
                rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
@@ -1703,7 +1727,8 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
        if (!rt2x00_rt(rt2x00dev, RT3070) &&
            !rt2x00_rt(rt2x00dev, RT3071) &&
            !rt2x00_rt(rt2x00dev, RT3090) &&
-           !rt2x00_rt(rt2x00dev, RT3390))
+           !rt2x00_rt(rt2x00dev, RT3390) &&
+           !rt2800_is_305x_soc(rt2x00dev))
                return 0;
 
        /*
@@ -1771,6 +1796,40 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
                rt2800_rfcsr_write(rt2x00dev, 29, 0x8f);
                rt2800_rfcsr_write(rt2x00dev, 30, 0x20);
                rt2800_rfcsr_write(rt2x00dev, 31, 0x0f);
+       } else if (rt2800_is_305x_soc(rt2x00dev)) {
+               rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
+               rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
+               rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
+               rt2800_rfcsr_write(rt2x00dev, 3, 0x75);
+               rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
+               rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
+               rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
+               rt2800_rfcsr_write(rt2x00dev, 7, 0x50);
+               rt2800_rfcsr_write(rt2x00dev, 8, 0x39);
+               rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
+               rt2800_rfcsr_write(rt2x00dev, 10, 0x60);
+               rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+               rt2800_rfcsr_write(rt2x00dev, 12, 0x75);
+               rt2800_rfcsr_write(rt2x00dev, 13, 0x75);
+               rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
+               rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
+               rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
+               rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
+               rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
+               rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
+               rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
+               rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
+               rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 23, 0x31);
+               rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
+               rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
+               rt2800_rfcsr_write(rt2x00dev, 26, 0x25);
+               rt2800_rfcsr_write(rt2x00dev, 27, 0x23);
+               rt2800_rfcsr_write(rt2x00dev, 28, 0x13);
+               rt2800_rfcsr_write(rt2x00dev, 29, 0x83);
+               rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
+               return 0;
        }
 
        if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
@@ -1986,7 +2045,6 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
                EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
        } else if (rt2x00_rt(rt2x00dev, RT2860) ||
                   rt2x00_rt(rt2x00dev, RT2870) ||
-                  rt2x00_rt(rt2x00dev, RT2872) ||
                   rt2x00_rt(rt2x00dev, RT2872)) {
                /*
                 * There is a max of 2 RX streams for RT28x0 series
@@ -2318,8 +2376,11 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        else
                spec->ht.ht_supported = false;
 
+       /*
+        * Don't set IEEE80211_HT_CAP_SUP_WIDTH_20_40 for now as it causes
+        * reception problems with HT40 capable 11n APs
+        */
        spec->ht.cap =
-           IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
            IEEE80211_HT_CAP_GRN_FLD |
            IEEE80211_HT_CAP_SGI_20 |
            IEEE80211_HT_CAP_SGI_40 |
index 0e52f174896c5cdf5805cbcace8f5186e08b7f47..f08b6a37bf2d143556ab1a7ec2467100bb736049 100644 (file)
@@ -663,7 +663,7 @@ static int rt2800pci_write_tx_data(struct queue_entry* entry,
                           test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
                           txdesc->key_idx : 0xff);
        rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
-                          skb->len - txdesc->l2pad);
+                          txdesc->length);
        rt2x00_set_field32(&word, TXWI_W1_PACKETID,
                           skbdesc->entry->queue->qid + 1);
        rt2x00_desc_write(txwi, 1, word);
@@ -895,10 +895,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
            (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) +
             rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2;
 
-       rxdesc->noise =
-           (rt2x00_get_field32(rxwi3, RXWI_W3_SNR0) +
-            rt2x00_get_field32(rxwi3, RXWI_W3_SNR1)) / 2;
-
        rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
 
        /*
index 95c8a6134ff8816911ea9f2cd018e5c955d754ce..e3f3a97db80773118c0228b6ced8e99822f4e5e7 100644 (file)
@@ -437,7 +437,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                           test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
                           txdesc->key_idx : 0xff);
        rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
-                          skb->len - txdesc->l2pad);
+                          txdesc->length);
        rt2x00_set_field32(&word, TXWI_W1_PACKETID,
                           skbdesc->entry->queue->qid + 1);
        rt2x00_desc_write(txwi, 1, word);
@@ -645,10 +645,6 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
            (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) +
             rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2;
 
-       rxdesc->noise =
-           (rt2x00_get_field32(rxwi3, RXWI_W3_SNR0) +
-            rt2x00_get_field32(rxwi3, RXWI_W3_SNR1)) / 2;
-
        rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
 
        /*
@@ -1027,7 +1023,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
 #ifdef CONFIG_RT2800USB_UNKNOWN
        /*
         * Unclear what kind of devices these are (they aren't supported by the
-        * vendor driver).
+        * vendor linux driver).
         */
        /* Amigo */
        { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -1040,6 +1036,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* 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) },
        /* Belkin */
        { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Buffalo */
@@ -1058,6 +1055,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { 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) },
        /* Encore */
        { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Gemtek */
@@ -1074,11 +1072,13 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* Motorola */
        { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Ovislink */
+       { USB_DEVICE(0x1b75, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* 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(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Planex */
        { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Qcom */
@@ -1087,6 +1087,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { 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) },
        /* Sweex */
        { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) },
index eda73ba735a6e388ed8d9f68d22668af84ead912..3ae468c4d7604b3b8e82eac570445bdbf098ab7a 100644 (file)
@@ -435,7 +435,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
        rx_status->mactime = rxdesc.timestamp;
        rx_status->rate_idx = rate_idx;
        rx_status->signal = rxdesc.rssi;
-       rx_status->noise = rxdesc.noise;
        rx_status->flag = rxdesc.flags;
        rx_status->antenna = rt2x00dev->link.ant.active.rx;
 
index 91b7fb99ceb44067f621bc562c2539274e3981bc..e22029fcf411580571fe696246ffb64659729e42 100644 (file)
@@ -334,12 +334,10 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
        txdesc->aifs = entry->queue->aifs;
 
        /*
-        * Header and alignment information.
+        * Header and frame information.
         */
+       txdesc->length = entry->skb->len;
        txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
-       if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags) &&
-           (entry->skb->len > txdesc->header_length))
-               txdesc->l2pad = L2PAD_SIZE(txdesc->header_length);
 
        /*
         * Check whether this frame is to be acked.
index c1e482bb37b36f18544d27eeaef8e41b6e1852be..94a48c174d6790e8000c5d4406efb3ffd9b0ea4e 100644 (file)
@@ -183,7 +183,6 @@ enum rxdone_entry_desc_flags {
  * @timestamp: RX Timestamp
  * @signal: Signal of the received frame.
  * @rssi: RSSI of the received frame.
- * @noise: Measured noise during frame reception.
  * @size: Data size of the received frame.
  * @flags: MAC80211 receive flags (See &enum mac80211_rx_flags).
  * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags).
@@ -197,7 +196,6 @@ struct rxdone_entry_desc {
        u64 timestamp;
        int signal;
        int rssi;
-       int noise;
        int size;
        int flags;
        int dev_flags;
@@ -287,8 +285,8 @@ enum txentry_desc_flags {
  *
  * @flags: Descriptor flags (See &enum queue_entry_flags).
  * @queue: Queue identification (See &enum data_queue_qid).
+ * @length: Length of the entire frame.
  * @header_length: Length of 802.11 header.
- * @l2pad: Amount of padding to align 802.11 payload to 4-byte boundrary.
  * @length_high: PLCP length high word.
  * @length_low: PLCP length low word.
  * @signal: PLCP signal.
@@ -313,8 +311,8 @@ struct txentry_desc {
 
        enum data_queue_qid queue;
 
+       u16 length;
        u16 header_length;
-       u16 l2pad;
 
        u16 length_high;
        u16 length_low;
index b9885981f3a8103d41c8bb04838920af9f314e78..26ee7911fba92c406330798a654539ffadcaa7df 100644 (file)
@@ -1809,7 +1809,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 
        if (skbdesc->desc_len > TXINFO_SIZE) {
                rt2x00_desc_read(txd, 11, &word);
-               rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skb->len);
+               rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0,
+                                  txdesc->length);
                rt2x00_desc_write(txd, 11, word);
        }
 
@@ -1832,7 +1833,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
                           test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
-       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
        rt2x00_set_field32(&word, TXD_W0_BURST,
                           test_bit(ENTRY_TXD_BURST, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
index 576ea9dd28249d7743e0b5664d8aa0ea9805c743..39b3c6d04af4b6260b80322ffe4d46339a000a42 100644 (file)
@@ -1495,7 +1495,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
                           test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
-       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
        rt2x00_set_field32(&word, TXD_W0_BURST2,
                           test_bit(ENTRY_TXD_BURST, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
index 6b46329b732f1446cf67af26765580e89ad8112c..21307f2412b8367e01f46b949438a15fd91918a0 100644 (file)
@@ -188,6 +188,7 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
                        info->flags |= IEEE80211_TX_STAT_ACK;
 
                info->status.rates[0].count = (flags & 0xFF) + 1;
+               info->status.rates[1].idx = -1;
 
                ieee80211_tx_status_irqsafe(dev, skb);
                if (ring->entries - skb_queue_len(&ring->queue) == 2)
@@ -297,7 +298,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        entry->flags = cpu_to_le32(tx_flags);
        __skb_queue_tail(&ring->queue, skb);
        if (ring->entries - skb_queue_len(&ring->queue) < 2)
-               ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
+               ieee80211_stop_queue(dev, prio);
        spin_unlock_irqrestore(&priv->lock, flags);
 
        rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
@@ -827,6 +828,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
        const char *chip_name, *rf_name = NULL;
        u32 reg;
        u16 eeprom_val;
+       u8 mac_addr[ETH_ALEN];
 
        err = pci_enable_device(pdev);
        if (err) {
@@ -987,12 +989,13 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
                eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam);
        }
 
-       eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)dev->wiphy->perm_addr, 3);
-       if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+       eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)mac_addr, 3);
+       if (!is_valid_ether_addr(mac_addr)) {
                printk(KERN_WARNING "%s (rtl8180): Invalid hwaddr! Using"
                       " randomly generated MAC addr\n", pci_name(pdev));
-               random_ether_addr(dev->wiphy->perm_addr);
+               random_ether_addr(mac_addr);
        }
+       SET_IEEE80211_PERM_ADDR(dev, mac_addr);
 
        /* CCK TX power */
        for (i = 0; i < 14; i += 2) {
@@ -1024,7 +1027,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
        }
 
        printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n",
-              wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
+              wiphy_name(dev->wiphy), mac_addr,
               chip_name, priv->rf->name);
 
        return 0;
index 738921fda02792ad1da89b7a070db7eec0d66289..891b8490e34978b0d0bbb71b777a9da617f35cb4 100644 (file)
@@ -1333,6 +1333,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
        u16 txpwr, reg;
        u16 product_id = le16_to_cpu(udev->descriptor.idProduct);
        int err, i;
+       u8 mac_addr[ETH_ALEN];
 
        dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
        if (!dev) {
@@ -1390,12 +1391,13 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
        udelay(10);
 
        eeprom_93cx6_multiread(&eeprom, RTL8187_EEPROM_MAC_ADDR,
-                              (__le16 __force *)dev->wiphy->perm_addr, 3);
-       if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+                              (__le16 __force *)mac_addr, 3);
+       if (!is_valid_ether_addr(mac_addr)) {
                printk(KERN_WARNING "rtl8187: Invalid hwaddr! Using randomly "
                       "generated MAC address\n");
-               random_ether_addr(dev->wiphy->perm_addr);
+               random_ether_addr(mac_addr);
        }
+       SET_IEEE80211_PERM_ADDR(dev, mac_addr);
 
        channel = priv->channels;
        for (i = 0; i < 3; i++) {
@@ -1526,7 +1528,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
        skb_queue_head_init(&priv->b_tx_status.queue);
 
        printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s, rfkill mask %d\n",
-              wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
+              wiphy_name(dev->wiphy), mac_addr,
               chip_name, priv->asic_rev, priv->rf->name, priv->rfkill_mask);
 
 #ifdef CONFIG_RTL8187_LEDS
index 51614d181ccb86c64951f7211ee2d6b7967664ed..00b24282fc738cad290466902ec12735e131cb50 100644 (file)
@@ -857,6 +857,7 @@ out:
 }
 
 static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif,
                             struct cfg80211_scan_request *req)
 {
        struct wl1251 *wl = hw->priv;
@@ -1291,7 +1292,6 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
        wl->hw->channel_change_time = 10000;
 
        wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
-               IEEE80211_HW_NOISE_DBM |
                IEEE80211_HW_SUPPORTS_PS |
                IEEE80211_HW_BEACON_FILTER |
                IEEE80211_HW_SUPPORTS_UAPSD;
index 6f229e0990f4efc45d3a54facaad939d994cbf3c..af5c67b4da9558909bc40551d83a3f6f233391fd 100644 (file)
@@ -74,12 +74,6 @@ static void wl1251_rx_status(struct wl1251 *wl,
 
        status->signal = desc->rssi;
 
-       /*
-        * FIXME: guessing that snr needs to be divided by two, otherwise
-        * the values don't make any sense
-        */
-       status->noise = desc->rssi - desc->snr / 2;
-
        status->freq = ieee80211_channel_to_frequency(desc->channel);
 
        status->flag |= RX_FLAG_TSFT;
index 2ad086efe06e8490ecb5d1c7405005695d6ad4d3..e19e2f8f1e522d7806fcde6224a35bfa90a4b65a 100644 (file)
@@ -590,7 +590,7 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl)
 
        /* BT-WLAN coext parameters */
        for (i = 0; i < CONF_SG_PARAMS_MAX; i++)
-               param->params[i] = c->params[i];
+               param->params[i] = cpu_to_le32(c->params[i]);
        param->param_idx = CONF_SG_PARAMS_ALL;
 
        ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
index 8087dc17f29d43b113a1e41c0d51931a19ea0fcb..acb1d9e6b7d2f0fc2578a6019653579f102d1d96 100644 (file)
@@ -351,7 +351,7 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
 static int wl1271_boot_run_firmware(struct wl1271 *wl)
 {
        int loop, ret;
-       u32 chip_id, interrupt;
+       u32 chip_id, intr;
 
        wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
 
@@ -368,15 +368,15 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
        loop = 0;
        while (loop++ < INIT_LOOP) {
                udelay(INIT_LOOP_DELAY);
-               interrupt = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+               intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
 
-               if (interrupt == 0xffffffff) {
+               if (intr == 0xffffffff) {
                        wl1271_error("error reading hardware complete "
                                     "init indication");
                        return -EIO;
                }
                /* check that ACX_INTR_INIT_COMPLETE is enabled */
-               else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) {
+               else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
                        wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
                                       WL1271_ACX_INTR_INIT_COMPLETE);
                        break;
index 6b5ba8ec94c9397c618839635bb2936215457cb9..62c11af1d8e2066a1606bac832aa61dea691422b 100644 (file)
@@ -37,7 +37,7 @@
 #include "wl1271_cmd.h"
 #include "wl1271_event.h"
 
-#define WL1271_CMD_POLL_COUNT       5
+#define WL1271_CMD_FAST_POLL_COUNT       50
 
 /*
  * send command to firmware
@@ -77,11 +77,11 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
                        goto out;
                }
 
-               udelay(10);
                poll_count++;
-               if (poll_count == WL1271_CMD_POLL_COUNT)
-                       wl1271_info("cmd polling took over %d cycles",
-                                   poll_count);
+               if (poll_count < WL1271_CMD_FAST_POLL_COUNT)
+                       udelay(10);
+               else
+                       msleep(1);
 
                intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
        }
@@ -318,7 +318,7 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
        join->rx_config_options = cpu_to_le32(wl->rx_config);
        join->rx_filter_options = cpu_to_le32(wl->rx_filter);
        join->bss_type = bss_type;
-       join->basic_rate_set = wl->basic_rate_set;
+       join->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
 
        if (wl->band == IEEE80211_BAND_5GHZ)
                join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
@@ -615,7 +615,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
        params->params.scan_options = cpu_to_le16(scan_options);
 
        params->params.num_probe_requests = probe_requests;
-       params->params.tx_rate = rate;
+       params->params.tx_rate = cpu_to_le32(rate);
        params->params.tid_trigger = 0;
        params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
 
index c44307c4bcf8ca8c62c6ba18934a84f487a57a9b..d046d044b5bd8a640acb99bfcc08259e2654b1f6 100644 (file)
@@ -401,7 +401,7 @@ enum {
 };
 
 struct conf_sg_settings {
-       __le32 params[CONF_SG_PARAMS_MAX];
+       u32 params[CONF_SG_PARAMS_MAX];
        u8 state;
 };
 
index e47a58d2cc19a10efbd7cb89c042360d2c191c89..62e544041d0d738ad71beda7196d14e33cdedf66 100644 (file)
@@ -1118,14 +1118,13 @@ static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
        }
 }
 
-static int wl1271_join_channel(struct wl1271 *wl, int channel)
+static int wl1271_dummy_join(struct wl1271 *wl)
 {
        int ret = 0;
        /* we need to use a dummy BSSID for now */
        static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
                                                  0xad, 0xbe, 0xef };
 
-       wl->channel = channel;
        memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
 
        /* pass through frames from all BSS */
@@ -1141,7 +1140,47 @@ out:
        return ret;
 }
 
-static int wl1271_unjoin_channel(struct wl1271 *wl)
+static int wl1271_join(struct wl1271 *wl)
+{
+       int ret;
+
+       ret = wl1271_cmd_join(wl, wl->set_bss_type);
+       if (ret < 0)
+               goto out;
+
+       set_bit(WL1271_FLAG_JOINED, &wl->flags);
+
+       if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+               goto out;
+
+       /*
+        * The join command disable the keep-alive mode, shut down its process,
+        * and also clear the template config, so we need to reset it all after
+        * the join. The acx_aid starts the keep-alive process, and the order
+        * of the commands below is relevant.
+        */
+       ret = wl1271_acx_keep_alive_mode(wl, true);
+       if (ret < 0)
+               goto out;
+
+       ret = wl1271_acx_aid(wl, wl->aid);
+       if (ret < 0)
+               goto out;
+
+       ret = wl1271_cmd_build_klv_null_data(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
+                                          ACX_KEEP_ALIVE_TPL_VALID);
+       if (ret < 0)
+               goto out;
+
+out:
+       return ret;
+}
+
+static int wl1271_unjoin(struct wl1271 *wl)
 {
        int ret;
 
@@ -1231,7 +1270,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
                                       "failed %d", ret);
 
                if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
-                       ret = wl1271_cmd_join(wl, wl->set_bss_type);
+                       ret = wl1271_join(wl);
                        if (ret < 0)
                                wl1271_warning("cmd join to update channel "
                                               "failed %d", ret);
@@ -1241,9 +1280,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
        if (changed & IEEE80211_CONF_CHANGE_IDLE) {
                if (conf->flags & IEEE80211_CONF_IDLE &&
                    test_bit(WL1271_FLAG_JOINED, &wl->flags))
-                       wl1271_unjoin_channel(wl);
+                       wl1271_unjoin(wl);
                else if (!(conf->flags & IEEE80211_CONF_IDLE))
-                       wl1271_join_channel(wl, channel);
+                       wl1271_dummy_join(wl);
 
                if (conf->flags & IEEE80211_CONF_IDLE) {
                        wl->rate_set = wl1271_min_rate_get(wl);
@@ -1519,6 +1558,7 @@ out:
 }
 
 static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif,
                             struct cfg80211_scan_request *req)
 {
        struct wl1271 *wl = hw->priv;
@@ -1607,7 +1647,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
        enum wl1271_cmd_ps_mode mode;
        struct wl1271 *wl = hw->priv;
        bool do_join = false;
-       bool do_keepalive = false;
        int ret;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
@@ -1702,6 +1741,10 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                        if (ret < 0)
                                goto out_sleep;
 
+                       ret = wl1271_build_qos_null_data(wl);
+                       if (ret < 0)
+                               goto out_sleep;
+
                        /* filter out all packets not from this BSSID */
                        wl1271_configure_filters(wl, 0);
 
@@ -1746,19 +1789,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                        ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
                                                         NULL, 0, wl->band);
 
-                       /* Enable the keep-alive feature */
-                       ret = wl1271_acx_keep_alive_mode(wl, true);
-                       if (ret < 0)
-                               goto out_sleep;
-
-                       /*
-                        * This is awkward. The keep-alive configs must be done
-                        * *after* the join command, because otherwise it will
-                        * not work, but it must only be done *once* because
-                        * otherwise the firmware will start complaining.
-                        */
-                       do_keepalive = true;
-
                        /* enable the connection monitoring feature */
                        ret = wl1271_acx_conn_monit_params(wl, true);
                        if (ret < 0)
@@ -1826,35 +1856,11 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (do_join) {
-               ret = wl1271_cmd_join(wl, wl->set_bss_type);
+               ret = wl1271_join(wl);
                if (ret < 0) {
                        wl1271_warning("cmd join failed %d", ret);
                        goto out_sleep;
                }
-               set_bit(WL1271_FLAG_JOINED, &wl->flags);
-       }
-
-       /*
-        * The JOIN operation shuts down the firmware keep-alive as a side
-        * effect, and the ACX_AID will start the keep-alive as a side effect.
-        * Hence, for non-IBSS, the ACX_AID must always happen *after* the
-        * JOIN operation, and the template config after the ACX_AID.
-        */
-       if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
-               ret = wl1271_acx_aid(wl, wl->aid);
-               if (ret < 0)
-                       goto out_sleep;
-       }
-
-       if (do_keepalive) {
-               ret = wl1271_cmd_build_klv_null_data(wl);
-               if (ret < 0)
-                       goto out_sleep;
-               ret = wl1271_acx_keep_alive_config(
-                       wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
-                       ACX_KEEP_ALIVE_TPL_VALID);
-               if (ret < 0)
-                       goto out_sleep;
        }
 
 out_sleep:
@@ -2265,7 +2271,6 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
        wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
 
        wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
-               IEEE80211_HW_NOISE_DBM |
                IEEE80211_HW_BEACON_FILTER |
                IEEE80211_HW_SUPPORTS_PS |
                IEEE80211_HW_SUPPORTS_UAPSD |
index 59c3c0fdbecde30f14188cac0a5f6eab95f2ec9a..59ae76bace14cb740483484b1a6a21b08157f259 100644 (file)
@@ -233,6 +233,8 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
 {
        if (!cc->dev)
                return; /* We don't have a ChipCommon */
+       if (cc->dev->id.revision >= 11)
+               cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
        ssb_pmu_init(cc);
        chipco_powercontrol_init(cc);
        ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
index 80ff7d9e60ded74e35c78dc1064cfd950af1eea3..7e5b8a8a64cc681c5e1478a12f1c39218a1ed602 100644 (file)
@@ -834,6 +834,9 @@ int ssb_bus_pcibus_register(struct ssb_bus *bus,
        if (!err) {
                ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
                           "PCI device %s\n", dev_name(&host_pci->dev));
+       } else {
+               ssb_printk(KERN_ERR PFX "Failed to register PCI version"
+                          " of SSB with error %d\n", err);
        }
 
        return err;
index a8dbb06623c96f17e61ad996df9647ab699a6740..989e2752cc36d8abb9613b6c77b50936be85184c 100644 (file)
@@ -168,7 +168,7 @@ err_pci:
 }
 
 /* Get the word-offset for a SSB_SPROM_XXX define. */
-#define SPOFF(offset)  (((offset) - SSB_SPROM_BASE) / sizeof(u16))
+#define SPOFF(offset)  ((offset) / sizeof(u16))
 /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
 #define SPEX16(_outvar, _offset, _mask, _shift)        \
        out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
@@ -254,7 +254,7 @@ static int sprom_do_read(struct ssb_bus *bus, u16 *sprom)
        int i;
 
        for (i = 0; i < bus->sprom_size; i++)
-               sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2));
+               sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2));
 
        return 0;
 }
@@ -285,7 +285,7 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
                        ssb_printk("75%%");
                else if (i % 2)
                        ssb_printk(".");
-               writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2));
+               writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
                mmiowb();
                msleep(20);
        }
@@ -621,6 +621,14 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
        int err = -ENOMEM;
        u16 *buf;
 
+       if (!ssb_is_sprom_available(bus)) {
+               ssb_printk(KERN_ERR PFX "No SPROM available!\n");
+               return -ENODEV;
+       }
+
+       bus->sprom_offset = (bus->chipco.dev->id.revision < 31) ?
+               SSB_SPROM_BASE1 : SSB_SPROM_BASE31;
+
        buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
        if (!buf)
                goto out;
index f2f920fef10df9f2d0f5845fcf7ff70875c12350..007bc3a03486b621034134f33a1c3029cb8e0b29 100644 (file)
@@ -176,3 +176,17 @@ const struct ssb_sprom *ssb_get_fallback_sprom(void)
 {
        return fallback_sprom;
 }
+
+/* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */
+bool ssb_is_sprom_available(struct ssb_bus *bus)
+{
+       /* status register only exists on chipcomon rev >= 11 and we need check
+          for >= 31 only */
+       /* this routine differs from specs as we do not access SPROM directly
+          on PCMCIA */
+       if (bus->bustype == SSB_BUSTYPE_PCI &&
+           bus->chipco.dev->id.revision >= 31)
+               return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM;
+
+       return true;
+}
index 2ea3edeee7aae9143db54ed1d12c030d8cfca13b..f8750f9a65b8f26fe268d174758a03200fcc1080 100644 (file)
@@ -709,6 +709,9 @@ enum nl80211_commands {
  *     NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE,
  *     NL80211_CMD_DISASSOCIATE.
  *
+ * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations
+ *     connected to this BSS.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -864,6 +867,8 @@ enum nl80211_attrs {
 
        NL80211_ATTR_LOCAL_STATE_CHANGE,
 
+       NL80211_ATTR_AP_ISOLATE,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
index 24f9885473610d66c01d0a8e0bc8d056bca3ba12..a2608bff9c78a3a3c69544dbb6c187572535e902 100644 (file)
@@ -305,6 +305,7 @@ struct ssb_bus {
        /* ID information about the Chip. */
        u16 chip_id;
        u16 chip_rev;
+       u16 sprom_offset;
        u16 sprom_size;         /* number of words in sprom */
        u8 chip_package;
 
@@ -394,6 +395,9 @@ extern int ssb_bus_sdiobus_register(struct ssb_bus *bus,
 
 extern void ssb_bus_unregister(struct ssb_bus *bus);
 
+/* Does the device have an SPROM? */
+extern bool ssb_is_sprom_available(struct ssb_bus *bus);
+
 /* Set a fallback SPROM.
  * See kdoc at the function definition for complete documentation. */
 extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
index 4e27acf0a92f91f3f3052f96dcdfa4d142ca369e..2cdf249b4e5f0627980e4140bf96170cb8546ad0 100644 (file)
@@ -53,6 +53,7 @@
 #define  SSB_CHIPCO_CAP_64BIT          0x08000000      /* 64-bit Backplane */
 #define  SSB_CHIPCO_CAP_PMU            0x10000000      /* PMU available (rev >= 20) */
 #define  SSB_CHIPCO_CAP_ECI            0x20000000      /* ECI available (rev >= 20) */
+#define  SSB_CHIPCO_CAP_SPROM          0x40000000      /* SPROM present */
 #define SSB_CHIPCO_CORECTL             0x0008
 #define  SSB_CHIPCO_CORECTL_UARTCLK0   0x00000001      /* Drive UART with internal clock */
 #define         SSB_CHIPCO_CORECTL_SE          0x00000002      /* sync clk out enable (corerev >= 3) */
 
 
 /** Chip specific Chip-Status register contents. */
+#define SSB_CHIPCO_CHST_4322_SPROM_EXISTS      0x00000040 /* SPROM present */
 #define SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL     0x00000003
 #define SSB_CHIPCO_CHST_4325_DEFCIS_SEL                0 /* OTP is powered up, use def. CIS, no SPROM */
 #define SSB_CHIPCO_CHST_4325_SPROM_SEL         1 /* OTP is powered up, SPROM is present */
 #define SSB_CHIPCO_CHST_4325_RCAL_VALUE_SHIFT  4
 #define SSB_CHIPCO_CHST_4325_PMUTOP_2B                 0x00000200 /* 1 for 2b, 0 for to 2a */
 
+/** Macros to determine SPROM presence based on Chip-Status register. */
+#define SSB_CHIPCO_CHST_4312_SPROM_PRESENT(status) \
+       ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+               SSB_CHIPCO_CHST_4325_OTP_SEL)
+#define SSB_CHIPCO_CHST_4322_SPROM_PRESENT(status) \
+       (status & SSB_CHIPCO_CHST_4322_SPROM_EXISTS)
+#define SSB_CHIPCO_CHST_4325_SPROM_PRESENT(status) \
+       (((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+               SSB_CHIPCO_CHST_4325_DEFCIS_SEL) && \
+        ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+               SSB_CHIPCO_CHST_4325_OTP_SEL))
+
 
 
 /** Clockcontrol masks and values **/
@@ -564,6 +578,7 @@ struct ssb_chipcommon_pmu {
 struct ssb_chipcommon {
        struct ssb_device *dev;
        u32 capabilities;
+       u32 status;
        /* Fast Powerup Delay constant */
        u16 fast_pwrup_delay;
        struct ssb_chipcommon_pmu pmu;
index 9ae9082eaeb46eb2f9d9573a2706d339ab8c06ab..a6d5225b9275e73b2d4beaf2c0017df325bb054b 100644 (file)
 #define SSB_SPROMSIZE_WORDS_R4         220
 #define SSB_SPROMSIZE_BYTES_R123       (SSB_SPROMSIZE_WORDS_R123 * sizeof(u16))
 #define SSB_SPROMSIZE_BYTES_R4         (SSB_SPROMSIZE_WORDS_R4 * sizeof(u16))
-#define SSB_SPROM_BASE                 0x1000
-#define SSB_SPROM_REVISION             0x107E
+#define SSB_SPROM_BASE1                        0x1000
+#define SSB_SPROM_BASE31               0x0800
+#define SSB_SPROM_REVISION             0x007E
 #define  SSB_SPROM_REVISION_REV                0x00FF  /* SPROM Revision number */
 #define  SSB_SPROM_REVISION_CRC                0xFF00  /* SPROM CRC8 value */
 #define  SSB_SPROM_REVISION_CRC_SHIFT  8
 
 /* SPROM Revision 1 */
-#define SSB_SPROM1_SPID                        0x1004  /* Subsystem Product ID for PCI */
-#define SSB_SPROM1_SVID                        0x1006  /* Subsystem Vendor ID for PCI */
-#define SSB_SPROM1_PID                 0x1008  /* Product ID for PCI */
-#define SSB_SPROM1_IL0MAC              0x1048  /* 6 bytes MAC address for 802.11b/g */
-#define SSB_SPROM1_ET0MAC              0x104E  /* 6 bytes MAC address for Ethernet */
-#define SSB_SPROM1_ET1MAC              0x1054  /* 6 bytes MAC address for 802.11a */
-#define SSB_SPROM1_ETHPHY              0x105A  /* Ethernet PHY settings */
+#define SSB_SPROM1_SPID                        0x0004  /* Subsystem Product ID for PCI */
+#define SSB_SPROM1_SVID                        0x0006  /* Subsystem Vendor ID for PCI */
+#define SSB_SPROM1_PID                 0x0008  /* Product ID for PCI */
+#define SSB_SPROM1_IL0MAC              0x0048  /* 6 bytes MAC address for 802.11b/g */
+#define SSB_SPROM1_ET0MAC              0x004E  /* 6 bytes MAC address for Ethernet */
+#define SSB_SPROM1_ET1MAC              0x0054  /* 6 bytes MAC address for 802.11a */
+#define SSB_SPROM1_ETHPHY              0x005A  /* Ethernet PHY settings */
 #define  SSB_SPROM1_ETHPHY_ET0A                0x001F  /* MII Address for enet0 */
 #define  SSB_SPROM1_ETHPHY_ET1A                0x03E0  /* MII Address for enet1 */
 #define  SSB_SPROM1_ETHPHY_ET1A_SHIFT  5
 #define  SSB_SPROM1_ETHPHY_ET0M                (1<<14) /* MDIO for enet0 */
 #define  SSB_SPROM1_ETHPHY_ET1M                (1<<15) /* MDIO for enet1 */
-#define SSB_SPROM1_BINF                        0x105C  /* Board info */
+#define SSB_SPROM1_BINF                        0x005C  /* Board info */
 #define  SSB_SPROM1_BINF_BREV          0x00FF  /* Board Revision */
 #define  SSB_SPROM1_BINF_CCODE         0x0F00  /* Country Code */
 #define  SSB_SPROM1_BINF_CCODE_SHIFT   8
 #define  SSB_SPROM1_BINF_ANTBG_SHIFT   12
 #define  SSB_SPROM1_BINF_ANTA          0xC000  /* Available A-PHY antennas */
 #define  SSB_SPROM1_BINF_ANTA_SHIFT    14
-#define SSB_SPROM1_PA0B0               0x105E
-#define SSB_SPROM1_PA0B1               0x1060
-#define SSB_SPROM1_PA0B2               0x1062
-#define SSB_SPROM1_GPIOA               0x1064  /* General Purpose IO pins 0 and 1 */
+#define SSB_SPROM1_PA0B0               0x005E
+#define SSB_SPROM1_PA0B1               0x0060
+#define SSB_SPROM1_PA0B2               0x0062
+#define SSB_SPROM1_GPIOA               0x0064  /* General Purpose IO pins 0 and 1 */
 #define  SSB_SPROM1_GPIOA_P0           0x00FF  /* Pin 0 */
 #define  SSB_SPROM1_GPIOA_P1           0xFF00  /* Pin 1 */
 #define  SSB_SPROM1_GPIOA_P1_SHIFT     8
-#define SSB_SPROM1_GPIOB               0x1066  /* General Purpuse IO pins 2 and 3 */
+#define SSB_SPROM1_GPIOB               0x0066  /* General Purpuse IO pins 2 and 3 */
 #define  SSB_SPROM1_GPIOB_P2           0x00FF  /* Pin 2 */
 #define  SSB_SPROM1_GPIOB_P3           0xFF00  /* Pin 3 */
 #define  SSB_SPROM1_GPIOB_P3_SHIFT     8
-#define SSB_SPROM1_MAXPWR              0x1068  /* Power Amplifier Max Power */
+#define SSB_SPROM1_MAXPWR              0x0068  /* Power Amplifier Max Power */
 #define  SSB_SPROM1_MAXPWR_BG          0x00FF  /* B-PHY and G-PHY (in dBm Q5.2) */
 #define  SSB_SPROM1_MAXPWR_A           0xFF00  /* A-PHY (in dBm Q5.2) */
 #define  SSB_SPROM1_MAXPWR_A_SHIFT     8
-#define SSB_SPROM1_PA1B0               0x106A
-#define SSB_SPROM1_PA1B1               0x106C
-#define SSB_SPROM1_PA1B2               0x106E
-#define SSB_SPROM1_ITSSI               0x1070  /* Idle TSSI Target */
+#define SSB_SPROM1_PA1B0               0x006A
+#define SSB_SPROM1_PA1B1               0x006C
+#define SSB_SPROM1_PA1B2               0x006E
+#define SSB_SPROM1_ITSSI               0x0070  /* Idle TSSI Target */
 #define  SSB_SPROM1_ITSSI_BG           0x00FF  /* B-PHY and G-PHY*/
 #define  SSB_SPROM1_ITSSI_A            0xFF00  /* A-PHY */
 #define  SSB_SPROM1_ITSSI_A_SHIFT      8
-#define SSB_SPROM1_BFLLO               0x1072  /* Boardflags (low 16 bits) */
-#define SSB_SPROM1_AGAIN               0x1074  /* Antenna Gain (in dBm Q5.2) */
+#define SSB_SPROM1_BFLLO               0x0072  /* Boardflags (low 16 bits) */
+#define SSB_SPROM1_AGAIN               0x0074  /* Antenna Gain (in dBm Q5.2) */
 #define  SSB_SPROM1_AGAIN_BG           0x00FF  /* B-PHY and G-PHY */
 #define  SSB_SPROM1_AGAIN_BG_SHIFT     0
 #define  SSB_SPROM1_AGAIN_A            0xFF00  /* A-PHY */
 #define  SSB_SPROM1_AGAIN_A_SHIFT      8
 
 /* SPROM Revision 2 (inherits from rev 1) */
-#define SSB_SPROM2_BFLHI               0x1038  /* Boardflags (high 16 bits) */
-#define SSB_SPROM2_MAXP_A              0x103A  /* A-PHY Max Power */
+#define SSB_SPROM2_BFLHI               0x0038  /* Boardflags (high 16 bits) */
+#define SSB_SPROM2_MAXP_A              0x003A  /* A-PHY Max Power */
 #define  SSB_SPROM2_MAXP_A_HI          0x00FF  /* Max Power High */
 #define  SSB_SPROM2_MAXP_A_LO          0xFF00  /* Max Power Low */
 #define  SSB_SPROM2_MAXP_A_LO_SHIFT    8
-#define SSB_SPROM2_PA1LOB0             0x103C  /* A-PHY PowerAmplifier Low Settings */
-#define SSB_SPROM2_PA1LOB1             0x103E  /* A-PHY PowerAmplifier Low Settings */
-#define SSB_SPROM2_PA1LOB2             0x1040  /* A-PHY PowerAmplifier Low Settings */
-#define SSB_SPROM2_PA1HIB0             0x1042  /* A-PHY PowerAmplifier High Settings */
-#define SSB_SPROM2_PA1HIB1             0x1044  /* A-PHY PowerAmplifier High Settings */
-#define SSB_SPROM2_PA1HIB2             0x1046  /* A-PHY PowerAmplifier High Settings */
-#define SSB_SPROM2_OPO                 0x1078  /* OFDM Power Offset from CCK Level */
+#define SSB_SPROM2_PA1LOB0             0x003C  /* A-PHY PowerAmplifier Low Settings */
+#define SSB_SPROM2_PA1LOB1             0x003E  /* A-PHY PowerAmplifier Low Settings */
+#define SSB_SPROM2_PA1LOB2             0x0040  /* A-PHY PowerAmplifier Low Settings */
+#define SSB_SPROM2_PA1HIB0             0x0042  /* A-PHY PowerAmplifier High Settings */
+#define SSB_SPROM2_PA1HIB1             0x0044  /* A-PHY PowerAmplifier High Settings */
+#define SSB_SPROM2_PA1HIB2             0x0046  /* A-PHY PowerAmplifier High Settings */
+#define SSB_SPROM2_OPO                 0x0078  /* OFDM Power Offset from CCK Level */
 #define  SSB_SPROM2_OPO_VALUE          0x00FF
 #define  SSB_SPROM2_OPO_UNUSED         0xFF00
-#define SSB_SPROM2_CCODE               0x107C  /* Two char Country Code */
+#define SSB_SPROM2_CCODE               0x007C  /* Two char Country Code */
 
 /* SPROM Revision 3 (inherits most data from rev 2) */
-#define SSB_SPROM3_IL0MAC              0x104A  /* 6 bytes MAC address for 802.11b/g */
-#define SSB_SPROM3_OFDMAPO             0x102C  /* A-PHY OFDM Mid Power Offset (4 bytes, BigEndian) */
-#define SSB_SPROM3_OFDMALPO            0x1030  /* A-PHY OFDM Low Power Offset (4 bytes, BigEndian) */
-#define SSB_SPROM3_OFDMAHPO            0x1034  /* A-PHY OFDM High Power Offset (4 bytes, BigEndian) */
-#define SSB_SPROM3_GPIOLDC             0x1042  /* GPIO LED Powersave Duty Cycle (4 bytes, BigEndian) */
+#define SSB_SPROM3_OFDMAPO             0x002C  /* A-PHY OFDM Mid Power Offset (4 bytes, BigEndian) */
+#define SSB_SPROM3_OFDMALPO            0x0030  /* A-PHY OFDM Low Power Offset (4 bytes, BigEndian) */
+#define SSB_SPROM3_OFDMAHPO            0x0034  /* A-PHY OFDM High Power Offset (4 bytes, BigEndian) */
+#define SSB_SPROM3_GPIOLDC             0x0042  /* GPIO LED Powersave Duty Cycle (4 bytes, BigEndian) */
 #define  SSB_SPROM3_GPIOLDC_OFF                0x0000FF00      /* Off Count */
 #define  SSB_SPROM3_GPIOLDC_OFF_SHIFT  8
 #define  SSB_SPROM3_GPIOLDC_ON         0x00FF0000      /* On Count */
 #define  SSB_SPROM3_GPIOLDC_ON_SHIFT   16
-#define SSB_SPROM3_CCKPO               0x1078  /* CCK Power Offset */
+#define SSB_SPROM3_IL0MAC              0x004A  /* 6 bytes MAC address for 802.11b/g */
+#define SSB_SPROM3_CCKPO               0x0078  /* CCK Power Offset */
 #define  SSB_SPROM3_CCKPO_1M           0x000F  /* 1M Rate PO */
 #define  SSB_SPROM3_CCKPO_2M           0x00F0  /* 2M Rate PO */
 #define  SSB_SPROM3_CCKPO_2M_SHIFT     4
 #define  SSB_SPROM3_OFDMGPO            0x107A  /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */
 
 /* SPROM Revision 4 */
-#define SSB_SPROM4_IL0MAC              0x104C  /* 6 byte MAC address for a/b/g/n */
-#define SSB_SPROM4_ETHPHY              0x105A  /* Ethernet PHY settings ?? */
+#define SSB_SPROM4_BFLLO               0x0044  /* Boardflags (low 16 bits) */
+#define SSB_SPROM4_BFLHI               0x0046  /* Board Flags Hi */
+#define SSB_SPROM4_IL0MAC              0x004C  /* 6 byte MAC address for a/b/g/n */
+#define SSB_SPROM4_CCODE               0x0052  /* Country Code (2 bytes) */
+#define SSB_SPROM4_GPIOA               0x0056  /* Gen. Purpose IO # 0 and 1 */
+#define  SSB_SPROM4_GPIOA_P0           0x00FF  /* Pin 0 */
+#define  SSB_SPROM4_GPIOA_P1           0xFF00  /* Pin 1 */
+#define  SSB_SPROM4_GPIOA_P1_SHIFT     8
+#define SSB_SPROM4_GPIOB               0x0058  /* Gen. Purpose IO # 2 and 3 */
+#define  SSB_SPROM4_GPIOB_P2           0x00FF  /* Pin 2 */
+#define  SSB_SPROM4_GPIOB_P3           0xFF00  /* Pin 3 */
+#define  SSB_SPROM4_GPIOB_P3_SHIFT     8
+#define SSB_SPROM4_ETHPHY              0x005A  /* Ethernet PHY settings ?? */
 #define  SSB_SPROM4_ETHPHY_ET0A                0x001F  /* MII Address for enet0 */
 #define  SSB_SPROM4_ETHPHY_ET1A                0x03E0  /* MII Address for enet1 */
 #define  SSB_SPROM4_ETHPHY_ET1A_SHIFT  5
 #define  SSB_SPROM4_ETHPHY_ET0M                (1<<14) /* MDIO for enet0 */
 #define  SSB_SPROM4_ETHPHY_ET1M                (1<<15) /* MDIO for enet1 */
-#define SSB_SPROM4_CCODE               0x1052  /* Country Code (2 bytes) */
-#define SSB_SPROM4_ANTAVAIL            0x105D  /* Antenna available bitfields */
-#define SSB_SPROM4_ANTAVAIL_A          0x00FF  /* A-PHY bitfield */
-#define SSB_SPROM4_ANTAVAIL_A_SHIFT    0
-#define SSB_SPROM4_ANTAVAIL_BG         0xFF00  /* B-PHY and G-PHY bitfield */
-#define SSB_SPROM4_ANTAVAIL_BG_SHIFT   8
-#define SSB_SPROM4_BFLLO               0x1044  /* Boardflags (low 16 bits) */
-#define SSB_SPROM4_AGAIN01             0x105E  /* Antenna Gain (in dBm Q5.2) */
+#define SSB_SPROM4_ANTAVAIL            0x005D  /* Antenna available bitfields */
+#define  SSB_SPROM4_ANTAVAIL_A         0x00FF  /* A-PHY bitfield */
+#define  SSB_SPROM4_ANTAVAIL_A_SHIFT   0
+#define  SSB_SPROM4_ANTAVAIL_BG                0xFF00  /* B-PHY and G-PHY bitfield */
+#define  SSB_SPROM4_ANTAVAIL_BG_SHIFT  8
+#define SSB_SPROM4_AGAIN01             0x005E  /* Antenna Gain (in dBm Q5.2) */
 #define  SSB_SPROM4_AGAIN0             0x00FF  /* Antenna 0 */
 #define  SSB_SPROM4_AGAIN0_SHIFT       0
 #define  SSB_SPROM4_AGAIN1             0xFF00  /* Antenna 1 */
 #define  SSB_SPROM4_AGAIN1_SHIFT       8
-#define SSB_SPROM4_AGAIN23             0x1060
+#define SSB_SPROM4_AGAIN23             0x0060
 #define  SSB_SPROM4_AGAIN2             0x00FF  /* Antenna 2 */
 #define  SSB_SPROM4_AGAIN2_SHIFT       0
 #define  SSB_SPROM4_AGAIN3             0xFF00  /* Antenna 3 */
 #define  SSB_SPROM4_AGAIN3_SHIFT       8
-#define SSB_SPROM4_BFLHI               0x1046  /* Board Flags Hi */
-#define SSB_SPROM4_MAXP_BG             0x1080  /* Max Power BG in path 1 */
+#define SSB_SPROM4_MAXP_BG             0x0080  /* Max Power BG in path 1 */
 #define  SSB_SPROM4_MAXP_BG_MASK       0x00FF  /* Mask for Max Power BG */
 #define  SSB_SPROM4_ITSSI_BG           0xFF00  /* Mask for path 1 itssi_bg */
 #define  SSB_SPROM4_ITSSI_BG_SHIFT     8
-#define SSB_SPROM4_MAXP_A              0x108A  /* Max Power A in path 1 */
+#define SSB_SPROM4_MAXP_A              0x008A  /* Max Power A in path 1 */
 #define  SSB_SPROM4_MAXP_A_MASK                0x00FF  /* Mask for Max Power A */
 #define  SSB_SPROM4_ITSSI_A            0xFF00  /* Mask for path 1 itssi_a */
 #define  SSB_SPROM4_ITSSI_A_SHIFT      8
-#define SSB_SPROM4_GPIOA               0x1056  /* Gen. Purpose IO # 0 and 1 */
-#define  SSB_SPROM4_GPIOA_P0           0x00FF  /* Pin 0 */
-#define  SSB_SPROM4_GPIOA_P1           0xFF00  /* Pin 1 */
-#define  SSB_SPROM4_GPIOA_P1_SHIFT     8
-#define SSB_SPROM4_GPIOB               0x1058  /* Gen. Purpose IO # 2 and 3 */
-#define  SSB_SPROM4_GPIOB_P2           0x00FF  /* Pin 2 */
-#define  SSB_SPROM4_GPIOB_P3           0xFF00  /* Pin 3 */
-#define  SSB_SPROM4_GPIOB_P3_SHIFT     8
-#define SSB_SPROM4_PA0B0               0x1082  /* The paXbY locations are */
-#define SSB_SPROM4_PA0B1               0x1084  /*   only guesses */
-#define SSB_SPROM4_PA0B2               0x1086
-#define SSB_SPROM4_PA1B0               0x108E
-#define SSB_SPROM4_PA1B1               0x1090
-#define SSB_SPROM4_PA1B2               0x1092
+#define SSB_SPROM4_PA0B0               0x0082  /* The paXbY locations are */
+#define SSB_SPROM4_PA0B1               0x0084  /*   only guesses */
+#define SSB_SPROM4_PA0B2               0x0086
+#define SSB_SPROM4_PA1B0               0x008E
+#define SSB_SPROM4_PA1B1               0x0090
+#define SSB_SPROM4_PA1B2               0x0092
 
 /* SPROM Revision 5 (inherits most data from rev 4) */
-#define SSB_SPROM5_BFLLO               0x104A  /* Boardflags (low 16 bits) */
-#define SSB_SPROM5_BFLHI               0x104C  /* Board Flags Hi */
-#define SSB_SPROM5_IL0MAC              0x1052  /* 6 byte MAC address for a/b/g/n */
-#define SSB_SPROM5_CCODE               0x1044  /* Country Code (2 bytes) */
-#define SSB_SPROM5_GPIOA               0x1076  /* Gen. Purpose IO # 0 and 1 */
+#define SSB_SPROM5_CCODE               0x0044  /* Country Code (2 bytes) */
+#define SSB_SPROM5_BFLLO               0x004A  /* Boardflags (low 16 bits) */
+#define SSB_SPROM5_BFLHI               0x004C  /* Board Flags Hi */
+#define SSB_SPROM5_IL0MAC              0x0052  /* 6 byte MAC address for a/b/g/n */
+#define SSB_SPROM5_GPIOA               0x0076  /* Gen. Purpose IO # 0 and 1 */
 #define  SSB_SPROM5_GPIOA_P0           0x00FF  /* Pin 0 */
 #define  SSB_SPROM5_GPIOA_P1           0xFF00  /* Pin 1 */
 #define  SSB_SPROM5_GPIOA_P1_SHIFT     8
-#define SSB_SPROM5_GPIOB               0x1078  /* Gen. Purpose IO # 2 and 3 */
+#define SSB_SPROM5_GPIOB               0x0078  /* Gen. Purpose IO # 2 and 3 */
 #define  SSB_SPROM5_GPIOB_P2           0x00FF  /* Pin 2 */
 #define  SSB_SPROM5_GPIOB_P3           0xFF00  /* Pin 3 */
 #define  SSB_SPROM5_GPIOB_P3_SHIFT     8
 
 /* SPROM Revision 8 */
-#define SSB_SPROM8_BOARDREV            0x1082  /* Board revision */
-#define SSB_SPROM8_BFLLO               0x1084  /* Board flags (bits 0-15) */
-#define SSB_SPROM8_BFLHI               0x1086  /* Board flags (bits 16-31) */
-#define SSB_SPROM8_BFL2LO              0x1088  /* Board flags (bits 32-47) */
-#define SSB_SPROM8_BFL2HI              0x108A  /* Board flags (bits 48-63) */
-#define SSB_SPROM8_IL0MAC              0x108C  /* 6 byte MAC address */
-#define SSB_SPROM8_CCODE               0x1092  /* 2 byte country code */
-#define SSB_SPROM8_ANTAVAIL            0x109C  /* Antenna available bitfields*/
-#define SSB_SPROM8_ANTAVAIL_A          0xFF00  /* A-PHY bitfield */
-#define SSB_SPROM8_ANTAVAIL_A_SHIFT    8
-#define SSB_SPROM8_ANTAVAIL_BG         0x00FF  /* B-PHY and G-PHY bitfield */
-#define SSB_SPROM8_ANTAVAIL_BG_SHIFT   0
-#define SSB_SPROM8_AGAIN01             0x109E  /* Antenna Gain (in dBm Q5.2) */
+#define SSB_SPROM8_BOARDREV            0x0082  /* Board revision */
+#define SSB_SPROM8_BFLLO               0x0084  /* Board flags (bits 0-15) */
+#define SSB_SPROM8_BFLHI               0x0086  /* Board flags (bits 16-31) */
+#define SSB_SPROM8_BFL2LO              0x0088  /* Board flags (bits 32-47) */
+#define SSB_SPROM8_BFL2HI              0x008A  /* Board flags (bits 48-63) */
+#define SSB_SPROM8_IL0MAC              0x008C  /* 6 byte MAC address */
+#define SSB_SPROM8_CCODE               0x0092  /* 2 byte country code */
+#define SSB_SPROM8_GPIOA               0x0096  /*Gen. Purpose IO # 0 and 1 */
+#define  SSB_SPROM8_GPIOA_P0           0x00FF  /* Pin 0 */
+#define  SSB_SPROM8_GPIOA_P1           0xFF00  /* Pin 1 */
+#define  SSB_SPROM8_GPIOA_P1_SHIFT     8
+#define SSB_SPROM8_GPIOB               0x0098  /* Gen. Purpose IO # 2 and 3 */
+#define  SSB_SPROM8_GPIOB_P2           0x00FF  /* Pin 2 */
+#define  SSB_SPROM8_GPIOB_P3           0xFF00  /* Pin 3 */
+#define  SSB_SPROM8_GPIOB_P3_SHIFT     8
+#define SSB_SPROM8_ANTAVAIL            0x009C  /* Antenna available bitfields*/
+#define  SSB_SPROM8_ANTAVAIL_A         0xFF00  /* A-PHY bitfield */
+#define  SSB_SPROM8_ANTAVAIL_A_SHIFT   8
+#define  SSB_SPROM8_ANTAVAIL_BG                0x00FF  /* B-PHY and G-PHY bitfield */
+#define  SSB_SPROM8_ANTAVAIL_BG_SHIFT  0
+#define SSB_SPROM8_AGAIN01             0x009E  /* Antenna Gain (in dBm Q5.2) */
 #define  SSB_SPROM8_AGAIN0             0x00FF  /* Antenna 0 */
 #define  SSB_SPROM8_AGAIN0_SHIFT       0
 #define  SSB_SPROM8_AGAIN1             0xFF00  /* Antenna 1 */
 #define  SSB_SPROM8_AGAIN1_SHIFT       8
-#define SSB_SPROM8_AGAIN23             0x10A0
+#define SSB_SPROM8_AGAIN23             0x00A0
 #define  SSB_SPROM8_AGAIN2             0x00FF  /* Antenna 2 */
 #define  SSB_SPROM8_AGAIN2_SHIFT       0
 #define  SSB_SPROM8_AGAIN3             0xFF00  /* Antenna 3 */
 #define  SSB_SPROM8_AGAIN3_SHIFT       8
-#define SSB_SPROM8_GPIOA               0x1096  /*Gen. Purpose IO # 0 and 1 */
-#define  SSB_SPROM8_GPIOA_P0           0x00FF  /* Pin 0 */
-#define  SSB_SPROM8_GPIOA_P1           0xFF00  /* Pin 1 */
-#define  SSB_SPROM8_GPIOA_P1_SHIFT     8
-#define SSB_SPROM8_GPIOB               0x1098  /* Gen. Purpose IO # 2 and 3 */
-#define  SSB_SPROM8_GPIOB_P2           0x00FF  /* Pin 2 */
-#define  SSB_SPROM8_GPIOB_P3           0xFF00  /* Pin 3 */
-#define  SSB_SPROM8_GPIOB_P3_SHIFT     8
-#define SSB_SPROM8_RSSIPARM2G          0x10A4  /* RSSI params for 2GHz */
+#define SSB_SPROM8_RSSIPARM2G          0x00A4  /* RSSI params for 2GHz */
 #define  SSB_SPROM8_RSSISMF2G          0x000F
 #define  SSB_SPROM8_RSSISMC2G          0x00F0
 #define  SSB_SPROM8_RSSISMC2G_SHIFT    4
 #define  SSB_SPROM8_RSSISAV2G_SHIFT    8
 #define  SSB_SPROM8_BXA2G              0x1800
 #define  SSB_SPROM8_BXA2G_SHIFT                11
-#define SSB_SPROM8_RSSIPARM5G          0x10A6  /* RSSI params for 5GHz */
+#define SSB_SPROM8_RSSIPARM5G          0x00A6  /* RSSI params for 5GHz */
 #define  SSB_SPROM8_RSSISMF5G          0x000F
 #define  SSB_SPROM8_RSSISMC5G          0x00F0
 #define  SSB_SPROM8_RSSISMC5G_SHIFT    4
 #define  SSB_SPROM8_RSSISAV5G_SHIFT    8
 #define  SSB_SPROM8_BXA5G              0x1800
 #define  SSB_SPROM8_BXA5G_SHIFT                11
-#define SSB_SPROM8_TRI25G              0x10A8  /* TX isolation 2.4&5.3GHz */
+#define SSB_SPROM8_TRI25G              0x00A8  /* TX isolation 2.4&5.3GHz */
 #define  SSB_SPROM8_TRI2G              0x00FF  /* TX isolation 2.4GHz */
 #define  SSB_SPROM8_TRI5G              0xFF00  /* TX isolation 5.3GHz */
 #define  SSB_SPROM8_TRI5G_SHIFT                8
-#define SSB_SPROM8_TRI5GHL             0x10AA  /* TX isolation 5.2/5.8GHz */
+#define SSB_SPROM8_TRI5GHL             0x00AA  /* TX isolation 5.2/5.8GHz */
 #define  SSB_SPROM8_TRI5GL             0x00FF  /* TX isolation 5.2GHz */
 #define  SSB_SPROM8_TRI5GH             0xFF00  /* TX isolation 5.8GHz */
 #define  SSB_SPROM8_TRI5GH_SHIFT       8
-#define SSB_SPROM8_RXPO                        0x10AC  /* RX power offsets */
+#define SSB_SPROM8_RXPO                        0x00AC  /* RX power offsets */
 #define  SSB_SPROM8_RXPO2G             0x00FF  /* 2GHz RX power offset */
 #define  SSB_SPROM8_RXPO5G             0xFF00  /* 5GHz RX power offset */
 #define  SSB_SPROM8_RXPO5G_SHIFT       8
-#define SSB_SPROM8_MAXP_BG             0x10C0  /* Max Power 2GHz in path 1 */
+#define SSB_SPROM8_MAXP_BG             0x00C0  /* Max Power 2GHz in path 1 */
 #define  SSB_SPROM8_MAXP_BG_MASK       0x00FF  /* Mask for Max Power 2GHz */
 #define  SSB_SPROM8_ITSSI_BG           0xFF00  /* Mask for path 1 itssi_bg */
 #define  SSB_SPROM8_ITSSI_BG_SHIFT     8
-#define SSB_SPROM8_PA0B0               0x10C2  /* 2GHz power amp settings */
-#define SSB_SPROM8_PA0B1               0x10C4
-#define SSB_SPROM8_PA0B2               0x10C6
-#define SSB_SPROM8_MAXP_A              0x10C8  /* Max Power 5.3GHz */
+#define SSB_SPROM8_PA0B0               0x00C2  /* 2GHz power amp settings */
+#define SSB_SPROM8_PA0B1               0x00C4
+#define SSB_SPROM8_PA0B2               0x00C6
+#define SSB_SPROM8_MAXP_A              0x00C8  /* Max Power 5.3GHz */
 #define  SSB_SPROM8_MAXP_A_MASK                0x00FF  /* Mask for Max Power 5.3GHz */
 #define  SSB_SPROM8_ITSSI_A            0xFF00  /* Mask for path 1 itssi_a */
 #define  SSB_SPROM8_ITSSI_A_SHIFT      8
-#define SSB_SPROM8_MAXP_AHL            0x10CA  /* Max Power 5.2/5.8GHz */
+#define SSB_SPROM8_MAXP_AHL            0x00CA  /* Max Power 5.2/5.8GHz */
 #define  SSB_SPROM8_MAXP_AH_MASK       0x00FF  /* Mask for Max Power 5.8GHz */
 #define  SSB_SPROM8_MAXP_AL_MASK       0xFF00  /* Mask for Max Power 5.2GHz */
 #define  SSB_SPROM8_MAXP_AL_SHIFT      8
-#define SSB_SPROM8_PA1B0               0x10CC  /* 5.3GHz power amp settings */
-#define SSB_SPROM8_PA1B1               0x10CE
-#define SSB_SPROM8_PA1B2               0x10D0
-#define SSB_SPROM8_PA1LOB0             0x10D2  /* 5.2GHz power amp settings */
-#define SSB_SPROM8_PA1LOB1             0x10D4
-#define SSB_SPROM8_PA1LOB2             0x10D6
-#define SSB_SPROM8_PA1HIB0             0x10D8  /* 5.8GHz power amp settings */
-#define SSB_SPROM8_PA1HIB1             0x10DA
-#define SSB_SPROM8_PA1HIB2             0x10DC
-#define SSB_SPROM8_CCK2GPO             0x1140  /* CCK power offset */
-#define SSB_SPROM8_OFDM2GPO            0x1142  /* 2.4GHz OFDM power offset */
-#define SSB_SPROM8_OFDM5GPO            0x1146  /* 5.3GHz OFDM power offset */
-#define SSB_SPROM8_OFDM5GLPO           0x114A  /* 5.2GHz OFDM power offset */
-#define SSB_SPROM8_OFDM5GHPO           0x114E  /* 5.8GHz OFDM power offset */
+#define SSB_SPROM8_PA1B0               0x00CC  /* 5.3GHz power amp settings */
+#define SSB_SPROM8_PA1B1               0x00CE
+#define SSB_SPROM8_PA1B2               0x00D0
+#define SSB_SPROM8_PA1LOB0             0x00D2  /* 5.2GHz power amp settings */
+#define SSB_SPROM8_PA1LOB1             0x00D4
+#define SSB_SPROM8_PA1LOB2             0x00D6
+#define SSB_SPROM8_PA1HIB0             0x00D8  /* 5.8GHz power amp settings */
+#define SSB_SPROM8_PA1HIB1             0x00DA
+#define SSB_SPROM8_PA1HIB2             0x00DC
+#define SSB_SPROM8_CCK2GPO             0x0140  /* CCK power offset */
+#define SSB_SPROM8_OFDM2GPO            0x0142  /* 2.4GHz OFDM power offset */
+#define SSB_SPROM8_OFDM5GPO            0x0146  /* 5.3GHz OFDM power offset */
+#define SSB_SPROM8_OFDM5GLPO           0x014A  /* 5.2GHz OFDM power offset */
+#define SSB_SPROM8_OFDM5GHPO           0x014E  /* 5.8GHz OFDM power offset */
 
 /* Values for SSB_SPROM1_BINF_CCODE */
 enum {
index 5a4efe54cffdb0ff047a62f53bd2c5e5dfa9b5db..7d10c0182f53b8a6a40612ecfdb4322bcc018cfe 100644 (file)
@@ -511,6 +511,7 @@ struct mpath_info {
  * @basic_rates: basic rates in IEEE 802.11 format
  *     (or NULL for no change)
  * @basic_rates_len: number of basic rates
+ * @ap_isolate: do not forward packets between connected stations
  */
 struct bss_parameters {
        int use_cts_prot;
@@ -518,6 +519,7 @@ struct bss_parameters {
        int use_short_slot_time;
        u8 *basic_rates;
        u8 basic_rates_len;
+       int ap_isolate;
 };
 
 struct mesh_config {
@@ -1018,6 +1020,8 @@ struct cfg80211_pmksa {
  *     RSN IE. It allows for faster roaming between WPA2 BSSIDs.
  * @del_pmksa: Delete a cached PMKID.
  * @flush_pmksa: Flush all cached PMKIDs.
+ * @set_power_mgmt: Configure WLAN power management. A timeout value of -1
+ *     allows the driver to adjust the dynamic ps timeout value.
  * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold.
  *
  */
index 78908b516f42f25e1aeacdebf9e0874b39fc6b3a..54aa16b98b76e4ffecfb45fbce7b3bab910f8f31 100644 (file)
@@ -145,6 +145,7 @@ struct ieee80211_low_level_stats {
  * @BSS_CHANGED_BEACON_ENABLED: Beaconing should be
  *     enabled/disabled (beaconing modes)
  * @BSS_CHANGED_CQM: Connection quality monitor config changed
+ * @BSS_CHANGED_IBSS: IBSS join status changed
  */
 enum ieee80211_bss_change {
        BSS_CHANGED_ASSOC               = 1<<0,
@@ -158,6 +159,7 @@ enum ieee80211_bss_change {
        BSS_CHANGED_BEACON              = 1<<8,
        BSS_CHANGED_BEACON_ENABLED      = 1<<9,
        BSS_CHANGED_CQM                 = 1<<10,
+       BSS_CHANGED_IBSS                = 1<<11,
 };
 
 /**
@@ -167,6 +169,8 @@ enum ieee80211_bss_change {
  * to that BSS) that can change during the lifetime of the BSS.
  *
  * @assoc: association status
+ * @ibss_joined: indicates whether this station is part of an IBSS
+ *     or not
  * @aid: association ID number, valid only when @assoc is true
  * @use_cts_prot: use CTS protection
  * @use_short_preamble: use 802.11b short preamble;
@@ -194,7 +198,7 @@ enum ieee80211_bss_change {
 struct ieee80211_bss_conf {
        const u8 *bssid;
        /* association related data */
-       bool assoc;
+       bool assoc, ibss_joined;
        u16 aid;
        /* erp related data */
        bool use_cts_prot;
@@ -556,7 +560,6 @@ enum mac80211_rx_flags {
  * @signal: signal strength when receiving this frame, either in dBm, in dB or
  *     unspecified depending on the hardware capabilities flags
  *     @IEEE80211_HW_SIGNAL_*
- * @noise: noise when receiving this frame, in dBm (DEPRECATED).
  * @antenna: antenna used
  * @rate_idx: index of data rate into band's supported rates or MCS index if
  *     HT rates are use (RX_FLAG_HT)
@@ -567,7 +570,6 @@ struct ieee80211_rx_status {
        enum ieee80211_band band;
        int freq;
        int signal;
-       int noise __deprecated;
        int antenna;
        int rate_idx;
        int flag;
@@ -668,6 +670,9 @@ enum ieee80211_smps_mode {
  * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the
  *     powersave documentation below. This variable is valid only when
  *     the CONF_PS flag is set.
+ * @dynamic_ps_forced_timeout: The dynamic powersave timeout (in ms) configured
+ *     by cfg80211 (essentially, wext) If set, this value overrules the value
+ *     chosen by mac80211 based on ps qos network latency.
  *
  * @power_level: requested transmit power (in dBm)
  *
@@ -687,7 +692,7 @@ enum ieee80211_smps_mode {
  */
 struct ieee80211_conf {
        u32 flags;
-       int power_level, dynamic_ps_timeout;
+       int power_level, dynamic_ps_timeout, dynamic_ps_forced_timeout;
        int max_sleep_period;
 
        u16 listen_interval;
@@ -927,10 +932,6 @@ enum ieee80211_tkip_key_type {
  *     one milliwatt. This is the preferred method since it is standardized
  *     between different devices. @max_signal does not need to be set.
  *
- * @IEEE80211_HW_NOISE_DBM:
- *     Hardware can provide noise (radio interference) values in units dBm,
- *      decibel difference from one milliwatt.
- *
  * @IEEE80211_HW_SPECTRUM_MGMT:
  *     Hardware supports spectrum management defined in 802.11h
  *     Measurement, Channel Switch, Quieting, TPC
@@ -994,7 +995,7 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE      = 1<<4,
        IEEE80211_HW_SIGNAL_UNSPEC                      = 1<<5,
        IEEE80211_HW_SIGNAL_DBM                         = 1<<6,
-       IEEE80211_HW_NOISE_DBM                          = 1<<7,
+       /* use this hole */
        IEEE80211_HW_SPECTRUM_MGMT                      = 1<<8,
        IEEE80211_HW_AMPDU_AGGREGATION                  = 1<<9,
        IEEE80211_HW_SUPPORTS_PS                        = 1<<10,
@@ -1654,7 +1655,7 @@ struct ieee80211_ops {
                                struct ieee80211_key_conf *conf,
                                struct ieee80211_sta *sta,
                                u32 iv32, u16 *phase1key);
-       int (*hw_scan)(struct ieee80211_hw *hw,
+       int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       struct cfg80211_scan_request *req);
        void (*sw_scan_start)(struct ieee80211_hw *hw);
        void (*sw_scan_complete)(struct ieee80211_hw *hw);
index 845a6e6b9d892b21be1d6ce0839b4908ffe10f58..ae37270a063338f57d188c5189c67007372240e4 100644 (file)
@@ -97,9 +97,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                                            params->mesh_id_len,
                                            params->mesh_id);
 
-       if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
-               return 0;
-
        if (type == NL80211_IFTYPE_AP_VLAN &&
            params && params->use_4addr == 0)
                rcu_assign_pointer(sdata->u.vlan.sta, NULL);
@@ -107,7 +104,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                 params && params->use_4addr >= 0)
                sdata->u.mgd.use_4addr = params->use_4addr;
 
-       sdata->u.mntr_flags = *flags;
+       if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags)
+               sdata->u.mntr_flags = *flags;
+
        return 0;
 }
 
@@ -1115,6 +1114,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
                changed |= BSS_CHANGED_BASIC_RATES;
        }
 
+       if (params->ap_isolate >= 0) {
+               if (params->ap_isolate)
+                       sdata->flags |= IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
+               else
+                       sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
+       }
+
        ieee80211_bss_info_change_notify(sdata, changed);
 
        return 0;
@@ -1399,11 +1405,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
                return -EOPNOTSUPP;
 
        if (enabled == sdata->u.mgd.powersave &&
-           timeout == conf->dynamic_ps_timeout)
+           timeout == conf->dynamic_ps_forced_timeout)
                return 0;
 
        sdata->u.mgd.powersave = enabled;
-       conf->dynamic_ps_timeout = timeout;
+       conf->dynamic_ps_forced_timeout = timeout;
 
        /* no change, but if automatic follow powersave */
        mutex_lock(&sdata->u.mgd.mtx);
index 6bc9b07c3edad96ab20d2c366686701f5bf72be2..e763f1529ddbca6ce54c3af0dd848cd96c643f61 100644 (file)
@@ -39,6 +39,13 @@ static const struct file_operations sta_ ##name## _ops = {           \
        .open = mac80211_open_file_generic,                             \
 }
 
+#define STA_OPS_RW(name)                                               \
+static const struct file_operations sta_ ##name## _ops = {             \
+       .read = sta_##name##_read,                                      \
+       .write = sta_##name##_write,                                    \
+       .open = mac80211_open_file_generic,                             \
+}
+
 #define STA_FILE(name, field, format)                                  \
                STA_READ_##format(name, field)                          \
                STA_OPS(name)
@@ -156,7 +163,63 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
 
        return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
 }
-STA_OPS(agg_status);
+
+static ssize_t sta_agg_status_write(struct file *file, const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       char _buf[12], *buf = _buf;
+       struct sta_info *sta = file->private_data;
+       bool start, tx;
+       unsigned long tid;
+       int ret;
+
+       if (count > sizeof(_buf))
+               return -EINVAL;
+
+       if (copy_from_user(buf, userbuf, count))
+               return -EFAULT;
+
+       buf[sizeof(_buf) - 1] = '\0';
+
+       if (strncmp(buf, "tx ", 3) == 0) {
+               buf += 3;
+               tx = true;
+       } else if (strncmp(buf, "rx ", 3) == 0) {
+               buf += 3;
+               tx = false;
+       } else
+               return -EINVAL;
+
+       if (strncmp(buf, "start ", 6) == 0) {
+               buf += 6;
+               start = true;
+               if (!tx)
+                       return -EINVAL;
+       } else if (strncmp(buf, "stop ", 5) == 0) {
+               buf += 5;
+               start = false;
+       } else
+               return -EINVAL;
+
+       tid = simple_strtoul(buf, NULL, 0);
+
+       if (tid >= STA_TID_NUM)
+               return -EINVAL;
+
+       if (tx) {
+               if (start)
+                       ret = ieee80211_start_tx_ba_session(&sta->sta, tid);
+               else
+                       ret = ieee80211_stop_tx_ba_session(&sta->sta, tid,
+                                                          WLAN_BACK_RECIPIENT);
+       } else {
+               __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, 3);
+               ret = 0;
+       }
+
+       return ret ?: count;
+}
+STA_OPS_RW(agg_status);
 
 static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
                                size_t count, loff_t *ppos)
index 35e1e581e806cc4510547fd5cbec865ee1724d8a..ee8b63f92f714f1c8e6d298e3c4fcbceac1e5837 100644 (file)
@@ -152,14 +152,15 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
 }
 
 static inline int drv_hw_scan(struct ieee80211_local *local,
+                             struct ieee80211_sub_if_data *sdata,
                              struct cfg80211_scan_request *req)
 {
        int ret;
 
        might_sleep();
 
-       ret = local->ops->hw_scan(&local->hw, req);
-       trace_drv_hw_scan(local, req, ret);
+       ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
+       trace_drv_hw_scan(local, sdata, req, ret);
        return ret;
 }
 
index e209cb82ff2984f50da8dea864611636aba53b3b..ce734b58d07ab6b0ac14cbfa88b6f6bb915c6b98 100644 (file)
@@ -363,23 +363,26 @@ TRACE_EVENT(drv_update_tkip_key,
 
 TRACE_EVENT(drv_hw_scan,
        TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
                 struct cfg80211_scan_request *req, int ret),
 
-       TP_ARGS(local, req, ret),
+       TP_ARGS(local, sdata, req, ret),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
+               VIF_ENTRY
                __field(int, ret)
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
+               VIF_ASSIGN;
                __entry->ret = ret;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT " ret:%d",
-               LOCAL_PR_ARG, __entry->ret
+               LOCAL_PR_FMT VIF_PR_FMT " ret:%d",
+               LOCAL_PR_ARG,VIF_PR_ARG, __entry->ret
        )
 );
 
index e6f3b0c7a71f3bc7b1d2e7dc5751cfb7ad3904a5..b72ee6435fa35e17c85bd93daf4664e6c0713c49 100644 (file)
@@ -92,6 +92,12 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        if (memcmp(ifibss->bssid, bssid, ETH_ALEN))
                sta_info_flush(sdata->local, sdata);
 
+       /* if merging, indicate to driver that we leave the old IBSS */
+       if (sdata->vif.bss_conf.ibss_joined) {
+               sdata->vif.bss_conf.ibss_joined = false;
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS);
+       }
+
        memcpy(ifibss->bssid, bssid, ETH_ALEN);
 
        sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
@@ -171,6 +177,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        bss_change |= BSS_CHANGED_BSSID;
        bss_change |= BSS_CHANGED_BEACON;
        bss_change |= BSS_CHANGED_BEACON_ENABLED;
+       bss_change |= BSS_CHANGED_IBSS;
+       sdata->vif.bss_conf.ibss_joined = true;
        ieee80211_bss_info_change_notify(sdata, bss_change);
 
        ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates);
@@ -481,7 +489,9 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
        printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
               "IBSS networks with same SSID (merge)\n", sdata->name);
 
-       ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len);
+       ieee80211_request_internal_scan(sdata,
+                       ifibss->ssid, ifibss->ssid_len,
+                       ifibss->fixed_channel ? ifibss->channel : NULL);
 }
 
 static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
@@ -588,8 +598,9 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
                       "join\n", sdata->name);
 
-               ieee80211_request_internal_scan(sdata, ifibss->ssid,
-                                               ifibss->ssid_len);
+               ieee80211_request_internal_scan(sdata,
+                               ifibss->ssid, ifibss->ssid_len,
+                               ifibss->fixed_channel ? ifibss->channel : NULL);
        } else {
                int interval = IEEE80211_SCAN_INTERVAL;
 
@@ -897,6 +908,12 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        sdata->u.ibss.channel = params->channel;
        sdata->u.ibss.fixed_channel = params->channel_fixed;
 
+       /* fix ourselves to that channel now already */
+       if (params->channel_fixed) {
+               sdata->local->oper_channel = params->channel;
+               sdata->local->oper_channel_type = NL80211_CHAN_NO_HT;
+       }
+
        if (params->ie) {
                sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len,
                                           GFP_KERNEL);
@@ -951,7 +968,9 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
        kfree(sdata->u.ibss.ie);
        skb = sdata->u.ibss.presp;
        rcu_assign_pointer(sdata->u.ibss.presp, NULL);
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
+       sdata->vif.bss_conf.ibss_joined = false;
+       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
+                                               BSS_CHANGED_IBSS);
        synchronize_rcu();
        kfree_skb(skb);
 
index c9712f35e59639e121317aaaa09496408a90b740..cbaf4981e110918f74970de39761a6d69de7dcca 100644 (file)
@@ -1019,7 +1019,8 @@ void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata);
 /* scan/BSS handling */
 void ieee80211_scan_work(struct work_struct *work);
 int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
-                                   const u8 *ssid, u8 ssid_len);
+                                   const u8 *ssid, u8 ssid_len,
+                                   struct ieee80211_channel *chan);
 int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
                           struct cfg80211_scan_request *req);
 void ieee80211_scan_cancel(struct ieee80211_local *local);
index 011ee85bcd5782a6867457baacaee72bcdd8b9c0..bd632e1ee2c5b66f531d46c70d0fb195a8bfae81 100644 (file)
@@ -442,7 +442,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        struct ieee80211_local *local = hw_to_local(hw);
        int result;
        enum ieee80211_band band;
-       int channels, i, j, max_bitrates;
+       int channels, max_bitrates;
        bool supp_ht;
        static const u32 cipher_suites[] = {
                WLAN_CIPHER_SUITE_WEP40,
@@ -572,6 +572,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        local->hw.conf.listen_interval = local->hw.max_listen_interval;
 
+       local->hw.conf.dynamic_ps_forced_timeout = -1;
+
        result = sta_info_start(local);
        if (result < 0)
                goto fail_sta_info;
@@ -606,21 +608,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        ieee80211_led_init(local);
 
-       /* alloc internal scan request */
-       i = 0;
-       local->int_scan_req->ssids = &local->scan_ssid;
-       local->int_scan_req->n_ssids = 1;
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
-               if (!hw->wiphy->bands[band])
-                       continue;
-               for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) {
-                       local->int_scan_req->channels[i] =
-                               &hw->wiphy->bands[band]->channels[j];
-                       i++;
-               }
-       }
-       local->int_scan_req->n_channels = i;
-
        local->network_latency_notifier.notifier_call =
                ieee80211_max_network_latency;
        result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
index 425f66c7001346f7edae7933a53ace1e82c89076..358226f63b81f5fe90af933b61bfa624e2f91e9f 100644 (file)
@@ -478,6 +478,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 {
        struct ieee80211_sub_if_data *sdata, *found = NULL;
        int count = 0;
+       int timeout;
 
        if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) {
                local->ps_sdata = NULL;
@@ -511,6 +512,26 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                beaconint_us = ieee80211_tu_to_usec(
                                        found->vif.bss_conf.beacon_int);
 
+               timeout = local->hw.conf.dynamic_ps_forced_timeout;
+               if (timeout < 0) {
+                       /*
+                        * The 2 second value is there for compatibility until
+                        * the PM_QOS_NETWORK_LATENCY is configured with real
+                        * values.
+                        */
+                       if (latency == 2000000000)
+                               timeout = 100;
+                       else if (latency <= 50000)
+                               timeout = 300;
+                       else if (latency <= 100000)
+                               timeout = 100;
+                       else if (latency <= 500000)
+                               timeout = 50;
+                       else
+                               timeout = 0;
+               }
+               local->hw.conf.dynamic_ps_timeout = timeout;
+
                if (beaconint_us > latency) {
                        local->ps_sdata = NULL;
                } else {
index 72efbd87c1ebdd51a5f752d0c3a892810ed9b619..9a08f2c446c6315a6c0aac8ffde0cf290af9b16d 100644 (file)
@@ -81,8 +81,6 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local,
                len += 8;
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                len += 1;
-       if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
-               len += 1;
 
        if (len & 1) /* padding for RX_FLAGS if necessary */
                len++;
index e1a3defdf581c5a0b7bfd62fcc992b01ea40bf68..e14c44195ae9ac6c7c27d7b74f4e8d5200be320d 100644 (file)
@@ -85,7 +85,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
 {
        struct cfg80211_bss *cbss;
        struct ieee80211_bss *bss;
-       int clen;
+       int clen, srlen;
        s32 signal = 0;
 
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
@@ -114,23 +114,24 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
                bss->dtim_period = tim_ie->dtim_period;
        }
 
-       bss->supp_rates_len = 0;
+       /* replace old supported rates if we get new values */
+       srlen = 0;
        if (elems->supp_rates) {
-               clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
+               clen = IEEE80211_MAX_SUPP_RATES;
                if (clen > elems->supp_rates_len)
                        clen = elems->supp_rates_len;
-               memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates,
-                      clen);
-               bss->supp_rates_len += clen;
+               memcpy(bss->supp_rates, elems->supp_rates, clen);
+               srlen += clen;
        }
        if (elems->ext_supp_rates) {
-               clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
+               clen = IEEE80211_MAX_SUPP_RATES - srlen;
                if (clen > elems->ext_supp_rates_len)
                        clen = elems->ext_supp_rates_len;
-               memcpy(&bss->supp_rates[bss->supp_rates_len],
-                      elems->ext_supp_rates, clen);
-               bss->supp_rates_len += clen;
+               memcpy(bss->supp_rates + srlen, elems->ext_supp_rates, clen);
+               srlen += clen;
        }
+       if (srlen)
+               bss->supp_rates_len = srlen;
 
        bss->wmm_used = elems->wmm_param || elems->wmm_info;
        bss->uapsd_supported = is_uapsd_supported(elems);
@@ -411,7 +412,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 
        if (local->ops->hw_scan) {
                WARN_ON(!ieee80211_prep_hw_scan(local));
-               rc = drv_hw_scan(local, local->hw_scan_req);
+               rc = drv_hw_scan(local, sdata, local->hw_scan_req);
        } else
                rc = ieee80211_start_sw_scan(local);
 
@@ -655,7 +656,7 @@ void ieee80211_scan_work(struct work_struct *work)
        }
 
        if (local->hw_scan_req) {
-               int rc = drv_hw_scan(local, local->hw_scan_req);
+               int rc = drv_hw_scan(local, sdata, local->hw_scan_req);
                mutex_unlock(&local->scan_mtx);
                if (rc)
                        ieee80211_scan_completed(&local->hw, true);
@@ -728,10 +729,12 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
 }
 
 int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
-                                   const u8 *ssid, u8 ssid_len)
+                                   const u8 *ssid, u8 ssid_len,
+                                   struct ieee80211_channel *chan)
 {
        struct ieee80211_local *local = sdata->local;
        int ret = -EBUSY;
+       enum nl80211_band band;
 
        mutex_lock(&local->scan_mtx);
 
@@ -739,6 +742,30 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
        if (local->scan_req)
                goto unlock;
 
+       /* fill internal scan request */
+       if (!chan) {
+               int i, nchan = 0;
+
+               for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+                       if (!local->hw.wiphy->bands[band])
+                               continue;
+                       for (i = 0;
+                            i < local->hw.wiphy->bands[band]->n_channels;
+                            i++) {
+                               local->int_scan_req->channels[nchan] =
+                                   &local->hw.wiphy->bands[band]->channels[i];
+                               nchan++;
+                       }
+               }
+
+               local->int_scan_req->n_channels = nchan;
+       } else {
+               local->int_scan_req->channels[0] = chan;
+               local->int_scan_req->n_channels = 1;
+       }
+
+       local->int_scan_req->ssids = &local->scan_ssid;
+       local->int_scan_req->n_ssids = 1;
        memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
        local->int_scan_req->ssids[0].ssid_len = ssid_len;
 
index 3de7a2260d651b33cf28b1591ca864ac6b2e561a..730197591ab5135e307317d7c9d8e358dae6bceb 100644 (file)
@@ -855,8 +855,12 @@ struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw,
        struct sta_info *sta, *nxt;
 
        /* Just return a random station ... first in list ... */
-       for_each_sta_info(hw_to_local(hw), addr, sta, nxt)
+       for_each_sta_info(hw_to_local(hw), addr, sta, nxt) {
+               if (!sta->uploaded)
+                       return NULL;
                return &sta->sta;
+       }
+
        return NULL;
 }
 EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw);
@@ -864,14 +868,19 @@ EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw);
 struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
                                         const u8 *addr)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct sta_info *sta;
 
        if (!vif)
                return NULL;
 
-       sdata = vif_to_sdata(vif);
+       sta = sta_info_get_bss(vif_to_sdata(vif), addr);
+       if (!sta)
+               return NULL;
+
+       if (!sta->uploaded)
+               return NULL;
 
-       return ieee80211_find_sta_by_hw(&sdata->local->hw, addr);
+       return &sta->sta;
 }
 EXPORT_SYMBOL(ieee80211_find_sta);
 
index 11805a3a626f5635b20857a8f1fc503374208625..94613af009f32d668f70e1522e5842d78eabf414 100644 (file)
@@ -171,6 +171,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        struct net_device *prev_dev = NULL;
        struct sta_info *sta, *tmp;
        int retry_count = -1, i;
+       int rates_idx = -1;
        bool send_to_cooked;
 
        for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
@@ -178,6 +179,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                if (i >= hw->max_rates) {
                        info->status.rates[i].idx = -1;
                        info->status.rates[i].count = 0;
+               } else if (info->status.rates[i].idx >= 0) {
+                       rates_idx = i;
                }
 
                retry_count += info->status.rates[i].count;
@@ -206,6 +209,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        return;
                }
 
+               if ((local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) &&
+                   (rates_idx != -1))
+                       sta->last_tx_rate = info->status.rates[rates_idx];
+
                if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
                    (ieee80211_is_data_qos(fc))) {
                        u16 tid, ssn;
index e2aa972d584fa28556d78a8dc9801acf3042b154..f3841f43249e8c9c6985fcb3cf8c0c32f0dbc59f 100644 (file)
@@ -593,7 +593,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
        struct ieee80211_hdr *hdr = (void *)tx->skb->data;
        struct ieee80211_supported_band *sband;
        struct ieee80211_rate *rate;
-       int i, len;
+       int i;
+       u32 len;
        bool inval = false, rts = false, short_preamble = false;
        struct ieee80211_tx_rate_control txrc;
        u32 sta_flags;
@@ -602,7 +603,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 
        sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
-       len = min_t(int, tx->skb->len + FCS_LEN,
+       len = min_t(u32, tx->skb->len + FCS_LEN,
                         tx->local->hw.wiphy->frag_threshold);
 
        /* set up the tx rate control struct we give the RC algo */
index bdb1d05b16fc7fd3e3cb0a65e248b9cb3b475d39..3dd07600199db6242502de0946aed3ee1cab1e59 100644 (file)
@@ -213,15 +213,25 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
 
        sband = local->hw.wiphy->bands[wk->chan->band];
 
-       /*
-        * Get all rates supported by the device and the AP as
-        * some APs don't like getting a superset of their rates
-        * in the association request (e.g. D-Link DAP 1353 in
-        * b-only mode)...
-        */
-       rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates,
-                                              wk->assoc.supp_rates_len,
-                                              sband, &rates);
+       if (wk->assoc.supp_rates_len) {
+               /*
+                * Get all rates supported by the device and the AP as
+                * some APs don't like getting a superset of their rates
+                * in the association request (e.g. D-Link DAP 1353 in
+                * b-only mode)...
+                */
+               rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates,
+                                                      wk->assoc.supp_rates_len,
+                                                      sband, &rates);
+       } else {
+               /*
+                * In case AP not provide any supported rates information
+                * before association, we send information element(s) with
+                * all rates that we support.
+                */
+               rates = ~0;
+               rates_len = sband->n_bitrates;
+       }
 
        skb = alloc_skb(local->hw.extra_tx_headroom +
                        sizeof(*mgmt) + /* bit too much but doesn't matter */
index 6ac70c1015235448fe79ebd3b25664b5f47479e3..37d0e0ab4432c7cecac400debdaeee1e1319c94b 100644 (file)
@@ -705,7 +705,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                        wdev->ps = true;
                else
                        wdev->ps = false;
-               wdev->ps_timeout = 100;
+               /* allow mac80211 to determine the timeout */
+               wdev->ps_timeout = -1;
                if (rdev->ops->set_power_mgmt)
                        if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
                                                      wdev->ps,
index 356a84a5daeeb8a0aeaf5706583aac297450635d..01da83ddcff775955ef14c358f1819ff77e74d44 100644 (file)
@@ -152,6 +152,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
        [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
        [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
+       [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
 };
 
 /* policy for the attributes */
@@ -2442,6 +2443,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
        params.use_cts_prot = -1;
        params.use_short_preamble = -1;
        params.use_short_slot_time = -1;
+       params.ap_isolate = -1;
 
        if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
                params.use_cts_prot =
@@ -2458,6 +2460,8 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
                params.basic_rates_len =
                        nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
        }
+       if (info->attrs[NL80211_ATTR_AP_ISOLATE])
+               params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
 
        rtnl_lock();