Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

Conflicts:
	drivers/net/wireless/iwlwifi/iwl-core.h
	drivers/net/wireless/rt2x00/rt2800pci.c
This commit is contained in:
David S. Miller 2010-02-25 23:26:21 -08:00
commit 19bc291c99
104 changed files with 3108 additions and 1632 deletions

View File

@ -5978,7 +5978,7 @@ S: Maintained
F: drivers/input/misc/wistron_btns.c
WL1251 WIRELESS DRIVER
M: Kalle Valo <kalle.valo@nokia.com>
M: Kalle Valo <kalle.valo@iki.fi>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git

View File

@ -112,6 +112,7 @@ config AIRO_CS
depends on PCMCIA && (BROKEN || !M32R)
select WIRELESS_EXT
select WEXT_SPY
select WEXT_PRIV
select CRYPTO
select CRYPTO_AES
---help---

View File

@ -51,6 +51,7 @@
#include <linux/freezer.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
#include "airo.h"

View File

@ -2329,54 +2329,55 @@ out:
return err;
}
static void ar9170_sta_notify(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta)
static int ar9170_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct ar9170 *ar = hw->priv;
struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
unsigned int i;
switch (cmd) {
case STA_NOTIFY_ADD:
memset(sta_info, 0, sizeof(*sta_info));
memset(sta_info, 0, sizeof(*sta_info));
if (!sta->ht_cap.ht_supported)
break;
if (!sta->ht_cap.ht_supported)
return 0;
if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
ar->global_ampdu_density = sta->ht_cap.ampdu_density;
if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
ar->global_ampdu_density = sta->ht_cap.ampdu_density;
if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
for (i = 0; i < AR9170_NUM_TID; i++) {
sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
sta_info->agg[i].active = false;
sta_info->agg[i].ssn = 0;
sta_info->agg[i].tid = i;
INIT_LIST_HEAD(&sta_info->agg[i].list);
skb_queue_head_init(&sta_info->agg[i].queue);
}
sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
break;
case STA_NOTIFY_REMOVE:
if (!sta->ht_cap.ht_supported)
break;
for (i = 0; i < AR9170_NUM_TID; i++) {
sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
skb_queue_purge(&sta_info->agg[i].queue);
}
break;
default:
break;
for (i = 0; i < AR9170_NUM_TID; i++) {
sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
sta_info->agg[i].active = false;
sta_info->agg[i].ssn = 0;
sta_info->agg[i].tid = i;
INIT_LIST_HEAD(&sta_info->agg[i].list);
skb_queue_head_init(&sta_info->agg[i].queue);
}
sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
return 0;
}
static int ar9170_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
unsigned int i;
if (!sta->ht_cap.ht_supported)
return 0;
for (i = 0; i < AR9170_NUM_TID; i++) {
sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
skb_queue_purge(&sta_info->agg[i].queue);
}
return 0;
}
static int ar9170_get_stats(struct ieee80211_hw *hw,
@ -2495,7 +2496,8 @@ static const struct ieee80211_ops ar9170_ops = {
.bss_info_changed = ar9170_op_bss_info_changed,
.get_tsf = ar9170_op_get_tsf,
.set_key = ar9170_set_key,
.sta_notify = ar9170_sta_notify,
.sta_add = ar9170_sta_add,
.sta_remove = ar9170_sta_remove,
.get_stats = ar9170_get_stats,
.ampdu_action = ar9170_ampdu_action,
};

View File

@ -62,7 +62,7 @@ int ath_beaconq_config(struct ath_softc *sc)
* Beacons are always sent out at the lowest rate, and are not retried.
*/
static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
struct ath_buf *bf)
struct ath_buf *bf, int rateidx)
{
struct sk_buff *skb = bf->bf_mpdu;
struct ath_hw *ah = sc->sc_ah;
@ -96,9 +96,9 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
ds->ds_data = bf->bf_buf_addr;
sband = &sc->sbands[common->hw->conf.channel->band];
rate = sband->bitrates[0].hw_value;
rate = sband->bitrates[rateidx].hw_value;
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
rate |= sband->bitrates[0].hw_value_short;
rate |= sband->bitrates[rateidx].hw_value_short;
ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN,
ATH9K_PKT_TYPE_BEACON,
@ -206,7 +206,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
}
}
ath_beacon_setup(sc, avp, bf);
ath_beacon_setup(sc, avp, bf, info->control.rates[0].idx);
while (skb) {
ath_tx_cabq(hw, skb);
@ -237,7 +237,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc,
bf = avp->av_bcbuf;
skb = bf->bf_mpdu;
ath_beacon_setup(sc, avp, bf);
ath_beacon_setup(sc, avp, bf, 0);
/* NB: caller is known to have already stopped tx dma */
ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
@ -526,16 +526,13 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
{
u32 nexttbtt, intval;
/* Configure the timers only when the TSF has to be reset */
if (!(sc->sc_flags & SC_OP_TSF_RESET))
return;
/* NB: the beacon interval is kept internally in TU's */
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
intval /= ATH_BCBUF; /* for staggered beacons */
nexttbtt = intval;
intval |= ATH9K_BEACON_RESET_TSF;
if (sc->sc_flags & SC_OP_TSF_RESET)
intval |= ATH9K_BEACON_RESET_TSF;
/*
* In AP mode we enable the beacon timers and SWBA interrupts to

View File

@ -1684,24 +1684,28 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
"Set HW RX filter: 0x%x\n", rfilt);
}
static void ath9k_sta_notify(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta)
static int ath9k_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
switch (cmd) {
case STA_NOTIFY_ADD:
ath_node_attach(sc, sta);
break;
case STA_NOTIFY_REMOVE:
ath_node_detach(sc, sta);
break;
default:
break;
}
ath_node_attach(sc, sta);
return 0;
}
static int ath9k_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
ath_node_detach(sc, sta);
return 0;
}
static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
@ -2045,7 +2049,8 @@ struct ieee80211_ops ath9k_ops = {
.remove_interface = ath9k_remove_interface,
.config = ath9k_config,
.configure_filter = ath9k_configure_filter,
.sta_notify = ath9k_sta_notify,
.sta_add = ath9k_sta_add,
.sta_remove = ath9k_sta_remove,
.conf_tx = ath9k_conf_tx,
.bss_info_changed = ath9k_bss_info_changed,
.set_key = ath9k_set_key,

View File

@ -668,7 +668,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_tx_rate *rates = tx_info->control.rates;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
u8 try_per_rate, i = 0, rix, nrix;
u8 try_per_rate, i = 0, rix;
int is_probe = 0;
if (rate_control_send_low(sta, priv_sta, txrc))
@ -688,26 +688,25 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
rate_table = sc->cur_rate_table;
rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
nrix = rix;
if (is_probe) {
/* set one try for probe rates. For the
* probes don't enable rts */
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
1, nrix, 0);
1, rix, 0);
/* Get the next tried/allowed rate. No RTS for the next series
* after the probe rate
*/
ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
try_per_rate, nrix, 0);
try_per_rate, rix, 0);
tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
} else {
/* Set the choosen rate. No RTS for first series entry. */
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
try_per_rate, nrix, 0);
try_per_rate, rix, 0);
}
/* Fill in the other rates for multirate retry */
@ -716,10 +715,10 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
if (i + 1 == 4)
try_per_rate = 8;
ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
/* All other rates in the series have RTS enabled */
ath_rc_rate_set_series(rate_table, &rates[i], txrc,
try_per_rate, nrix, 1);
try_per_rate, rix, 1);
}
/*

View File

@ -45,7 +45,7 @@ enum b43legacy_led_behaviour {
void b43legacy_leds_init(struct b43legacy_wldev *dev);
void b43legacy_leds_exit(struct b43legacy_wldev *dev);
#else /* CONFIG_B43EGACY_LEDS */
#else /* CONFIG_B43LEGACY_LEDS */
/* LED support disabled */
struct b43legacy_led {

View File

@ -793,13 +793,6 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
0x4b801a17),
PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus",
0x7a954bd9, 0x74be00c6),
PCMCIA_DEVICE_PROD_ID123(
"Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P",
0x4b801a17, 0x6345a0bf, 0xc9049a39),
/* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */
PCMCIA_DEVICE_PROD_ID123(
"D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10",
0x1a424a1c, 0x6ea57632, 0xdd97a26b),
PCMCIA_DEVICE_PROD_ID123(
"Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
0xe6ec52ce, 0x08649af2, 0x4b74baa0),
@ -833,15 +826,13 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
"Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio",
"Ver. 1.00",
0x5cd01705, 0x4271660f, 0x9d08ee12),
PCMCIA_DEVICE_PROD_ID123(
"corega", "WL PCCL-11", "ISL37300P",
0xa21501a, 0x59868926, 0xc9049a39),
PCMCIA_DEVICE_PROD_ID123(
"The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P",
0xa5f472c2, 0x9c05598d, 0xc9049a39),
PCMCIA_DEVICE_PROD_ID123(
"Wireless LAN" , "11Mbps PC Card", "Version 01.02",
0x4b8870ff, 0x70e946d1, 0x4b74baa0),
PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);

View File

@ -246,7 +246,7 @@ struct iwl_cfg iwl1000_bgn_cfg = {
.use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
};
@ -274,7 +274,7 @@ struct iwl_cfg iwl1000_bg_cfg = {
.led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
};

View File

@ -45,8 +45,8 @@
#include "iwl-sta.h"
#include "iwl-3945.h"
#include "iwl-eeprom.h"
#include "iwl-helpers.h"
#include "iwl-core.h"
#include "iwl-helpers.h"
#include "iwl-led.h"
#include "iwl-3945-led.h"
@ -2470,11 +2470,9 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
memset((void *)&priv->hw_params, 0,
sizeof(struct iwl_hw_params));
priv->shared_virt =
pci_alloc_consistent(priv->pci_dev,
sizeof(struct iwl3945_shared),
&priv->shared_phys);
priv->shared_virt = dma_alloc_coherent(&priv->pci_dev->dev,
sizeof(struct iwl3945_shared),
&priv->shared_phys, GFP_KERNEL);
if (!priv->shared_virt) {
IWL_ERR(priv, "failed to allocate pci memory\n");
mutex_unlock(&priv->mutex);

View File

@ -171,24 +171,6 @@ struct iwl3945_frame {
#define SCAN_INTERVAL 100
#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
#define STATUS_INT_ENABLED 2
#define STATUS_RF_KILL_HW 3
#define STATUS_INIT 5
#define STATUS_ALIVE 6
#define STATUS_READY 7
#define STATUS_TEMPERATURE 8
#define STATUS_GEO_CONFIGURED 9
#define STATUS_EXIT_PENDING 10
#define STATUS_STATISTICS 12
#define STATUS_SCANNING 13
#define STATUS_SCAN_ABORTING 14
#define STATUS_SCAN_HW 15
#define STATUS_POWER_PMI 16
#define STATUS_FW_ERROR 17
#define STATUS_CONF_PENDING 18
#define MAX_TID_COUNT 9
#define IWL_INVALID_RATE 0xFF

View File

@ -581,6 +581,13 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
/* make sure all queue are not stopped */
memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
for (i = 0; i < 4; i++)
atomic_set(&priv->queue_stop_count[i], 0);
/* reset to 0 to enable all the queue first */
priv->txq_ctx_active_msk = 0;
/* Map each Tx/cmd queue to its corresponding fifo */
for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
int ac = default_queue_to_tx_fifo[i];

View File

@ -648,6 +648,13 @@ int iwl5000_alive_notify(struct iwl_priv *priv)
iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
/* make sure all queue are not stopped */
memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
for (i = 0; i < 4; i++)
atomic_set(&priv->queue_stop_count[i], 0);
/* reset to 0 to enable all the queue first */
priv->txq_ctx_active_msk = 0;
/* map qos queues to fifos one-to-one */
for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) {
int ac = iwl5000_default_queue_to_tx_fifo[i];

View File

@ -70,6 +70,14 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
}
/* Indicate calibration version to uCode. */
static void iwl6050_set_calib_version(struct iwl_priv *priv)
{
if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
iwl_set_bit(priv, CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
}
/* NIC configuration for 6000 series */
static void iwl6000_nic_config(struct iwl_priv *priv)
{
@ -96,6 +104,8 @@ static void iwl6000_nic_config(struct iwl_priv *priv)
CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
}
/* else do nothing, uCode configured */
if (priv->cfg->ops->lib->temp_ops.set_calib_version)
priv->cfg->ops->lib->temp_ops.set_calib_version(priv);
}
static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
@ -277,6 +287,71 @@ static const struct iwl_ops iwl6000_ops = {
.led = &iwlagn_led_ops,
};
static struct iwl_lib_ops iwl6050_lib = {
.set_hw_params = iwl6000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
.txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwl5000_txq_set_sched,
.txq_agg_enable = iwl5000_txq_agg_enable,
.txq_agg_disable = iwl5000_txq_agg_disable,
.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl_hw_txq_free_tfd,
.txq_init = iwl_hw_tx_queue_init,
.rx_handler_setup = iwl5000_rx_handler_setup,
.setup_deferred_work = iwl5000_setup_deferred_work,
.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
.load_ucode = iwl5000_load_ucode,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
.dump_csr = iwl_dump_csr,
.dump_fh = iwl_dump_fh,
.init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
.set_channel_switch = iwl6000_hw_channel_switch,
.apm_ops = {
.init = iwl_apm_init,
.stop = iwl_apm_stop,
.config = iwl6000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
.regulatory_bands = {
EEPROM_5000_REG_BAND_1_CHANNELS,
EEPROM_5000_REG_BAND_2_CHANNELS,
EEPROM_5000_REG_BAND_3_CHANNELS,
EEPROM_5000_REG_BAND_4_CHANNELS,
EEPROM_5000_REG_BAND_5_CHANNELS,
EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
EEPROM_5000_REG_BAND_52_HT40_CHANNELS
},
.verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
.calib_version = iwl5000_eeprom_calib_version,
.query_addr = iwl5000_eeprom_query_addr,
.update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
},
.post_associate = iwl_post_associate,
.isr = iwl_isr_ict,
.config_ap = iwl_config_ap,
.temp_ops = {
.temperature = iwl5000_temperature,
.set_ct_kill = iwl6000_set_ct_threshold,
.set_calib_version = iwl6050_set_calib_version,
},
.add_bcast_station = iwl_add_bcast_station,
};
static const struct iwl_ops iwl6050_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl6050_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
.led = &iwlagn_led_ops,
};
/*
* "i": Internal configuration, use internal Power Amplifier
*/
@ -380,7 +455,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
.ops = &iwl6050_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
@ -412,7 +487,7 @@ struct iwl_cfg iwl6050_2abg_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
.ops = &iwl6000_ops,
.ops = &iwl6050_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,

View File

@ -298,10 +298,23 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
struct iwl_lq_sta *lq_data, u8 tid,
struct ieee80211_sta *sta)
{
int ret;
if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
sta->addr, tid);
ieee80211_start_tx_ba_session(sta, tid);
ret = ieee80211_start_tx_ba_session(sta, tid);
if (ret == -EAGAIN) {
/*
* driver and mac80211 is out of sync
* this might be cause by reloading firmware
* stop the tx ba session here
*/
IWL_DEBUG_HT(priv, "Fail start Tx agg on tid: %d\n",
tid);
ret = ieee80211_stop_tx_ba_session(sta, tid,
WLAN_BACK_INITIATOR);
}
}
}

View File

@ -2941,10 +2941,21 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
return ret;
case IEEE80211_AMPDU_TX_START:
IWL_DEBUG_HT(priv, "start Tx\n");
return iwl_tx_agg_start(priv, sta->addr, tid, ssn);
ret = iwl_tx_agg_start(priv, sta->addr, tid, ssn);
if (ret == 0) {
priv->agg_tids_count++;
IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
priv->agg_tids_count);
}
return ret;
case IEEE80211_AMPDU_TX_STOP:
IWL_DEBUG_HT(priv, "stop Tx\n");
ret = iwl_tx_agg_stop(priv, sta->addr, tid);
if ((ret == 0) && (priv->agg_tids_count > 0)) {
priv->agg_tids_count--;
IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
priv->agg_tids_count);
}
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return 0;
else
@ -3353,6 +3364,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
INIT_LIST_HEAD(&priv->free_frames);
mutex_init(&priv->mutex);
mutex_init(&priv->sync_cmd_mutex);
/* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv);
@ -3364,6 +3376,13 @@ static int iwl_init_drv(struct iwl_priv *priv)
priv->iw_mode = NL80211_IFTYPE_STATION;
priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
priv->agg_tids_count = 0;
/* initialize force reset */
priv->force_reset[IWL_RF_RESET].reset_duration =
IWL_DELAY_NEXT_FORCE_RF_RESET;
priv->force_reset[IWL_FW_RESET].reset_duration =
IWL_DELAY_NEXT_FORCE_FW_RELOAD;
/* Choose which receivers/antennas to use */
if (priv->cfg->ops->hcmd->set_rxon_chain)
@ -3540,6 +3559,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
spin_lock_init(&priv->reg_lock);
spin_lock_init(&priv->lock);
/*
* stop and reset the on-board processor just in case it is in a
* strange state ... like being left stranded by a primary kernel
* and this is now the kdump kernel trying to start up
*/
iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
iwl_hw_detect(priv);
IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n",
priv->cfg->name, priv->hw_rev);

View File

@ -3470,11 +3470,7 @@ enum {
IWL_PHY_CALIBRATE_DIFF_GAIN_CMD = 7,
IWL_PHY_CALIBRATE_DC_CMD = 8,
IWL_PHY_CALIBRATE_LO_CMD = 9,
IWL_PHY_CALIBRATE_RX_BB_CMD = 10,
IWL_PHY_CALIBRATE_TX_IQ_CMD = 11,
IWL_PHY_CALIBRATE_RX_IQ_CMD = 12,
IWL_PHY_CALIBRATION_NOISE_CMD = 13,
IWL_PHY_CALIBRATE_AGC_TABLE_CMD = 14,
IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15,
IWL_PHY_CALIBRATE_BASE_BAND_CMD = 16,
IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17,

View File

@ -1670,9 +1670,9 @@ EXPORT_SYMBOL(iwl_set_tx_power);
void iwl_free_isr_ict(struct iwl_priv *priv)
{
if (priv->ict_tbl_vir) {
pci_free_consistent(priv->pci_dev, (sizeof(u32) * ICT_COUNT) +
PAGE_SIZE, priv->ict_tbl_vir,
priv->ict_tbl_dma);
dma_free_coherent(&priv->pci_dev->dev,
(sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
priv->ict_tbl_vir, priv->ict_tbl_dma);
priv->ict_tbl_vir = NULL;
}
}
@ -1688,9 +1688,9 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv)
if (priv->cfg->use_isr_legacy)
return 0;
/* allocate shrared data table */
priv->ict_tbl_vir = pci_alloc_consistent(priv->pci_dev, (sizeof(u32) *
ICT_COUNT) + PAGE_SIZE,
&priv->ict_tbl_dma);
priv->ict_tbl_vir = dma_alloc_coherent(&priv->pci_dev->dev,
(sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
&priv->ict_tbl_dma, GFP_KERNEL);
if (!priv->ict_tbl_vir)
return -ENOMEM;
@ -3334,7 +3334,7 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
}
EXPORT_SYMBOL(iwl_dump_fh);
void iwl_force_rf_reset(struct iwl_priv *priv)
static void iwl_force_rf_reset(struct iwl_priv *priv)
{
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
@ -3356,7 +3356,50 @@ void iwl_force_rf_reset(struct iwl_priv *priv)
iwl_internal_short_hw_scan(priv);
return;
}
EXPORT_SYMBOL(iwl_force_rf_reset);
int iwl_force_reset(struct iwl_priv *priv, int mode)
{
struct iwl_force_reset *force_reset;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return -EINVAL;
if (mode >= IWL_MAX_FORCE_RESET) {
IWL_DEBUG_INFO(priv, "invalid reset request.\n");
return -EINVAL;
}
force_reset = &priv->force_reset[mode];
force_reset->reset_request_count++;
if (force_reset->last_force_reset_jiffies &&
time_after(force_reset->last_force_reset_jiffies +
force_reset->reset_duration, jiffies)) {
IWL_DEBUG_INFO(priv, "force reset rejected\n");
force_reset->reset_reject_count++;
return -EAGAIN;
}
force_reset->reset_success_count++;
force_reset->last_force_reset_jiffies = jiffies;
IWL_DEBUG_INFO(priv, "perform force reset (%d)\n", mode);
switch (mode) {
case IWL_RF_RESET:
iwl_force_rf_reset(priv);
break;
case IWL_FW_RESET:
IWL_ERR(priv, "On demand firmware reload\n");
/* Set the FW error flag -- cleared on iwl_down */
set_bit(STATUS_FW_ERROR, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
/*
* Keep the restart process from trying to send host
* commands by clearing the INIT status bit
*/
clear_bit(STATUS_READY, &priv->status);
queue_work(priv->workqueue, &priv->restart);
break;
}
return 0;
}
#ifdef CONFIG_PM

View File

@ -117,6 +117,7 @@ struct iwl_apm_ops {
struct iwl_temp_ops {
void (*temperature)(struct iwl_priv *priv);
void (*set_ct_kill)(struct iwl_priv *priv);
void (*set_calib_version)(struct iwl_priv *priv);
};
struct iwl_ucode_ops {
@ -414,13 +415,13 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
void iwl_cmd_queue_free(struct iwl_priv *priv);
int iwl_rx_queue_alloc(struct iwl_priv *priv);
void iwl_rx_handle(struct iwl_priv *priv);
int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl_rx_queue *q);
void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
void iwl_rx_replenish(struct iwl_priv *priv);
void iwl_rx_replenish_now(struct iwl_priv *priv);
int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
int iwl_rx_queue_restock(struct iwl_priv *priv);
void iwl_rx_queue_restock(struct iwl_priv *priv);
int iwl_rx_queue_space(const struct iwl_rx_queue *q);
void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority);
void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
@ -450,9 +451,9 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
int iwl_hw_tx_queue_init(struct iwl_priv *priv,
struct iwl_tx_queue *txq);
int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
void iwl_free_tfds_in_queue(struct iwl_priv *priv,
int sta_id, int tid, int freed);
void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
int slots_num, u32 txq_id);
void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
@ -503,7 +504,7 @@ 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_internal_short_hw_scan(struct iwl_priv *priv);
void iwl_force_rf_reset(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,
const u8 *ie, int ie_len, int left);
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
@ -605,7 +606,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
/*************** DRIVER STATUS FUNCTIONS *****/
#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
/* 1 is unused (used to be STATUS_HCMD_SYNC_ACTIVE) */
#define STATUS_INT_ENABLED 2
#define STATUS_RF_KILL_HW 3
#define STATUS_CT_KILL 4

View File

@ -369,7 +369,7 @@
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_3x3_HYB (0x00000000)
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB (0x00000001)
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002)
#define CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6 (0x00000004)
/* GIO Chicken Bits (PCI Express bus link power management) */
#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)

View File

@ -530,8 +530,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
test_bit(STATUS_HCMD_ACTIVE, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_SYNC_ACTIVE: %d\n",
test_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n",
test_bit(STATUS_INT_ENABLED, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
@ -2223,6 +2221,62 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
return count;
}
static ssize_t iwl_dbgfs_force_reset_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
struct iwl_priv *priv = file->private_data;
int i, pos = 0;
char buf[300];
const size_t bufsz = sizeof(buf);
struct iwl_force_reset *force_reset;
for (i = 0; i < IWL_MAX_FORCE_RESET; i++) {
force_reset = &priv->force_reset[i];
pos += scnprintf(buf + pos, bufsz - pos,
"Force reset method %d\n", i);
pos += scnprintf(buf + pos, bufsz - pos,
"\tnumber of reset request: %d\n",
force_reset->reset_request_count);
pos += scnprintf(buf + pos, bufsz - pos,
"\tnumber of reset request success: %d\n",
force_reset->reset_success_count);
pos += scnprintf(buf + pos, bufsz - pos,
"\tnumber of reset request reject: %d\n",
force_reset->reset_reject_count);
pos += scnprintf(buf + pos, bufsz - pos,
"\treset duration: %lu\n",
force_reset->reset_duration);
}
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
static ssize_t iwl_dbgfs_force_reset_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos) {
struct iwl_priv *priv = file->private_data;
char buf[8];
int buf_size;
int reset, ret;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
if (sscanf(buf, "%d", &reset) != 1)
return -EINVAL;
switch (reset) {
case IWL_RF_RESET:
case IWL_FW_RESET:
ret = iwl_force_reset(priv, reset);
break;
default:
return -EINVAL;
}
return ret ? ret : count;
}
DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@ -2243,6 +2297,7 @@ DEBUGFS_READ_FILE_OPS(fh_reg);
DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
DEBUGFS_WRITE_FILE_OPS(internal_scan);
DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
/*
* Create the debugfs files and directories
@ -2296,6 +2351,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(internal_scan, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);

View File

@ -1033,8 +1033,26 @@ struct iwl_event_log {
#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (0)
#define IWL_MAX_PLCP_ERR_THRESHOLD_DEF (50)
#define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100)
#define IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF (200)
#define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255)
#define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3)
#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
enum iwl_reset {
IWL_RF_RESET = 0,
IWL_FW_RESET,
IWL_MAX_FORCE_RESET,
};
struct iwl_force_reset {
int reset_request_count;
int reset_success_count;
int reset_reject_count;
unsigned long reset_duration;
unsigned long last_force_reset_jiffies;
};
struct iwl_priv {
/* ieee device used by generic ieee processing code */
@ -1066,6 +1084,12 @@ struct iwl_priv {
/* storing the jiffies when the plcp error rate is received */
unsigned long plcp_jiffies;
/* reporting the number of tids has AGG on. 0 means no AGGREGATION */
u8 agg_tids_count;
/* force reset */
struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET];
/* we allocate array of iwl4965_channel_info for NIC's valid channels.
* Access via channel # using indirect index array */
struct iwl_channel_info *channel_info; /* channel info array */
@ -1087,7 +1111,6 @@ struct iwl_priv {
unsigned long scan_start;
unsigned long scan_pass_start;
unsigned long scan_start_tsf;
unsigned long last_internal_scan_jiffies;
void *scan;
int scan_bands;
struct cfg80211_scan_request *scan_request;
@ -1100,6 +1123,7 @@ struct iwl_priv {
spinlock_t hcmd_lock; /* protect hcmd */
spinlock_t reg_lock; /* protect hw register access */
struct mutex mutex;
struct mutex sync_cmd_mutex; /* enable serialization of sync commands */
/* basic pci-network driver stuff */
struct pci_dev *pci_dev;

View File

@ -164,15 +164,13 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
/* A synchronous command can not have a callback set. */
BUG_ON(cmd->callback);
if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
IWL_ERR(priv,
"Error sending %s: Already sending a host command\n",
IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
get_cmd_string(cmd->id));
ret = -EBUSY;
goto out;
}
mutex_lock(&priv->sync_cmd_mutex);
set_bit(STATUS_HCMD_ACTIVE, &priv->status);
IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s \n",
get_cmd_string(cmd->id));
cmd_idx = iwl_enqueue_hcmd(priv, cmd);
if (cmd_idx < 0) {
@ -193,6 +191,8 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
get_cmd_string(cmd->id));
ret = -ETIMEDOUT;
goto cancel;
}
@ -237,7 +237,7 @@ fail:
cmd->reply_page = 0;
}
out:
clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
mutex_unlock(&priv->sync_cmd_mutex);
return ret;
}
EXPORT_SYMBOL(iwl_send_cmd_sync);

View File

@ -80,8 +80,8 @@ static inline void iwl_free_fw_desc(struct pci_dev *pci_dev,
struct fw_desc *desc)
{
if (desc->v_addr)
pci_free_consistent(pci_dev, desc->len,
desc->v_addr, desc->p_addr);
dma_free_coherent(&pci_dev->dev, desc->len,
desc->v_addr, desc->p_addr);
desc->v_addr = NULL;
desc->len = 0;
}
@ -89,7 +89,8 @@ static inline void iwl_free_fw_desc(struct pci_dev *pci_dev,
static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev,
struct fw_desc *desc)
{
desc->v_addr = pci_alloc_consistent(pci_dev, desc->len, &desc->p_addr);
desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len,
&desc->p_addr, GFP_KERNEL);
return (desc->v_addr != NULL) ? 0 : -ENOMEM;
}

View File

@ -123,12 +123,11 @@ EXPORT_SYMBOL(iwl_rx_queue_space);
/**
* iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
*/
int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
{
unsigned long flags;
u32 rx_wrt_ptr_reg = priv->hw_params.rx_wrt_ptr_reg;
u32 reg;
int ret = 0;
spin_lock_irqsave(&q->lock, flags);
@ -161,7 +160,6 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
exit_unlock:
spin_unlock_irqrestore(&q->lock, flags);
return ret;
}
EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr);
/**
@ -184,14 +182,13 @@ static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
* also updates the memory address in the firmware to reference the new
* target buffer.
*/
int iwl_rx_queue_restock(struct iwl_priv *priv)
void iwl_rx_queue_restock(struct iwl_priv *priv)
{
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
unsigned long flags;
int write;
int ret = 0;
spin_lock_irqsave(&rxq->lock, flags);
write = rxq->write & ~0x7;
@ -220,10 +217,8 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
spin_lock_irqsave(&rxq->lock, flags);
rxq->need_update = 1;
spin_unlock_irqrestore(&rxq->lock, flags);
ret = iwl_rx_queue_update_write_ptr(priv, rxq);
iwl_rx_queue_update_write_ptr(priv, rxq);
}
return ret;
}
EXPORT_SYMBOL(iwl_rx_queue_restock);
@ -350,10 +345,10 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
}
}
pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
rxq->dma_addr);
pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status),
rxq->rb_stts, rxq->rb_stts_dma);
dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
rxq->dma_addr);
dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
rxq->rb_stts, rxq->rb_stts_dma);
rxq->bd = NULL;
rxq->rb_stts = NULL;
}
@ -362,7 +357,7 @@ EXPORT_SYMBOL(iwl_rx_queue_free);
int iwl_rx_queue_alloc(struct iwl_priv *priv)
{
struct iwl_rx_queue *rxq = &priv->rxq;
struct pci_dev *dev = priv->pci_dev;
struct device *dev = &priv->pci_dev->dev;
int i;
spin_lock_init(&rxq->lock);
@ -370,12 +365,13 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
INIT_LIST_HEAD(&rxq->rx_used);
/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr,
GFP_KERNEL);
if (!rxq->bd)
goto err_bd;
rxq->rb_stts = pci_alloc_consistent(dev, sizeof(struct iwl_rb_status),
&rxq->rb_stts_dma);
rxq->rb_stts = dma_alloc_coherent(dev, sizeof(struct iwl_rb_status),
&rxq->rb_stts_dma, GFP_KERNEL);
if (!rxq->rb_stts)
goto err_rb;
@ -392,8 +388,8 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
return 0;
err_rb:
pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
rxq->dma_addr);
dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
rxq->dma_addr);
err_bd:
return -ENOMEM;
}
@ -620,6 +616,11 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
#define REG_RECALIB_PERIOD (60)
/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
#define ACK_CNT_RATIO (50)
#define BA_TIMEOUT_CNT (5)
#define BA_TIMEOUT_MAX (16)
#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n"
void iwl_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
@ -629,6 +630,9 @@ void iwl_rx_statistics(struct iwl_priv *priv,
int combined_plcp_delta;
unsigned int plcp_msec;
unsigned long plcp_received_jiffies;
int actual_ack_cnt_delta;
int expected_ack_cnt_delta;
int ba_timeout_delta;
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
(int)sizeof(priv->statistics),
@ -643,6 +647,44 @@ void iwl_rx_statistics(struct iwl_priv *priv,
#ifdef CONFIG_IWLWIFI_DEBUG
iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
#endif
actual_ack_cnt_delta = le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -
le32_to_cpu(priv->statistics.tx.actual_ack_cnt);
expected_ack_cnt_delta = le32_to_cpu(
pkt->u.stats.tx.expected_ack_cnt) -
le32_to_cpu(priv->statistics.tx.expected_ack_cnt);
ba_timeout_delta = le32_to_cpu(
pkt->u.stats.tx.agg.ba_timeout) -
le32_to_cpu(priv->statistics.tx.agg.ba_timeout);
if ((priv->agg_tids_count > 0) &&
(expected_ack_cnt_delta > 0) &&
(((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta) <
ACK_CNT_RATIO) &&
(ba_timeout_delta > BA_TIMEOUT_CNT)) {
IWL_DEBUG_RADIO(priv,
"actual_ack_cnt delta = %d, expected_ack_cnt = %d\n",
actual_ack_cnt_delta, expected_ack_cnt_delta);
#ifdef CONFIG_IWLWIFI_DEBUG
IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
priv->delta_statistics.tx.rx_detected_cnt);
IWL_DEBUG_RADIO(priv,
"ack_or_ba_timeout_collision delta = %d\n",
priv->delta_statistics.tx.ack_or_ba_timeout_collision);
#endif
IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
ba_timeout_delta);
if ((actual_ack_cnt_delta == 0) &&
(ba_timeout_delta >=
BA_TIMEOUT_MAX)) {
IWL_DEBUG_RADIO(priv,
"call iwl_force_reset(IWL_FW_RESET)\n");
iwl_force_reset(priv, IWL_FW_RESET);
} else {
IWL_DEBUG_RADIO(priv,
"call iwl_force_reset(IWL_RF_RESET)\n");
iwl_force_reset(priv, IWL_RF_RESET);
}
}
/*
* check for plcp_err and trigger radio reset if it exceeds
* the plcp error threshold plcp_delta.
@ -689,7 +731,7 @@ void iwl_rx_statistics(struct iwl_priv *priv,
* Reset the RF radio due to the high plcp
* error rate
*/
iwl_force_rf_reset(priv);
iwl_force_reset(priv, IWL_RF_RESET);
}
}

View File

@ -250,8 +250,6 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
if (!priv->is_internal_short_scan)
priv->next_scan_jiffies = 0;
else
priv->last_internal_scan_jiffies = jiffies;
IWL_DEBUG_INFO(priv, "Setting scan to off\n");
@ -471,21 +469,6 @@ EXPORT_SYMBOL(iwl_init_scan_params);
static int iwl_scan_initiate(struct iwl_priv *priv)
{
if (!iwl_is_ready_rf(priv)) {
IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n");
return -EIO;
}
if (test_bit(STATUS_SCANNING, &priv->status)) {
IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
return -EAGAIN;
}
if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
return -EAGAIN;
}
IWL_DEBUG_INFO(priv, "Starting scan...\n");
set_bit(STATUS_SCANNING, &priv->status);
priv->is_internal_short_scan = false;
@ -517,6 +500,18 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
goto out_unlock;
}
if (test_bit(STATUS_SCANNING, &priv->status)) {
IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
ret = -EAGAIN;
goto out_unlock;
}
if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
ret = -EAGAIN;
goto out_unlock;
}
/* We don't schedule scan within next_scan_jiffies period.
* Avoid scanning during possible EAPOL exchange, return
* success immediately.
@ -551,8 +546,6 @@ EXPORT_SYMBOL(iwl_mac_hw_scan);
* internal short scan, this function should only been called while associated.
* It will reset and tune the radio to prevent possible RF related problem
*/
#define IWL_DELAY_NEXT_INTERNAL_SCAN (HZ*1)
int iwl_internal_short_hw_scan(struct iwl_priv *priv)
{
int ret = 0;
@ -572,12 +565,6 @@ int iwl_internal_short_hw_scan(struct iwl_priv *priv)
ret = -EAGAIN;
goto out;
}
if (priv->last_internal_scan_jiffies &&
time_after(priv->last_internal_scan_jiffies +
IWL_DELAY_NEXT_INTERNAL_SCAN, jiffies)) {
IWL_DEBUG_SCAN(priv, "internal scan rejected\n");
goto out;
}
priv->scan_bands = 0;
if (priv->band == IEEE80211_BAND_5GHZ)

View File

@ -60,7 +60,8 @@ static const u16 default_tid_to_tx_fifo[] = {
static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv,
struct iwl_dma_ptr *ptr, size_t size)
{
ptr->addr = pci_alloc_consistent(priv->pci_dev, size, &ptr->dma);
ptr->addr = dma_alloc_coherent(&priv->pci_dev->dev, size, &ptr->dma,
GFP_KERNEL);
if (!ptr->addr)
return -ENOMEM;
ptr->size = size;
@ -73,21 +74,20 @@ static inline void iwl_free_dma_ptr(struct iwl_priv *priv,
if (unlikely(!ptr->addr))
return;
pci_free_consistent(priv->pci_dev, ptr->size, ptr->addr, ptr->dma);
dma_free_coherent(&priv->pci_dev->dev, ptr->size, ptr->addr, ptr->dma);
memset(ptr, 0, sizeof(*ptr));
}
/**
* iwl_txq_update_write_ptr - Send new write index to hardware
*/
int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
{
u32 reg = 0;
int ret = 0;
int txq_id = txq->q.id;
if (txq->need_update == 0)
return ret;
return;
/* if we're trying to save power */
if (test_bit(STATUS_POWER_PMI, &priv->status)) {
@ -101,7 +101,7 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
txq_id, reg);
iwl_set_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
return ret;
return;
}
iwl_write_direct32(priv, HBUS_TARG_WRPTR,
@ -114,8 +114,6 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
txq->q.write_ptr | (txq_id << 8));
txq->need_update = 0;
return ret;
}
EXPORT_SYMBOL(iwl_txq_update_write_ptr);
@ -146,7 +144,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
{
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q;
struct pci_dev *dev = priv->pci_dev;
struct device *dev = &priv->pci_dev->dev;
int i;
if (q->n_bd == 0)
@ -163,8 +161,8 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
/* De-alloc circular buffer of TFDs */
if (txq->q.n_bd)
pci_free_consistent(dev, priv->hw_params.tfd_size *
txq->q.n_bd, txq->tfds, txq->q.dma_addr);
dma_free_coherent(dev, priv->hw_params.tfd_size *
txq->q.n_bd, txq->tfds, txq->q.dma_addr);
/* De-alloc array of per-TFD driver data */
kfree(txq->txb);
@ -193,7 +191,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
{
struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
struct iwl_queue *q = &txq->q;
struct pci_dev *dev = priv->pci_dev;
struct device *dev = &priv->pci_dev->dev;
int i;
if (q->n_bd == 0)
@ -205,8 +203,8 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
/* De-alloc circular buffer of TFDs */
if (txq->q.n_bd)
pci_free_consistent(dev, priv->hw_params.tfd_size *
txq->q.n_bd, txq->tfds, txq->q.dma_addr);
dma_free_coherent(dev, priv->hw_params.tfd_size * txq->q.n_bd,
txq->tfds, txq->q.dma_addr);
/* deallocate arrays */
kfree(txq->cmd);
@ -297,7 +295,7 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
static int iwl_tx_queue_alloc(struct iwl_priv *priv,
struct iwl_tx_queue *txq, u32 id)
{
struct pci_dev *dev = priv->pci_dev;
struct device *dev = &priv->pci_dev->dev;
size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX;
/* Driver private data, only for Tx (not command) queues,
@ -316,8 +314,8 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
/* Circular buffer of transmit frame descriptors (TFDs),
* shared with device */
txq->tfds = pci_alloc_consistent(dev, tfd_sz, &txq->q.dma_addr);
txq->tfds = dma_alloc_coherent(dev, tfd_sz, &txq->q.dma_addr,
GFP_KERNEL);
if (!txq->tfds) {
IWL_ERR(priv, "pci_alloc_consistent(%zd) failed\n", tfd_sz);
goto error;
@ -745,7 +743,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
u8 tid = 0;
u8 *qc = NULL;
unsigned long flags;
int ret;
spin_lock_irqsave(&priv->lock, flags);
if (iwl_is_rfkill(priv)) {
@ -820,8 +817,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr->seq_ctrl |= cpu_to_le16(seq_number);
seq_number += 0x10;
/* aggregation is on for this <sta,tid> */
if (info->flags & IEEE80211_TX_CTL_AMPDU)
if (info->flags & IEEE80211_TX_CTL_AMPDU &&
priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) {
txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
}
}
txq = &priv->txq[txq_id];
@ -963,7 +962,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Tell device the write index *just past* this latest filled TFD */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
ret = iwl_txq_update_write_ptr(priv, txq);
iwl_txq_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->lock, flags);
/*
@ -977,9 +976,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (sta_priv && sta_priv->client)
atomic_inc(&sta_priv->pending_frames);
if (ret)
return ret;
if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
if (wait_write_ptr) {
spin_lock_irqsave(&priv->lock, flags);
@ -1018,7 +1014,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
struct iwl_cmd_meta *out_meta;
dma_addr_t phys_addr;
unsigned long flags;
int len, ret;
int len;
u32 idx;
u16 fix_size;
@ -1115,10 +1111,10 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
/* Increment and update queue's write index */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
ret = iwl_txq_update_write_ptr(priv, txq);
iwl_txq_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->hcmd_lock, flags);
return ret ? ret : idx;
return idx;
}
static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
@ -1260,6 +1256,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
if (!(meta->flags & CMD_ASYNC)) {
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
get_cmd_string(cmd->hdr.cmd));
wake_up_interruptible(&priv->wait_command_queue);
}
}
@ -1346,7 +1344,7 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
{
int tx_fifo_id, txq_id, sta_id, ssn = -1;
struct iwl_tid_data *tid_data;
int ret, write_ptr, read_ptr;
int write_ptr, read_ptr;
unsigned long flags;
if (!ra) {
@ -1398,13 +1396,17 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
spin_lock_irqsave(&priv->lock, flags);
ret = priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
/*
* the only reason this call can fail is queue number out of range,
* which can happen if uCode is reloaded and all the station
* information are lost. if it is outside the range, there is no need
* to deactivate the uCode queue, just return "success" to allow
* mac80211 to clean up it own data.
*/
priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
tx_fifo_id);
spin_unlock_irqrestore(&priv->lock, flags);
if (ret)
return ret;
ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
return 0;

View File

@ -53,8 +53,8 @@
#include "iwl-commands.h"
#include "iwl-sta.h"
#include "iwl-3945.h"
#include "iwl-helpers.h"
#include "iwl-core.h"
#include "iwl-helpers.h"
#include "iwl-dev.h"
#include "iwl-spectrum.h"
@ -352,10 +352,10 @@ static int iwl3945_send_beacon_cmd(struct iwl_priv *priv)
static void iwl3945_unset_hw_params(struct iwl_priv *priv)
{
if (priv->shared_virt)
pci_free_consistent(priv->pci_dev,
sizeof(struct iwl3945_shared),
priv->shared_virt,
priv->shared_phys);
dma_free_coherent(&priv->pci_dev->dev,
sizeof(struct iwl3945_shared),
priv->shared_virt,
priv->shared_phys);
}
static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
@ -478,7 +478,6 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
u8 wait_write_ptr = 0;
u8 *qc = NULL;
unsigned long flags;
int rc;
spin_lock_irqsave(&priv->lock, flags);
if (iwl_is_rfkill(priv)) {
@ -663,12 +662,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Tell device the write index *just past* this latest filled TFD */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
rc = iwl_txq_update_write_ptr(priv, txq);
iwl_txq_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->lock, flags);
if (rc)
return rc;
if ((iwl_queue_space(q) < q->high_mark)
&& priv->mac80211_registered) {
if (wait_write_ptr) {
@ -1063,13 +1059,13 @@ static inline __le32 iwl3945_dma_addr2rbd_ptr(struct iwl_priv *priv,
* also updates the memory address in the firmware to reference the new
* target buffer.
*/
static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
static void iwl3945_rx_queue_restock(struct iwl_priv *priv)
{
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
unsigned long flags;
int write, rc;
int write;
spin_lock_irqsave(&rxq->lock, flags);
write = rxq->write & ~0x7;
@ -1099,12 +1095,8 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
spin_lock_irqsave(&rxq->lock, flags);
rxq->need_update = 1;
spin_unlock_irqrestore(&rxq->lock, flags);
rc = iwl_rx_queue_update_write_ptr(priv, rxq);
if (rc)
return rc;
iwl_rx_queue_update_write_ptr(priv, rxq);
}
return 0;
}
/**
@ -1249,10 +1241,10 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx
}
}
pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
rxq->dma_addr);
pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status),
rxq->rb_stts, rxq->rb_stts_dma);
dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
rxq->dma_addr);
dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
rxq->rb_stts, rxq->rb_stts_dma);
rxq->bd = NULL;
rxq->rb_stts = NULL;
}
@ -3855,6 +3847,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
INIT_LIST_HEAD(&priv->free_frames);
mutex_init(&priv->mutex);
mutex_init(&priv->sync_cmd_mutex);
/* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv);
@ -4047,6 +4040,13 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
spin_lock_init(&priv->reg_lock);
spin_lock_init(&priv->lock);
/*
* stop and reset the on-board processor just in case it is in a
* strange state ... like being left stranded by a primary kernel
* and this is now the kdump kernel trying to start up
*/
iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
/***********************
* 4. Read EEPROM
* ********************/

View File

@ -771,23 +771,41 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
}
}
static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
hwsim_check_magic(vif);
hwsim_set_sta_magic(sta);
return 0;
}
static int mac80211_hwsim_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
hwsim_check_magic(vif);
hwsim_clear_sta_magic(sta);
return 0;
}
static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta)
{
hwsim_check_magic(vif);
switch (cmd) {
case STA_NOTIFY_ADD:
hwsim_set_sta_magic(sta);
break;
case STA_NOTIFY_REMOVE:
hwsim_clear_sta_magic(sta);
break;
case STA_NOTIFY_SLEEP:
case STA_NOTIFY_AWAKE:
/* TODO: make good use of these flags */
break;
default:
WARN(1, "Invalid sta notify: %d\n", cmd);
break;
}
}
@ -958,6 +976,8 @@ static struct ieee80211_ops mac80211_hwsim_ops =
.config = mac80211_hwsim_config,
.configure_filter = mac80211_hwsim_configure_filter,
.bss_info_changed = mac80211_hwsim_bss_info_changed,
.sta_add = mac80211_hwsim_sta_add,
.sta_remove = mac80211_hwsim_sta_remove,
.sta_notify = mac80211_hwsim_sta_notify,
.set_tim = mac80211_hwsim_set_tim,
.conf_tx = mac80211_hwsim_conf_tx,

View File

@ -188,10 +188,6 @@ struct mwl8k_priv {
bool sniffer_enabled;
bool wmm_enabled;
struct work_struct sta_notify_worker;
spinlock_t sta_notify_list_lock;
struct list_head sta_notify_list;
/* XXX need to convert this to handle multiple interfaces */
bool capture_beacon;
u8 capture_bssid[ETH_ALEN];
@ -3706,90 +3702,36 @@ static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return mwl8k_cmd_set_rts_threshold(hw, value);
}
struct mwl8k_sta_notify_item
{
struct list_head list;
struct ieee80211_vif *vif;
enum sta_notify_cmd cmd;
struct ieee80211_sta sta;
};
static void
mwl8k_do_sta_notify(struct ieee80211_hw *hw, struct mwl8k_sta_notify_item *s)
static int mwl8k_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mwl8k_priv *priv = hw->priv;
/*
* STA firmware uses UPDATE_STADB, AP firmware uses SET_NEW_STN.
*/
if (!priv->ap_fw && s->cmd == STA_NOTIFY_ADD) {
int rc;
if (priv->ap_fw)
return mwl8k_cmd_set_new_stn_del(hw, vif, sta->addr);
else
return mwl8k_cmd_update_stadb_del(hw, vif, sta->addr);
}
rc = mwl8k_cmd_update_stadb_add(hw, s->vif, &s->sta);
if (rc >= 0) {
struct ieee80211_sta *sta;
static int mwl8k_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mwl8k_priv *priv = hw->priv;
int ret;
rcu_read_lock();
sta = ieee80211_find_sta(s->vif, s->sta.addr);
if (sta != NULL)
MWL8K_STA(sta)->peer_id = rc;
rcu_read_unlock();
if (!priv->ap_fw) {
ret = mwl8k_cmd_update_stadb_add(hw, vif, sta);
if (ret >= 0) {
MWL8K_STA(sta)->peer_id = ret;
return 0;
}
} else if (!priv->ap_fw && s->cmd == STA_NOTIFY_REMOVE) {
mwl8k_cmd_update_stadb_del(hw, s->vif, s->sta.addr);
} else if (priv->ap_fw && s->cmd == STA_NOTIFY_ADD) {
mwl8k_cmd_set_new_stn_add(hw, s->vif, &s->sta);
} else if (priv->ap_fw && s->cmd == STA_NOTIFY_REMOVE) {
mwl8k_cmd_set_new_stn_del(hw, s->vif, s->sta.addr);
return ret;
}
}
static void mwl8k_sta_notify_worker(struct work_struct *work)
{
struct mwl8k_priv *priv =
container_of(work, struct mwl8k_priv, sta_notify_worker);
struct ieee80211_hw *hw = priv->hw;
spin_lock_bh(&priv->sta_notify_list_lock);
while (!list_empty(&priv->sta_notify_list)) {
struct mwl8k_sta_notify_item *s;
s = list_entry(priv->sta_notify_list.next,
struct mwl8k_sta_notify_item, list);
list_del(&s->list);
spin_unlock_bh(&priv->sta_notify_list_lock);
mwl8k_do_sta_notify(hw, s);
kfree(s);
spin_lock_bh(&priv->sta_notify_list_lock);
}
spin_unlock_bh(&priv->sta_notify_list_lock);
}
static void
mwl8k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
{
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_sta_notify_item *s;
if (cmd != STA_NOTIFY_ADD && cmd != STA_NOTIFY_REMOVE)
return;
s = kmalloc(sizeof(*s), GFP_ATOMIC);
if (s != NULL) {
s->vif = vif;
s->cmd = cmd;
s->sta = *sta;
spin_lock(&priv->sta_notify_list_lock);
list_add_tail(&s->list, &priv->sta_notify_list);
spin_unlock(&priv->sta_notify_list_lock);
ieee80211_queue_work(hw, &priv->sta_notify_worker);
}
return mwl8k_cmd_set_new_stn_add(hw, vif, sta);
}
static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
@ -3849,7 +3791,8 @@ static const struct ieee80211_ops mwl8k_ops = {
.prepare_multicast = mwl8k_prepare_multicast,
.configure_filter = mwl8k_configure_filter,
.set_rts_threshold = mwl8k_set_rts_threshold,
.sta_notify = mwl8k_sta_notify,
.sta_add = mwl8k_sta_add,
.sta_remove = mwl8k_sta_remove,
.conf_tx = mwl8k_conf_tx,
.get_stats = mwl8k_get_stats,
.ampdu_action = mwl8k_ampdu_action,
@ -4051,11 +3994,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
priv->radio_on = 0;
priv->radio_short_preamble = 0;
/* Station database handling */
INIT_WORK(&priv->sta_notify_worker, mwl8k_sta_notify_worker);
spin_lock_init(&priv->sta_notify_list_lock);
INIT_LIST_HEAD(&priv->sta_notify_list);
/* Finalize join worker */
INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);

View File

@ -407,7 +407,6 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5),
PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2),
PCMCIA_DEVICE_PROD_ID123("AIRVAST", "IEEE 802.11b Wireless PCMCIA Card", "HFA3863", 0xea569531, 0x4bcb9645, 0x355cb092),
PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f),
PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842),
PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e),
@ -417,7 +416,6 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18),
PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b),
PCMCIA_DEVICE_PROD_ID123("corega", "WL PCCL-11", "ISL37300P", 0x0a21501a, 0x59868926, 0xc9049a39),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae),
@ -432,7 +430,6 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18),
PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77),
PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf),
PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2),
PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92),
PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395),
PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
@ -445,7 +442,6 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767),
PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6),
PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed),
PCMCIA_DEVICE_PROD_ID123("PCMCIA", "11M WLAN Card v2.5", "ISL37300P", 0x281f1c5d, 0x6e440487, 0xc9049a39),
PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264),
PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178),
PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
@ -454,8 +450,11 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757),
PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a),
PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e),
PCMCIA_DEVICE_PROD_ID123("The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", 0xa5f472c2, 0x590eb502, 0xc9049a39),
PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee),
PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);

View File

@ -33,21 +33,29 @@ MODULE_DESCRIPTION("Softmac Prism54 common code");
MODULE_LICENSE("GPL");
MODULE_ALIAS("prism54common");
static int p54_sta_add_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct p54_common *priv = hw->priv;
/*
* Notify the firmware that we don't want or we don't
* need to buffer frames for this station anymore.
*/
p54_sta_unlock(priv, sta->addr);
return 0;
}
static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
enum sta_notify_cmd notify_cmd,
struct ieee80211_sta *sta)
{
struct p54_common *priv = dev->priv;
switch (notify_cmd) {
case STA_NOTIFY_ADD:
case STA_NOTIFY_REMOVE:
/*
* Notify the firmware that we don't want or we don't
* need to buffer frames for this station anymore.
*/
p54_sta_unlock(priv, sta->addr);
break;
switch (notify_cmd) {
case STA_NOTIFY_AWAKE:
/* update the firmware's filter table */
p54_sta_unlock(priv, sta->addr);
@ -506,6 +514,8 @@ static const struct ieee80211_ops p54_ops = {
.remove_interface = p54_remove_interface,
.set_tim = p54_set_tim,
.sta_notify = p54_sta_notify,
.sta_add = p54_sta_add_remove,
.sta_remove = p54_sta_add_remove,
.set_key = p54_set_key,
.config = p54_config,
.bss_info_changed = p54_bss_info_changed,

View File

@ -36,6 +36,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
/* Version 1 devices (pci chip + net2280) */
{USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
{USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
{USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */
{USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
{USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
{USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
@ -60,6 +61,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
{USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
{USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
{USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
{USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
{USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
{USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */

View File

@ -186,7 +186,7 @@ static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
struct p54_tx_queue_stats *queue;
unsigned long flags;
if (WARN_ON(p54_queue > P54_QUEUE_NUM))
if (WARN_ON(p54_queue >= P54_QUEUE_NUM))
return -EINVAL;
queue = &priv->tx_stats[p54_queue];

View File

@ -64,7 +64,7 @@ config RT2800PCI_SOC
default y
config RT2800PCI
tristate "Ralink rt2800 (PCI/PCMCIA) support (VERY EXPERIMENTAL)"
tristate "Ralink rt28xx/rt30xx/rt35xx (PCI/PCIe/PCMCIA) support (EXPERIMENTAL)"
depends on (RT2800PCI_PCI || RT2800PCI_SOC) && EXPERIMENTAL
select RT2800_LIB
select RT2X00_LIB_PCI if RT2800PCI_PCI
@ -75,7 +75,7 @@ config RT2800PCI
select CRC_CCITT
select EEPROM_93CX6
---help---
This adds support for rt2800 wireless chipset family.
This adds support for rt2800/rt3000/rt3500 wireless chipset family.
Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890 & RT3052
This driver is non-functional at the moment and is intended for
@ -83,6 +83,32 @@ config RT2800PCI
When compiled as a module, this driver will be called "rt2800pci.ko".
if RT2800PCI
config RT2800PCI_RT30XX
bool "rt2800pci - Include support for rt30xx (PCI/PCIe/PCMCIA) devices"
default n
---help---
This adds support for rt30xx wireless chipset family to the
rt2800pci driver.
Supported chips: RT3090, RT3091 & RT3092
Support for these devices is non-functional at the moment and is
intended for testers and developers.
config RT2800PCI_RT35XX
bool "rt2800pci - Include support for rt35xx (PCI/PCIe/PCMCIA) devices"
default n
---help---
This adds support for rt35xx wireless chipset family to the
rt2800pci driver.
Supported chips: RT3060, RT3062, RT3562, RT3592
Support for these devices is non-functional at the moment and is
intended for testers and developers.
endif
config RT2500USB
tristate "Ralink rt2500 (USB) support"
depends on USB
@ -126,6 +152,43 @@ config RT2800USB
When compiled as a module, this driver will be called "rt2800usb.ko".
if RT2800USB
config RT2800USB_RT30XX
bool "rt2800usb - Include support for rt30xx (USB) devices"
default n
---help---
This adds support for rt30xx wireless chipset family to the
rt2800usb driver.
Supported chips: RT3070, RT3071 & RT3072
Support for these devices is non-functional at the moment and is
intended for testers and developers.
config RT2800USB_RT35XX
bool "rt2800usb - Include support for rt35xx (USB) devices"
default n
---help---
This adds support for rt35xx wireless chipset family to the
rt2800usb driver.
Supported chips: RT3572
Support for these devices is non-functional at the moment and is
intended for testers and developers.
config RT2800USB_UNKNOWN
bool "rt2800usb - Include support for unknown (USB) devices"
default n
---help---
This adds support for rt2800 family devices that are known to
have a rt2800 family chipset, but for which the exact chipset
is unknown.
Support status for these devices is unknown, and enabling these
devices may or may not work.
endif
config RT2800_LIB
tristate

View File

@ -1340,8 +1340,8 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
rt2x00_set_chip_rf(rt2x00dev, value, reg);
rt2x00_print_chip(rt2x00dev);
rt2x00_set_chip(rt2x00dev, RT2460, value,
rt2x00_get_field32(reg, CSR0_REVISION));
if (!rt2x00_rf(rt2x00dev, RF2420) && !rt2x00_rf(rt2x00dev, RF2421)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");

View File

@ -65,6 +65,7 @@
* CSR0: ASIC revision number.
*/
#define CSR0 0x0000
#define CSR0_REVISION FIELD32(0x0000ffff)
/*
* CSR1: System control register.

View File

@ -1503,8 +1503,8 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
rt2x00_set_chip_rf(rt2x00dev, value, reg);
rt2x00_print_chip(rt2x00dev);
rt2x00_set_chip(rt2x00dev, RT2560, value,
rt2x00_get_field32(reg, CSR0_REVISION));
if (!rt2x00_rf(rt2x00dev, RF2522) &&
!rt2x00_rf(rt2x00dev, RF2523) &&

View File

@ -76,6 +76,7 @@
* CSR0: ASIC revision number.
*/
#define CSR0 0x0000
#define CSR0_REVISION FIELD32(0x0000ffff)
/*
* CSR1: System control register.

View File

@ -1408,10 +1408,8 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2500usb_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0) ||
rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) {
if (((reg & 0xfff0) != 0) || ((reg & 0x0000000f) == 0)) {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}

View File

@ -60,11 +60,11 @@
/*
* Chipset version.
*/
#define RT2860C_VERSION 0x28600100
#define RT2860D_VERSION 0x28600101
#define RT2880E_VERSION 0x28720200
#define RT2883_VERSION 0x28830300
#define RT3070_VERSION 0x30700200
#define RT2860C_VERSION 0x0100
#define RT2860D_VERSION 0x0101
#define RT2880E_VERSION 0x0200
#define RT2883_VERSION 0x0300
#define RT3070_VERSION 0x0200
/*
* Signal information.
@ -408,8 +408,8 @@
* ASIC_VER: 2860 or 2870
*/
#define MAC_CSR0 0x1000
#define MAC_CSR0_ASIC_REV FIELD32(0x0000ffff)
#define MAC_CSR0_ASIC_VER FIELD32(0xffff0000)
#define MAC_CSR0_REVISION FIELD32(0x0000ffff)
#define MAC_CSR0_CHIPSET FIELD32(0xffff0000)
/*
* MAC_SYS_CTRL:

View File

@ -40,6 +40,9 @@
#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"
@ -89,7 +92,7 @@ static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 0);
if (rt2x00_intf_is_pci(rt2x00dev))
if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
@ -118,7 +121,7 @@ static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 1);
if (rt2x00_intf_is_pci(rt2x00dev))
if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
@ -218,9 +221,9 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
u32 reg;
/*
* RT2880 and RT3052 don't support MCU requests.
* SOC devices don't support MCU requests.
*/
if (rt2x00_rt(rt2x00dev, RT2880) || rt2x00_rt(rt2x00dev, RT3052))
if (rt2x00_is_soc(rt2x00dev))
return;
mutex_lock(&rt2x00dev->csr_mutex);
@ -660,7 +663,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
switch ((int)ant->tx) {
case 1:
rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
if (rt2x00_intf_is_pci(rt2x00dev))
if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
break;
case 2:
@ -895,7 +898,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf));
rt2800_bbp_write(rt2x00dev, 3, bbp);
if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) {
if (rt2x00_rt(rt2x00dev, RT2860) &&
(rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) {
if (conf_is_ht40(conf)) {
rt2800_bbp_write(rt2x00dev, 69, 0x1a);
rt2800_bbp_write(rt2x00dev, 70, 0x0a);
@ -1057,8 +1061,9 @@ EXPORT_SYMBOL_GPL(rt2800_link_stats);
static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
if (rt2x00_intf_is_usb(rt2x00dev) &&
rt2x00_rev(rt2x00dev) == RT3070_VERSION)
if (rt2x00_is_usb(rt2x00dev) &&
rt2x00_rt(rt2x00dev, RT3070) &&
(rt2x00_rev(rt2x00dev) == RT3070_VERSION))
return 0x1c + (2 * rt2x00dev->lna_gain);
else
return 0x2e + rt2x00dev->lna_gain;
@ -1089,7 +1094,8 @@ EXPORT_SYMBOL_GPL(rt2800_reset_tuner);
void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
const u32 count)
{
if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)
if (rt2x00_rt(rt2x00dev, RT2860) &&
(rt2x00_rev(rt2x00dev) == RT2860C_VERSION))
return;
/*
@ -1109,7 +1115,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
u32 reg;
unsigned int i;
if (rt2x00_intf_is_usb(rt2x00dev)) {
if (rt2x00_is_usb(rt2x00dev)) {
/*
* Wait until BBP and RF are ready.
*/
@ -1128,7 +1134,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL,
reg & ~0x00002000);
} else if (rt2x00_intf_is_pci(rt2x00dev))
} else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
@ -1136,7 +1142,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
if (rt2x00_intf_is_usb(rt2x00dev)) {
if (rt2x00_is_usb(rt2x00dev)) {
rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
@ -1174,8 +1180,9 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0);
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
if (rt2x00_intf_is_usb(rt2x00dev) &&
rt2x00_rev(rt2x00dev) == RT3070_VERSION) {
if (rt2x00_is_usb(rt2x00dev) &&
rt2x00_rt(rt2x00dev, RT3070) &&
(rt2x00_rev(rt2x00dev) == RT3070_VERSION)) {
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
@ -1202,8 +1209,14 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, MAX_LEN_CFG, &reg);
rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE);
if (rt2x00_rev(rt2x00dev) >= RT2880E_VERSION &&
rt2x00_rev(rt2x00dev) < RT3070_VERSION)
if ((rt2x00_rt(rt2x00dev, RT2872) &&
(rt2x00_rev(rt2x00dev) >= RT2880E_VERSION)) ||
rt2x00_rt(rt2x00dev, RT2880) ||
rt2x00_rt(rt2x00dev, RT2883) ||
rt2x00_rt(rt2x00dev, RT2890) ||
rt2x00_rt(rt2x00dev, RT3052) ||
(rt2x00_rt(rt2x00dev, RT3070) &&
(rt2x00_rev(rt2x00dev) < RT3070_VERSION)))
rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 2);
else
rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
@ -1293,7 +1306,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1);
rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg);
if (rt2x00_intf_is_usb(rt2x00dev)) {
if (rt2x00_is_usb(rt2x00dev)) {
rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006);
rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
@ -1353,7 +1366,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0);
rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0);
if (rt2x00_intf_is_usb(rt2x00dev)) {
if (rt2x00_is_usb(rt2x00dev)) {
rt2800_register_read(rt2x00dev, USB_CYC_CFG, &reg);
rt2x00_set_field32(&reg, USB_CYC_CFG_CLOCK_CYCLE, 30);
rt2800_register_write(rt2x00dev, USB_CYC_CFG, reg);
@ -1482,16 +1495,19 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
rt2800_bbp_write(rt2x00dev, 103, 0x00);
rt2800_bbp_write(rt2x00dev, 105, 0x05);
if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) {
if (rt2x00_rt(rt2x00dev, RT2860) &&
(rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) {
rt2800_bbp_write(rt2x00dev, 69, 0x16);
rt2800_bbp_write(rt2x00dev, 73, 0x12);
}
if (rt2x00_rev(rt2x00dev) > RT2860D_VERSION)
if (rt2x00_rt(rt2x00dev, RT2860) &&
(rt2x00_rev(rt2x00dev) > RT2860D_VERSION))
rt2800_bbp_write(rt2x00dev, 84, 0x19);
if (rt2x00_intf_is_usb(rt2x00dev) &&
rt2x00_rev(rt2x00dev) == RT3070_VERSION) {
if (rt2x00_is_usb(rt2x00dev) &&
rt2x00_rt(rt2x00dev, RT3070) &&
(rt2x00_rev(rt2x00dev) == RT3070_VERSION)) {
rt2800_bbp_write(rt2x00dev, 70, 0x0a);
rt2800_bbp_write(rt2x00dev, 84, 0x99);
rt2800_bbp_write(rt2x00dev, 105, 0x05);
@ -1582,11 +1598,12 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
u8 rfcsr;
u8 bbp;
if (rt2x00_intf_is_usb(rt2x00dev) &&
rt2x00_rev(rt2x00dev) != RT3070_VERSION)
if (rt2x00_is_usb(rt2x00dev) &&
rt2x00_rt(rt2x00dev, RT3070) &&
(rt2x00_rev(rt2x00dev) != RT3070_VERSION))
return 0;
if (rt2x00_intf_is_pci(rt2x00dev)) {
if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
if (!rt2x00_rf(rt2x00dev, RF3020) &&
!rt2x00_rf(rt2x00dev, RF3021) &&
!rt2x00_rf(rt2x00dev, RF3022))
@ -1603,7 +1620,7 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0);
rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
if (rt2x00_intf_is_usb(rt2x00dev)) {
if (rt2x00_is_usb(rt2x00dev)) {
rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
@ -1624,7 +1641,7 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
} else if (rt2x00_intf_is_pci(rt2x00dev)) {
} else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
@ -1754,7 +1771,12 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
} else if (rt2x00_rev(rt2x00dev) < RT2883_VERSION) {
} else if (rt2x00_rt(rt2x00dev, RT2860) ||
rt2x00_rt(rt2x00dev, RT2870) ||
rt2x00_rt(rt2x00dev, RT2872) ||
rt2x00_rt(rt2x00dev, RT2880) ||
(rt2x00_rt(rt2x00dev, RT2883) &&
(rt2x00_rev(rt2x00dev) < RT2883_VERSION))) {
/*
* There is a max of 2 RX streams for RT28x0 series
*/
@ -1853,25 +1875,24 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip_rf(rt2x00dev, value, reg);
rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
if (rt2x00_intf_is_usb(rt2x00dev)) {
/*
* The check for rt2860 is not a typo, some rt2870 hardware
* identifies itself as rt2860 in the CSR register.
*/
if (rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28600000) ||
rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28700000) ||
rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28800000)) {
rt2x00_set_chip_rt(rt2x00dev, RT2870);
} else if (rt2x00_check_rev(rt2x00dev, 0xffff0000, 0x30700000)) {
rt2x00_set_chip_rt(rt2x00dev, RT3070);
} else {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}
if (!rt2x00_rt(rt2x00dev, RT2860) &&
!rt2x00_rt(rt2x00dev, RT2870) &&
!rt2x00_rt(rt2x00dev, RT2872) &&
!rt2x00_rt(rt2x00dev, RT2880) &&
!rt2x00_rt(rt2x00dev, RT2883) &&
!rt2x00_rt(rt2x00dev, RT2890) &&
!rt2x00_rt(rt2x00dev, RT3052) &&
!rt2x00_rt(rt2x00dev, RT3070) &&
!rt2x00_rt(rt2x00dev, RT3071) &&
!rt2x00_rt(rt2x00dev, RT3090) &&
!rt2x00_rt(rt2x00dev, RT3390) &&
!rt2x00_rt(rt2x00dev, RT3572)) {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_rf(rt2x00dev, RF2820) &&
!rt2x00_rf(rt2x00dev, RF2850) &&
@ -2039,7 +2060,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Disable powersaving as default on PCI devices.
*/
if (rt2x00_intf_is_pci(rt2x00dev))
if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
/*

View File

@ -1041,18 +1041,12 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Read EEPROM into buffer
*/
switch (rt2x00dev->chip.rt) {
case RT2880:
case RT3052:
if (rt2x00_is_soc(rt2x00dev))
rt2800pci_read_eeprom_soc(rt2x00dev);
break;
default:
if (rt2800pci_efuse_detect(rt2x00dev))
rt2800pci_read_eeprom_efuse(rt2x00dev);
else
rt2800pci_read_eeprom_pci(rt2x00dev);
break;
}
else if (rt2800pci_efuse_detect(rt2x00dev))
rt2800pci_read_eeprom_efuse(rt2x00dev);
else
rt2800pci_read_eeprom_pci(rt2x00dev);
return rt2800_validate_eeprom(rt2x00dev);
}
@ -1103,7 +1097,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* This device requires firmware.
*/
if (!rt2x00_rt(rt2x00dev, RT2880) && !rt2x00_rt(rt2x00dev, RT3052))
if (!rt2x00_is_soc(rt2x00dev))
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
@ -1191,7 +1185,10 @@ static const struct rt2x00_ops rt2800pci_ops = {
* RT2800pci module information.
*/
static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
{ PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) },
@ -1199,18 +1196,19 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
{ PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) },
#ifdef CONFIG_RT2800PCI_RT30XX
{ PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) },
#endif
#ifdef CONFIG_RT2800PCI_RT35XX
{ PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) },
#endif
{ 0, }
};
@ -1225,11 +1223,10 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);
MODULE_LICENSE("GPL");
#ifdef CONFIG_RT2800PCI_SOC
#if defined(CONFIG_RALINK_RT288X)
__rt2x00soc_probe(RT2880, &rt2800pci_ops);
#elif defined(CONFIG_RALINK_RT305X)
__rt2x00soc_probe(RT3052, &rt2800pci_ops);
#endif
static int rt2800soc_probe(struct platform_device *pdev)
{
return rt2x00soc_probe(pdev, rt2800pci_ops);
}
static struct platform_driver rt2800soc_driver = {
.driver = {
@ -1237,7 +1234,7 @@ static struct platform_driver rt2800soc_driver = {
.owner = THIS_MODULE,
.mod_name = KBUILD_MODNAME,
},
.probe = __rt2x00soc_probe,
.probe = rt2800soc_probe,
.remove = __devexit_p(rt2x00soc_remove),
.suspend = rt2x00soc_suspend,
.resume = rt2x00soc_resume,

View File

@ -92,7 +92,6 @@ static bool rt2800usb_check_crc(const u8 *data, const size_t len)
static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff;
size_t offset = 0;
/*
@ -111,9 +110,9 @@ static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev,
* Check if we need the upper 4kb firmware data or not.
*/
if ((len == 4096) &&
(chipset != 0x2860) &&
(chipset != 0x2872) &&
(chipset != 0x3070))
!rt2x00_rt(rt2x00dev, RT2860) &&
!rt2x00_rt(rt2x00dev, RT2872) &&
!rt2x00_rt(rt2x00dev, RT3070))
return FW_BAD_VERSION;
/*
@ -138,14 +137,13 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
u32 reg;
u32 offset;
u32 length;
u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff;
/*
* Check which section of the firmware we need.
*/
if ((chipset == 0x2860) ||
(chipset == 0x2872) ||
(chipset == 0x3070)) {
if (rt2x00_rt(rt2x00dev, RT2860) ||
rt2x00_rt(rt2x00dev, RT2872) ||
rt2x00_rt(rt2x00dev, RT3070)) {
offset = 0;
length = 4096;
} else {
@ -200,9 +198,9 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
*/
rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0);
if ((chipset == 0x3070) ||
(chipset == 0x3071) ||
(chipset == 0x3572)) {
if (rt2x00_rt(rt2x00dev, RT3070) ||
rt2x00_rt(rt2x00dev, RT3071) ||
rt2x00_rt(rt2x00dev, RT3572)) {
udelay(200);
rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0);
udelay(10);
@ -807,51 +805,27 @@ static struct usb_device_id rt2800usb_device_table[] = {
/* Abocom */
{ USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
/* AirTies */
{ USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Amigo */
{ USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Amit */
{ USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Askey */
{ USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) },
/* ASUS */
{ USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
/* AzureWave */
{ USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Belkin */
{ USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Buffalo */
{ USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Cisco */
{ USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Conceptronic */
{ USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) },
@ -860,103 +834,38 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
/* D-Link */
{ USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Edimax */
{ USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Encore */
{ USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
/* EnGenius */
{ USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Gemtek */
{ USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Gigabyte */
{ USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Hawking */
{ USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
/* I-O DATA */
{ USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
/* LevelOne */
{ USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Linksys */
{ USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Logitec */
{ USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Motorola */
{ USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) },
/* MSI */
{ USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Ovislink */
{ USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Para */
{ USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Pegatron */
{ USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Philips */
{ USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Planex */
{ USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Qcom */
{ USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Quanta */
{ USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Ralink */
{ USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Samsung */
{ USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Siemens */
@ -967,36 +876,18 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x004a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x004d), USB_DEVICE_DATA(&rt2800usb_ops) },
/* SMC */
{ USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Sparklan */
{ USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Sweex */
{ USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) },
/* U-Media*/
{ USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) },
/* ZCOM */
@ -1005,12 +896,195 @@ static struct usb_device_id rt2800usb_device_table[] = {
/* Zinwell */
{ USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Zyxel */
{ USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
#ifdef CONFIG_RT2800USB_RT30XX
/* Abocom */
{ USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
/* AirTies */
{ USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) },
/* AzureWave */
{ USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Conceptronic */
{ USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Corega */
{ USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
/* D-Link */
{ USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Edimax */
{ USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Encore */
{ USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
/* EnGenius */
{ USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Gigabyte */
{ USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) },
/* I-O DATA */
{ USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
/* MSI */
{ USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Pegatron */
{ USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Planex */
{ USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Quanta */
{ USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Ralink */
{ USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Sitecom */
{ USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
/* SMC */
{ USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Zinwell */
{ USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
#endif
#ifdef CONFIG_RT2800USB_RT35XX
/* Askey */
{ USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Cisco */
{ USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) },
/* EnGenius */
{ USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) },
/* I-O DATA */
{ USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Ralink */
{ USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Sitecom */
{ USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Zinwell */
{ USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
#endif
#ifdef CONFIG_RT2800USB_UNKNOWN
/*
* Unclear what kind of devices these are (they aren't supported by the
* vendor driver).
*/
/* Allwin */
{ USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Amigo */
{ USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Askey */
{ USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) },
/* ASUS */
{ USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) },
/* AzureWave */
{ USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Belkin */
{ USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Buffalo */
{ USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0411, 0x0148), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0411, 0x0150), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0411, 0x015d), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Conceptronic */
{ USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Corega */
{ USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
/* D-Link */
{ USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Encore */
{ USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
/* EnGenius */
{ USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Gemtek */
{ USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Gigabyte */
{ USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Hawking */
{ USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
/* I-O DATA */
{ USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
/* LevelOne */
{ USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Linksys */
{ USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1737, 0x0078), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Motorola */
{ USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) },
/* MSI */
{ USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Ovislink */
{ USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Para */
{ USB_DEVICE(0x20b8, 0x8888), 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) },
/* Planex */
{ USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Qcom */
{ USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Sitecom */
{ USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x004a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x004d), USB_DEVICE_DATA(&rt2800usb_ops) },
/* SMC */
{ USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xd522), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Sweex */
{ USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Zyxel */
{ USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) },
#endif
{ 0, }
};

View File

@ -160,6 +160,7 @@ struct avg_val {
enum rt2x00_chip_intf {
RT2X00_CHIP_INTF_PCI,
RT2X00_CHIP_INTF_USB,
RT2X00_CHIP_INTF_SOC,
};
/*
@ -169,25 +170,26 @@ enum rt2x00_chip_intf {
*/
struct rt2x00_chip {
u16 rt;
#define RT2460 0x0101
#define RT2560 0x0201
#define RT2570 0x1201
#define RT2561s 0x0301 /* Turbo */
#define RT2561 0x0302
#define RT2661 0x0401
#define RT2571 0x1300
#define RT2860 0x0601 /* 2.4GHz PCI/CB */
#define RT2860D 0x0681 /* 2.4GHz, 5GHz PCI/CB */
#define RT2890 0x0701 /* 2.4GHz PCIe */
#define RT2890D 0x0781 /* 2.4GHz, 5GHz PCIe */
#define RT2460 0x2460
#define RT2560 0x2560
#define RT2570 0x2570
#define RT2661 0x2661
#define RT2573 0x2573
#define RT2860 0x2860 /* 2.4GHz PCI/CB */
#define RT2870 0x2870
#define RT2872 0x2872
#define RT2880 0x2880 /* WSOC */
#define RT2883 0x2883 /* WSOC */
#define RT2890 0x2890 /* 2.4GHz PCIe */
#define RT3052 0x3052 /* WSOC */
#define RT3070 0x3070
#define RT3071 0x3071
#define RT3090 0x3090 /* 2.4GHz PCIe */
#define RT2870 0x1600
#define RT3070 0x1800
#define RT3390 0x3390
#define RT3572 0x3572
u16 rf;
u32 rev;
u16 rev;
enum rt2x00_chip_intf intf;
};
@ -917,29 +919,14 @@ static inline void rt2x00_eeprom_write(struct rt2x00_dev *rt2x00dev,
* Chipset handlers
*/
static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev,
const u16 rt, const u16 rf, const u32 rev)
const u16 rt, const u16 rf, const u16 rev)
{
rt2x00dev->chip.rt = rt;
rt2x00dev->chip.rf = rf;
rt2x00dev->chip.rev = rev;
}
static inline void rt2x00_set_chip_rt(struct rt2x00_dev *rt2x00dev,
const u16 rt)
{
rt2x00dev->chip.rt = rt;
}
static inline void rt2x00_set_chip_rf(struct rt2x00_dev *rt2x00dev,
const u16 rf, const u32 rev)
{
rt2x00_set_chip(rt2x00dev, rt2x00dev->chip.rt, rf, rev);
}
static inline void rt2x00_print_chip(struct rt2x00_dev *rt2x00dev)
{
INFO(rt2x00dev,
"Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n",
"Chipset detected - rt: %04x, rf: %04x, rev: %04x.\n",
rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev);
}
@ -953,17 +940,11 @@ static inline char rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf)
return (rt2x00dev->chip.rf == rf);
}
static inline u32 rt2x00_rev(struct rt2x00_dev *rt2x00dev)
static inline u16 rt2x00_rev(struct rt2x00_dev *rt2x00dev)
{
return rt2x00dev->chip.rev;
}
static inline bool rt2x00_check_rev(struct rt2x00_dev *rt2x00dev,
const u32 mask, const u32 rev)
{
return ((rt2x00dev->chip.rev & mask) == rev);
}
static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev,
enum rt2x00_chip_intf intf)
{
@ -976,16 +957,21 @@ static inline bool rt2x00_intf(struct rt2x00_dev *rt2x00dev,
return (rt2x00dev->chip.intf == intf);
}
static inline bool rt2x00_intf_is_pci(struct rt2x00_dev *rt2x00dev)
static inline bool rt2x00_is_pci(struct rt2x00_dev *rt2x00dev)
{
return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
}
static inline bool rt2x00_intf_is_usb(struct rt2x00_dev *rt2x00dev)
static inline bool rt2x00_is_usb(struct rt2x00_dev *rt2x00dev)
{
return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
}
static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev)
{
return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC);
}
/**
* rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
* @rt2x00dev: Pointer to &struct rt2x00_dev.

View File

@ -184,7 +184,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
dump_hdr->data_length = cpu_to_le32(skb->len);
dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev);
dump_hdr->chip_rev = cpu_to_le16(rt2x00dev->chip.rev);
dump_hdr->type = cpu_to_le16(type);
dump_hdr->queue_index = desc->entry->queue->qid;
dump_hdr->entry_index = desc->entry->entry_idx;
@ -573,7 +573,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
blob->data = data;
data += sprintf(data, "rt chip:\t%04x\n", intf->rt2x00dev->chip.rt);
data += sprintf(data, "rf chip:\t%04x\n", intf->rt2x00dev->chip.rf);
data += sprintf(data, "revision:\t%08x\n", intf->rt2x00dev->chip.rev);
data += sprintf(data, "revision:\t%04x\n", intf->rt2x00dev->chip.rev);
data += sprintf(data, "\n");
data += sprintf(data, "register\tbase\twords\twordsize\n");
data += sprintf(data, "csr\t%d\t%d\t%d\n",

View File

@ -272,7 +272,6 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
int retval;
u16 chip;
retval = pci_request_regions(pci_dev, pci_name(pci_dev));
if (retval) {
@ -315,12 +314,6 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
/*
* Determine RT chipset by reading PCI header.
*/
pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip);
rt2x00_set_chip_rt(rt2x00dev, chip);
retval = rt2x00pci_alloc_reg(rt2x00dev);
if (retval)
goto exit_free_device;

View File

@ -27,6 +27,7 @@
#define RT2X00PCI_H
#include <linux/io.h>
#include <linux/pci.h>
/*
* This variable should be used with the

View File

@ -71,9 +71,7 @@ exit:
return -ENOMEM;
}
int rt2x00soc_probe(struct platform_device *pdev,
const unsigned short chipset,
const struct rt2x00_ops *ops)
int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops)
{
struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
@ -94,12 +92,7 @@ int rt2x00soc_probe(struct platform_device *pdev,
rt2x00dev->irq = platform_get_irq(pdev, 0);
rt2x00dev->name = pdev->dev.driver->name;
/*
* SoC devices mimic PCI behavior.
*/
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
rt2x00_set_chip_rt(rt2x00dev, chipset);
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC);
retval = rt2x00soc_alloc_reg(rt2x00dev);
if (retval)

View File

@ -28,18 +28,10 @@
#define KSEG1ADDR(__ptr) __ptr
#define __rt2x00soc_probe(__chipset, __ops) \
static int __rt2x00soc_probe(struct platform_device *pdev) \
{ \
return rt2x00soc_probe(pdev, (__chipset), (__ops)); \
}
/*
* SoC driver handlers.
*/
int rt2x00soc_probe(struct platform_device *pdev,
const unsigned short chipset,
const struct rt2x00_ops *ops);
int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops);
int rt2x00soc_remove(struct platform_device *pdev);
#ifdef CONFIG_PM
int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state);

View File

@ -1131,16 +1131,18 @@ dynamic_cca_tune:
*/
static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
{
u16 chip;
char *fw_name;
switch (rt2x00dev->chip.rt) {
case RT2561:
pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip);
switch (chip) {
case RT2561_PCI_ID:
fw_name = FIRMWARE_RT2561;
break;
case RT2561s:
case RT2561s_PCI_ID:
fw_name = FIRMWARE_RT2561s;
break;
case RT2661:
case RT2661_PCI_ID:
fw_name = FIRMWARE_RT2661;
break;
default:
@ -2295,8 +2297,8 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip_rf(rt2x00dev, value, reg);
rt2x00_print_chip(rt2x00dev);
rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
if (!rt2x00_rf(rt2x00dev, RF5225) &&
!rt2x00_rf(rt2x00dev, RF5325) &&

View File

@ -27,6 +27,13 @@
#ifndef RT61PCI_H
#define RT61PCI_H
/*
* RT chip PCI IDs.
*/
#define RT2561s_PCI_ID 0x0301
#define RT2561_PCI_ID 0x0302
#define RT2661_PCI_ID 0x0401
/*
* RF chip defines.
*/
@ -225,6 +232,8 @@ struct hw_pairwise_ta_entry {
* MAC_CSR0: ASIC revision number.
*/
#define MAC_CSR0 0x3000
#define MAC_CSR0_REVISION FIELD32(0x0000000f)
#define MAC_CSR0_CHIPSET FIELD32(0x000ffff0)
/*
* MAC_CSR1: System control register.

View File

@ -1820,11 +1820,10 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
rt2x00_print_chip(rt2x00dev);
rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0x25730) ||
rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) {
if (!rt2x00_rt(rt2x00dev, RT2573) || (rt2x00_rev(rt2x00dev) == 0)) {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}

View File

@ -142,6 +142,8 @@ struct hw_pairwise_ta_entry {
* MAC_CSR0: ASIC revision number.
*/
#define MAC_CSR0 0x3000
#define MAC_CSR0_REVISION FIELD32(0x0000000f)
#define MAC_CSR0_CHIPSET FIELD32(0x000ffff0)
/*
* MAC_CSR1: System control register.

View File

@ -241,5 +241,5 @@ void rtl8187_leds_exit(struct ieee80211_hw *dev)
cancel_delayed_work_sync(&priv->led_off);
cancel_delayed_work_sync(&priv->led_on);
}
#endif /* def CONFIG_RTL8187_LED */
#endif /* def CONFIG_RTL8187_LEDS */

View File

@ -54,6 +54,6 @@ struct rtl8187_led {
void rtl8187_leds_init(struct ieee80211_hw *dev, u16 code);
void rtl8187_leds_exit(struct ieee80211_hw *dev);
#endif /* def CONFIG_RTL8187_LED */
#endif /* def CONFIG_RTL8187_LEDS */
#endif /* RTL8187_LED_H */

View File

@ -10,5 +10,7 @@ obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o
wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \
wl1271_event.o wl1271_tx.o wl1271_rx.o \
wl1271_ps.o wl1271_acx.o wl1271_boot.o \
wl1271_init.o wl1271_debugfs.o
wl1271_init.o wl1271_debugfs.o wl1271_io.o
wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o
obj-$(CONFIG_WL1271) += wl1271.o

View File

@ -43,7 +43,7 @@ enum {
DEBUG_SPI = BIT(1),
DEBUG_BOOT = BIT(2),
DEBUG_MAILBOX = BIT(3),
DEBUG_NETLINK = BIT(4),
DEBUG_TESTMODE = BIT(4),
DEBUG_EVENT = BIT(5),
DEBUG_TX = BIT(6),
DEBUG_RX = BIT(7),
@ -109,7 +109,33 @@ enum {
#define WL1271_FW_NAME "wl1271-fw.bin"
#define WL1271_NVS_NAME "wl1271-nvs.bin"
#define WL1271_NVS_LEN 468
/* NVS data structure */
#define WL1271_NVS_SECTION_SIZE 468
#define WL1271_NVS_GENERAL_PARAMS_SIZE 57
#define WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED \
(WL1271_NVS_GENERAL_PARAMS_SIZE + 1)
#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE 17
#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED \
(WL1271_NVS_STAT_RADIO_PARAMS_SIZE + 1)
#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE 65
#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED \
(WL1271_NVS_DYN_RADIO_PARAMS_SIZE + 1)
#define WL1271_NVS_FEM_COUNT 2
#define WL1271_NVS_INI_SPARE_SIZE 124
struct wl1271_nvs_file {
/* NVS section */
u8 nvs[WL1271_NVS_SECTION_SIZE];
/* INI section */
u8 general_params[WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED];
u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED];
u8 dyn_radio_params[WL1271_NVS_FEM_COUNT]
[WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED];
u8 ini_spare[WL1271_NVS_INI_SPARE_SIZE];
} __attribute__ ((packed));
/*
* Enable/disable 802.11a support for WL1273
@ -342,8 +368,7 @@ struct wl1271 {
u8 *fw;
size_t fw_len;
u8 *nvs;
size_t nvs_len;
struct wl1271_nvs_file *nvs;
u8 bssid[ETH_ALEN];
u8 mac_addr[ETH_ALEN];
@ -461,6 +486,7 @@ int wl1271_plt_stop(struct wl1271 *wl);
static inline bool wl1271_11a_enabled(void)
{
/* FIXME: this could be determined based on the NVS-INI file */
#ifdef WL1271_80211A_ENABLED
return true;
#else

View File

@ -830,12 +830,14 @@ out:
return ret;
}
int wl1271_acx_ac_cfg(struct wl1271 *wl)
int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
u8 aifsn, u16 txop)
{
struct acx_ac_cfg *acx;
int i, ret = 0;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx access category config");
wl1271_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d "
"aifs %d txop %d", ac, cw_min, cw_max, aifsn, txop);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
@ -844,21 +846,16 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl)
goto out;
}
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
struct conf_tx_ac_category *c = &(wl->conf.tx.ac_conf[i]);
acx->ac = c->ac;
acx->cw_min = c->cw_min;
acx->cw_max = cpu_to_le16(c->cw_max);
acx->aifsn = c->aifsn;
acx->reserved = 0;
acx->tx_op_limit = cpu_to_le16(c->tx_op_limit);
acx->ac = ac;
acx->cw_min = cw_min;
acx->cw_max = cpu_to_le16(cw_max);
acx->aifsn = aifsn;
acx->tx_op_limit = cpu_to_le16(txop);
ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of access category "
"config: %d", ret);
goto out;
}
ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx ac cfg failed: %d", ret);
goto out;
}
out:
@ -866,10 +863,12 @@ out:
return ret;
}
int wl1271_acx_tid_cfg(struct wl1271 *wl)
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
u8 tsid, u8 ps_scheme, u8 ack_policy,
u32 apsd_conf0, u32 apsd_conf1)
{
struct acx_tid_config *acx;
int i, ret = 0;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx tid config");
@ -880,21 +879,18 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl)
goto out;
}
for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
struct conf_tx_tid *c = &(wl->conf.tx.tid_conf[i]);
acx->queue_id = c->queue_id;
acx->channel_type = c->channel_type;
acx->tsid = c->tsid;
acx->ps_scheme = c->ps_scheme;
acx->ack_policy = c->ack_policy;
acx->apsd_conf[0] = cpu_to_le32(c->apsd_conf[0]);
acx->apsd_conf[1] = cpu_to_le32(c->apsd_conf[1]);
acx->queue_id = queue_id;
acx->channel_type = channel_type;
acx->tsid = tsid;
acx->ps_scheme = ps_scheme;
acx->ack_policy = ack_policy;
acx->apsd_conf[0] = cpu_to_le32(apsd_conf0);
acx->apsd_conf[1] = cpu_to_le32(apsd_conf1);
ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of tid config failed: %d", ret);
goto out;
}
ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of tid config failed: %d", ret);
goto out;
}
out:

View File

@ -2,7 +2,7 @@
* This file is part of wl1271
*
* Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
* Copyright (C) 2008-2009 Nokia Corporation
* Copyright (C) 2008-2010 Nokia Corporation
*
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
@ -348,7 +348,7 @@ struct acx_beacon_filter_option {
* ACXBeaconFilterEntry (not 221)
* Byte Offset Size (Bytes) Definition
* =========== ============ ==========
* 0 1 IE identifier
* 0 1 IE identifier
* 1 1 Treatment bit mask
*
* ACXBeaconFilterEntry (221)
@ -381,8 +381,8 @@ struct acx_beacon_filter_ie_table {
struct acx_header header;
u8 num_ie;
u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
u8 pad[3];
u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
} __attribute__ ((packed));
struct acx_conn_monit_params {
@ -1070,8 +1070,11 @@ int wl1271_acx_cts_protect(struct wl1271 *wl,
enum acx_ctsprotect_type ctsprotect);
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
int wl1271_acx_rate_policies(struct wl1271 *wl);
int wl1271_acx_ac_cfg(struct wl1271 *wl);
int wl1271_acx_tid_cfg(struct wl1271 *wl);
int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
u8 aifsn, u16 txop);
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
u8 tsid, u8 ps_scheme, u8 ack_policy,
u32 apsd_conf0, u32 apsd_conf1);
int wl1271_acx_frag_threshold(struct wl1271 *wl);
int wl1271_acx_tx_config_options(struct wl1271 *wl);
int wl1271_acx_mem_cfg(struct wl1271 *wl);

View File

@ -27,6 +27,7 @@
#include "wl1271_reg.h"
#include "wl1271_boot.h"
#include "wl1271_spi.h"
#include "wl1271_io.h"
#include "wl1271_event.h"
static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
@ -93,19 +94,19 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
u32 cpu_ctrl;
/* 10.5.0 run the firmware (I) */
cpu_ctrl = wl1271_spi_read32(wl, ACX_REG_ECPU_CONTROL);
cpu_ctrl = wl1271_read32(wl, ACX_REG_ECPU_CONTROL);
/* 10.5.1 run the firmware (II) */
cpu_ctrl |= flag;
wl1271_spi_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
}
static void wl1271_boot_fw_version(struct wl1271 *wl)
{
struct wl1271_static_data static_data;
wl1271_spi_read(wl, wl->cmd_box_addr,
&static_data, sizeof(static_data), false);
wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data),
false);
strncpy(wl->chip.fw_ver, static_data.fw_version,
sizeof(wl->chip.fw_ver));
@ -164,7 +165,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
memcpy(chunk, p, CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
p, addr);
wl1271_spi_write(wl, addr, chunk, CHUNK_SIZE, false);
wl1271_write(wl, addr, chunk, CHUNK_SIZE, false);
chunk_num++;
}
@ -175,7 +176,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
fw_data_len % CHUNK_SIZE, p, addr);
wl1271_spi_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
kfree(chunk);
return 0;
@ -219,29 +220,14 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
size_t nvs_len, burst_len;
int i;
u32 dest_addr, val;
u8 *nvs_ptr, *nvs, *nvs_aligned;
u8 *nvs_ptr, *nvs_aligned;
nvs = wl->nvs;
if (nvs == NULL)
if (wl->nvs == NULL)
return -ENODEV;
if (wl->nvs_len < WL1271_NVS_LEN)
return -EINVAL;
nvs_ptr = nvs;
/* only the first part of the NVS needs to be uploaded */
nvs_len = WL1271_NVS_LEN;
/* FIXME: read init settings from the remaining part of the NVS */
/* Update the device MAC address into the nvs */
nvs[11] = wl->mac_addr[0];
nvs[10] = wl->mac_addr[1];
nvs[6] = wl->mac_addr[2];
nvs[5] = wl->mac_addr[3];
nvs[4] = wl->mac_addr[4];
nvs[3] = wl->mac_addr[5];
nvs_len = sizeof(wl->nvs->nvs);
nvs_ptr = (u8 *)wl->nvs->nvs;
/*
* Layout before the actual NVS tables:
@ -271,7 +257,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT,
"nvs burst write 0x%x: 0x%x",
dest_addr, val);
wl1271_spi_write32(wl, dest_addr, val);
wl1271_write32(wl, dest_addr, val);
nvs_ptr += 4;
dest_addr += 4;
@ -283,7 +269,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
* is 7 bytes further.
*/
nvs_ptr += 7;
nvs_len -= nvs_ptr - nvs;
nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
nvs_len = ALIGN(nvs_len, 4);
/* FIXME: The driver sets the partition here, but this is not needed,
@ -292,15 +278,20 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
wl1271_set_partition(wl, &part_table[PART_WORK]);
/* Copy the NVS tables to a new block to ensure alignment */
nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
if (!nvs_aligned)
return -ENOMEM;
/* FIXME: We jump 3 more bytes before uploading the NVS. It seems
that our NVS files have three extra zeros here. I'm not sure whether
the problem is in our NVS generation or we should really jumpt these
3 bytes here */
nvs_ptr += 3;
nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); if
(!nvs_aligned) return -ENOMEM;
/* And finally we upload the NVS tables */
/* FIXME: In wl1271, we upload everything at once.
No endianness handling needed here?! The ref driver doesn't do
anything about it at this point */
wl1271_spi_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
kfree(nvs_aligned);
return 0;
@ -309,9 +300,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
{
enable_irq(wl->irq);
wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
wl1271_spi_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
}
static int wl1271_boot_soft_reset(struct wl1271 *wl)
@ -320,13 +311,12 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
u32 boot_data;
/* perform soft reset */
wl1271_spi_write32(wl, ACX_REG_SLV_SOFT_RESET,
ACX_SLV_SOFT_RESET_BIT);
wl1271_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
/* SOFT_RESET is self clearing */
timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
while (1) {
boot_data = wl1271_spi_read32(wl, ACX_REG_SLV_SOFT_RESET);
boot_data = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET);
wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
break;
@ -342,10 +332,10 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
}
/* disable Rx/Tx */
wl1271_spi_write32(wl, ENABLE, 0x0);
wl1271_write32(wl, ENABLE, 0x0);
/* disable auto calibration on start*/
wl1271_spi_write32(wl, SPARE_A2, 0xffff);
wl1271_write32(wl, SPARE_A2, 0xffff);
return 0;
}
@ -357,7 +347,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
chip_id = wl1271_spi_read32(wl, CHIP_ID_B);
chip_id = wl1271_read32(wl, CHIP_ID_B);
wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
@ -370,8 +360,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
loop = 0;
while (loop++ < INIT_LOOP) {
udelay(INIT_LOOP_DELAY);
interrupt = wl1271_spi_read32(wl,
ACX_REG_INTERRUPT_NO_CLEAR);
interrupt = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
if (interrupt == 0xffffffff) {
wl1271_error("error reading hardware complete "
@ -380,8 +369,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
}
/* check that ACX_INTR_INIT_COMPLETE is enabled */
else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) {
wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_INIT_COMPLETE);
wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_INIT_COMPLETE);
break;
}
}
@ -393,10 +382,10 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
}
/* get hardware config command mail box */
wl->cmd_box_addr = wl1271_spi_read32(wl, REG_COMMAND_MAILBOX_PTR);
wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR);
/* get hardware config event mail box */
wl->event_box_addr = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
/* set the working partition to its "running" mode offset */
wl1271_set_partition(wl, &part_table[PART_WORK]);
@ -469,9 +458,9 @@ int wl1271_boot(struct wl1271 *wl)
wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
}
wl1271_spi_write32(wl, PLL_PARAMETERS, clk);
wl1271_write32(wl, PLL_PARAMETERS, clk);
pause = wl1271_spi_read32(wl, PLL_PARAMETERS);
pause = wl1271_read32(wl, PLL_PARAMETERS);
wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
@ -480,10 +469,10 @@ int wl1271_boot(struct wl1271 *wl)
* 0x3ff (magic number ). How does
* this work?! */
pause |= WU_COUNTER_PAUSE_VAL;
wl1271_spi_write32(wl, WU_COUNTER_PAUSE, pause);
wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
/* Continue the ELP wake up sequence */
wl1271_spi_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
udelay(500);
wl1271_set_partition(wl, &part_table[PART_DRPW]);
@ -493,18 +482,18 @@ int wl1271_boot(struct wl1271 *wl)
before taking DRPw out of reset */
wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
clk = wl1271_spi_read32(wl, DRPW_SCRATCH_START);
clk = wl1271_read32(wl, DRPW_SCRATCH_START);
wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
/* 2 */
clk |= (REF_CLOCK << 1) << 4;
wl1271_spi_write32(wl, DRPW_SCRATCH_START, clk);
wl1271_write32(wl, DRPW_SCRATCH_START, clk);
wl1271_set_partition(wl, &part_table[PART_WORK]);
/* Disable interrupts */
wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
ret = wl1271_boot_soft_reset(wl);
if (ret < 0)
@ -519,23 +508,22 @@ int wl1271_boot(struct wl1271 *wl)
* ACX_EEPROMLESS_IND_REG */
wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
wl1271_spi_write32(wl, ACX_EEPROMLESS_IND_REG,
ACX_EEPROMLESS_IND_REG);
wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
tmp = wl1271_spi_read32(wl, CHIP_ID_B);
tmp = wl1271_read32(wl, CHIP_ID_B);
wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
/* 6. read the EEPROM parameters */
tmp = wl1271_spi_read32(wl, SCR_PAD2);
tmp = wl1271_read32(wl, SCR_PAD2);
ret = wl1271_boot_write_irq_polarity(wl);
if (ret < 0)
goto out;
/* FIXME: Need to check whether this is really what we want */
wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_ALL_EVENTS_VECTOR);
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_ALL_EVENTS_VECTOR);
/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
* to upload_fw) */

View File

@ -30,6 +30,7 @@
#include "wl1271.h"
#include "wl1271_reg.h"
#include "wl1271_spi.h"
#include "wl1271_io.h"
#include "wl1271_acx.h"
#include "wl12xx_80211.h"
#include "wl1271_cmd.h"
@ -57,13 +58,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
WARN_ON(len % 4 != 0);
wl1271_spi_write(wl, wl->cmd_box_addr, buf, len, false);
wl1271_write(wl, wl->cmd_box_addr, buf, len, false);
wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout");
@ -73,13 +74,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
msleep(1);
intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
}
/* read back the status code of the command */
if (res_len == 0)
res_len = sizeof(struct wl1271_cmd_header);
wl1271_spi_read(wl, wl->cmd_box_addr, cmd, res_len, false);
wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false);
status = le16_to_cpu(cmd->status);
if (status != CMD_STATUS_SUCCESS) {
@ -87,8 +88,8 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
ret = -EIO;
}
wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE);
wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE);
out:
return ret;
@ -191,43 +192,19 @@ static int wl1271_cmd_cal(struct wl1271 *wl)
int wl1271_cmd_general_parms(struct wl1271 *wl)
{
struct wl1271_general_parms_cmd *gen_parms;
struct conf_general_parms *g = &wl->conf.init.genparam;
int ret;
if (!wl->nvs)
return -ENODEV;
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
if (!gen_parms)
return -ENOMEM;
gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
gen_parms->ref_clk = g->ref_clk;
gen_parms->settling_time = g->settling_time;
gen_parms->clk_valid_on_wakeup = g->clk_valid_on_wakeup;
gen_parms->dc2dcmode = g->dc2dcmode;
gen_parms->single_dual_band = g->single_dual_band;
gen_parms->tx_bip_fem_autodetect = g->tx_bip_fem_autodetect;
gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer;
gen_parms->settings = g->settings;
gen_parms->sr_state = g->sr_state;
memcpy(gen_parms->srf1,
g->srf1,
CONF_MAX_SMART_REFLEX_PARAMS);
memcpy(gen_parms->srf2,
g->srf2,
CONF_MAX_SMART_REFLEX_PARAMS);
memcpy(gen_parms->srf3,
g->srf3,
CONF_MAX_SMART_REFLEX_PARAMS);
memcpy(gen_parms->sr_debug_table,
g->sr_debug_table,
CONF_MAX_SMART_REFLEX_PARAMS);
gen_parms->sr_sen_n_p = g->sr_sen_n_p;
gen_parms->sr_sen_n_p_gain = g->sr_sen_n_p_gain;
gen_parms->sr_sen_nrn = g->sr_sen_nrn;
gen_parms->sr_sen_prn = g->sr_sen_prn;
memcpy(gen_parms->params, wl->nvs->general_params,
WL1271_NVS_GENERAL_PARAMS_SIZE);
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
if (ret < 0)
@ -240,8 +217,11 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
int wl1271_cmd_radio_parms(struct wl1271 *wl)
{
struct wl1271_radio_parms_cmd *radio_parms;
struct conf_radio_parms *r = &wl->conf.init.radioparam;
int i, ret;
struct conf_radio_parms *rparam = &wl->conf.init.radioparam;
int ret;
if (!wl->nvs)
return -ENODEV;
radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
if (!radio_parms)
@ -249,73 +229,13 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
/* Static radio parameters */
radio_parms->rx_trace_loss = r->rx_trace_loss;
radio_parms->tx_trace_loss = r->tx_trace_loss;
memcpy(radio_parms->rx_rssi_and_proc_compens,
r->rx_rssi_and_proc_compens,
CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE);
memcpy(radio_parms->stat_radio_params, wl->nvs->stat_radio_params,
WL1271_NVS_STAT_RADIO_PARAMS_SIZE);
memcpy(radio_parms->dyn_radio_params,
wl->nvs->dyn_radio_params[rparam->fem],
WL1271_NVS_DYN_RADIO_PARAMS_SIZE);
memcpy(radio_parms->rx_trace_loss_5, r->rx_trace_loss_5,
CONF_NUMBER_OF_SUB_BANDS_5);
memcpy(radio_parms->tx_trace_loss_5, r->tx_trace_loss_5,
CONF_NUMBER_OF_SUB_BANDS_5);
memcpy(radio_parms->rx_rssi_and_proc_compens_5,
r->rx_rssi_and_proc_compens_5,
CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE);
/* Dynamic radio parameters */
radio_parms->tx_ref_pd_voltage = cpu_to_le16(r->tx_ref_pd_voltage);
radio_parms->tx_ref_power = r->tx_ref_power;
radio_parms->tx_offset_db = r->tx_offset_db;
memcpy(radio_parms->tx_rate_limits_normal, r->tx_rate_limits_normal,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_rate_limits_extreme, r->tx_rate_limits_extreme,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b,
CONF_NUMBER_OF_CHANNELS_2_4);
memcpy(radio_parms->tx_channel_limits_ofdm, r->tx_channel_limits_ofdm,
CONF_NUMBER_OF_CHANNELS_2_4);
memcpy(radio_parms->tx_pdv_rate_offsets, r->tx_pdv_rate_offsets,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS);
radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss;
radio_parms->degraded_low_to_normal_threshold =
r->degraded_low_to_normal_threshold;
radio_parms->degraded_normal_to_high_threshold =
r->degraded_normal_to_high_threshold;
for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++)
radio_parms->tx_ref_pd_voltage_5[i] =
cpu_to_le16(r->tx_ref_pd_voltage_5[i]);
memcpy(radio_parms->tx_ref_power_5, r->tx_ref_power_5,
CONF_NUMBER_OF_SUB_BANDS_5);
memcpy(radio_parms->tx_offset_db_5, r->tx_offset_db_5,
CONF_NUMBER_OF_SUB_BANDS_5);
memcpy(radio_parms->tx_rate_limits_normal_5,
r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_rate_limits_degraded_5,
r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_rate_limits_extreme_5,
r->tx_rate_limits_extreme_5, CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_channel_limits_ofdm_5,
r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5);
memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_ibias_5, r->tx_ibias_5,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->rx_fem_insertion_loss_5,
r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5);
radio_parms->degraded_low_to_normal_threshold_5 =
r->degraded_low_to_normal_threshold_5;
radio_parms->degraded_normal_to_high_threshold_5 =
r->degraded_normal_to_high_threshold_5;
/* FIXME: current NVS is missing 5GHz parameters */
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
radio_parms, sizeof(*radio_parms));
@ -555,7 +475,7 @@ out:
return ret;
}
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
{
struct wl1271_cmd_ps_params *ps_params = NULL;
int ret = 0;
@ -576,7 +496,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
}
ps_params->ps_mode = ps_mode;
ps_params->send_null_data = 1;
ps_params->send_null_data = send;
ps_params->retries = 5;
ps_params->hang_over_period = 128;
ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
@ -1022,7 +942,7 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_warning("could not set keys");
goto out;
goto out;
}
out:

View File

@ -38,7 +38,7 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len);
int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
@ -428,90 +428,24 @@ struct wl1271_general_parms_cmd {
struct wl1271_cmd_test_header test;
u8 ref_clk;
u8 settling_time;
u8 clk_valid_on_wakeup;
u8 dc2dcmode;
u8 single_dual_band;
u8 tx_bip_fem_autodetect;
u8 tx_bip_fem_manufacturer;
u8 settings;
u8 sr_state;
s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS];
s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS];
s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS];
s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS];
u8 sr_sen_n_p;
u8 sr_sen_n_p_gain;
u8 sr_sen_nrn;
u8 sr_sen_prn;
u8 padding[3];
u8 params[WL1271_NVS_GENERAL_PARAMS_SIZE];
s8 reserved[23];
} __attribute__ ((packed));
#define WL1271_STAT_RADIO_PARAMS_5_SIZE 29
#define WL1271_DYN_RADIO_PARAMS_5_SIZE 104
struct wl1271_radio_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
/* Static radio parameters */
/* 2.4GHz */
u8 rx_trace_loss;
u8 tx_trace_loss;
s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE];
u8 stat_radio_params_5[WL1271_STAT_RADIO_PARAMS_5_SIZE];
/* 5GHz */
u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
/* Dynamic radio parameters */
/* 2.4GHz */
__le16 tx_ref_pd_voltage;
u8 tx_ref_power;
s8 tx_offset_db;
s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS];
u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
u8 rx_fem_insertion_loss;
u8 degraded_low_to_normal_threshold;
u8 degraded_normal_to_high_threshold;
u8 padding1; /* our own padding, not in ref driver */
/* 5GHz */
__le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
/* FIXME: this is inconsistent with the types for 2.4GHz */
s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 degraded_low_to_normal_threshold_5;
u8 degraded_normal_to_high_threshold_5;
u8 padding2[2];
u8 dyn_radio_params[WL1271_NVS_DYN_RADIO_PARAMS_SIZE];
u8 reserved;
u8 dyn_radio_params_5[WL1271_DYN_RADIO_PARAMS_5_SIZE];
} __attribute__ ((packed));
struct wl1271_cmd_cal_channel_tune {

View File

@ -735,81 +735,6 @@ enum single_dual_band_enum {
CONF_DUAL_BAND
};
#define CONF_MAX_SMART_REFLEX_PARAMS 16
struct conf_general_parms {
/*
* RF Reference Clock type / speed
*
* Range: CONF_REF_CLK_*
*/
u8 ref_clk;
/*
* Settling time of the reference clock after boot.
*
* Range: u8
*/
u8 settling_time;
/*
* Flag defining whether clock is valid on wakeup.
*
* Range: 0 - not valid on wakeup, 1 - valid on wakeup
*/
u8 clk_valid_on_wakeup;
/*
* DC-to-DC mode.
*
* Range: Unknown
*/
u8 dc2dcmode;
/*
* Flag defining whether used as single or dual-band.
*
* Range: CONF_SINGLE_BAND, CONF_DUAL_BAND
*/
u8 single_dual_band;
/*
* TX bip fem autodetect flag.
*
* Range: Unknown
*/
u8 tx_bip_fem_autodetect;
/*
* TX bip gem manufacturer.
*
* Range: Unknown
*/
u8 tx_bip_fem_manufacturer;
/*
* Settings flags.
*
* Range: Unknown
*/
u8 settings;
/* Smart reflex settings */
u8 sr_state;
s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS];
s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS];
s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS];
s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS];
u8 sr_sen_n_p;
u8 sr_sen_n_p_gain;
u8 sr_sen_nrn;
u8 sr_sen_prn;
};
#define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15
#define CONF_NUMBER_OF_SUB_BANDS_5 7
#define CONF_NUMBER_OF_RATE_GROUPS 6
@ -818,77 +743,14 @@ struct conf_general_parms {
struct conf_radio_parms {
/*
* Static radio parameters for 2.4GHz
* FEM parameter set to use
*
* Range: unknown
* Range: 0 or 1
*/
u8 rx_trace_loss;
u8 tx_trace_loss;
s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
/*
* Static radio parameters for 5GHz
*
* Range: unknown
*/
u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
/*
* Dynamic radio parameters for 2.4GHz
*
* Range: unknown
*/
u16 tx_ref_pd_voltage;
u8 tx_ref_power;
s8 tx_offset_db;
s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS];
u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
u8 rx_fem_insertion_loss;
u8 degraded_low_to_normal_threshold;
u8 degraded_normal_to_high_threshold;
/*
* Dynamic radio parameters for 5GHz
*
* Range: unknown
*/
u16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
/* FIXME: this is inconsistent with the types for 2.4GHz */
s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 degraded_low_to_normal_threshold_5;
u8 degraded_normal_to_high_threshold_5;
u8 fem;
};
struct conf_init_settings {
/*
* Configure general parameters.
*/
struct conf_general_parms genparam;
/*
* Configure radio parameters.
*/

View File

@ -24,6 +24,7 @@
#include "wl1271.h"
#include "wl1271_reg.h"
#include "wl1271_spi.h"
#include "wl1271_io.h"
#include "wl1271_event.h"
#include "wl1271_ps.h"
#include "wl12xx_80211.h"
@ -78,24 +79,61 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
switch (mbox->ps_status) {
case EVENT_ENTER_POWER_SAVE_FAIL:
wl1271_debug(DEBUG_PSM, "PSM entry failed");
if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
/* remain in active mode */
wl->psm_entry_retry = 0;
break;
}
if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
wl->psm_entry_retry++;
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
true);
} else {
wl1271_error("PSM entry failed, giving up.\n");
/* FIXME: this may need to be reconsidered. for now it
is not possible to indicate to the mac80211
afterwards that PSM entry failed. To maximize
functionality (receiving data and remaining
associated) make sure that we are in sync with the
AP in regard of PSM mode. */
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
false);
wl->psm_entry_retry = 0;
}
break;
case EVENT_ENTER_POWER_SAVE_SUCCESS:
wl->psm_entry_retry = 0;
/* enable beacon filtering */
ret = wl1271_acx_beacon_filter_opt(wl, true);
if (ret < 0)
break;
/* enable beacon early termination */
ret = wl1271_acx_bet_enable(wl, true);
if (ret < 0)
break;
/* go to extremely low power mode */
wl1271_ps_elp_sleep(wl);
if (ret < 0)
break;
break;
case EVENT_EXIT_POWER_SAVE_FAIL:
wl1271_info("PSM exit failed");
wl1271_debug(DEBUG_PSM, "PSM exit failed");
if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
wl->psm_entry_retry = 0;
break;
}
/* make sure the firmware goes to active mode - the frame to
be sent next will indicate to the AP, that we are active. */
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
false);
break;
case EVENT_EXIT_POWER_SAVE_SUCCESS:
default:
@ -177,7 +215,7 @@ int wl1271_event_unmask(struct wl1271 *wl)
void wl1271_event_mbox_config(struct wl1271 *wl)
{
wl->mbox_ptr[0] = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
@ -195,8 +233,8 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
return -EINVAL;
/* first we read the mbox descriptor */
wl1271_spi_read(wl, wl->mbox_ptr[mbox_num], &mbox,
sizeof(struct event_mailbox), false);
wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
sizeof(struct event_mailbox), false);
/* process the descriptor */
ret = wl1271_event_process(wl, &mbox);
@ -204,7 +242,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
return ret;
/* then we let the firmware know it can go on...*/
wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
return 0;
}

View File

@ -49,7 +49,7 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl)
return 0;
}
static int wl1271_init_templates_config(struct wl1271 *wl)
int wl1271_init_templates_config(struct wl1271 *wl)
{
int ret;
@ -113,7 +113,7 @@ static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
return 0;
}
static int wl1271_init_phy_config(struct wl1271 *wl)
int wl1271_init_phy_config(struct wl1271 *wl)
{
int ret;
@ -156,7 +156,7 @@ static int wl1271_init_beacon_filter(struct wl1271 *wl)
return 0;
}
static int wl1271_init_pta(struct wl1271 *wl)
int wl1271_init_pta(struct wl1271 *wl)
{
int ret;
@ -171,7 +171,7 @@ static int wl1271_init_pta(struct wl1271 *wl)
return 0;
}
static int wl1271_init_energy_detection(struct wl1271 *wl)
int wl1271_init_energy_detection(struct wl1271 *wl)
{
int ret;
@ -195,7 +195,9 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
int wl1271_hw_init(struct wl1271 *wl)
{
int ret;
struct conf_tx_ac_category *conf_ac;
struct conf_tx_tid *conf_tid;
int ret, i;
ret = wl1271_cmd_general_parms(wl);
if (ret < 0)
@ -274,14 +276,28 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap;
/* Default TID configuration */
ret = wl1271_acx_tid_cfg(wl);
if (ret < 0)
goto out_free_memmap;
for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
conf_tid = &wl->conf.tx.tid_conf[i];
ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
conf_tid->channel_type,
conf_tid->tsid,
conf_tid->ps_scheme,
conf_tid->ack_policy,
conf_tid->apsd_conf[0],
conf_tid->apsd_conf[1]);
if (ret < 0)
goto out_free_memmap;
}
/* Default AC configuration */
ret = wl1271_acx_ac_cfg(wl);
if (ret < 0)
goto out_free_memmap;
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
conf_ac = &wl->conf.tx.ac_conf[i];
ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
conf_ac->cw_max, conf_ac->aifsn,
conf_ac->tx_op_limit);
if (ret < 0)
goto out_free_memmap;
}
/* Configure TX rate classes */
ret = wl1271_acx_rate_policies(wl);

View File

@ -27,6 +27,10 @@
#include "wl1271.h"
int wl1271_hw_init_power_auth(struct wl1271 *wl);
int wl1271_init_templates_config(struct wl1271 *wl);
int wl1271_init_phy_config(struct wl1271 *wl);
int wl1271_init_pta(struct wl1271 *wl);
int wl1271_init_energy_detection(struct wl1271 *wl);
int wl1271_hw_init(struct wl1271 *wl);
#endif

View File

@ -0,0 +1,213 @@
/*
* This file is part of wl1271
*
* Copyright (C) 2008-2010 Nokia Corporation
*
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/crc7.h>
#include <linux/spi/spi.h>
#include "wl1271.h"
#include "wl12xx_80211.h"
#include "wl1271_spi.h"
#include "wl1271_io.h"
static int wl1271_translate_addr(struct wl1271 *wl, int addr)
{
/*
* To translate, first check to which window of addresses the
* particular address belongs. Then subtract the starting address
* of that window from the address. Then, add offset of the
* translated region.
*
* The translated regions occur next to each other in physical device
* memory, so just add the sizes of the preceeding address regions to
* get the offset to the new region.
*
* Currently, only the two first regions are addressed, and the
* assumption is that all addresses will fall into either of those
* two.
*/
if ((addr >= wl->part.reg.start) &&
(addr < wl->part.reg.start + wl->part.reg.size))
return addr - wl->part.reg.start + wl->part.mem.size;
else
return addr - wl->part.mem.start;
}
/* Set the SPI partitions to access the chip addresses
*
* To simplify driver code, a fixed (virtual) memory map is defined for
* register and memory addresses. Because in the chipset, in different stages
* of operation, those addresses will move around, an address translation
* mechanism is required.
*
* There are four partitions (three memory and one register partition),
* which are mapped to two different areas of the hardware memory.
*
* Virtual address
* space
*
* | |
* ...+----+--> mem.start
* Physical address ... | |
* space ... | | [PART_0]
* ... | |
* 00000000 <--+----+... ...+----+--> mem.start + mem.size
* | | ... | |
* |MEM | ... | |
* | | ... | |
* mem.size <--+----+... | | {unused area)
* | | ... | |
* |REG | ... | |
* mem.size | | ... | |
* + <--+----+... ...+----+--> reg.start
* reg.size | | ... | |
* |MEM2| ... | | [PART_1]
* | | ... | |
* ...+----+--> reg.start + reg.size
* | |
*
*/
int wl1271_set_partition(struct wl1271 *wl,
struct wl1271_partition_set *p)
{
/* copy partition info */
memcpy(&wl->part, p, sizeof(*p));
wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
p->mem.start, p->mem.size);
wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
p->reg.start, p->reg.size);
wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X",
p->mem2.start, p->mem2.size);
wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X",
p->mem3.start, p->mem3.size);
/* write partition info to the chipset */
wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
return 0;
}
void wl1271_io_reset(struct wl1271 *wl)
{
wl1271_spi_reset(wl);
}
void wl1271_io_init(struct wl1271 *wl)
{
wl1271_spi_init(wl);
}
void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed)
{
wl1271_spi_raw_write(wl, addr, buf, len, fixed);
}
void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed)
{
wl1271_spi_raw_read(wl, addr, buf, len, fixed);
}
void wl1271_read(struct wl1271 *wl, int addr, void *buf, size_t len,
bool fixed)
{
int physical;
physical = wl1271_translate_addr(wl, addr);
wl1271_spi_raw_read(wl, physical, buf, len, fixed);
}
void wl1271_write(struct wl1271 *wl, int addr, void *buf, size_t len,
bool fixed)
{
int physical;
physical = wl1271_translate_addr(wl, addr);
wl1271_spi_raw_write(wl, physical, buf, len, fixed);
}
u32 wl1271_read32(struct wl1271 *wl, int addr)
{
return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
}
void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
{
wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val);
}
void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
{
/* write address >> 1 + 0x30000 to OCP_POR_CTR */
addr = (addr >> 1) + 0x30000;
wl1271_write32(wl, OCP_POR_CTR, addr);
/* write value to OCP_POR_WDATA */
wl1271_write32(wl, OCP_DATA_WRITE, val);
/* write 1 to OCP_CMD */
wl1271_write32(wl, OCP_CMD, OCP_CMD_WRITE);
}
u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
{
u32 val;
int timeout = OCP_CMD_LOOP;
/* write address >> 1 + 0x30000 to OCP_POR_CTR */
addr = (addr >> 1) + 0x30000;
wl1271_write32(wl, OCP_POR_CTR, addr);
/* write 2 to OCP_CMD */
wl1271_write32(wl, OCP_CMD, OCP_CMD_READ);
/* poll for data ready */
do {
val = wl1271_read32(wl, OCP_DATA_READ);
} while (!(val & OCP_READY_MASK) && --timeout);
if (!timeout) {
wl1271_warning("Top register access timed out.");
return 0xffff;
}
/* check data status and return if OK */
if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
return val & 0xffff;
else {
wl1271_warning("Top register access returned error.");
return 0xffff;
}
}

View File

@ -0,0 +1,68 @@
/*
* This file is part of wl1271
*
* Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
* Copyright (C) 2008-2010 Nokia Corporation
*
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL1271_IO_H__
#define __WL1271_IO_H__
struct wl1271;
void wl1271_io_reset(struct wl1271 *wl);
void wl1271_io_init(struct wl1271 *wl);
/* Raw target IO, address is not translated */
void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed);
void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed);
/* Translated target IO */
void wl1271_read(struct wl1271 *wl, int addr, void *buf, size_t len,
bool fixed);
void wl1271_write(struct wl1271 *wl, int addr, void *buf, size_t len,
bool fixed);
u32 wl1271_read32(struct wl1271 *wl, int addr);
void wl1271_write32(struct wl1271 *wl, int addr, u32 val);
/* Top Register IO */
void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val);
u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
int wl1271_set_partition(struct wl1271 *wl,
struct wl1271_partition_set *p);
static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
{
wl1271_raw_read(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
return wl->buffer_32;
}
static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
{
wl->buffer_32 = val;
wl1271_raw_write(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
}
#endif

View File

@ -1,7 +1,7 @@
/*
* This file is part of wl1271
*
* Copyright (C) 2008-2009 Nokia Corporation
* Copyright (C) 2008-2010 Nokia Corporation
*
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
@ -38,6 +38,7 @@
#include "wl12xx_80211.h"
#include "wl1271_reg.h"
#include "wl1271_spi.h"
#include "wl1271_io.h"
#include "wl1271_event.h"
#include "wl1271_tx.h"
#include "wl1271_rx.h"
@ -46,6 +47,7 @@
#include "wl1271_debugfs.h"
#include "wl1271_cmd.h"
#include "wl1271_boot.h"
#include "wl1271_testmode.h"
#define WL1271_BOOT_RETRIES 3
@ -229,93 +231,8 @@ static struct conf_drv_settings default_conf = {
.psm_entry_retries = 3
},
.init = {
.genparam = {
.ref_clk = CONF_REF_CLK_38_4_E,
.settling_time = 5,
.clk_valid_on_wakeup = 0,
.dc2dcmode = 0,
.single_dual_band = CONF_SINGLE_BAND,
.tx_bip_fem_autodetect = 1,
.tx_bip_fem_manufacturer = 1,
.settings = 1,
.sr_state = 1,
.srf1 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
.srf2 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
.srf3 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
.sr_debug_table = { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
.sr_sen_n_p = 0,
.sr_sen_n_p_gain = 0,
.sr_sen_nrn = 0,
.sr_sen_prn = 0,
},
.radioparam = {
.rx_trace_loss = 0x24,
.tx_trace_loss = 0x0,
.rx_rssi_and_proc_compens = {
0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
0xfc, 0x00, 0x80, 0x10, 0xf0, 0xf8,
0x00, 0x0a, 0x14 },
.rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
.tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
.rx_rssi_and_proc_compens_5 = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00 },
.tx_ref_pd_voltage = 0x1a9,
.tx_ref_power = 0x80,
.tx_offset_db = 0x0,
.tx_rate_limits_normal = {
0x1d, 0x1f, 0x24, 0x28, 0x28, 0x29 },
.tx_rate_limits_degraded = {
0x19, 0x1f, 0x22, 0x23, 0x27, 0x28 },
.tx_rate_limits_extreme = {
0x19, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
.tx_channel_limits_11b = {
0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
0x22, 0x50 },
.tx_channel_limits_ofdm = {
0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
0x20, 0x50 },
.tx_pdv_rate_offsets = {
0x07, 0x08, 0x04, 0x02, 0x02, 0x00 },
.tx_ibias = {
0x11, 0x11, 0x15, 0x11, 0x15, 0x0f },
.rx_fem_insertion_loss = 0x0e,
.degraded_low_to_normal_threshold = 0x1e,
.degraded_normal_to_high_threshold = 0x2d,
.tx_ref_pd_voltage_5 = {
0x0190, 0x01a4, 0x01c3, 0x01d8,
0x020a, 0x021c },
.tx_ref_power_5 = {
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
.tx_offset_db_5 = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
.tx_rate_limits_normal_5 = {
0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
.tx_rate_limits_degraded_5 = {
0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
.tx_rate_limits_extreme_5 = {
0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
.tx_channel_limits_ofdm_5 = {
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
0x50, 0x50, 0x50 },
.tx_pdv_rate_offsets_5 = {
0x01, 0x02, 0x02, 0x02, 0x02, 0x00 },
.tx_ibias_5 = {
0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
.rx_fem_insertion_loss_5 = {
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
.degraded_low_to_normal_threshold_5 = 0x00,
.degraded_normal_to_high_threshold_5 = 0x00
.fem = 1,
}
},
.itrim = {
@ -345,15 +262,14 @@ static void wl1271_conf_init(struct wl1271 *wl)
/* apply driver default configuration */
memcpy(&wl->conf, &default_conf, sizeof(default_conf));
if (wl1271_11a_enabled())
wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
}
static int wl1271_plt_init(struct wl1271 *wl)
{
int ret;
struct conf_tx_ac_category *conf_ac;
struct conf_tx_tid *conf_tid;
int ret, i;
ret = wl1271_cmd_general_parms(wl);
if (ret < 0)
@ -363,15 +279,89 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0)
return ret;
ret = wl1271_init_templates_config(wl);
if (ret < 0)
return ret;
ret = wl1271_acx_init_mem_config(wl);
if (ret < 0)
return ret;
/* PHY layer config */
ret = wl1271_init_phy_config(wl);
if (ret < 0)
goto out_free_memmap;
ret = wl1271_acx_dco_itrim_params(wl);
if (ret < 0)
goto out_free_memmap;
/* Initialize connection monitoring thresholds */
ret = wl1271_acx_conn_monit_params(wl);
if (ret < 0)
goto out_free_memmap;
/* Bluetooth WLAN coexistence */
ret = wl1271_init_pta(wl);
if (ret < 0)
goto out_free_memmap;
/* Energy detection */
ret = wl1271_init_energy_detection(wl);
if (ret < 0)
goto out_free_memmap;
/* Default fragmentation threshold */
ret = wl1271_acx_frag_threshold(wl);
if (ret < 0)
goto out_free_memmap;
/* Default TID configuration */
for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
conf_tid = &wl->conf.tx.tid_conf[i];
ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
conf_tid->channel_type,
conf_tid->tsid,
conf_tid->ps_scheme,
conf_tid->ack_policy,
conf_tid->apsd_conf[0],
conf_tid->apsd_conf[1]);
if (ret < 0)
goto out_free_memmap;
}
/* Default AC configuration */
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
conf_ac = &wl->conf.tx.ac_conf[i];
ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
conf_ac->cw_max, conf_ac->aifsn,
conf_ac->tx_op_limit);
if (ret < 0)
goto out_free_memmap;
}
/* Enable data path */
ret = wl1271_cmd_data_path(wl, 1);
if (ret < 0)
return ret;
goto out_free_memmap;
/* Configure for CAM power saving (ie. always active) */
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
if (ret < 0)
goto out_free_memmap;
/* configure PM */
ret = wl1271_acx_pm_config(wl);
if (ret < 0)
goto out_free_memmap;
return 0;
out_free_memmap:
kfree(wl->target_mem_map);
wl->target_mem_map = NULL;
return ret;
}
static void wl1271_disable_interrupts(struct wl1271 *wl)
@ -397,8 +387,7 @@ static void wl1271_fw_status(struct wl1271 *wl,
u32 total = 0;
int i;
wl1271_spi_read(wl, FW_STATUS_ADDR, status,
sizeof(*status), false);
wl1271_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)",
@ -445,7 +434,7 @@ static void wl1271_irq_work(struct work_struct *work)
if (ret < 0)
goto out;
wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
wl1271_fw_status(wl, wl->fw_status);
intr = le32_to_cpu(wl->fw_status->intr);
@ -487,8 +476,8 @@ static void wl1271_irq_work(struct work_struct *work)
}
out_sleep:
wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
wl1271_ps_elp_sleep(wl);
out:
@ -555,6 +544,40 @@ out:
return ret;
}
static int wl1271_update_mac_addr(struct wl1271 *wl)
{
int ret = 0;
u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
/* get mac address from the NVS */
wl->mac_addr[0] = nvs_ptr[11];
wl->mac_addr[1] = nvs_ptr[10];
wl->mac_addr[2] = nvs_ptr[6];
wl->mac_addr[3] = nvs_ptr[5];
wl->mac_addr[4] = nvs_ptr[4];
wl->mac_addr[5] = nvs_ptr[3];
/* FIXME: if it is a zero-address, we should bail out. Now, instead,
we randomize an address */
if (is_zero_ether_addr(wl->mac_addr)) {
static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
memcpy(wl->mac_addr, nokia_oui, 3);
get_random_bytes(wl->mac_addr + 3, 3);
/* update this address to the NVS */
nvs_ptr[11] = wl->mac_addr[0];
nvs_ptr[10] = wl->mac_addr[1];
nvs_ptr[6] = wl->mac_addr[2];
nvs_ptr[5] = wl->mac_addr[3];
nvs_ptr[4] = wl->mac_addr[4];
nvs_ptr[3] = wl->mac_addr[5];
}
SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
return ret;
}
static int wl1271_fetch_nvs(struct wl1271 *wl)
{
const struct firmware *fw;
@ -567,15 +590,14 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
return ret;
}
if (fw->size % 4) {
wl1271_error("nvs size is not multiple of 32 bits: %zu",
fw->size);
if (fw->size != sizeof(struct wl1271_nvs_file)) {
wl1271_error("nvs size is not as expected: %zu != %zu",
fw->size, sizeof(struct wl1271_nvs_file));
ret = -EILSEQ;
goto out;
}
wl->nvs_len = fw->size;
wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
if (!wl->nvs) {
wl1271_error("could not allocate memory for the nvs file");
@ -583,9 +605,9 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
goto out;
}
memcpy(wl->nvs, fw->data, wl->nvs_len);
memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
ret = 0;
ret = wl1271_update_mac_addr(wl);
out:
release_firmware(fw);
@ -626,8 +648,8 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
msleep(WL1271_PRE_POWER_ON_SLEEP);
wl1271_power_on(wl);
msleep(WL1271_POWER_ON_SLEEP);
wl1271_spi_reset(wl);
wl1271_spi_init(wl);
wl1271_io_reset(wl);
wl1271_io_init(wl);
/* We don't need a real memory partition here, because we only want
* to use the registers at this point. */
@ -642,7 +664,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
/* whal_FwCtrl_BootSm() */
/* 0. read chip id from CHIP_ID */
wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
/* 1. check if chip id is valid */
@ -716,11 +738,6 @@ int wl1271_plt_start(struct wl1271 *wl)
if (ret < 0)
goto irq_disable;
/* Make sure power saving is disabled */
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
if (ret < 0)
goto irq_disable;
wl->state = WL1271_STATE_PLT;
wl1271_notice("firmware booted in PLT mode (%s)",
wl->chip.fw_ver);
@ -1234,8 +1251,16 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
}
/* if the channel changes while joined, join again */
if (channel != wl->channel && test_bit(WL1271_FLAG_JOINED, &wl->flags))
wl1271_join_channel(wl, channel);
if (channel != wl->channel &&
test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
wl->channel = channel;
/* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
ret = wl1271_cmd_join(wl);
if (ret < 0)
wl1271_warning("cmd join to update channel failed %d",
ret);
} else
wl->channel = channel;
if (conf->flags & IEEE80211_CONF_PS &&
!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
@ -1248,7 +1273,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
*/
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
wl1271_info("psm enabled");
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
true);
}
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
@ -1257,7 +1283,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
if (test_bit(WL1271_FLAG_PSM, &wl->flags))
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
true);
}
if (conf->power_level != wl->power_level) {
@ -1449,9 +1476,24 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
wl1271_error("Could not add or replace key");
goto out_sleep;
}
/* the default WEP key needs to be configured at least once */
if (key_type == KEY_WEP) {
ret = wl1271_cmd_set_default_wep_key(wl,
wl->default_key);
if (ret < 0)
goto out_sleep;
}
break;
case DISABLE_KEY:
/* The wl1271 does not allow to remove unicast keys - they
will be cleared automatically on next CMD_JOIN. Ignore the
request silently, as we dont want the mac80211 to emit
an error message. */
if (!is_broadcast_ether_addr(addr))
break;
ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
key_conf->keyidx, key_type,
key_conf->keylen, key_conf->key,
@ -1539,6 +1581,23 @@ out:
return ret;
}
static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
{
u8 *ptr = beacon->data +
offsetof(struct ieee80211_mgmt, u.beacon.variable);
/* find the location of the ssid in the beacon */
while (ptr < beacon->data + beacon->len) {
if (ptr[0] == WLAN_EID_SSID) {
wl->ssid_len = ptr[1];
memcpy(wl->ssid, ptr+2, wl->ssid_len);
return;
}
ptr += ptr[1];
}
wl1271_error("ad-hoc beacon template has no SSID!\n");
}
static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@ -1546,6 +1605,7 @@ 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;
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
@ -1556,40 +1616,17 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
if ((changed & BSS_CHANGED_BSSID) &&
/*
* Now we know the correct bssid, so we send a new join command
* and enable the BSSID filter
*/
memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
wl->rx_config |= CFG_BSSID_FILTER_EN;
memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
ret = wl1271_cmd_build_null_data(wl);
if (ret < 0) {
wl1271_warning("cmd buld null data failed %d",
ret);
goto out_sleep;
}
ret = wl1271_cmd_join(wl);
if (ret < 0) {
wl1271_warning("cmd join failed %d", ret);
goto out_sleep;
}
set_bit(WL1271_FLAG_JOINED, &wl->flags);
}
if (wl->bss_type == BSS_TYPE_IBSS) {
/* FIXME: This implements rudimentary ad-hoc support -
proper templates are on the wish list and notification
on when they change. This patch will update the templates
on every call to this function. Also, the firmware will not
answer to probe-requests as it does not have the proper
SSID set in the JOIN command. The probe-response template
is set nevertheless, as the FW will ASSERT without it */
on every call to this function. */
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
if (beacon) {
struct ieee80211_hdr *hdr;
wl1271_ssid_set(wl, beacon);
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
beacon->data,
beacon->len);
@ -1611,9 +1648,31 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
dev_kfree_skb(beacon);
if (ret < 0)
goto out_sleep;
/* Need to update the SSID (for filtering etc) */
do_join = true;
}
}
if ((changed & BSS_CHANGED_BSSID) &&
/*
* Now we know the correct bssid, so we send a new join command
* and enable the BSSID filter
*/
memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
wl->rx_config |= CFG_BSSID_FILTER_EN;
memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
ret = wl1271_cmd_build_null_data(wl);
if (ret < 0) {
wl1271_warning("cmd buld null data failed %d",
ret);
goto out_sleep;
}
/* Need to update the BSSID (for filtering etc) */
do_join = true;
}
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
wl->aid = bss_conf->aid;
@ -1637,7 +1696,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
mode = STATION_POWER_SAVE_MODE;
ret = wl1271_ps_set_mode(wl, mode);
ret = wl1271_ps_set_mode(wl, mode, true);
if (ret < 0)
goto out_sleep;
}
@ -1678,6 +1737,15 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
}
}
if (do_join) {
ret = wl1271_cmd_join(wl);
if (ret < 0) {
wl1271_warning("cmd join failed %d", ret);
goto out_sleep;
}
set_bit(WL1271_FLAG_JOINED, &wl->flags);
}
out_sleep:
wl1271_ps_elp_sleep(wl);
@ -1685,6 +1753,43 @@ out:
mutex_unlock(&wl->mutex);
}
static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct wl1271 *wl = hw->priv;
int ret;
mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
goto out;
ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
params->cw_min, params->cw_max,
params->aifs, params->txop);
if (ret < 0)
goto out_sleep;
ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
CONF_CHANNEL_TYPE_EDCF,
wl1271_tx_get_queue(queue),
CONF_PS_SCHEME_LEGACY_PSPOLL,
CONF_ACK_POLICY_LEGACY, 0, 0);
if (ret < 0)
goto out_sleep;
out_sleep:
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
return ret;
}
/* can't be const, mac80211 writes to this */
static struct ieee80211_rate wl1271_rates[] = {
@ -1850,6 +1955,8 @@ static const struct ieee80211_ops wl1271_ops = {
.hw_scan = wl1271_op_hw_scan,
.bss_info_changed = wl1271_op_bss_info_changed,
.set_rts_threshold = wl1271_op_set_rts_threshold,
.conf_tx = wl1271_op_conf_tx,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
static int wl1271_register_hw(struct wl1271 *wl)
@ -1918,24 +2025,17 @@ static struct platform_device wl1271_device = {
};
#define WL1271_DEFAULT_CHANNEL 0
static int __devinit wl1271_probe(struct spi_device *spi)
static struct ieee80211_hw *wl1271_alloc_hw(void)
{
struct wl12xx_platform_data *pdata;
struct ieee80211_hw *hw;
struct wl1271 *wl;
int ret, i;
static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
pdata = spi->dev.platform_data;
if (!pdata) {
wl1271_error("no platform data");
return -ENODEV;
}
int i;
hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
if (!hw) {
wl1271_error("could not alloc ieee80211_hw");
return -ENOMEM;
return ERR_PTR(-ENOMEM);
}
wl = hw->priv;
@ -1944,8 +2044,6 @@ static int __devinit wl1271_probe(struct spi_device *spi)
INIT_LIST_HEAD(&wl->list);
wl->hw = hw;
dev_set_drvdata(&spi->dev, wl);
wl->spi = spi;
skb_queue_head_init(&wl->tx_queue);
@ -1969,16 +2067,57 @@ static int __devinit wl1271_probe(struct spi_device *spi)
spin_lock_init(&wl->wl_lock);
/*
* In case our MAC address is not correctly set,
* we use a random but Nokia MAC.
*/
memcpy(wl->mac_addr, nokia_oui, 3);
get_random_bytes(wl->mac_addr + 3, 3);
wl->state = WL1271_STATE_OFF;
mutex_init(&wl->mutex);
/* Apply default driver configuration. */
wl1271_conf_init(wl);
return hw;
}
int wl1271_free_hw(struct wl1271 *wl)
{
ieee80211_unregister_hw(wl->hw);
wl1271_debugfs_exit(wl);
kfree(wl->target_mem_map);
vfree(wl->fw);
wl->fw = NULL;
kfree(wl->nvs);
wl->nvs = NULL;
kfree(wl->fw_status);
kfree(wl->tx_res_if);
ieee80211_free_hw(wl->hw);
return 0;
}
static int __devinit wl1271_probe(struct spi_device *spi)
{
struct wl12xx_platform_data *pdata;
struct ieee80211_hw *hw;
struct wl1271 *wl;
int ret;
pdata = spi->dev.platform_data;
if (!pdata) {
wl1271_error("no platform data");
return -ENODEV;
}
hw = wl1271_alloc_hw();
if (IS_ERR(hw))
return PTR_ERR(hw);
wl = hw->priv;
dev_set_drvdata(&spi->dev, wl);
wl->spi = spi;
/* This is the only SPI value that we need to set here, the rest
* comes from the board-peripherals file */
spi->bits_per_word = 32;
@ -2020,9 +2159,6 @@ static int __devinit wl1271_probe(struct spi_device *spi)
}
dev_set_drvdata(&wl1271_device.dev, wl);
/* Apply default driver configuration. */
wl1271_conf_init(wl);
ret = wl1271_init_ieee80211(wl);
if (ret)
goto out_platform;
@ -2053,21 +2189,10 @@ static int __devexit wl1271_remove(struct spi_device *spi)
{
struct wl1271 *wl = dev_get_drvdata(&spi->dev);
ieee80211_unregister_hw(wl->hw);
wl1271_debugfs_exit(wl);
platform_device_unregister(&wl1271_device);
free_irq(wl->irq, wl);
kfree(wl->target_mem_map);
vfree(wl->fw);
wl->fw = NULL;
kfree(wl->nvs);
wl->nvs = NULL;
kfree(wl->fw_status);
kfree(wl->tx_res_if);
ieee80211_free_hw(wl->hw);
wl1271_free_hw(wl);
return 0;
}

View File

@ -24,6 +24,7 @@
#include "wl1271_reg.h"
#include "wl1271_ps.h"
#include "wl1271_spi.h"
#include "wl1271_io.h"
#define WL1271_WAKEUP_TIMEOUT 500
@ -118,7 +119,8 @@ out:
return 0;
}
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
bool send)
{
int ret;
@ -126,21 +128,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
case STATION_POWER_SAVE_MODE:
wl1271_debug(DEBUG_PSM, "entering psm");
/* enable beacon filtering */
ret = wl1271_acx_beacon_filter_opt(wl, true);
if (ret < 0)
return ret;
/* enable beacon early termination */
ret = wl1271_acx_bet_enable(wl, true);
if (ret < 0)
return ret;
ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
if (ret < 0)
return ret;
wl1271_ps_elp_sleep(wl);
ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, send);
if (ret < 0)
return ret;
@ -163,7 +151,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
if (ret < 0)
return ret;
ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, send);
if (ret < 0)
return ret;

View File

@ -27,7 +27,8 @@
#include "wl1271.h"
#include "wl1271_acx.h"
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode);
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
bool send);
void wl1271_ps_elp_sleep(struct wl1271 *wl);
int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake);
void wl1271_elp_work(struct work_struct *work);

View File

@ -26,6 +26,7 @@
#include "wl1271_reg.h"
#include "wl1271_rx.h"
#include "wl1271_spi.h"
#include "wl1271_io.h"
static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status,
u32 drv_rx_counter)
@ -166,7 +167,7 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
}
buf = skb_put(skb, length);
wl1271_spi_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
wl1271_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
/* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) buf;
@ -210,15 +211,13 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
wl->rx_mem_pool_addr.addr + 4;
/* Choose the block we want to read */
wl1271_spi_write(wl, WL1271_SLV_REG_DATA,
&wl->rx_mem_pool_addr,
sizeof(wl->rx_mem_pool_addr), false);
wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr,
sizeof(wl->rx_mem_pool_addr), false);
wl1271_rx_handle_data(wl, buf_size);
wl->rx_counter++;
drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
}
wl1271_spi_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
}

View File

@ -30,28 +30,6 @@
#include "wl12xx_80211.h"
#include "wl1271_spi.h"
static int wl1271_translate_addr(struct wl1271 *wl, int addr)
{
/*
* To translate, first check to which window of addresses the
* particular address belongs. Then subtract the starting address
* of that window from the address. Then, add offset of the
* translated region.
*
* The translated regions occur next to each other in physical device
* memory, so just add the sizes of the preceeding address regions to
* get the offset to the new region.
*
* Currently, only the two first regions are addressed, and the
* assumption is that all addresses will fall into either of those
* two.
*/
if ((addr >= wl->part.reg.start) &&
(addr < wl->part.reg.start + wl->part.reg.size))
return addr - wl->part.reg.start + wl->part.mem.size;
else
return addr - wl->part.mem.start;
}
void wl1271_spi_reset(struct wl1271 *wl)
{
@ -133,67 +111,6 @@ void wl1271_spi_init(struct wl1271 *wl)
wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
}
/* Set the SPI partitions to access the chip addresses
*
* To simplify driver code, a fixed (virtual) memory map is defined for
* register and memory addresses. Because in the chipset, in different stages
* of operation, those addresses will move around, an address translation
* mechanism is required.
*
* There are four partitions (three memory and one register partition),
* which are mapped to two different areas of the hardware memory.
*
* Virtual address
* space
*
* | |
* ...+----+--> mem.start
* Physical address ... | |
* space ... | | [PART_0]
* ... | |
* 00000000 <--+----+... ...+----+--> mem.start + mem.size
* | | ... | |
* |MEM | ... | |
* | | ... | |
* mem.size <--+----+... | | {unused area)
* | | ... | |
* |REG | ... | |
* mem.size | | ... | |
* + <--+----+... ...+----+--> reg.start
* reg.size | | ... | |
* |MEM2| ... | | [PART_1]
* | | ... | |
* ...+----+--> reg.start + reg.size
* | |
*
*/
int wl1271_set_partition(struct wl1271 *wl,
struct wl1271_partition_set *p)
{
/* copy partition info */
memcpy(&wl->part, p, sizeof(*p));
wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
p->mem.start, p->mem.size);
wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
p->reg.start, p->reg.size);
wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X",
p->mem2.start, p->mem2.size);
wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X",
p->mem3.start, p->mem3.size);
/* write partition info to the chipset */
wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
return 0;
}
#define WL1271_BUSY_WORD_TIMEOUT 1000
/* FIXME: Check busy words, removed due to SPI bug */
@ -338,77 +255,3 @@ void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
}
void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len,
bool fixed)
{
int physical;
physical = wl1271_translate_addr(wl, addr);
wl1271_spi_raw_read(wl, physical, buf, len, fixed);
}
void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len,
bool fixed)
{
int physical;
physical = wl1271_translate_addr(wl, addr);
wl1271_spi_raw_write(wl, physical, buf, len, fixed);
}
u32 wl1271_spi_read32(struct wl1271 *wl, int addr)
{
return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
}
void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val)
{
wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val);
}
void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
{
/* write address >> 1 + 0x30000 to OCP_POR_CTR */
addr = (addr >> 1) + 0x30000;
wl1271_spi_write32(wl, OCP_POR_CTR, addr);
/* write value to OCP_POR_WDATA */
wl1271_spi_write32(wl, OCP_DATA_WRITE, val);
/* write 1 to OCP_CMD */
wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_WRITE);
}
u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
{
u32 val;
int timeout = OCP_CMD_LOOP;
/* write address >> 1 + 0x30000 to OCP_POR_CTR */
addr = (addr >> 1) + 0x30000;
wl1271_spi_write32(wl, OCP_POR_CTR, addr);
/* write 2 to OCP_CMD */
wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_READ);
/* poll for data ready */
do {
val = wl1271_spi_read32(wl, OCP_DATA_READ);
} while (!(val & OCP_READY_MASK) && --timeout);
if (!timeout) {
wl1271_warning("Top register access timed out.");
return 0xffff;
}
/* check data status and return if OK */
if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
return val & 0xffff;
else {
wl1271_warning("Top register access returned error.");
return 0xffff;
}
}

View File

@ -90,37 +90,7 @@ void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed);
/* Translated target IO */
void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len,
bool fixed);
void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len,
bool fixed);
u32 wl1271_spi_read32(struct wl1271 *wl, int addr);
void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val);
/* Top Register IO */
void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val);
u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
/* INIT and RESET words */
void wl1271_spi_reset(struct wl1271 *wl);
void wl1271_spi_init(struct wl1271 *wl);
int wl1271_set_partition(struct wl1271 *wl,
struct wl1271_partition_set *p);
static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
{
wl1271_spi_raw_read(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
return wl->buffer_32;
}
static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
{
wl->buffer_32 = val;
wl1271_spi_raw_write(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
}
#endif /* __WL1271_SPI_H__ */

View File

@ -0,0 +1,283 @@
/*
* This file is part of wl1271
*
* Copyright (C) 2010 Nokia Corporation
*
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "wl1271_testmode.h"
#include <net/genetlink.h>
#include "wl1271.h"
#include "wl1271_spi.h"
#include "wl1271_acx.h"
#define WL1271_TM_MAX_DATA_LENGTH 1024
enum wl1271_tm_commands {
WL1271_TM_CMD_UNSPEC,
WL1271_TM_CMD_TEST,
WL1271_TM_CMD_INTERROGATE,
WL1271_TM_CMD_CONFIGURE,
WL1271_TM_CMD_NVS_PUSH,
WL1271_TM_CMD_SET_PLT_MODE,
__WL1271_TM_CMD_AFTER_LAST
};
#define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1)
enum wl1271_tm_attrs {
WL1271_TM_ATTR_UNSPEC,
WL1271_TM_ATTR_CMD_ID,
WL1271_TM_ATTR_ANSWER,
WL1271_TM_ATTR_DATA,
WL1271_TM_ATTR_IE_ID,
WL1271_TM_ATTR_PLT_MODE,
__WL1271_TM_ATTR_AFTER_LAST
};
#define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1)
static struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = {
[WL1271_TM_ATTR_CMD_ID] = { .type = NLA_U32 },
[WL1271_TM_ATTR_ANSWER] = { .type = NLA_U8 },
[WL1271_TM_ATTR_DATA] = { .type = NLA_BINARY,
.len = WL1271_TM_MAX_DATA_LENGTH },
[WL1271_TM_ATTR_IE_ID] = { .type = NLA_U32 },
[WL1271_TM_ATTR_PLT_MODE] = { .type = NLA_U32 },
};
static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
{
int buf_len, ret, len;
struct sk_buff *skb;
void *buf;
u8 answer = 0;
wl1271_debug(DEBUG_TESTMODE, "testmode cmd test");
if (!tb[WL1271_TM_ATTR_DATA])
return -EINVAL;
buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
if (tb[WL1271_TM_ATTR_ANSWER])
answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]);
if (buf_len > sizeof(struct wl1271_command))
return -EMSGSIZE;
mutex_lock(&wl->mutex);
ret = wl1271_cmd_test(wl, buf, buf_len, answer);
mutex_unlock(&wl->mutex);
if (ret < 0) {
wl1271_warning("testmode cmd test failed: %d", ret);
return ret;
}
if (answer) {
len = nla_total_size(buf_len);
skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
if (!skb)
return -ENOMEM;
NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf);
ret = cfg80211_testmode_reply(skb);
if (ret < 0)
return ret;
}
return 0;
nla_put_failure:
kfree_skb(skb);
return -EMSGSIZE;
}
static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
{
int ret;
struct wl1271_command *cmd;
struct sk_buff *skb;
u8 ie_id;
wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate");
if (!tb[WL1271_TM_ATTR_IE_ID])
return -EINVAL;
ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
mutex_lock(&wl->mutex);
ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd));
mutex_unlock(&wl->mutex);
if (ret < 0) {
wl1271_warning("testmode cmd interrogate failed: %d", ret);
return ret;
}
skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd));
if (!skb)
return -ENOMEM;
NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd);
return 0;
nla_put_failure:
kfree_skb(skb);
return -EMSGSIZE;
}
static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[])
{
int buf_len, ret;
void *buf;
u8 ie_id;
wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure");
if (!tb[WL1271_TM_ATTR_DATA])
return -EINVAL;
if (!tb[WL1271_TM_ATTR_IE_ID])
return -EINVAL;
ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
if (buf_len > sizeof(struct wl1271_command))
return -EMSGSIZE;
mutex_lock(&wl->mutex);
ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len);
mutex_unlock(&wl->mutex);
if (ret < 0) {
wl1271_warning("testmode cmd configure failed: %d", ret);
return ret;
}
return 0;
}
static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
{
int ret = 0;
size_t len;
void *buf;
wl1271_debug(DEBUG_TESTMODE, "testmode cmd nvs push");
if (!tb[WL1271_TM_ATTR_DATA])
return -EINVAL;
buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
len = nla_len(tb[WL1271_TM_ATTR_DATA]);
if (len != sizeof(struct wl1271_nvs_file)) {
wl1271_error("nvs size is not as expected: %zu != %zu",
len, sizeof(struct wl1271_nvs_file));
return -EMSGSIZE;
}
mutex_lock(&wl->mutex);
kfree(wl->nvs);
wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
if (!wl->nvs) {
wl1271_error("could not allocate memory for the nvs file");
ret = -ENOMEM;
goto out;
}
memcpy(wl->nvs, buf, len);
wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs");
out:
mutex_unlock(&wl->mutex);
return ret;
}
static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
{
u32 val;
int ret;
wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode");
if (!tb[WL1271_TM_ATTR_PLT_MODE])
return -EINVAL;
val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]);
switch (val) {
case 0:
ret = wl1271_plt_stop(wl);
break;
case 1:
ret = wl1271_plt_start(wl);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
{
struct wl1271 *wl = hw->priv;
struct nlattr *tb[WL1271_TM_ATTR_MAX + 1];
int err;
err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy);
if (err)
return err;
if (!tb[WL1271_TM_ATTR_CMD_ID])
return -EINVAL;
switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) {
case WL1271_TM_CMD_TEST:
return wl1271_tm_cmd_test(wl, tb);
case WL1271_TM_CMD_INTERROGATE:
return wl1271_tm_cmd_interrogate(wl, tb);
case WL1271_TM_CMD_CONFIGURE:
return wl1271_tm_cmd_configure(wl, tb);
case WL1271_TM_CMD_NVS_PUSH:
return wl1271_tm_cmd_nvs_push(wl, tb);
case WL1271_TM_CMD_SET_PLT_MODE:
return wl1271_tm_cmd_set_plt_mode(wl, tb);
default:
return -EOPNOTSUPP;
}
}

View File

@ -0,0 +1,31 @@
/*
* This file is part of wl1271
*
* Copyright (C) 2010 Nokia Corporation
*
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL1271_TESTMODE_H__
#define __WL1271_TESTMODE_H__
#include <net/mac80211.h>
int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len);
#endif /* __WL1271_TESTMODE_H__ */

View File

@ -26,6 +26,7 @@
#include "wl1271.h"
#include "wl1271_spi.h"
#include "wl1271_io.h"
#include "wl1271_reg.h"
#include "wl1271_ps.h"
#include "wl1271_tx.h"
@ -87,7 +88,7 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
u32 extra, struct ieee80211_tx_info *control)
{
struct wl1271_tx_hw_descr *desc;
int pad;
int pad, ac;
u16 tx_attr;
desc = (struct wl1271_tx_hw_descr *) skb->data;
@ -107,9 +108,11 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
/* configure the tx attributes */
tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
/* FIXME: do we know the packet priority? can we identify mgmt
packets, and use max prio for them at least? */
desc->tid = 0;
/* queue */
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
desc->tid = wl1271_tx_ac_to_tid(ac);
desc->aid = TX_HW_DEFAULT_AID;
desc->reserved = 0;
@ -163,11 +166,11 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,
len = WL1271_TX_ALIGN(skb->len);
/* perform a fixed address block write with the packet */
wl1271_spi_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
wl1271_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
/* write packet new counter into the write access register */
wl->tx_packets_count++;
wl1271_spi_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
desc = (struct wl1271_tx_hw_descr *) skb->data;
wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)",
@ -201,6 +204,7 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
ret = wl1271_cmd_set_default_wep_key(wl, idx);
if (ret < 0)
return ret;
wl->default_key = idx;
}
}
@ -372,8 +376,8 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
/* read the tx results from the chipset */
wl1271_spi_read(wl, le32_to_cpu(memmap->tx_result),
wl->tx_res_if, sizeof(*wl->tx_res_if), false);
wl1271_read(wl, le32_to_cpu(memmap->tx_result),
wl->tx_res_if, sizeof(*wl->tx_res_if), false);
/* verify that the result buffer is not getting overrun */
if (count > TX_HW_RESULT_QUEUE_LEN) {
@ -394,10 +398,10 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
}
/* write host counter to chipset (to ack) */
wl1271_spi_write32(wl, le32_to_cpu(memmap->tx_result) +
offsetof(struct wl1271_tx_hw_res_if,
tx_result_host_counter),
le32_to_cpu(wl->tx_res_if->tx_result_fw_counter));
wl1271_write32(wl, le32_to_cpu(memmap->tx_result) +
offsetof(struct wl1271_tx_hw_res_if,
tx_result_host_counter),
le32_to_cpu(wl->tx_res_if->tx_result_fw_counter));
}
/* caller must hold wl->mutex */

View File

@ -123,6 +123,42 @@ struct wl1271_tx_hw_res_if {
struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN];
} __attribute__ ((packed));
static inline int wl1271_tx_get_queue(int queue)
{
/* FIXME: use best effort until WMM is enabled */
return CONF_TX_AC_BE;
switch (queue) {
case 0:
return CONF_TX_AC_VO;
case 1:
return CONF_TX_AC_VI;
case 2:
return CONF_TX_AC_BE;
case 3:
return CONF_TX_AC_BK;
default:
return CONF_TX_AC_BE;
}
}
/* wl1271 tx descriptor needs the tid and we need to convert it from ac */
static inline int wl1271_tx_ac_to_tid(int ac)
{
switch (ac) {
case 0:
return 0;
case 1:
return 2;
case 2:
return 4;
case 3:
return 6;
default:
return 0;
}
}
void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_complete(struct wl1271 *wl, u32 count);
void wl1271_tx_flush(struct wl1271 *wl);

View File

@ -332,6 +332,12 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
case 0x5354:
ssb_pmu0_pllinit_r0(cc, crystalfreq);
break;
case 0x4322:
if (cc->pmu.rev == 2) {
chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, 0x0000000A);
chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, 0x380005C0);
}
break;
default:
ssb_printk(KERN_ERR PFX
"ERROR: PLL init unknown for device %04X\n",
@ -417,6 +423,7 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
switch (bus->chip_id) {
case 0x4312:
case 0x4322:
/* We keep the default settings:
* min_msk = 0xCBB
* max_msk = 0x7FFFF

View File

@ -196,7 +196,7 @@ extern int ssb_devices_thaw(struct ssb_freeze_context *ctx);
#ifdef CONFIG_SSB_B43_PCI_BRIDGE
extern int __init b43_pci_ssb_bridge_init(void);
extern void __exit b43_pci_ssb_bridge_exit(void);
#else /* CONFIG_SSB_B43_PCI_BRIDGR */
#else /* CONFIG_SSB_B43_PCI_BRIDGE */
static inline int b43_pci_ssb_bridge_init(void)
{
return 0;
@ -204,6 +204,6 @@ static inline int b43_pci_ssb_bridge_init(void)
static inline void b43_pci_ssb_bridge_exit(void)
{
}
#endif /* CONFIG_SSB_PCIHOST */
#endif /* CONFIG_SSB_B43_PCI_BRIDGE */
#endif /* LINUX_SSB_PRIVATE_H_ */

View File

@ -609,16 +609,6 @@ struct ieee80211_hdr_2addr {
u8 payload[0];
} __attribute__ ((packed));
struct ieee80211_hdr_3addr {
__le16 frame_ctl;
__le16 duration_id;
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
u8 addr3[ETH_ALEN];
__le16 seq_ctl;
u8 payload[0];
} __attribute__ ((packed));
struct ieee80211_hdr_4addr {
__le16 frame_ctl;
__le16 duration_id;
@ -1672,7 +1662,7 @@ static inline u8 *ieee80211_get_payload(struct rtl_ieee80211_hdr *hdr)
case IEEE80211_2ADDR_LEN:
return ((struct ieee80211_hdr_2addr *)hdr)->payload;
case IEEE80211_3ADDR_LEN:
return ((struct ieee80211_hdr_3addr *)hdr)->payload;
return (void *)hdr+sizeof(struct ieee80211_hdr_3addr);
case IEEE80211_4ADDR_LEN:
return ((struct ieee80211_hdr_4addr *)hdr)->payload;
}

View File

@ -201,7 +201,7 @@ typedef union _frameqos {
static inline u8 Frame_QoSTID(u8 *buf)
{
struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)buf;
u16 fc = le16_to_cpu(hdr->frame_ctl);
u16 fc = le16_to_cpu(hdr->frame_control);
return (u8)((frameqos *)(buf +
(((fc & IEEE80211_FCTL_TODS) &&

View File

@ -744,7 +744,7 @@ u8 parse_subframe(struct sk_buff *skb,
struct ieee80211_rxb *rxb,u8* src,u8* dst)
{
struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr* )skb->data;
u16 fc = le16_to_cpu(hdr->frame_ctl);
u16 fc = le16_to_cpu(hdr->frame_control);
u16 LLCOffset= sizeof(struct ieee80211_hdr_3addr);
u16 ChkLength;
@ -756,7 +756,7 @@ u8 parse_subframe(struct sk_buff *skb,
struct sk_buff *sub_skb;
u8 *data_ptr;
/* just for debug purpose */
SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctl));
SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctrl));
if((IEEE80211_QOS_HAS_SEQ(fc))&&\
(((frameqos *)(skb->data + IEEE80211_3ADDR_LEN))->field.reserved)) {
@ -2370,7 +2370,7 @@ static inline void ieee80211_process_probe_response(
escape_essid(info_element->data,
info_element->len),
MAC_ARG(beacon->header.addr3),
WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
WLAN_FC_GET_STYPE(beacon->header.frame_control) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
return;
@ -2387,7 +2387,7 @@ static inline void ieee80211_process_probe_response(
return;
if(ieee->bGlobalDomain)
{
if (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP)
if (WLAN_FC_GET_STYPE(beacon->header.frame_control) == IEEE80211_STYPE_PROBE_RESP)
{
// Case 1: Country code
if(IS_COUNTRY_IE_VALID(ieee) )
@ -2454,7 +2454,7 @@ static inline void ieee80211_process_probe_response(
else
ieee->current_network.buseprotection = false;
}
if(is_beacon(beacon->header.frame_ctl))
if(is_beacon(beacon->header.frame_control))
{
if(ieee->state == IEEE80211_LINKED)
ieee->LinkDetectInfo.NumRecvBcnInPeriod++;
@ -2496,7 +2496,7 @@ static inline void ieee80211_process_probe_response(
escape_essid(network.ssid,
network.ssid_len),
MAC_ARG(network.bssid),
WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
WLAN_FC_GET_STYPE(beacon->header.frame_control) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
#endif
@ -2509,7 +2509,7 @@ static inline void ieee80211_process_probe_response(
escape_essid(target->ssid,
target->ssid_len),
MAC_ARG(target->bssid),
WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
WLAN_FC_GET_STYPE(beacon->header.frame_control) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
@ -2519,7 +2519,7 @@ static inline void ieee80211_process_probe_response(
*/
renew = !time_after(target->last_scanned + ieee->scan_age, jiffies);
//YJ,add,080819,for hidden ap
if(is_beacon(beacon->header.frame_ctl) == 0)
if(is_beacon(beacon->header.frame_control) == 0)
network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & target->flags);
//if(strncmp(network.ssid, "linksys-c",9) == 0)
// printk("====>2 network.ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network.ssid, network.flags, target->ssid, target->flags);
@ -2535,7 +2535,7 @@ static inline void ieee80211_process_probe_response(
}
spin_unlock_irqrestore(&ieee->lock, flags);
if (is_beacon(beacon->header.frame_ctl)&&is_same_network(&ieee->current_network, &network, ieee)&&\
if (is_beacon(beacon->header.frame_control)&&is_same_network(&ieee->current_network, &network, ieee)&&\
(ieee->state == IEEE80211_LINKED)) {
if(ieee->handle_beacon != NULL) {
ieee->handle_beacon(ieee->dev,beacon,&ieee->current_network);

View File

@ -242,7 +242,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee
if(ieee->queue_stop){
enqueue_mgmt(ieee,skb);
}else{
header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@ -260,7 +260,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee
spin_unlock_irqrestore(&ieee->lock, flags);
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags);
header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@ -302,7 +302,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
//printk("=============>%s()\n", __FUNCTION__);
if(single){
header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@ -315,7 +315,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
}else{
header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@ -347,7 +347,7 @@ inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee)
skb_reserve(skb, ieee->tx_headroom);
req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request));
req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
req->header.frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
req->header.duration_id = 0; //FIXME: is this OK ?
memset(req->header.addr1, 0xff, ETH_ALEN);
@ -662,8 +662,8 @@ inline struct sk_buff *ieee80211_authentication_req(struct ieee80211_network *be
auth = (struct ieee80211_authentication *)
skb_put(skb, sizeof(struct ieee80211_authentication));
auth->header.frame_ctl = IEEE80211_STYPE_AUTH;
if (challengelen) auth->header.frame_ctl |= IEEE80211_FCTL_WEP;
auth->header.frame_control = IEEE80211_STYPE_AUTH;
if (challengelen) auth->header.frame_control |= IEEE80211_FCTL_WEP;
auth->header.duration_id = 0x013a; //FIXME
@ -801,7 +801,7 @@ static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *d
beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP);
beacon_buf->header.frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP);
beacon_buf->info_element[0].id = MFIE_TYPE_SSID;
beacon_buf->info_element[0].len = ssid_len;
@ -880,7 +880,7 @@ struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest)
assoc = (struct ieee80211_assoc_response_frame *)
skb_put(skb,sizeof(struct ieee80211_assoc_response_frame));
assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
assoc->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
memcpy(assoc->header.addr1, dest,ETH_ALEN);
memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
@ -935,7 +935,7 @@ struct sk_buff* ieee80211_auth_resp(struct ieee80211_device *ieee,int status, u8
memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
memcpy(auth->header.addr1, dest, ETH_ALEN);
auth->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_AUTH);
auth->header.frame_control = cpu_to_le16(IEEE80211_STYPE_AUTH);
return skb;
@ -957,7 +957,7 @@ struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr)
memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN);
memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN);
hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS |
(pwr ? IEEE80211_FCTL_PM:0));
@ -1083,7 +1083,7 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco
skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)+2);
hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ;
hdr->header.frame_control = IEEE80211_STYPE_ASSOC_REQ;
hdr->header.duration_id= 37; //FIXME
memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN);
memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
@ -1940,13 +1940,13 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
if(!ieee->proto_started)
return 0;
switch (WLAN_FC_GET_STYPE(header->frame_ctl)) {
switch (WLAN_FC_GET_STYPE(header->frame_control)) {
case IEEE80211_STYPE_ASSOC_RESP:
case IEEE80211_STYPE_REASSOC_RESP:
IEEE80211_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n",
WLAN_FC_GET_STYPE(header->frame_ctl));
WLAN_FC_GET_STYPE(header->frame_control));
if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED &&
ieee->iw_mode == IW_MODE_INFRA){
@ -2088,7 +2088,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
ieee->state == IEEE80211_LINKED &&
ieee->iw_mode == IW_MODE_INFRA){
printk("==========>received disassoc/deauth(%x) frame, reason code:%x\n",WLAN_FC_GET_STYPE(header->frame_ctl), ((struct ieee80211_disassoc*)skb->data)->reason);
printk("==========>received disassoc/deauth(%x) frame, reason code:%x\n",WLAN_FC_GET_STYPE(header->frame_control), ((struct ieee80211_disassoc*)skb->data)->reason);
ieee->state = IEEE80211_ASSOCIATING;
ieee->softmac_stats.reassoc++;
ieee->is_roaming = true;
@ -2239,7 +2239,7 @@ void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
header = (struct ieee80211_hdr_3addr *) skb->data;
header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@ -2574,7 +2574,7 @@ struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee)
return NULL;
b = (struct ieee80211_probe_response *) skb->data;
b->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_BEACON);
b->header.frame_control = cpu_to_le16(IEEE80211_STYPE_BEACON);
return skb;
@ -2590,7 +2590,7 @@ struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee)
return NULL;
b = (struct ieee80211_probe_response *) skb->data;
b->header.seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
b->header.seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@ -3139,7 +3139,7 @@ inline struct sk_buff *ieee80211_disassociate_skb(
return NULL;
disass = (struct ieee80211_disassoc *) skb_put(skb,sizeof(struct ieee80211_disassoc));
disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
disass->header.duration_id = 0;
memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN);

View File

@ -136,7 +136,7 @@ static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, P
memcpy(BAReq->addr3, ieee->current_network.bssid, ETH_ALEN);
BAReq->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame
BAReq->frame_control = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame
//tag += sizeof( struct ieee80211_hdr_3addr); //move to action field
tag = (u8*)skb_put(skb, 9);
@ -221,7 +221,7 @@ static struct sk_buff* ieee80211_DELBA(
memcpy(Delba->addr1, dst, ETH_ALEN);
memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN);
memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN);
Delba->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame
Delba->frame_control = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame
tag = (u8*)skb_put(skb, 6);

View File

@ -6168,7 +6168,7 @@ void rtl8192_process_phyinfo(struct r8192_priv * priv,u8* buffer, struct ieee802
u16 sc ;
unsigned int frag,seq;
hdr = (struct ieee80211_hdr_3addr *)buffer;
sc = le16_to_cpu(hdr->seq_ctl);
sc = le16_to_cpu(hdr->seq_ctrl);
frag = WLAN_GET_SEQ_FRAG(sc);
seq = WLAN_GET_SEQ_SEQ(sc);
//cosa add 04292008 to record the sequence number
@ -6827,7 +6827,7 @@ void rtl8192SU_TranslateRxSignalStuff(struct sk_buff *skb,
tmp_buf = (u8*)skb->data;// + get_rxpacket_shiftbytes_819xusb(pstats);
hdr = (struct ieee80211_hdr_3addr *)tmp_buf;
fc = le16_to_cpu(hdr->frame_ctl);
fc = le16_to_cpu(hdr->frame_control);
type = WLAN_FC_GET_TYPE(fc);
praddr = hdr->addr1;

View File

@ -3,7 +3,7 @@
/*
* 802.11 netlink interface public header
*
* Copyright 2006, 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2008 Michael Wu <flamingice@sourmilk.net>
* Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com>
* Copyright 2008 Michael Buesch <mb@bu3sch.de>
@ -299,6 +299,31 @@
* rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
* and @NL80211_ATTR_TX_RATES the set of allowed rates.
*
* @NL80211_CMD_REGISTER_ACTION: Register for receiving certain action frames
* (via @NL80211_CMD_ACTION) for processing in userspace. This command
* requires an interface index and a match attribute containing the first
* few bytes of the frame that should match, e.g. a single byte for only
* a category match or four bytes for vendor frames including the OUI.
* The registration cannot be dropped, but is removed automatically
* when the netlink socket is closed. Multiple registrations can be made.
* @NL80211_CMD_ACTION: Action frame TX request and RX notification. This
* command is used both as a request to transmit an Action frame and as an
* event indicating reception of an Action frame that was not processed in
* kernel code, but is for us (i.e., which may need to be processed in a
* user space application). %NL80211_ATTR_FRAME is used to specify the
* frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
* optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on
* which channel the frame is to be transmitted or was received. This
* channel has to be the current channel (remain-on-channel or the
* operational channel). When called, this operation returns a cookie
* (%NL80211_ATTR_COOKIE) that will be included with the TX status event
* pertaining to the TX request.
* @NL80211_CMD_ACTION_TX_STATUS: Report TX status of an Action frame
* transmitted with %NL80211_CMD_ACTION. %NL80211_ATTR_COOKIE identifies
* the TX command and %NL80211_ATTR_FRAME includes the contents of the
* frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
* the frame.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@ -387,6 +412,13 @@ enum nl80211_commands {
NL80211_CMD_SET_TX_BITRATE_MASK,
NL80211_CMD_REGISTER_ACTION,
NL80211_CMD_ACTION,
NL80211_CMD_ACTION_TX_STATUS,
NL80211_CMD_SET_POWER_SAVE,
NL80211_CMD_GET_POWER_SAVE,
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@ -653,6 +685,12 @@ enum nl80211_commands {
* rates based on negotiated supported rates information. This attribute
* is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
*
* @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
* at least one byte, currently used with @NL80211_CMD_REGISTER_ACTION.
*
* @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
* acknowledged by the recipient.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@ -798,6 +836,12 @@ enum nl80211_attrs {
NL80211_ATTR_TX_RATES,
NL80211_ATTR_FRAME_MATCH,
NL80211_ATTR_ACK,
NL80211_ATTR_PS_STATE,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@ -1534,4 +1578,9 @@ enum nl80211_band {
NL80211_BAND_5GHZ,
};
enum nl80211_ps_state {
NL80211_PS_DISABLED,
NL80211_PS_ENABLED,
};
#endif /* __LINUX_NL80211_H */

View File

@ -3,7 +3,7 @@
/*
* 802.11 device and configuration interface
*
* Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -998,6 +998,7 @@ struct cfg80211_pmksa {
* @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation.
* This allows the operation to be terminated prior to timeout based on
* the duration value.
* @action: Transmit an action frame
*
* @testmode_cmd: run a test mode command
*
@ -1144,7 +1145,11 @@ struct cfg80211_ops {
struct net_device *dev,
u64 cookie);
/* some temporary stuff to finish wext */
int (*action)(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
const u8 *buf, size_t len, u64 *cookie);
int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
bool enabled, int timeout);
};
@ -1445,6 +1450,8 @@ struct cfg80211_cached_keys;
* set by driver (if supported) on add_interface BEFORE registering the
* netdev and may otherwise be used by driver read-only, will be update
* by cfg80211 on change_interface
* @action_registrations: list of registrations for action frames
* @action_registrations_lock: lock for the list
*/
struct wireless_dev {
struct wiphy *wiphy;
@ -1454,6 +1461,9 @@ struct wireless_dev {
struct list_head list;
struct net_device *netdev;
struct list_head action_registrations;
spinlock_t action_registrations_lock;
struct mutex mtx;
struct work_struct cleanup_work;
@ -1478,6 +1488,9 @@ struct wireless_dev {
struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES];
struct cfg80211_internal_bss *current_bss; /* associated / joined */
bool ps;
int ps_timeout;
#ifdef CONFIG_CFG80211_WEXT
/* wext data */
struct {
@ -1489,8 +1502,7 @@ struct wireless_dev {
u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
u8 ssid[IEEE80211_MAX_SSID_LEN];
s8 default_key, default_mgmt_key;
bool ps, prev_bssid_valid;
int ps_timeout;
bool prev_bssid_valid;
} wext;
#endif
};
@ -2291,4 +2303,38 @@ void cfg80211_remain_on_channel_expired(struct net_device *dev,
void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
struct station_info *sinfo, gfp_t gfp);
/**
* cfg80211_rx_action - notification of received, unprocessed Action frame
* @dev: network device
* @freq: Frequency on which the frame was received in MHz
* @buf: Action frame (header + body)
* @len: length of the frame data
* @gfp: context flags
* Returns %true if a user space application is responsible for rejecting the
* unrecognized Action frame; %false if no such application is registered
* (i.e., the driver is responsible for rejecting the unrecognized Action
* frame)
*
* This function is called whenever an Action frame is received for a station
* mode interface, but is not processed in kernel.
*/
bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
size_t len, gfp_t gfp);
/**
* cfg80211_action_tx_status - notification of TX status for Action frame
* @dev: network device
* @cookie: Cookie returned by cfg80211_ops::action()
* @buf: Action frame (header + body)
* @len: length of the frame data
* @ack: Whether frame was acknowledged
* @gfp: context flags
*
* This function is called whenever an Action frame was requested to be
* transmitted with cfg80211_ops::action() to report the TX status of the
* transmission attempt.
*/
void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
const u8 *buf, size_t len, bool ack, gfp_t gfp);
#endif /* __NET_CFG80211_H */

View File

@ -3,7 +3,7 @@
*
* Copyright 2002-2005, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -264,6 +264,9 @@ struct ieee80211_bss_conf {
* be modified again (no seqno assignment, crypto, etc.)
* @IEEE80211_TX_INTFL_HAS_RADIOTAP: This frame was injected and still
* has a radiotap header at skb->data.
* @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211
* MLME command (internal to mac80211 to figure out whether to send TX
* status to user space)
*/
enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
@ -286,6 +289,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_MORE_FRAMES = BIT(18),
IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19),
IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20),
IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21),
};
/**

View File

@ -34,6 +34,11 @@
.prod_id = { NULL, (v2), NULL, NULL }, \
.prod_id_hash = { 0, (vh2), 0, 0 }, }
#define PCMCIA_DEVICE_PROD_ID3(v3, vh3) { \
.match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID3, \
.prod_id = { NULL, NULL, (v3), NULL }, \
.prod_id_hash = { 0, 0, (vh3), 0 }, }
#define PCMCIA_DEVICE_PROD_ID12(v1, v2, vh1, vh2) { \
.match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
PCMCIA_DEV_ID_MATCH_PROD_ID2, \

View File

@ -1,7 +1,7 @@
/*
* mac80211 configuration hooks for cfg80211
*
* Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
*
* This file is GPLv2 as found in COPYING.
*/
@ -1448,6 +1448,15 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
}
static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
const u8 *buf, size_t len, u64 *cookie)
{
return ieee80211_mgd_action(IEEE80211_DEV_TO_SUB_IF(dev), chan,
channel_type, buf, len, cookie);
}
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@ -1496,4 +1505,5 @@ struct cfg80211_ops mac80211_config_ops = {
.set_bitrate_mask = ieee80211_set_bitrate_mask,
.remain_on_channel = ieee80211_remain_on_channel,
.cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
.action = ieee80211_action,
};

View File

@ -2,7 +2,7 @@
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -966,6 +966,10 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
struct cfg80211_disassoc_request *req,
void *cookie);
int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
const u8 *buf, size_t len, u64 *cookie);
ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
void ieee80211_send_pspoll(struct ieee80211_local *local,

View File

@ -1031,7 +1031,7 @@ static int netdev_notify(struct notifier_block *nb,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
memcpy(sdata->name, sdata->name, IFNAMSIZ);
memcpy(sdata->name, dev->name, IFNAMSIZ);
ieee80211_debugfs_rename_netdev(sdata);
return 0;

View File

@ -2084,3 +2084,38 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
return 0;
}
int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
const u8 *buf, size_t len, u64 *cookie)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct sk_buff *skb;
/* Check that we are on the requested channel for transmission */
if ((chan != local->tmp_channel ||
channel_type != local->tmp_channel_type) &&
(chan != local->oper_channel ||
channel_type != local->oper_channel_type))
return -EBUSY;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
if (!skb)
return -ENOMEM;
skb_reserve(skb, local->hw.extra_tx_headroom);
memcpy(skb_put(skb, len), buf, len);
if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
IEEE80211_SKB_CB(skb)->flags |=
IEEE80211_TX_INTFL_DONT_ENCRYPT;
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX |
IEEE80211_TX_CTL_REQ_TX_STATUS;
skb->dev = sdata->dev;
ieee80211_tx_skb(sdata, skb);
*cookie = (unsigned long) skb;
return 0;
}

View File

@ -2,7 +2,7 @@
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -1397,6 +1397,21 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
ieee80211_is_data(fc) &&
(rx->key || rx->sdata->drop_unencrypted)))
return -EACCES;
return 0;
}
static int
ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
__le16 fc = hdr->frame_control;
int res;
res = ieee80211_drop_unencrypted(rx, fc);
if (unlikely(res))
return res;
if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) {
if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
rx->key))
@ -1855,23 +1870,25 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
struct ieee80211_local *local = rx->local;
struct ieee80211_sub_if_data *sdata = rx->sdata;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
struct sk_buff *nskb;
struct ieee80211_rx_status *status;
int len = rx->skb->len;
if (!ieee80211_is_action(mgmt->frame_control))
return RX_CONTINUE;
if (!rx->sta)
return RX_DROP_MONITOR;
/* drop too small frames */
if (len < IEEE80211_MIN_ACTION_SIZE)
return RX_DROP_UNUSABLE;
if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
return RX_DROP_UNUSABLE;
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_MONITOR;
return RX_DROP_UNUSABLE;
if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
return RX_DROP_MONITOR;
/* all categories we currently handle have action_code */
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
return RX_DROP_MONITOR;
if (ieee80211_drop_unencrypted_mgmt(rx))
return RX_DROP_UNUSABLE;
switch (mgmt->u.action.category) {
case WLAN_CATEGORY_BACK:
@ -1884,7 +1901,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_AP)
return RX_DROP_MONITOR;
break;
/* verify action_code is present */
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
break;
switch (mgmt->u.action.u.addba_req.action_code) {
case WLAN_ACTION_ADDBA_REQ:
@ -1892,45 +1913,49 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
sizeof(mgmt->u.action.u.addba_req)))
return RX_DROP_MONITOR;
ieee80211_process_addba_request(local, rx->sta, mgmt, len);
break;
goto handled;
case WLAN_ACTION_ADDBA_RESP:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.addba_resp)))
return RX_DROP_MONITOR;
break;
ieee80211_process_addba_resp(local, rx->sta, mgmt, len);
break;
goto handled;
case WLAN_ACTION_DELBA:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.delba)))
return RX_DROP_MONITOR;
break;
ieee80211_process_delba(sdata, rx->sta, mgmt, len);
break;
goto handled;
}
break;
case WLAN_CATEGORY_SPECTRUM_MGMT:
if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
return RX_DROP_MONITOR;
break;
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return RX_DROP_MONITOR;
break;
/* verify action_code is present */
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
break;
switch (mgmt->u.action.u.measurement.action_code) {
case WLAN_ACTION_SPCT_MSR_REQ:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.measurement)))
return RX_DROP_MONITOR;
break;
ieee80211_process_measurement_req(sdata, mgmt, len);
break;
goto handled;
case WLAN_ACTION_SPCT_CHL_SWITCH:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.chan_switch)))
return RX_DROP_MONITOR;
break;
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return RX_DROP_MONITOR;
break;
if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
return RX_DROP_MONITOR;
break;
return ieee80211_sta_rx_mgmt(sdata, rx->skb);
}
@ -1938,30 +1963,64 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
case WLAN_CATEGORY_SA_QUERY:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.sa_query)))
return RX_DROP_MONITOR;
break;
switch (mgmt->u.action.u.sa_query.action) {
case WLAN_ACTION_SA_QUERY_REQUEST:
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return RX_DROP_MONITOR;
break;
ieee80211_process_sa_query_req(sdata, mgmt, len);
break;
case WLAN_ACTION_SA_QUERY_RESPONSE:
/*
* SA Query response is currently only used in AP mode
* and it is processed in user space.
*/
return RX_CONTINUE;
goto handled;
}
break;
default:
/* do not process rejected action frames */
if (mgmt->u.action.category & 0x80)
return RX_DROP_MONITOR;
return RX_CONTINUE;
}
rx->sta->rx_packets++;
/*
* For AP mode, hostapd is responsible for handling any action
* frames that we didn't handle, including returning unknown
* ones. For all other modes we will return them to the sender,
* setting the 0x80 bit in the action category, as required by
* 802.11-2007 7.3.1.11.
*/
if (sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
return RX_DROP_MONITOR;
/*
* Getting here means the kernel doesn't know how to handle
* it, but maybe userspace does ... include returned frames
* so userspace can register for those to know whether ones
* it transmitted were processed or returned.
*/
status = IEEE80211_SKB_RXCB(rx->skb);
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
cfg80211_rx_action(rx->sdata->dev, status->freq,
rx->skb->data, rx->skb->len,
GFP_ATOMIC))
goto handled;
/* do not return rejected action frames */
if (mgmt->u.action.category & 0x80)
return RX_DROP_UNUSABLE;
nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0,
GFP_ATOMIC);
if (nskb) {
struct ieee80211_mgmt *mgmt = (void *)nskb->data;
mgmt->u.action.category |= 0x80;
memcpy(mgmt->da, mgmt->sa, ETH_ALEN);
memcpy(mgmt->sa, rx->sdata->vif.addr, ETH_ALEN);
memset(nskb->cb, 0, sizeof(nskb->cb));
ieee80211_tx_skb(rx->sdata, nskb);
}
handled:
if (rx->sta)
rx->sta->rx_packets++;
dev_kfree_skb(rx->skb);
return RX_QUEUED;
}
@ -1970,14 +2029,13 @@ static ieee80211_rx_result debug_noinline
ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = rx->sdata;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
ieee80211_rx_result rxs;
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_MONITOR;
if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
return RX_DROP_MONITOR;
if (ieee80211_drop_unencrypted_mgmt(rx))
return RX_DROP_UNUSABLE;
rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);
if (rxs != RX_CONTINUE)

View File

@ -2,7 +2,7 @@
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2008-2010 Johannes Berg <johannes@sipsolutions.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -288,6 +288,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
msecs_to_jiffies(10));
}
if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX)
cfg80211_action_tx_status(
skb->dev, (unsigned long) skb, skb->data, skb->len,
!!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
/* this was a transmitted frame, but now we want to reuse it */
skb_orphan(skb);

View File

@ -677,6 +677,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work);
INIT_LIST_HEAD(&wdev->event_list);
spin_lock_init(&wdev->event_lock);
INIT_LIST_HEAD(&wdev->action_registrations);
spin_lock_init(&wdev->action_registrations_lock);
mutex_lock(&rdev->devlist_mtx);
list_add_rcu(&wdev->list, &rdev->netdev_list);
rdev->devlist_generation++;
@ -695,19 +698,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
wdev->wext.default_key = -1;
wdev->wext.default_mgmt_key = -1;
wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
#endif
if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT)
wdev->wext.ps = true;
wdev->ps = true;
else
wdev->wext.ps = false;
wdev->wext.ps_timeout = 100;
wdev->ps = false;
wdev->ps_timeout = 100;
if (rdev->ops->set_power_mgmt)
if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
wdev->wext.ps,
wdev->wext.ps_timeout)) {
wdev->ps,
wdev->ps_timeout)) {
/* assume this means it's off */
wdev->wext.ps = false;
wdev->ps = false;
}
#endif
if (!dev->ethtool_ops)
dev->ethtool_ops = &cfg80211_ethtool_ops;
@ -792,6 +797,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
sysfs_remove_link(&dev->dev.kobj, "phy80211");
list_del_rcu(&wdev->list);
rdev->devlist_generation++;
cfg80211_mlme_purge_actions(wdev);
#ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.keys);
#endif

View File

@ -329,6 +329,15 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
const u8 *resp_ie, size_t resp_ie_len,
u16 status, bool wextev,
struct cfg80211_bss *bss);
int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
const u8 *match_data, int match_len);
void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid);
void cfg80211_mlme_purge_actions(struct wireless_dev *wdev);
int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
const u8 *buf, size_t len, u64 *cookie);
/* SME */
int __cfg80211_connect(struct cfg80211_registered_device *rdev,

Some files were not shown because too many files have changed in this diff Show More