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

This commit is contained in:
David S. Miller 2011-01-06 10:55:42 -08:00
Родитель 2c6607c611 06778b1c38
Коммит 5f9251cb93
108 изменённых файлов: 6017 добавлений и 1645 удалений

Просмотреть файл

@ -5053,7 +5053,7 @@ L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained
F: drivers/net/wireless/rtl818x/rtl8180*
F: drivers/net/wireless/rtl818x/rtl8180/
RTL8187 WIRELESS DRIVER
M: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
@ -5063,7 +5063,7 @@ L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained
F: drivers/net/wireless/rtl818x/rtl8187*
F: drivers/net/wireless/rtl818x/rtl8187/
RTL8192CE WIRELESS DRIVER
M: Larry Finger <Larry.Finger@lwfinger.net>

Просмотреть файл

@ -4652,24 +4652,18 @@ static ssize_t proc_write( struct file *file,
size_t len,
loff_t *offset )
{
loff_t pos = *offset;
ssize_t ret;
struct proc_data *priv = file->private_data;
if (!priv->wbuffer)
return -EINVAL;
if (pos < 0)
return -EINVAL;
if (pos >= priv->maxwritelen)
return 0;
if (len > priv->maxwritelen - pos)
len = priv->maxwritelen - pos;
if (copy_from_user(priv->wbuffer + pos, buffer, len))
return -EFAULT;
if ( pos + len > priv->writelen )
priv->writelen = len + file->f_pos;
*offset = pos + len;
return len;
ret = simple_write_to_buffer(priv->wbuffer, priv->maxwritelen, offset,
buffer, len);
if (ret > 0)
priv->writelen = max_t(int, priv->writelen, *offset);
return ret;
}
static int proc_status_open(struct inode *inode, struct file *file)

Просмотреть файл

@ -14,6 +14,7 @@ ath5k-y += led.o
ath5k-y += rfkill.o
ath5k-y += ani.o
ath5k-y += sysfs.o
ath5k-y += mac80211-ops.o
ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o
ath5k-$(CONFIG_ATH5K_AHB) += ahb.o
ath5k-$(CONFIG_ATH5K_PCI) += pci.o

Просмотреть файл

@ -154,10 +154,6 @@
udelay(1); \
} while (0)
/* Register dumps are done per operation mode */
#define AR5K_INI_RFGAIN_5GHZ 0
#define AR5K_INI_RFGAIN_2GHZ 1
/*
* Some tuneable values (these should be changeable by the user)
* TODO: Make use of them and add more options OR use debug/configfs
@ -1107,12 +1103,14 @@ struct ath5k_hw {
/* Values in 0.25dB units */
s16 txp_min_pwr;
s16 txp_max_pwr;
s16 txp_cur_pwr;
/* Values in 0.5dB units */
s16 txp_offset;
s16 txp_ofdm;
s16 txp_cck_ofdm_gainf_delta;
/* Value in dB units */
s16 txp_cck_ofdm_pwr_delta;
bool txp_setup;
} ah_txpower;
struct {
@ -1320,7 +1318,7 @@ void ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode);
int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower);
/* Init function */
int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
u8 mode, u8 ee_mode, u8 freq, bool fast);
u8 mode, bool fast);
/*
* Functions used internaly

Просмотреть файл

@ -276,7 +276,7 @@ int ath5k_hw_init(struct ath5k_softc *sc)
/*
* Write PCI-E power save settings
*/
if ((ah->ah_version == AR5K_AR5212) && pdev && (pdev->is_pcie)) {
if ((ah->ah_version == AR5K_AR5212) && pdev && (pci_is_pcie(pdev))) {
ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);

Просмотреть файл

@ -61,8 +61,8 @@
#include "debug.h"
#include "ani.h"
static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
int ath5k_modparam_nohwcrypt;
module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
static int modparam_all_channels;
@ -79,9 +79,8 @@ MODULE_LICENSE("Dual BSD/GPL");
static int ath5k_init(struct ieee80211_hw *hw);
static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
bool skip_pcu);
static int ath5k_beacon_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
/* Known SREVs */
static const struct ath5k_srev_name srev_names[] = {
@ -177,38 +176,6 @@ static const struct ieee80211_rate ath5k_rates[] = {
/* XR missing */
};
static inline void ath5k_txbuf_free_skb(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
BUG_ON(!bf);
if (!bf->skb)
return;
dma_unmap_single(sc->dev, bf->skbaddr, bf->skb->len,
DMA_TO_DEVICE);
dev_kfree_skb_any(bf->skb);
bf->skb = NULL;
bf->skbaddr = 0;
bf->desc->ds_data = 0;
}
static inline void ath5k_rxbuf_free_skb(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
BUG_ON(!bf);
if (!bf->skb)
return;
dma_unmap_single(sc->dev, bf->skbaddr, common->rx_bufsize,
DMA_FROM_DEVICE);
dev_kfree_skb_any(bf->skb);
bf->skb = NULL;
bf->skbaddr = 0;
bf->desc->ds_data = 0;
}
static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
{
u64 tsf = ath5k_hw_get_tsf64(ah);
@ -462,7 +429,7 @@ ath5k_setup_bands(struct ieee80211_hw *hw)
*
* Called with sc->lock.
*/
static int
int
ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
{
ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
@ -537,8 +504,9 @@ static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
iter_data->opmode = avf->opmode;
}
static void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
struct ieee80211_vif *vif)
void
ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
struct ieee80211_vif *vif)
{
struct ath_common *common = ath5k_hw_common(sc->ah);
struct ath_vif_iter_data iter_data;
@ -577,7 +545,7 @@ static void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
}
static void
void
ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif)
{
struct ath5k_hw *ah = sc->ah;
@ -887,6 +855,37 @@ err:
return ret;
}
void
ath5k_txbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf)
{
BUG_ON(!bf);
if (!bf->skb)
return;
dma_unmap_single(sc->dev, bf->skbaddr, bf->skb->len,
DMA_TO_DEVICE);
dev_kfree_skb_any(bf->skb);
bf->skb = NULL;
bf->skbaddr = 0;
bf->desc->ds_data = 0;
}
void
ath5k_rxbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf)
{
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
BUG_ON(!bf);
if (!bf->skb)
return;
dma_unmap_single(sc->dev, bf->skbaddr, common->rx_bufsize,
DMA_FROM_DEVICE);
dev_kfree_skb_any(bf->skb);
bf->skb = NULL;
bf->skbaddr = 0;
bf->desc->ds_data = 0;
}
static void
ath5k_desc_free(struct ath5k_softc *sc)
{
@ -1534,8 +1533,9 @@ unlock:
* TX Handling *
\*************/
static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath5k_txq *txq)
int
ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath5k_txq *txq)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_buf *bf;
@ -1801,7 +1801,7 @@ err_unmap:
*
* Called with the beacon lock.
*/
static int
int
ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
int ret;
@ -1947,7 +1947,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
* when we otherwise know we have to update the timers, but we keep it in this
* function to have it all together in one place.
*/
static void
void
ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
{
struct ath5k_hw *ah = sc->ah;
@ -2049,7 +2049,7 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
* In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA
* interrupts to detect TSF updates only.
*/
static void
void
ath5k_beacon_config(struct ath5k_softc *sc)
{
struct ath5k_hw *ah = sc->ah;
@ -2525,7 +2525,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
return 0;
}
static int
int
ath5k_init_hw(struct ath5k_softc *sc)
{
struct ath5k_hw *ah = sc->ah;
@ -2601,7 +2601,7 @@ static void stop_tasklets(struct ath5k_softc *sc)
* if another thread does a system call and the thread doing the
* stop is preempted).
*/
static int
int
ath5k_stop_hw(struct ath5k_softc *sc)
{
int ret;
@ -2703,11 +2703,11 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
/* clear survey data and cycle counters */
memset(&sc->survey, 0, sizeof(sc->survey));
spin_lock(&common->cc_lock);
spin_lock_bh(&common->cc_lock);
ath_hw_cycle_counters_update(common);
memset(&common->cc_survey, 0, sizeof(common->cc_survey));
memset(&common->cc_ani, 0, sizeof(common->cc_ani));
spin_unlock(&common->cc_lock);
spin_unlock_bh(&common->cc_lock);
/*
* Change channels and update the h/w rate map if we're switching;
@ -2939,230 +2939,8 @@ ath5k_deinit_softc(struct ath5k_softc *sc)
free_irq(sc->irq, sc);
}
/********************\
* Mac80211 functions *
\********************/
static int
ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath5k_softc *sc = hw->priv;
u16 qnum = skb_get_queue_mapping(skb);
if (WARN_ON(qnum >= sc->ah->ah_capabilities.cap_queues.q_tx_num)) {
dev_kfree_skb_any(skb);
return 0;
}
return ath5k_tx_queue(hw, skb, &sc->txqs[qnum]);
}
static int ath5k_start(struct ieee80211_hw *hw)
{
return ath5k_init_hw(hw->priv);
}
static void ath5k_stop(struct ieee80211_hw *hw)
{
ath5k_stop_hw(hw->priv);
}
static int ath5k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath5k_softc *sc = hw->priv;
int ret;
struct ath5k_vif *avf = (void *)vif->drv_priv;
mutex_lock(&sc->lock);
if ((vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_ADHOC)
&& (sc->num_ap_vifs + sc->num_adhoc_vifs) >= ATH_BCBUF) {
ret = -ELNRNG;
goto end;
}
/* Don't allow other interfaces if one ad-hoc is configured.
* TODO: Fix the problems with ad-hoc and multiple other interfaces.
* We would need to operate the HW in ad-hoc mode to allow TSF updates
* for the IBSS, but this breaks with additional AP or STA interfaces
* at the moment. */
if (sc->num_adhoc_vifs ||
(sc->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
ATH5K_ERR(sc, "Only one single ad-hoc interface is allowed.\n");
ret = -ELNRNG;
goto end;
}
switch (vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
avf->opmode = vif->type;
break;
default:
ret = -EOPNOTSUPP;
goto end;
}
sc->nvifs++;
ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode);
/* Assign the vap/adhoc to a beacon xmit slot. */
if ((avf->opmode == NL80211_IFTYPE_AP) ||
(avf->opmode == NL80211_IFTYPE_ADHOC) ||
(avf->opmode == NL80211_IFTYPE_MESH_POINT)) {
int slot;
WARN_ON(list_empty(&sc->bcbuf));
avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf,
list);
list_del(&avf->bbuf->list);
avf->bslot = 0;
for (slot = 0; slot < ATH_BCBUF; slot++) {
if (!sc->bslot[slot]) {
avf->bslot = slot;
break;
}
}
BUG_ON(sc->bslot[avf->bslot] != NULL);
sc->bslot[avf->bslot] = vif;
if (avf->opmode == NL80211_IFTYPE_AP)
sc->num_ap_vifs++;
else if (avf->opmode == NL80211_IFTYPE_ADHOC)
sc->num_adhoc_vifs++;
}
/* Any MAC address is fine, all others are included through the
* filter.
*/
memcpy(&sc->lladdr, vif->addr, ETH_ALEN);
ath5k_hw_set_lladdr(sc->ah, vif->addr);
memcpy(&avf->lladdr, vif->addr, ETH_ALEN);
ath5k_mode_setup(sc, vif);
ret = 0;
end:
mutex_unlock(&sc->lock);
return ret;
}
static void
ath5k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_vif *avf = (void *)vif->drv_priv;
unsigned int i;
mutex_lock(&sc->lock);
sc->nvifs--;
if (avf->bbuf) {
ath5k_txbuf_free_skb(sc, avf->bbuf);
list_add_tail(&avf->bbuf->list, &sc->bcbuf);
for (i = 0; i < ATH_BCBUF; i++) {
if (sc->bslot[i] == vif) {
sc->bslot[i] = NULL;
break;
}
}
avf->bbuf = NULL;
}
if (avf->opmode == NL80211_IFTYPE_AP)
sc->num_ap_vifs--;
else if (avf->opmode == NL80211_IFTYPE_ADHOC)
sc->num_adhoc_vifs--;
ath5k_update_bssid_mask_and_opmode(sc, NULL);
mutex_unlock(&sc->lock);
}
/*
* TODO: Phy disable/diversity etc
*/
static int
ath5k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
struct ieee80211_conf *conf = &hw->conf;
int ret = 0;
mutex_lock(&sc->lock);
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
ret = ath5k_chan_set(sc, conf->channel);
if (ret < 0)
goto unlock;
}
if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
(sc->power_level != conf->power_level)) {
sc->power_level = conf->power_level;
/* Half dB steps */
ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));
}
/* TODO:
* 1) Move this on config_interface and handle each case
* separately eg. when we have only one STA vif, use
* AR5K_ANTMODE_SINGLE_AP
*
* 2) Allow the user to change antenna mode eg. when only
* one antenna is present
*
* 3) Allow the user to set default/tx antenna when possible
*
* 4) Default mode should handle 90% of the cases, together
* with fixed a/b and single AP modes we should be able to
* handle 99%. Sectored modes are extreme cases and i still
* haven't found a usage for them. If we decide to support them,
* then we must allow the user to set how many tx antennas we
* have available
*/
ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
unlock:
mutex_unlock(&sc->lock);
return ret;
}
static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list)
{
u32 mfilt[2], val;
u8 pos;
struct netdev_hw_addr *ha;
mfilt[0] = 0;
mfilt[1] = 1;
netdev_hw_addr_list_for_each(ha, mc_list) {
/* calculate XOR of eight 6-bit values */
val = get_unaligned_le32(ha->addr + 0);
pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
val = get_unaligned_le32(ha->addr + 3);
pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
pos &= 0x3f;
mfilt[pos / 32] |= (1 << (pos % 32));
/* XXX: we might be able to just do this instead,
* but not sure, needs testing, if we do use this we'd
* neet to inform below to not reset the mcast */
/* ath5k_hw_set_mcast_filterindex(ah,
* ha->addr[5]); */
}
return ((u64)(mfilt[1]) << 32) | mfilt[0];
}
static bool ath_any_vif_assoc(struct ath5k_softc *sc)
bool
ath_any_vif_assoc(struct ath5k_softc *sc)
{
struct ath_vif_iter_data iter_data;
iter_data.hw_macaddr = NULL;
@ -3175,262 +2953,7 @@ static bool ath_any_vif_assoc(struct ath5k_softc *sc)
return iter_data.any_assoc;
}
#define SUPPORTED_FIF_FLAGS \
FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
FIF_BCN_PRBRESP_PROMISC
/*
* o always accept unicast, broadcast, and multicast traffic
* o multicast traffic for all BSSIDs will be enabled if mac80211
* says it should be
* o maintain current state of phy ofdm or phy cck error reception.
* If the hardware detects any of these type of errors then
* ath5k_hw_get_rx_filter() will pass to us the respective
* hardware filters to be able to receive these type of frames.
* o probe request frames are accepted only when operating in
* hostap, adhoc, or monitor modes
* o enable promiscuous mode according to the interface state
* o accept beacons:
* - when operating in adhoc mode so the 802.11 layer creates
* node table entries for peers,
* - when operating in station mode for collecting rssi data when
* the station is otherwise quiet, or
* - when scanning
*/
static void ath5k_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *new_flags,
u64 multicast)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
u32 mfilt[2], rfilt;
mutex_lock(&sc->lock);
mfilt[0] = multicast;
mfilt[1] = multicast >> 32;
/* Only deal with supported flags */
changed_flags &= SUPPORTED_FIF_FLAGS;
*new_flags &= SUPPORTED_FIF_FLAGS;
/* If HW detects any phy or radar errors, leave those filters on.
* Also, always enable Unicast, Broadcasts and Multicast
* XXX: move unicast, bssid broadcasts and multicast to mac80211 */
rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) |
(AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
AR5K_RX_FILTER_MCAST);
if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
if (*new_flags & FIF_PROMISC_IN_BSS) {
__set_bit(ATH_STAT_PROMISC, sc->status);
} else {
__clear_bit(ATH_STAT_PROMISC, sc->status);
}
}
if (test_bit(ATH_STAT_PROMISC, sc->status))
rfilt |= AR5K_RX_FILTER_PROM;
/* Note, AR5K_RX_FILTER_MCAST is already enabled */
if (*new_flags & FIF_ALLMULTI) {
mfilt[0] = ~0;
mfilt[1] = ~0;
}
/* This is the best we can do */
if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))
rfilt |= AR5K_RX_FILTER_PHYERR;
/* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
* and probes for any BSSID */
if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1))
rfilt |= AR5K_RX_FILTER_BEACON;
/* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
* set we should only pass on control frames for this
* station. This needs testing. I believe right now this
* enables *all* control frames, which is OK.. but
* but we should see if we can improve on granularity */
if (*new_flags & FIF_CONTROL)
rfilt |= AR5K_RX_FILTER_CONTROL;
/* Additional settings per mode -- this is per ath5k */
/* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
switch (sc->opmode) {
case NL80211_IFTYPE_MESH_POINT:
rfilt |= AR5K_RX_FILTER_CONTROL |
AR5K_RX_FILTER_BEACON |
AR5K_RX_FILTER_PROBEREQ |
AR5K_RX_FILTER_PROM;
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
rfilt |= AR5K_RX_FILTER_PROBEREQ |
AR5K_RX_FILTER_BEACON;
break;
case NL80211_IFTYPE_STATION:
if (sc->assoc)
rfilt |= AR5K_RX_FILTER_BEACON;
default:
break;
}
/* Set filters */
ath5k_hw_set_rx_filter(ah, rfilt);
/* Set multicast bits */
ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
/* Set the cached hw filter flags, this will later actually
* be set in HW */
sc->filter_flags = rfilt;
mutex_unlock(&sc->lock);
}
static int
ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
int ret = 0;
if (modparam_nohwcrypt)
return -EOPNOTSUPP;
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
case WLAN_CIPHER_SUITE_TKIP:
break;
case WLAN_CIPHER_SUITE_CCMP:
if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)
break;
return -EOPNOTSUPP;
default:
WARN_ON(1);
return -EINVAL;
}
mutex_lock(&sc->lock);
switch (cmd) {
case SET_KEY:
ret = ath_key_config(common, vif, sta, key);
if (ret >= 0) {
key->hw_key_idx = ret;
/* push IV and Michael MIC generation to stack */
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
ret = 0;
}
break;
case DISABLE_KEY:
ath_key_delete(common, key);
break;
default:
ret = -EINVAL;
}
mmiowb();
mutex_unlock(&sc->lock);
return ret;
}
static int
ath5k_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
struct ath5k_softc *sc = hw->priv;
/* Force update */
ath5k_hw_update_mib_counters(sc->ah);
stats->dot11ACKFailureCount = sc->stats.ack_fail;
stats->dot11RTSFailureCount = sc->stats.rts_fail;
stats->dot11RTSSuccessCount = sc->stats.rts_ok;
stats->dot11FCSErrorCount = sc->stats.fcs_error;
return 0;
}
static int ath5k_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey)
{
struct ath5k_softc *sc = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
struct ath_common *common = ath5k_hw_common(sc->ah);
struct ath_cycle_counters *cc = &common->cc_survey;
unsigned int div = common->clockrate * 1000;
if (idx != 0)
return -ENOENT;
spin_lock_bh(&common->cc_lock);
ath_hw_cycle_counters_update(common);
if (cc->cycles > 0) {
sc->survey.channel_time += cc->cycles / div;
sc->survey.channel_time_busy += cc->rx_busy / div;
sc->survey.channel_time_rx += cc->rx_frame / div;
sc->survey.channel_time_tx += cc->tx_frame / div;
}
memset(cc, 0, sizeof(*cc));
spin_unlock_bh(&common->cc_lock);
memcpy(survey, &sc->survey, sizeof(*survey));
survey->channel = conf->channel;
survey->noise = sc->ah->ah_noise_floor;
survey->filled = SURVEY_INFO_NOISE_DBM |
SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_RX |
SURVEY_INFO_CHANNEL_TIME_TX;
return 0;
}
static u64
ath5k_get_tsf(struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
return ath5k_hw_get_tsf64(sc->ah);
}
static void
ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
{
struct ath5k_softc *sc = hw->priv;
ath5k_hw_set_tsf64(sc->ah, tsf);
}
static void
ath5k_reset_tsf(struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
/*
* in IBSS mode we need to update the beacon timers too.
* this will also reset the TSF if we call it with 0
*/
if (sc->opmode == NL80211_IFTYPE_ADHOC)
ath5k_beacon_update_timers(sc, 0);
else
ath5k_hw_reset_tsf(sc->ah);
}
static void
void
set_beacon_filter(struct ieee80211_hw *hw, bool enable)
{
struct ath5k_softc *sc = hw->priv;
@ -3444,189 +2967,3 @@ set_beacon_filter(struct ieee80211_hw *hw, bool enable)
ath5k_hw_set_rx_filter(ah, rfilt);
sc->filter_flags = rfilt;
}
static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changes)
{
struct ath5k_vif *avf = (void *)vif->drv_priv;
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
unsigned long flags;
mutex_lock(&sc->lock);
if (changes & BSS_CHANGED_BSSID) {
/* Cache for later use during resets */
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
common->curaid = 0;
ath5k_hw_set_bssid(ah);
mmiowb();
}
if (changes & BSS_CHANGED_BEACON_INT)
sc->bintval = bss_conf->beacon_int;
if (changes & BSS_CHANGED_ASSOC) {
avf->assoc = bss_conf->assoc;
if (bss_conf->assoc)
sc->assoc = bss_conf->assoc;
else
sc->assoc = ath_any_vif_assoc(sc);
if (sc->opmode == NL80211_IFTYPE_STATION)
set_beacon_filter(hw, sc->assoc);
ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
AR5K_LED_ASSOC : AR5K_LED_INIT);
if (bss_conf->assoc) {
ATH5K_DBG(sc, ATH5K_DEBUG_ANY,
"Bss Info ASSOC %d, bssid: %pM\n",
bss_conf->aid, common->curbssid);
common->curaid = bss_conf->aid;
ath5k_hw_set_bssid(ah);
/* Once ANI is available you would start it here */
}
}
if (changes & BSS_CHANGED_BEACON) {
spin_lock_irqsave(&sc->block, flags);
ath5k_beacon_update(hw, vif);
spin_unlock_irqrestore(&sc->block, flags);
}
if (changes & BSS_CHANGED_BEACON_ENABLED)
sc->enable_beacon = bss_conf->enable_beacon;
if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |
BSS_CHANGED_BEACON_INT))
ath5k_beacon_config(sc);
mutex_unlock(&sc->lock);
}
static void ath5k_sw_scan_start(struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
if (!sc->assoc)
ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN);
}
static void ath5k_sw_scan_complete(struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
AR5K_LED_ASSOC : AR5K_LED_INIT);
}
/**
* ath5k_set_coverage_class - Set IEEE 802.11 coverage class
*
* @hw: struct ieee80211_hw pointer
* @coverage_class: IEEE 802.11 coverage class number
*
* Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given
* coverage class. The values are persistent, they are restored after device
* reset.
*/
static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
{
struct ath5k_softc *sc = hw->priv;
mutex_lock(&sc->lock);
ath5k_hw_set_coverage_class(sc->ah, coverage_class);
mutex_unlock(&sc->lock);
}
static int ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
struct ath5k_txq_info qi;
int ret = 0;
if (queue >= ah->ah_capabilities.cap_queues.q_tx_num)
return 0;
mutex_lock(&sc->lock);
ath5k_hw_get_tx_queueprops(ah, queue, &qi);
qi.tqi_aifs = params->aifs;
qi.tqi_cw_min = params->cw_min;
qi.tqi_cw_max = params->cw_max;
qi.tqi_burst_time = params->txop;
ATH5K_DBG(sc, ATH5K_DEBUG_ANY,
"Configure tx [queue %d], "
"aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
queue, params->aifs, params->cw_min,
params->cw_max, params->txop);
if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) {
ATH5K_ERR(sc,
"Unable to update hardware queue %u!\n", queue);
ret = -EIO;
} else
ath5k_hw_reset_tx_queue(ah, queue);
mutex_unlock(&sc->lock);
return ret;
}
static int ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
{
struct ath5k_softc *sc = hw->priv;
if (tx_ant == 1 && rx_ant == 1)
ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_A);
else if (tx_ant == 2 && rx_ant == 2)
ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_B);
else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3)
ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_DEFAULT);
else
return -EINVAL;
return 0;
}
static int ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
{
struct ath5k_softc *sc = hw->priv;
switch (sc->ah->ah_ant_mode) {
case AR5K_ANTMODE_FIXED_A:
*tx_ant = 1; *rx_ant = 1; break;
case AR5K_ANTMODE_FIXED_B:
*tx_ant = 2; *rx_ant = 2; break;
case AR5K_ANTMODE_DEFAULT:
*tx_ant = 3; *rx_ant = 3; break;
}
return 0;
}
const struct ieee80211_ops ath5k_hw_ops = {
.tx = ath5k_tx,
.start = ath5k_start,
.stop = ath5k_stop,
.add_interface = ath5k_add_interface,
.remove_interface = ath5k_remove_interface,
.config = ath5k_config,
.prepare_multicast = ath5k_prepare_multicast,
.configure_filter = ath5k_configure_filter,
.set_key = ath5k_set_key,
.get_stats = ath5k_get_stats,
.get_survey = ath5k_get_survey,
.conf_tx = ath5k_conf_tx,
.get_tsf = ath5k_get_tsf,
.set_tsf = ath5k_set_tsf,
.reset_tsf = ath5k_reset_tsf,
.bss_info_changed = ath5k_bss_info_changed,
.sw_scan_start = ath5k_sw_scan_start,
.sw_scan_complete = ath5k_sw_scan_complete,
.set_coverage_class = ath5k_set_coverage_class,
.set_antenna = ath5k_set_antenna,
.get_antenna = ath5k_get_antenna,
};

Просмотреть файл

@ -1802,3 +1802,19 @@ ath5k_eeprom_detach(struct ath5k_hw *ah)
for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++)
ath5k_eeprom_free_pcal_info(ah, mode);
}
int
ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel)
{
switch (channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
case CHANNEL_XR:
return AR5K_EEPROM_MODE_11A;
case CHANNEL_G:
return AR5K_EEPROM_MODE_11G;
case CHANNEL_B:
return AR5K_EEPROM_MODE_11B;
default:
return -1;
}
}

Просмотреть файл

@ -517,3 +517,5 @@ struct ath5k_eeprom_info {
u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
};
int
ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel);

Просмотреть файл

@ -0,0 +1,774 @@
/*-
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
* Copyright (c) 2004-2005 Atheros Communications, Inc.
* Copyright (c) 2006 Devicescape Software, Inc.
* Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
* Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
* Copyright (c) 2010 Bruno Randolf <br1@einfach.org>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
* 3. Neither the names of the above-listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
*/
#include <asm/unaligned.h>
#include "base.h"
#include "reg.h"
extern int ath5k_modparam_nohwcrypt;
/* functions used from base.c */
void set_beacon_filter(struct ieee80211_hw *hw, bool enable);
bool ath_any_vif_assoc(struct ath5k_softc *sc);
int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath5k_txq *txq);
int ath5k_init_hw(struct ath5k_softc *sc);
int ath5k_stop_hw(struct ath5k_softc *sc);
void ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif);
void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
struct ieee80211_vif *vif);
int ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan);
void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void ath5k_beacon_config(struct ath5k_softc *sc);
void ath5k_txbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf);
void ath5k_rxbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf);
/********************\
* Mac80211 functions *
\********************/
static int
ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath5k_softc *sc = hw->priv;
u16 qnum = skb_get_queue_mapping(skb);
if (WARN_ON(qnum >= sc->ah->ah_capabilities.cap_queues.q_tx_num)) {
dev_kfree_skb_any(skb);
return 0;
}
return ath5k_tx_queue(hw, skb, &sc->txqs[qnum]);
}
static int
ath5k_start(struct ieee80211_hw *hw)
{
return ath5k_init_hw(hw->priv);
}
static void
ath5k_stop(struct ieee80211_hw *hw)
{
ath5k_stop_hw(hw->priv);
}
static int
ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct ath5k_softc *sc = hw->priv;
int ret;
struct ath5k_vif *avf = (void *)vif->drv_priv;
mutex_lock(&sc->lock);
if ((vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_ADHOC)
&& (sc->num_ap_vifs + sc->num_adhoc_vifs) >= ATH_BCBUF) {
ret = -ELNRNG;
goto end;
}
/* Don't allow other interfaces if one ad-hoc is configured.
* TODO: Fix the problems with ad-hoc and multiple other interfaces.
* We would need to operate the HW in ad-hoc mode to allow TSF updates
* for the IBSS, but this breaks with additional AP or STA interfaces
* at the moment. */
if (sc->num_adhoc_vifs ||
(sc->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
ATH5K_ERR(sc, "Only one single ad-hoc interface is allowed.\n");
ret = -ELNRNG;
goto end;
}
switch (vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
avf->opmode = vif->type;
break;
default:
ret = -EOPNOTSUPP;
goto end;
}
sc->nvifs++;
ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode);
/* Assign the vap/adhoc to a beacon xmit slot. */
if ((avf->opmode == NL80211_IFTYPE_AP) ||
(avf->opmode == NL80211_IFTYPE_ADHOC) ||
(avf->opmode == NL80211_IFTYPE_MESH_POINT)) {
int slot;
WARN_ON(list_empty(&sc->bcbuf));
avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf,
list);
list_del(&avf->bbuf->list);
avf->bslot = 0;
for (slot = 0; slot < ATH_BCBUF; slot++) {
if (!sc->bslot[slot]) {
avf->bslot = slot;
break;
}
}
BUG_ON(sc->bslot[avf->bslot] != NULL);
sc->bslot[avf->bslot] = vif;
if (avf->opmode == NL80211_IFTYPE_AP)
sc->num_ap_vifs++;
else if (avf->opmode == NL80211_IFTYPE_ADHOC)
sc->num_adhoc_vifs++;
}
/* Any MAC address is fine, all others are included through the
* filter.
*/
memcpy(&sc->lladdr, vif->addr, ETH_ALEN);
ath5k_hw_set_lladdr(sc->ah, vif->addr);
memcpy(&avf->lladdr, vif->addr, ETH_ALEN);
ath5k_mode_setup(sc, vif);
ret = 0;
end:
mutex_unlock(&sc->lock);
return ret;
}
static void
ath5k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_vif *avf = (void *)vif->drv_priv;
unsigned int i;
mutex_lock(&sc->lock);
sc->nvifs--;
if (avf->bbuf) {
ath5k_txbuf_free_skb(sc, avf->bbuf);
list_add_tail(&avf->bbuf->list, &sc->bcbuf);
for (i = 0; i < ATH_BCBUF; i++) {
if (sc->bslot[i] == vif) {
sc->bslot[i] = NULL;
break;
}
}
avf->bbuf = NULL;
}
if (avf->opmode == NL80211_IFTYPE_AP)
sc->num_ap_vifs--;
else if (avf->opmode == NL80211_IFTYPE_ADHOC)
sc->num_adhoc_vifs--;
ath5k_update_bssid_mask_and_opmode(sc, NULL);
mutex_unlock(&sc->lock);
}
/*
* TODO: Phy disable/diversity etc
*/
static int
ath5k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
struct ieee80211_conf *conf = &hw->conf;
int ret = 0;
mutex_lock(&sc->lock);
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
ret = ath5k_chan_set(sc, conf->channel);
if (ret < 0)
goto unlock;
}
if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
(sc->power_level != conf->power_level)) {
sc->power_level = conf->power_level;
/* Half dB steps */
ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));
}
/* TODO:
* 1) Move this on config_interface and handle each case
* separately eg. when we have only one STA vif, use
* AR5K_ANTMODE_SINGLE_AP
*
* 2) Allow the user to change antenna mode eg. when only
* one antenna is present
*
* 3) Allow the user to set default/tx antenna when possible
*
* 4) Default mode should handle 90% of the cases, together
* with fixed a/b and single AP modes we should be able to
* handle 99%. Sectored modes are extreme cases and i still
* haven't found a usage for them. If we decide to support them,
* then we must allow the user to set how many tx antennas we
* have available
*/
ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
unlock:
mutex_unlock(&sc->lock);
return ret;
}
static void
ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf, u32 changes)
{
struct ath5k_vif *avf = (void *)vif->drv_priv;
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
unsigned long flags;
mutex_lock(&sc->lock);
if (changes & BSS_CHANGED_BSSID) {
/* Cache for later use during resets */
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
common->curaid = 0;
ath5k_hw_set_bssid(ah);
mmiowb();
}
if (changes & BSS_CHANGED_BEACON_INT)
sc->bintval = bss_conf->beacon_int;
if (changes & BSS_CHANGED_ASSOC) {
avf->assoc = bss_conf->assoc;
if (bss_conf->assoc)
sc->assoc = bss_conf->assoc;
else
sc->assoc = ath_any_vif_assoc(sc);
if (sc->opmode == NL80211_IFTYPE_STATION)
set_beacon_filter(hw, sc->assoc);
ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
AR5K_LED_ASSOC : AR5K_LED_INIT);
if (bss_conf->assoc) {
ATH5K_DBG(sc, ATH5K_DEBUG_ANY,
"Bss Info ASSOC %d, bssid: %pM\n",
bss_conf->aid, common->curbssid);
common->curaid = bss_conf->aid;
ath5k_hw_set_bssid(ah);
/* Once ANI is available you would start it here */
}
}
if (changes & BSS_CHANGED_BEACON) {
spin_lock_irqsave(&sc->block, flags);
ath5k_beacon_update(hw, vif);
spin_unlock_irqrestore(&sc->block, flags);
}
if (changes & BSS_CHANGED_BEACON_ENABLED)
sc->enable_beacon = bss_conf->enable_beacon;
if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |
BSS_CHANGED_BEACON_INT))
ath5k_beacon_config(sc);
mutex_unlock(&sc->lock);
}
static u64
ath5k_prepare_multicast(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list)
{
u32 mfilt[2], val;
u8 pos;
struct netdev_hw_addr *ha;
mfilt[0] = 0;
mfilt[1] = 1;
netdev_hw_addr_list_for_each(ha, mc_list) {
/* calculate XOR of eight 6-bit values */
val = get_unaligned_le32(ha->addr + 0);
pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
val = get_unaligned_le32(ha->addr + 3);
pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
pos &= 0x3f;
mfilt[pos / 32] |= (1 << (pos % 32));
/* XXX: we might be able to just do this instead,
* but not sure, needs testing, if we do use this we'd
* neet to inform below to not reset the mcast */
/* ath5k_hw_set_mcast_filterindex(ah,
* ha->addr[5]); */
}
return ((u64)(mfilt[1]) << 32) | mfilt[0];
}
/*
* o always accept unicast, broadcast, and multicast traffic
* o multicast traffic for all BSSIDs will be enabled if mac80211
* says it should be
* o maintain current state of phy ofdm or phy cck error reception.
* If the hardware detects any of these type of errors then
* ath5k_hw_get_rx_filter() will pass to us the respective
* hardware filters to be able to receive these type of frames.
* o probe request frames are accepted only when operating in
* hostap, adhoc, or monitor modes
* o enable promiscuous mode according to the interface state
* o accept beacons:
* - when operating in adhoc mode so the 802.11 layer creates
* node table entries for peers,
* - when operating in station mode for collecting rssi data when
* the station is otherwise quiet, or
* - when scanning
*/
static void
ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
unsigned int *new_flags, u64 multicast)
{
#define SUPPORTED_FIF_FLAGS \
(FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
FIF_BCN_PRBRESP_PROMISC)
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
u32 mfilt[2], rfilt;
mutex_lock(&sc->lock);
mfilt[0] = multicast;
mfilt[1] = multicast >> 32;
/* Only deal with supported flags */
changed_flags &= SUPPORTED_FIF_FLAGS;
*new_flags &= SUPPORTED_FIF_FLAGS;
/* If HW detects any phy or radar errors, leave those filters on.
* Also, always enable Unicast, Broadcasts and Multicast
* XXX: move unicast, bssid broadcasts and multicast to mac80211 */
rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) |
(AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
AR5K_RX_FILTER_MCAST);
if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
if (*new_flags & FIF_PROMISC_IN_BSS)
__set_bit(ATH_STAT_PROMISC, sc->status);
else
__clear_bit(ATH_STAT_PROMISC, sc->status);
}
if (test_bit(ATH_STAT_PROMISC, sc->status))
rfilt |= AR5K_RX_FILTER_PROM;
/* Note, AR5K_RX_FILTER_MCAST is already enabled */
if (*new_flags & FIF_ALLMULTI) {
mfilt[0] = ~0;
mfilt[1] = ~0;
}
/* This is the best we can do */
if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))
rfilt |= AR5K_RX_FILTER_PHYERR;
/* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
* and probes for any BSSID */
if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1))
rfilt |= AR5K_RX_FILTER_BEACON;
/* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
* set we should only pass on control frames for this
* station. This needs testing. I believe right now this
* enables *all* control frames, which is OK.. but
* but we should see if we can improve on granularity */
if (*new_flags & FIF_CONTROL)
rfilt |= AR5K_RX_FILTER_CONTROL;
/* Additional settings per mode -- this is per ath5k */
/* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
switch (sc->opmode) {
case NL80211_IFTYPE_MESH_POINT:
rfilt |= AR5K_RX_FILTER_CONTROL |
AR5K_RX_FILTER_BEACON |
AR5K_RX_FILTER_PROBEREQ |
AR5K_RX_FILTER_PROM;
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
rfilt |= AR5K_RX_FILTER_PROBEREQ |
AR5K_RX_FILTER_BEACON;
break;
case NL80211_IFTYPE_STATION:
if (sc->assoc)
rfilt |= AR5K_RX_FILTER_BEACON;
default:
break;
}
/* Set filters */
ath5k_hw_set_rx_filter(ah, rfilt);
/* Set multicast bits */
ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
/* Set the cached hw filter flags, this will later actually
* be set in HW */
sc->filter_flags = rfilt;
mutex_unlock(&sc->lock);
}
static int
ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
int ret = 0;
if (ath5k_modparam_nohwcrypt)
return -EOPNOTSUPP;
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
case WLAN_CIPHER_SUITE_TKIP:
break;
case WLAN_CIPHER_SUITE_CCMP:
if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)
break;
return -EOPNOTSUPP;
default:
WARN_ON(1);
return -EINVAL;
}
mutex_lock(&sc->lock);
switch (cmd) {
case SET_KEY:
ret = ath_key_config(common, vif, sta, key);
if (ret >= 0) {
key->hw_key_idx = ret;
/* push IV and Michael MIC generation to stack */
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
ret = 0;
}
break;
case DISABLE_KEY:
ath_key_delete(common, key);
break;
default:
ret = -EINVAL;
}
mmiowb();
mutex_unlock(&sc->lock);
return ret;
}
static void
ath5k_sw_scan_start(struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
if (!sc->assoc)
ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN);
}
static void
ath5k_sw_scan_complete(struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
AR5K_LED_ASSOC : AR5K_LED_INIT);
}
static int
ath5k_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
struct ath5k_softc *sc = hw->priv;
/* Force update */
ath5k_hw_update_mib_counters(sc->ah);
stats->dot11ACKFailureCount = sc->stats.ack_fail;
stats->dot11RTSFailureCount = sc->stats.rts_fail;
stats->dot11RTSSuccessCount = sc->stats.rts_ok;
stats->dot11FCSErrorCount = sc->stats.fcs_error;
return 0;
}
static int
ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
struct ath5k_txq_info qi;
int ret = 0;
if (queue >= ah->ah_capabilities.cap_queues.q_tx_num)
return 0;
mutex_lock(&sc->lock);
ath5k_hw_get_tx_queueprops(ah, queue, &qi);
qi.tqi_aifs = params->aifs;
qi.tqi_cw_min = params->cw_min;
qi.tqi_cw_max = params->cw_max;
qi.tqi_burst_time = params->txop;
ATH5K_DBG(sc, ATH5K_DEBUG_ANY,
"Configure tx [queue %d], "
"aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
queue, params->aifs, params->cw_min,
params->cw_max, params->txop);
if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) {
ATH5K_ERR(sc,
"Unable to update hardware queue %u!\n", queue);
ret = -EIO;
} else
ath5k_hw_reset_tx_queue(ah, queue);
mutex_unlock(&sc->lock);
return ret;
}
static u64
ath5k_get_tsf(struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
return ath5k_hw_get_tsf64(sc->ah);
}
static void
ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
{
struct ath5k_softc *sc = hw->priv;
ath5k_hw_set_tsf64(sc->ah, tsf);
}
static void
ath5k_reset_tsf(struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
/*
* in IBSS mode we need to update the beacon timers too.
* this will also reset the TSF if we call it with 0
*/
if (sc->opmode == NL80211_IFTYPE_ADHOC)
ath5k_beacon_update_timers(sc, 0);
else
ath5k_hw_reset_tsf(sc->ah);
}
static int
ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
{
struct ath5k_softc *sc = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
struct ath_common *common = ath5k_hw_common(sc->ah);
struct ath_cycle_counters *cc = &common->cc_survey;
unsigned int div = common->clockrate * 1000;
if (idx != 0)
return -ENOENT;
spin_lock_bh(&common->cc_lock);
ath_hw_cycle_counters_update(common);
if (cc->cycles > 0) {
sc->survey.channel_time += cc->cycles / div;
sc->survey.channel_time_busy += cc->rx_busy / div;
sc->survey.channel_time_rx += cc->rx_frame / div;
sc->survey.channel_time_tx += cc->tx_frame / div;
}
memset(cc, 0, sizeof(*cc));
spin_unlock_bh(&common->cc_lock);
memcpy(survey, &sc->survey, sizeof(*survey));
survey->channel = conf->channel;
survey->noise = sc->ah->ah_noise_floor;
survey->filled = SURVEY_INFO_NOISE_DBM |
SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_RX |
SURVEY_INFO_CHANNEL_TIME_TX;
return 0;
}
/**
* ath5k_set_coverage_class - Set IEEE 802.11 coverage class
*
* @hw: struct ieee80211_hw pointer
* @coverage_class: IEEE 802.11 coverage class number
*
* Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given
* coverage class. The values are persistent, they are restored after device
* reset.
*/
static void
ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
{
struct ath5k_softc *sc = hw->priv;
mutex_lock(&sc->lock);
ath5k_hw_set_coverage_class(sc->ah, coverage_class);
mutex_unlock(&sc->lock);
}
static int
ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
{
struct ath5k_softc *sc = hw->priv;
if (tx_ant == 1 && rx_ant == 1)
ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_A);
else if (tx_ant == 2 && rx_ant == 2)
ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_B);
else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3)
ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_DEFAULT);
else
return -EINVAL;
return 0;
}
static int
ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
{
struct ath5k_softc *sc = hw->priv;
switch (sc->ah->ah_ant_mode) {
case AR5K_ANTMODE_FIXED_A:
*tx_ant = 1; *rx_ant = 1; break;
case AR5K_ANTMODE_FIXED_B:
*tx_ant = 2; *rx_ant = 2; break;
case AR5K_ANTMODE_DEFAULT:
*tx_ant = 3; *rx_ant = 3; break;
}
return 0;
}
const struct ieee80211_ops ath5k_hw_ops = {
.tx = ath5k_tx,
.start = ath5k_start,
.stop = ath5k_stop,
.add_interface = ath5k_add_interface,
/* .change_interface = not implemented */
.remove_interface = ath5k_remove_interface,
.config = ath5k_config,
.bss_info_changed = ath5k_bss_info_changed,
.prepare_multicast = ath5k_prepare_multicast,
.configure_filter = ath5k_configure_filter,
/* .set_tim = not implemented */
.set_key = ath5k_set_key,
/* .update_tkip_key = not implemented */
/* .hw_scan = not implemented */
.sw_scan_start = ath5k_sw_scan_start,
.sw_scan_complete = ath5k_sw_scan_complete,
.get_stats = ath5k_get_stats,
/* .get_tkip_seq = not implemented */
/* .set_frag_threshold = not implemented */
/* .set_rts_threshold = not implemented */
/* .sta_add = not implemented */
/* .sta_remove = not implemented */
/* .sta_notify = not implemented */
.conf_tx = ath5k_conf_tx,
.get_tsf = ath5k_get_tsf,
.set_tsf = ath5k_set_tsf,
.reset_tsf = ath5k_reset_tsf,
/* .tx_last_beacon = not implemented */
/* .ampdu_action = not needed */
.get_survey = ath5k_get_survey,
.set_coverage_class = ath5k_set_coverage_class,
/* .rfkill_poll = not implemented */
/* .flush = not implemented */
/* .channel_switch = not implemented */
/* .napi_poll = not implemented */
.set_antenna = ath5k_set_antenna,
.get_antenna = ath5k_get_antenna,
};

Просмотреть файл

@ -609,10 +609,10 @@ done:
/* Write initial RF gain table to set the RF sensitivity
* this one works on all RF chips and has nothing to do
* with gain_F calibration */
static int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
static int ath5k_hw_rfgain_init(struct ath5k_hw *ah, enum ieee80211_band band)
{
const struct ath5k_ini_rfgain *ath5k_rfg;
unsigned int i, size;
unsigned int i, size, index;
switch (ah->ah_radio) {
case AR5K_RF5111:
@ -644,17 +644,11 @@ static int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
return -EINVAL;
}
switch (freq) {
case AR5K_INI_RFGAIN_2GHZ:
case AR5K_INI_RFGAIN_5GHZ:
break;
default:
return -EINVAL;
}
index = (band == IEEE80211_BAND_2GHZ) ? 1 : 0;
for (i = 0; i < size; i++) {
AR5K_REG_WAIT(i);
ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[index],
(u32)ath5k_rfg[i].rfg_register);
}
@ -1361,20 +1355,7 @@ void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
return;
}
switch (ah->ah_current_channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
case CHANNEL_XR:
ee_mode = AR5K_EEPROM_MODE_11A;
break;
case CHANNEL_G:
ee_mode = AR5K_EEPROM_MODE_11G;
break;
default:
case CHANNEL_B:
ee_mode = AR5K_EEPROM_MODE_11B;
break;
}
ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel);
/* completed NF calibration, test threshold */
nf = ath5k_hw_read_measured_noise_floor(ah);
@ -1935,7 +1916,8 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
struct ieee80211_channel *channel = ah->ah_current_channel;
bool use_def_for_tx, update_def_on_tx, use_def_for_rts, fast_div;
bool use_def_for_sg;
u8 def_ant, tx_ant, ee_mode;
int ee_mode;
u8 def_ant, tx_ant;
u32 sta_id1 = 0;
/* if channel is not initialized yet we can't set the antennas
@ -1947,18 +1929,8 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
def_ant = ah->ah_def_ant;
switch (channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
case CHANNEL_XR:
ee_mode = AR5K_EEPROM_MODE_11A;
break;
case CHANNEL_G:
ee_mode = AR5K_EEPROM_MODE_11G;
break;
case CHANNEL_B:
ee_mode = AR5K_EEPROM_MODE_11B;
break;
default:
ee_mode = ath5k_eeprom_mode_from_channel(channel);
if (ee_mode < 0) {
ATH5K_ERR(ah->ah_sc,
"invalid channel: %d\n", channel->center_freq);
return;
@ -2593,7 +2565,7 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
/* Write PCDAC values on hw */
static void
ath5k_setup_pcdac_table(struct ath5k_hw *ah)
ath5k_write_pcdac_table(struct ath5k_hw *ah)
{
u8 *pcdac_out = ah->ah_txpower.txp_pd_table;
int i;
@ -2742,7 +2714,7 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah,
/* Write PDADC values on hw */
static void
ath5k_setup_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode)
ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
u8 *pdadc_out = ah->ah_txpower.txp_pd_table;
@ -2957,8 +2929,7 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
(s16) pcinfo_R->freq,
pcinfo_L->max_pwr, pcinfo_R->max_pwr);
/* We are ready to go, fill PCDAC/PDADC
* table and write settings on hardware */
/* Fill PCDAC/PDADC table */
switch (type) {
case AR5K_PWRTABLE_LINEAR_PCDAC:
/* For RF5112 we can have one or two curves
@ -2971,9 +2942,6 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
* match max power value with max
* table index */
ah->ah_txpower.txp_offset = 64 - (table_max[0] / 2);
/* Write settings on hw */
ath5k_setup_pcdac_table(ah);
break;
case AR5K_PWRTABLE_PWR_TO_PCDAC:
/* We are done for RF5111 since it has only
@ -2983,9 +2951,6 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
/* No rate powertable adjustment for RF5111 */
ah->ah_txpower.txp_min_idx = 0;
ah->ah_txpower.txp_offset = 0;
/* Write settings on hw */
ath5k_setup_pcdac_table(ah);
break;
case AR5K_PWRTABLE_PWR_TO_PDADC:
/* Set PDADC boundaries and fill
@ -2993,9 +2958,6 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
ath5k_combine_pwr_to_pdadc_curves(ah, table_min, table_max,
ee->ee_pd_gains[ee_mode]);
/* Write settings on hw */
ath5k_setup_pwr_to_pdadc_table(ah, ee_mode);
/* Set txp.offset, note that table_min
* can be negative */
ah->ah_txpower.txp_offset = table_min[0];
@ -3004,9 +2966,20 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
return -EINVAL;
}
ah->ah_txpower.txp_setup = true;
return 0;
}
/* Write power table for current channel to hw */
static void
ath5k_write_channel_powertable(struct ath5k_hw *ah, u8 ee_mode, u8 type)
{
if (type == AR5K_PWRTABLE_PWR_TO_PDADC)
ath5k_write_pwr_to_pdadc_table(ah, ee_mode);
else
ath5k_write_pcdac_table(ah);
}
/*
* Per-rate tx power setting
@ -3095,7 +3068,7 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
/* Min/max in 0.25dB units */
ah->ah_txpower.txp_min_pwr = 2 * rates[7];
ah->ah_txpower.txp_max_pwr = 2 * rates[0];
ah->ah_txpower.txp_cur_pwr = 2 * rates[0];
ah->ah_txpower.txp_ofdm = rates[7];
}
@ -3105,9 +3078,11 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
*/
static int
ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
u8 ee_mode, u8 txpower, bool fast)
u8 txpower)
{
struct ath5k_rate_pcal_info rate_info;
struct ieee80211_channel *curr_channel = ah->ah_current_channel;
int ee_mode;
u8 type;
int ret;
@ -3116,6 +3091,13 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
return -EINVAL;
}
ee_mode = ath5k_eeprom_mode_from_channel(channel);
if (ee_mode < 0) {
ATH5K_ERR(ah->ah_sc,
"invalid channel: %d\n", channel->center_freq);
return -EINVAL;
}
/* Initialize TX power table */
switch (ah->ah_radio) {
case AR5K_RF5110:
@ -3138,28 +3120,26 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
return -EINVAL;
}
/* If fast is set it means we are on the same channel/mode
* so there is no need to recalculate the powertable, we 'll
* just use the cached one */
if (!fast) {
/*
* If we don't change channel/mode skip tx powertable calculation
* and use the cached one.
*/
if (!ah->ah_txpower.txp_setup ||
(channel->hw_value != curr_channel->hw_value) ||
(channel->center_freq != curr_channel->center_freq)) {
/* Reset TX power values */
memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
ah->ah_txpower.txp_min_pwr = 0;
ah->ah_txpower.txp_max_pwr = AR5K_TUNE_MAX_TXPOWER;
/* Calculate the powertable */
ret = ath5k_setup_channel_powertable(ah, channel,
ee_mode, type);
if (ret)
return ret;
/* Write cached table on hw */
} else if (type == AR5K_PWRTABLE_PWR_TO_PDADC)
ath5k_setup_pwr_to_pdadc_table(ah, ee_mode);
else
ath5k_setup_pcdac_table(ah);
}
/* Write table on hw */
ath5k_write_channel_powertable(ah, ee_mode, type);
/* Limit max power if we have a CTL available */
ath5k_get_max_ctl_power(ah, channel);
@ -3214,31 +3194,10 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
{
/*Just a try M.F.*/
struct ieee80211_channel *channel = ah->ah_current_channel;
u8 ee_mode;
switch (channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
case CHANNEL_XR:
ee_mode = AR5K_EEPROM_MODE_11A;
break;
case CHANNEL_G:
ee_mode = AR5K_EEPROM_MODE_11G;
break;
case CHANNEL_B:
ee_mode = AR5K_EEPROM_MODE_11B;
break;
default:
ATH5K_ERR(ah->ah_sc,
"invalid channel: %d\n", channel->center_freq);
return -EINVAL;
}
ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER,
"changing txpower to %d\n", txpower);
return ath5k_hw_txpower(ah, channel, ee_mode, txpower, true);
return ath5k_hw_txpower(ah, ah->ah_current_channel, txpower);
}
/*************\
@ -3246,12 +3205,11 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
\*************/
int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
u8 mode, u8 ee_mode, u8 freq, bool fast)
u8 mode, bool fast)
{
struct ieee80211_channel *curr_channel;
int ret, i;
u32 phy_tst1;
bool fast_txp;
ret = 0;
/*
@ -3281,17 +3239,6 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
return -EIO;
}
/*
* If we don't change channel/mode skip
* tx powertable calculation and use the
* cached one.
*/
if ((channel->hw_value == curr_channel->hw_value) &&
(channel->center_freq == curr_channel->center_freq))
fast_txp = true;
else
fast_txp = false;
/*
* Set TX power
*
@ -3299,9 +3246,8 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
* RF buffer settings on 5211/5212+ so that we
* properly set curve indices.
*/
ret = ath5k_hw_txpower(ah, channel, ee_mode,
ah->ah_txpower.txp_max_pwr / 2,
fast_txp);
ret = ath5k_hw_txpower(ah, channel, ah->ah_txpower.txp_cur_pwr ?
ah->ah_txpower.txp_cur_pwr / 2 : AR5K_TUNE_MAX_TXPOWER);
if (ret)
return ret;
@ -3317,7 +3263,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
* Write initial RF gain settings
* This should work for both 5111/5112
*/
ret = ath5k_hw_rfgain_init(ah, freq);
ret = ath5k_hw_rfgain_init(ah, channel->band);
if (ret)
return ret;

Просмотреть файл

@ -537,7 +537,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
* we ingore that flag for PCI-E cards. On PCI cards
* this flag gets cleared after 64 PCI clocks.
*/
bus_flags = (pdev && pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
bus_flags = (pdev && pci_is_pcie(pdev)) ? 0 : AR5K_RESET_CTL_PCI;
if (ah->ah_version == AR5K_AR5210) {
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
@ -594,7 +594,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
* we ingore that flag for PCI-E cards. On PCI cards
* this flag gets cleared after 64 PCI clocks.
*/
bus_flags = (pdev && pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
bus_flags = (pdev && pci_is_pcie(pdev)) ? 0 : AR5K_RESET_CTL_PCI;
if (ah->ah_version == AR5K_AR5210) {
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
@ -866,15 +866,18 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
}
static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
struct ieee80211_channel *channel, u8 ee_mode)
struct ieee80211_channel *channel)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
s16 cck_ofdm_pwr_delta;
u8 ee_mode;
/* TODO: Add support for AR5210 EEPROM */
if (ah->ah_version == AR5K_AR5210)
return;
ee_mode = ath5k_eeprom_mode_from_channel(channel);
/* Adjust power delta for channel 14 */
if (channel->center_freq == 2484)
cck_ofdm_pwr_delta =
@ -1020,13 +1023,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
struct ieee80211_channel *channel, bool fast, bool skip_pcu)
{
u32 s_seq[10], s_led[3], tsf_up, tsf_lo;
u8 mode, freq, ee_mode;
u8 mode;
int i, ret;
ee_mode = 0;
tsf_up = 0;
tsf_lo = 0;
freq = 0;
mode = 0;
/*
@ -1071,8 +1072,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
switch (channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
mode = AR5K_MODE_11A;
freq = AR5K_INI_RFGAIN_5GHZ;
ee_mode = AR5K_EEPROM_MODE_11A;
break;
case CHANNEL_G:
@ -1083,8 +1082,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
}
mode = AR5K_MODE_11G;
freq = AR5K_INI_RFGAIN_2GHZ;
ee_mode = AR5K_EEPROM_MODE_11G;
break;
case CHANNEL_B:
@ -1095,8 +1092,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
}
mode = AR5K_MODE_11B;
freq = AR5K_INI_RFGAIN_2GHZ;
ee_mode = AR5K_EEPROM_MODE_11B;
break;
case CHANNEL_XR:
if (ah->ah_version == AR5K_AR5211) {
@ -1105,8 +1100,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
return -EINVAL;
}
mode = AR5K_MODE_XR;
freq = AR5K_INI_RFGAIN_5GHZ;
ee_mode = AR5K_EEPROM_MODE_11A;
break;
default:
ATH5K_ERR(ah->ah_sc,
@ -1119,8 +1112,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
* go on. If it fails continue with a normal reset.
*/
if (fast) {
ret = ath5k_hw_phy_init(ah, channel, mode,
ee_mode, freq, true);
ret = ath5k_hw_phy_init(ah, channel, mode, true);
if (ret) {
ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_RESET,
"fast chan change failed, falling back to normal reset\n");
@ -1217,7 +1209,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
ath5k_hw_tweak_initval_settings(ah, channel);
/* Commit values from EEPROM */
ath5k_hw_commit_eeprom_settings(ah, channel, ee_mode);
ath5k_hw_commit_eeprom_settings(ah, channel);
/*
@ -1256,7 +1248,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
/*
* Initialize PHY
*/
ret = ath5k_hw_phy_init(ah, channel, mode, ee_mode, freq, false);
ret = ath5k_hw_phy_init(ah, channel, mode, false);
if (ret) {
ATH5K_ERR(ah->ah_sc,
"failed to initialize PHY (%i) !\n", ret);

Просмотреть файл

@ -22,7 +22,7 @@
int modparam_force_new_ani;
module_param_named(force_new_ani, modparam_force_new_ani, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Force new ANI for AR5008, AR9001, AR9002");
MODULE_PARM_DESC(force_new_ani, "Force new ANI for AR5008, AR9001, AR9002");
/* General hardware code for the A5008/AR9001/AR9002 hadware families */

Просмотреть файл

@ -203,13 +203,14 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
if (AR_NO_SPUR == cur_bb_spur)
break;
if (is2GHz)
cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ;
else
cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ;
if (AR_NO_SPUR == cur_bb_spur)
break;
cur_bb_spur = cur_bb_spur - freq;
if (IS_CHAN_HT40(chan)) {

Просмотреть файл

@ -59,6 +59,8 @@
#define CTL(_tpower, _flag) ((_tpower) | ((_flag) << 6))
#define EEPROM_DATA_LEN_9485 1088
static int ar9003_hw_power_interpolate(int32_t x,
int32_t *px, int32_t *py, u_int16_t np);
@ -3368,7 +3370,7 @@ found:
"Found block at %x: code=%d ref=%d length=%d major=%d minor=%d\n",
cptr, code, reference, length, major, minor);
if ((!AR_SREV_9485(ah) && length >= 1024) ||
(AR_SREV_9485(ah) && length >= (4 * 1024))) {
(AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485)) {
ath_dbg(common, ATH_DBG_EEPROM,
"Skipping bad header\n");
cptr -= COMP_HDR_LEN;

Просмотреть файл

@ -613,9 +613,9 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
* possibly be reviewing the last subframe. AR_CRCErr
* is the CRC of the actual data.
*/
if (rxsp->status11 & AR_CRCErr) {
if (rxsp->status11 & AR_CRCErr)
rxs->rs_status |= ATH9K_RXERR_CRC;
} else if (rxsp->status11 & AR_PHYErr) {
if (rxsp->status11 & AR_PHYErr) {
phyerr = MS(rxsp->status11, AR_PHYErrCode);
/*
* If we reach a point here where AR_PostDelimCRCErr is
@ -638,11 +638,12 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
rxs->rs_phyerr = phyerr;
}
} else if (rxsp->status11 & AR_DecryptCRCErr) {
}
if (rxsp->status11 & AR_DecryptCRCErr)
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
} else if (rxsp->status11 & AR_MichaelErr) {
if (rxsp->status11 & AR_MichaelErr)
rxs->rs_status |= ATH9K_RXERR_MIC;
} else if (rxsp->status11 & AR_KeyMiss)
if (rxsp->status11 & AR_KeyMiss)
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
}

Просмотреть файл

@ -664,11 +664,13 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
}
extern struct ieee80211_ops ath9k_ops;
extern int modparam_nohwcrypt;
extern int ath9k_modparam_nohwcrypt;
extern int led_blink;
extern int ath9k_pm_qos_value;
extern bool is_ath9k_unloaded;
irqreturn_t ath_isr(int irq, void *dev);
void ath9k_init_crypto(struct ath_softc *sc);
int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
const struct ath_bus_ops *bus_ops);
void ath9k_deinit_device(struct ath_softc *sc);

Просмотреть файл

@ -566,8 +566,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
* last beacon we received (which may be none).
*/
dtimperiod = conf->dtim_period;
if (dtimperiod <= 0) /* NB: 0 if not known */
dtimperiod = 1;
dtimcount = conf->dtim_count;
if (dtimcount >= dtimperiod) /* NB: sanity check */
dtimcount = 0;
@ -575,8 +573,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
cfpcount = 0;
sleepduration = conf->listen_interval * intval;
if (sleepduration <= 0)
sleepduration = intval;
/*
* Pull nexttbtt forward to reflect the current
@ -662,8 +658,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
}
static void ath_beacon_config_adhoc(struct ath_softc *sc,
struct ath_beacon_config *conf,
struct ieee80211_vif *vif)
struct ath_beacon_config *conf)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
@ -718,18 +713,17 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
/* Setup the beacon configuration parameters */
if (vif) {
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
iftype = vif->type;
cur_conf->beacon_interval = bss_conf->beacon_int;
cur_conf->dtim_period = bss_conf->dtim_period;
} else {
iftype = sc->sc_ah->opmode;
}
cur_conf->listen_interval = 1;
cur_conf->dtim_count = 1;
cur_conf->bmiss_timeout =
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
} else {
iftype = sc->sc_ah->opmode;
}
/*
* It looks like mac80211 may end up using beacon interval of zero in
@ -740,13 +734,20 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
if (cur_conf->beacon_interval == 0)
cur_conf->beacon_interval = 100;
/*
* Some times we dont parse dtim period from mac80211, in that case
* use a default value
*/
if (cur_conf->dtim_period == 0)
cur_conf->dtim_period = 1;
switch (iftype) {
case NL80211_IFTYPE_AP:
ath_beacon_config_ap(sc, cur_conf);
break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
ath_beacon_config_adhoc(sc, cur_conf, vif);
ath_beacon_config_adhoc(sc, cur_conf);
break;
case NL80211_IFTYPE_STATION:
ath_beacon_config_sta(sc, cur_conf);

Просмотреть файл

@ -23,8 +23,6 @@
#include <net/cfg80211.h>
#include "ar9003_eeprom.h"
#define AH_USE_EEPROM 0x1
#ifdef __BIG_ENDIAN
#define AR5416_EEPROM_MAGIC 0x5aa5
#else

Просмотреть файл

@ -153,16 +153,36 @@ static void hif_usb_tx_cb(struct urb *urb)
case -ENODEV:
case -ESHUTDOWN:
/*
* The URB has been killed, free the SKBs
* and return.
* The URB has been killed, free the SKBs.
*/
ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
return;
/*
* If the URBs are being flushed, no need to add this
* URB to the free list.
*/
spin_lock(&hif_dev->tx.tx_lock);
if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
spin_unlock(&hif_dev->tx.tx_lock);
return;
}
spin_unlock(&hif_dev->tx.tx_lock);
/*
* In the stop() case, this URB has to be added to
* the free list.
*/
goto add_free;
default:
break;
}
/* Check if TX has been stopped */
/*
* Check if TX has been stopped, this is needed because
* this CB could have been invoked just after the TX lock
* was released in hif_stop() and kill_urb() hasn't been
* called yet.
*/
spin_lock(&hif_dev->tx.tx_lock);
if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
spin_unlock(&hif_dev->tx.tx_lock);
@ -314,6 +334,7 @@ static void hif_usb_start(void *hif_handle, u8 pipe_id)
static void hif_usb_stop(void *hif_handle, u8 pipe_id)
{
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
unsigned long flags;
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
@ -321,6 +342,12 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id)
hif_dev->tx.tx_skb_cnt = 0;
hif_dev->tx.flags |= HIF_USB_TX_STOP;
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
/* The pending URBs have to be canceled. */
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
&hif_dev->tx.tx_pending, list) {
usb_kill_urb(tx_buf->urb);
}
}
static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
@ -587,6 +614,7 @@ free:
static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
{
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
unsigned long flags;
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
&hif_dev->tx.tx_buf, list) {
@ -597,6 +625,10 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
kfree(tx_buf);
}
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
hif_dev->tx.flags |= HIF_USB_TX_FLUSH;
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
&hif_dev->tx.tx_pending, list) {
usb_kill_urb(tx_buf->urb);
@ -993,16 +1025,16 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
{
struct usb_device *udev = interface_to_usbdev(interface);
struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
bool unplugged = (udev->state == USB_STATE_NOTATTACHED) ? true : false;
if (hif_dev) {
ath9k_htc_hw_deinit(hif_dev->htc_handle,
(udev->state == USB_STATE_NOTATTACHED) ? true : false);
ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged);
ath9k_htc_hw_free(hif_dev->htc_handle);
ath9k_hif_usb_dev_deinit(hif_dev);
usb_set_intfdata(interface, NULL);
}
if (hif_dev->flags & HIF_USB_START)
if (!unplugged && (hif_dev->flags & HIF_USB_START))
ath9k_hif_usb_reboot(udev);
kfree(hif_dev);

Просмотреть файл

@ -64,6 +64,7 @@ struct tx_buf {
};
#define HIF_USB_TX_STOP BIT(0)
#define HIF_USB_TX_FLUSH BIT(1)
struct hif_usb_tx {
u8 flags;

Просмотреть файл

@ -331,17 +331,15 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv);
#define OP_INVALID BIT(0)
#define OP_SCANNING BIT(1)
#define OP_FULL_RESET BIT(2)
#define OP_LED_ASSOCIATED BIT(3)
#define OP_LED_ON BIT(4)
#define OP_PREAMBLE_SHORT BIT(5)
#define OP_PROTECT_ENABLE BIT(6)
#define OP_ASSOCIATED BIT(7)
#define OP_ENABLE_BEACON BIT(8)
#define OP_LED_DEINIT BIT(9)
#define OP_UNPLUGGED BIT(10)
#define OP_BT_PRIORITY_DETECTED BIT(11)
#define OP_BT_SCAN BIT(12)
#define OP_LED_ASSOCIATED BIT(2)
#define OP_LED_ON BIT(3)
#define OP_PREAMBLE_SHORT BIT(4)
#define OP_PROTECT_ENABLE BIT(5)
#define OP_ASSOCIATED BIT(6)
#define OP_ENABLE_BEACON BIT(7)
#define OP_LED_DEINIT BIT(8)
#define OP_BT_PRIORITY_DETECTED BIT(9)
#define OP_BT_SCAN BIT(10)
struct ath9k_htc_priv {
struct device *dev;
@ -378,7 +376,7 @@ struct ath9k_htc_priv {
struct ieee80211_vif *vif;
struct htc_beacon_config cur_beacon_conf;
unsigned int rxfilter;
struct tasklet_struct wmi_tasklet;
struct tasklet_struct swba_tasklet;
struct tasklet_struct rx_tasklet;
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
struct ath9k_htc_rx rx;
@ -386,6 +384,7 @@ struct ath9k_htc_priv {
struct sk_buff_head tx_queue;
struct delayed_work ath9k_ani_work;
struct work_struct ps_work;
struct work_struct fatal_work;
struct mutex htc_pm_lock;
unsigned long ps_usecount;
@ -420,6 +419,8 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
common->bus_ops->read_cachesize(common, csz);
}
void ath9k_htc_reset(struct ath9k_htc_priv *priv);
void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif);
@ -435,6 +436,7 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
void ath9k_htc_station_work(struct work_struct *work);
void ath9k_htc_aggr_work(struct work_struct *work);
void ath9k_ani_work(struct work_struct *work);;
void ath_start_ani(struct ath9k_htc_priv *priv);
int ath9k_tx_init(struct ath9k_htc_priv *priv);
void ath9k_tx_tasklet(unsigned long data);
@ -457,8 +459,13 @@ void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv);
void ath9k_ps_work(struct work_struct *work);
bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
enum ath9k_power_mode mode);
void ath_update_txpow(struct ath9k_htc_priv *priv);
void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv);
void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw);
void ath9k_htc_radio_enable(struct ieee80211_hw *hw);
void ath9k_htc_radio_disable(struct ieee80211_hw *hw);
void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv);
void ath9k_init_leds(struct ath9k_htc_priv *priv);
void ath9k_deinit_leds(struct ath9k_htc_priv *priv);

Просмотреть файл

@ -1,3 +1,19 @@
/*
* Copyright (c) 2010 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "htc.h"
/******************/
@ -131,3 +147,314 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
cancel_delayed_work_sync(&priv->coex_period_work);
cancel_delayed_work_sync(&priv->duty_cycle_work);
}
/*******/
/* LED */
/*******/
static void ath9k_led_blink_work(struct work_struct *work)
{
struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
ath9k_led_blink_work.work);
if (!(priv->op_flags & OP_LED_ASSOCIATED))
return;
if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
(priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
else
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
(priv->op_flags & OP_LED_ON) ? 1 : 0);
ieee80211_queue_delayed_work(priv->hw,
&priv->ath9k_led_blink_work,
(priv->op_flags & OP_LED_ON) ?
msecs_to_jiffies(priv->led_off_duration) :
msecs_to_jiffies(priv->led_on_duration));
priv->led_on_duration = priv->led_on_cnt ?
max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
ATH_LED_ON_DURATION_IDLE;
priv->led_off_duration = priv->led_off_cnt ?
max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
ATH_LED_OFF_DURATION_IDLE;
priv->led_on_cnt = priv->led_off_cnt = 0;
if (priv->op_flags & OP_LED_ON)
priv->op_flags &= ~OP_LED_ON;
else
priv->op_flags |= OP_LED_ON;
}
static void ath9k_led_brightness_work(struct work_struct *work)
{
struct ath_led *led = container_of(work, struct ath_led,
brightness_work.work);
struct ath9k_htc_priv *priv = led->priv;
switch (led->brightness) {
case LED_OFF:
if (led->led_type == ATH_LED_ASSOC ||
led->led_type == ATH_LED_RADIO) {
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
(led->led_type == ATH_LED_RADIO));
priv->op_flags &= ~OP_LED_ASSOCIATED;
if (led->led_type == ATH_LED_RADIO)
priv->op_flags &= ~OP_LED_ON;
} else {
priv->led_off_cnt++;
}
break;
case LED_FULL:
if (led->led_type == ATH_LED_ASSOC) {
priv->op_flags |= OP_LED_ASSOCIATED;
ieee80211_queue_delayed_work(priv->hw,
&priv->ath9k_led_blink_work, 0);
} else if (led->led_type == ATH_LED_RADIO) {
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
priv->op_flags |= OP_LED_ON;
} else {
priv->led_on_cnt++;
}
break;
default:
break;
}
}
static void ath9k_led_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
struct ath9k_htc_priv *priv = led->priv;
led->brightness = brightness;
if (!(priv->op_flags & OP_LED_DEINIT))
ieee80211_queue_delayed_work(priv->hw,
&led->brightness_work, 0);
}
void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
{
cancel_delayed_work_sync(&priv->radio_led.brightness_work);
cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
cancel_delayed_work_sync(&priv->tx_led.brightness_work);
cancel_delayed_work_sync(&priv->rx_led.brightness_work);
}
static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
char *trigger)
{
int ret;
led->priv = priv;
led->led_cdev.name = led->name;
led->led_cdev.default_trigger = trigger;
led->led_cdev.brightness_set = ath9k_led_brightness;
ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
if (ret)
ath_err(ath9k_hw_common(priv->ah),
"Failed to register led:%s", led->name);
else
led->registered = 1;
INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
return ret;
}
static void ath9k_unregister_led(struct ath_led *led)
{
if (led->registered) {
led_classdev_unregister(&led->led_cdev);
led->registered = 0;
}
}
void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
{
priv->op_flags |= OP_LED_DEINIT;
ath9k_unregister_led(&priv->assoc_led);
priv->op_flags &= ~OP_LED_ASSOCIATED;
ath9k_unregister_led(&priv->tx_led);
ath9k_unregister_led(&priv->rx_led);
ath9k_unregister_led(&priv->radio_led);
}
void ath9k_init_leds(struct ath9k_htc_priv *priv)
{
char *trigger;
int ret;
if (AR_SREV_9287(priv->ah))
priv->ah->led_pin = ATH_LED_PIN_9287;
else if (AR_SREV_9271(priv->ah))
priv->ah->led_pin = ATH_LED_PIN_9271;
else if (AR_DEVID_7010(priv->ah))
priv->ah->led_pin = ATH_LED_PIN_7010;
else
priv->ah->led_pin = ATH_LED_PIN_DEF;
/* Configure gpio 1 for output */
ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
/* LED off, active low */
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
trigger = ieee80211_get_radio_led_name(priv->hw);
snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
"ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
ret = ath9k_register_led(priv, &priv->radio_led, trigger);
priv->radio_led.led_type = ATH_LED_RADIO;
if (ret)
goto fail;
trigger = ieee80211_get_assoc_led_name(priv->hw);
snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
"ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
priv->assoc_led.led_type = ATH_LED_ASSOC;
if (ret)
goto fail;
trigger = ieee80211_get_tx_led_name(priv->hw);
snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
"ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
ret = ath9k_register_led(priv, &priv->tx_led, trigger);
priv->tx_led.led_type = ATH_LED_TX;
if (ret)
goto fail;
trigger = ieee80211_get_rx_led_name(priv->hw);
snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
"ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
ret = ath9k_register_led(priv, &priv->rx_led, trigger);
priv->rx_led.led_type = ATH_LED_RX;
if (ret)
goto fail;
priv->op_flags &= ~OP_LED_DEINIT;
return;
fail:
cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
ath9k_deinit_leds(priv);
}
/*******************/
/* Rfkill */
/*******************/
static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
{
return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
priv->ah->rfkill_polarity;
}
void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
bool blocked = !!ath_is_rfkill_set(priv);
wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
}
void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
{
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
wiphy_rfkill_start_polling(priv->hw->wiphy);
}
void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(ah);
int ret;
u8 cmd_rsp;
if (!ah->curchan)
ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
/* Reset the HW */
ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
if (ret) {
ath_err(common,
"Unable to reset hardware; reset status %d (freq %u MHz)\n",
ret, ah->curchan->channel);
}
ath_update_txpow(priv);
/* Start RX */
WMI_CMD(WMI_START_RECV_CMDID);
ath9k_host_rx_init(priv);
/* Start TX */
htc_start(priv->htc);
spin_lock_bh(&priv->tx_lock);
priv->tx_queues_stop = false;
spin_unlock_bh(&priv->tx_lock);
ieee80211_wake_queues(hw);
WMI_CMD(WMI_ENABLE_INTR_CMDID);
/* Enable LED */
ath9k_hw_cfg_output(ah, ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_set_gpio(ah, ah->led_pin, 0);
}
void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(ah);
int ret;
u8 cmd_rsp;
ath9k_htc_ps_wakeup(priv);
/* Disable LED */
ath9k_hw_set_gpio(ah, ah->led_pin, 1);
ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
WMI_CMD(WMI_DISABLE_INTR_CMDID);
/* Stop TX */
ieee80211_stop_queues(hw);
htc_stop(priv->htc);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
skb_queue_purge(&priv->tx_queue);
/* Stop RX */
WMI_CMD(WMI_STOP_RECV_CMDID);
/*
* The MIB counters have to be disabled here,
* since the target doesn't do it.
*/
ath9k_hw_disable_mib_counters(ah);
if (!ah->curchan)
ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
/* Reset the HW */
ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
if (ret) {
ath_err(common,
"Unable to reset hardware; reset status %d (freq %u MHz)\n",
ret, ah->curchan->channel);
}
/* Disable the PHY */
ath9k_hw_phy_disable(ah);
ath9k_htc_ps_restore(priv);
ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
}

Просмотреть файл

@ -142,7 +142,7 @@ static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
{
ath9k_htc_exit_debug(priv->ah);
ath9k_hw_deinit(priv->ah);
tasklet_kill(&priv->wmi_tasklet);
tasklet_kill(&priv->swba_tasklet);
tasklet_kill(&priv->rx_tasklet);
tasklet_kill(&priv->tx_tasklet);
kfree(priv->ah);
@ -647,13 +647,15 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
spin_lock_init(&priv->tx_lock);
mutex_init(&priv->mutex);
mutex_init(&priv->htc_pm_lock);
tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet,
tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet,
(unsigned long)priv);
tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
(unsigned long)priv);
tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv);
tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet,
(unsigned long)priv);
INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work);
INIT_WORK(&priv->ps_work, ath9k_ps_work);
INIT_WORK(&priv->fatal_work, ath9k_fatal_work);
/*
* Cache line size is used to size and align various
@ -714,8 +716,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_NEED_DTIM_PERIOD;
IEEE80211_HW_PS_NULLFUNC_STACK;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
@ -851,9 +852,6 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
if (ret)
goto err_init;
/* The device may have been unplugged earlier. */
priv->op_flags &= ~OP_UNPLUGGED;
ret = ath9k_init_device(priv, devid, product, drv_info);
if (ret)
goto err_init;
@ -873,7 +871,7 @@ void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug)
/* Check if the device has been yanked out. */
if (hotunplug)
htc_handle->drv_priv->op_flags |= OP_UNPLUGGED;
htc_handle->drv_priv->ah->ah_flags |= AH_UNPLUGGED;
ath9k_deinit_device(htc_handle->drv_priv);
ath9k_deinit_wmi(htc_handle->drv_priv);

Просмотреть файл

@ -24,7 +24,7 @@ static struct dentry *ath9k_debugfs_root;
/* Utilities */
/*************/
static void ath_update_txpow(struct ath9k_htc_priv *priv)
void ath_update_txpow(struct ath9k_htc_priv *priv)
{
struct ath_hw *ah = priv->ah;
@ -116,6 +116,60 @@ void ath9k_ps_work(struct work_struct *work)
ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
}
void ath9k_htc_reset(struct ath9k_htc_priv *priv)
{
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_channel *channel = priv->hw->conf.channel;
struct ath9k_hw_cal_data *caldata;
enum htc_phymode mode;
__be16 htc_mode;
u8 cmd_rsp;
int ret;
mutex_lock(&priv->mutex);
ath9k_htc_ps_wakeup(priv);
if (priv->op_flags & OP_ASSOCIATED)
cancel_delayed_work_sync(&priv->ath9k_ani_work);
ieee80211_stop_queues(priv->hw);
htc_stop(priv->htc);
WMI_CMD(WMI_DISABLE_INTR_CMDID);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
WMI_CMD(WMI_STOP_RECV_CMDID);
caldata = &priv->caldata[channel->hw_value];
ret = ath9k_hw_reset(ah, ah->curchan, caldata, false);
if (ret) {
ath_err(common,
"Unable to reset device (%u Mhz) reset status %d\n",
channel->center_freq, ret);
}
ath_update_txpow(priv);
WMI_CMD(WMI_START_RECV_CMDID);
ath9k_host_rx_init(priv);
mode = ath9k_htc_get_curmode(priv, ah->curchan);
htc_mode = cpu_to_be16(mode);
WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
WMI_CMD(WMI_ENABLE_INTR_CMDID);
htc_start(priv->htc);
if (priv->op_flags & OP_ASSOCIATED) {
ath9k_htc_beacon_config(priv, priv->vif);
ath_start_ani(priv);
}
ieee80211_wake_queues(priv->hw);
ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
}
static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
struct ieee80211_hw *hw,
struct ath9k_channel *hchan)
@ -123,7 +177,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_conf *conf = &common->hw->conf;
bool fastcc = true;
bool fastcc;
struct ieee80211_channel *channel = hw->conf.channel;
struct ath9k_hw_cal_data *caldata;
enum htc_phymode mode;
@ -134,8 +188,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
if (priv->op_flags & OP_INVALID)
return -EIO;
if (priv->op_flags & OP_FULL_RESET)
fastcc = false;
fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
ath9k_htc_ps_wakeup(priv);
htc_stop(priv->htc);
@ -177,23 +230,43 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
goto err;
htc_start(priv->htc);
priv->op_flags &= ~OP_FULL_RESET;
err:
ath9k_htc_ps_restore(priv);
return ret;
}
static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_target_vif hvif;
int ret = 0;
u8 cmd_rsp;
memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
hvif.index = 0; /* Should do for now */
WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
priv->nvifs--;
}
static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_target_vif hvif;
struct ath9k_htc_target_sta tsta;
int ret = 0;
u8 cmd_rsp;
if (priv->nvifs > 0)
return -ENOBUFS;
if (priv->nstations >= ATH9K_HTC_MAX_STA)
return -ENOBUFS;
/*
* Add an interface.
*/
memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
@ -206,23 +279,57 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
return ret;
priv->nvifs++;
/*
* Associate a station with the interface for packet injection.
*/
memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta));
memcpy(&tsta.macaddr, common->macaddr, ETH_ALEN);
tsta.is_vif_sta = 1;
tsta.sta_index = priv->nstations;
tsta.vif_index = hvif.index;
tsta.maxampdu = 0xffff;
WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
if (ret) {
ath_err(common, "Unable to add station entry for monitor mode\n");
goto err_vif;
}
priv->nstations++;
return 0;
err_vif:
/*
* Remove the interface from the target.
*/
__ath9k_htc_remove_monitor_interface(priv);
return ret;
}
static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_target_vif hvif;
int ret = 0;
u8 cmd_rsp;
u8 cmd_rsp, sta_idx;
memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
hvif.index = 0; /* Should do for now */
WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
priv->nvifs--;
__ath9k_htc_remove_monitor_interface(priv);
return ret;
sta_idx = 0; /* Only single interface, for now */
WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
if (ret) {
ath_err(common, "Unable to remove station entry for monitor mode\n");
return ret;
}
priv->nstations--;
return 0;
}
static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
@ -690,7 +797,7 @@ void ath9k_htc_debug_remove_root(void)
/* ANI */
/*******/
static void ath_start_ani(struct ath9k_htc_priv *priv)
void ath_start_ani(struct ath9k_htc_priv *priv)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
unsigned long timestamp = jiffies_to_msecs(jiffies);
@ -789,317 +896,6 @@ set_timer:
msecs_to_jiffies(cal_interval));
}
/*******/
/* LED */
/*******/
static void ath9k_led_blink_work(struct work_struct *work)
{
struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
ath9k_led_blink_work.work);
if (!(priv->op_flags & OP_LED_ASSOCIATED))
return;
if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
(priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
else
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
(priv->op_flags & OP_LED_ON) ? 1 : 0);
ieee80211_queue_delayed_work(priv->hw,
&priv->ath9k_led_blink_work,
(priv->op_flags & OP_LED_ON) ?
msecs_to_jiffies(priv->led_off_duration) :
msecs_to_jiffies(priv->led_on_duration));
priv->led_on_duration = priv->led_on_cnt ?
max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
ATH_LED_ON_DURATION_IDLE;
priv->led_off_duration = priv->led_off_cnt ?
max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
ATH_LED_OFF_DURATION_IDLE;
priv->led_on_cnt = priv->led_off_cnt = 0;
if (priv->op_flags & OP_LED_ON)
priv->op_flags &= ~OP_LED_ON;
else
priv->op_flags |= OP_LED_ON;
}
static void ath9k_led_brightness_work(struct work_struct *work)
{
struct ath_led *led = container_of(work, struct ath_led,
brightness_work.work);
struct ath9k_htc_priv *priv = led->priv;
switch (led->brightness) {
case LED_OFF:
if (led->led_type == ATH_LED_ASSOC ||
led->led_type == ATH_LED_RADIO) {
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
(led->led_type == ATH_LED_RADIO));
priv->op_flags &= ~OP_LED_ASSOCIATED;
if (led->led_type == ATH_LED_RADIO)
priv->op_flags &= ~OP_LED_ON;
} else {
priv->led_off_cnt++;
}
break;
case LED_FULL:
if (led->led_type == ATH_LED_ASSOC) {
priv->op_flags |= OP_LED_ASSOCIATED;
ieee80211_queue_delayed_work(priv->hw,
&priv->ath9k_led_blink_work, 0);
} else if (led->led_type == ATH_LED_RADIO) {
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
priv->op_flags |= OP_LED_ON;
} else {
priv->led_on_cnt++;
}
break;
default:
break;
}
}
static void ath9k_led_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
struct ath9k_htc_priv *priv = led->priv;
led->brightness = brightness;
if (!(priv->op_flags & OP_LED_DEINIT))
ieee80211_queue_delayed_work(priv->hw,
&led->brightness_work, 0);
}
static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
{
cancel_delayed_work_sync(&priv->radio_led.brightness_work);
cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
cancel_delayed_work_sync(&priv->tx_led.brightness_work);
cancel_delayed_work_sync(&priv->rx_led.brightness_work);
}
static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
char *trigger)
{
int ret;
led->priv = priv;
led->led_cdev.name = led->name;
led->led_cdev.default_trigger = trigger;
led->led_cdev.brightness_set = ath9k_led_brightness;
ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
if (ret)
ath_err(ath9k_hw_common(priv->ah),
"Failed to register led:%s", led->name);
else
led->registered = 1;
INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
return ret;
}
static void ath9k_unregister_led(struct ath_led *led)
{
if (led->registered) {
led_classdev_unregister(&led->led_cdev);
led->registered = 0;
}
}
void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
{
priv->op_flags |= OP_LED_DEINIT;
ath9k_unregister_led(&priv->assoc_led);
priv->op_flags &= ~OP_LED_ASSOCIATED;
ath9k_unregister_led(&priv->tx_led);
ath9k_unregister_led(&priv->rx_led);
ath9k_unregister_led(&priv->radio_led);
}
void ath9k_init_leds(struct ath9k_htc_priv *priv)
{
char *trigger;
int ret;
if (AR_SREV_9287(priv->ah))
priv->ah->led_pin = ATH_LED_PIN_9287;
else if (AR_SREV_9271(priv->ah))
priv->ah->led_pin = ATH_LED_PIN_9271;
else if (AR_DEVID_7010(priv->ah))
priv->ah->led_pin = ATH_LED_PIN_7010;
else
priv->ah->led_pin = ATH_LED_PIN_DEF;
/* Configure gpio 1 for output */
ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
/* LED off, active low */
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
trigger = ieee80211_get_radio_led_name(priv->hw);
snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
"ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
ret = ath9k_register_led(priv, &priv->radio_led, trigger);
priv->radio_led.led_type = ATH_LED_RADIO;
if (ret)
goto fail;
trigger = ieee80211_get_assoc_led_name(priv->hw);
snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
"ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
priv->assoc_led.led_type = ATH_LED_ASSOC;
if (ret)
goto fail;
trigger = ieee80211_get_tx_led_name(priv->hw);
snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
"ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
ret = ath9k_register_led(priv, &priv->tx_led, trigger);
priv->tx_led.led_type = ATH_LED_TX;
if (ret)
goto fail;
trigger = ieee80211_get_rx_led_name(priv->hw);
snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
"ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
ret = ath9k_register_led(priv, &priv->rx_led, trigger);
priv->rx_led.led_type = ATH_LED_RX;
if (ret)
goto fail;
priv->op_flags &= ~OP_LED_DEINIT;
return;
fail:
cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
ath9k_deinit_leds(priv);
}
/*******************/
/* Rfkill */
/*******************/
static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
{
return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
priv->ah->rfkill_polarity;
}
static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
bool blocked = !!ath_is_rfkill_set(priv);
wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
}
void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
{
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
wiphy_rfkill_start_polling(priv->hw->wiphy);
}
static void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(ah);
int ret;
u8 cmd_rsp;
if (!ah->curchan)
ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
/* Reset the HW */
ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
if (ret) {
ath_err(common,
"Unable to reset hardware; reset status %d (freq %u MHz)\n",
ret, ah->curchan->channel);
}
ath_update_txpow(priv);
/* Start RX */
WMI_CMD(WMI_START_RECV_CMDID);
ath9k_host_rx_init(priv);
/* Start TX */
htc_start(priv->htc);
spin_lock_bh(&priv->tx_lock);
priv->tx_queues_stop = false;
spin_unlock_bh(&priv->tx_lock);
ieee80211_wake_queues(hw);
WMI_CMD(WMI_ENABLE_INTR_CMDID);
/* Enable LED */
ath9k_hw_cfg_output(ah, ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_set_gpio(ah, ah->led_pin, 0);
}
static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(ah);
int ret;
u8 cmd_rsp;
ath9k_htc_ps_wakeup(priv);
/* Disable LED */
ath9k_hw_set_gpio(ah, ah->led_pin, 1);
ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
WMI_CMD(WMI_DISABLE_INTR_CMDID);
/* Stop TX */
ieee80211_stop_queues(hw);
htc_stop(priv->htc);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
skb_queue_purge(&priv->tx_queue);
/* Stop RX */
WMI_CMD(WMI_STOP_RECV_CMDID);
/*
* The MIB counters have to be disabled here,
* since the target doesn't do it.
*/
ath9k_hw_disable_mib_counters(ah);
if (!ah->curchan)
ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
/* Reset the HW */
ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
if (ret) {
ath_err(common,
"Unable to reset hardware; reset status %d (freq %u MHz)\n",
ret, ah->curchan->channel);
}
/* Disable the PHY */
ath9k_hw_phy_disable(ah);
ath9k_htc_ps_restore(priv);
ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
}
/**********************/
/* mac80211 Callbacks */
/**********************/
@ -1218,6 +1014,12 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
int ret = 0;
u8 cmd_rsp;
/* Cancel all the running timers/work .. */
cancel_work_sync(&priv->fatal_work);
cancel_work_sync(&priv->ps_work);
cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
ath9k_led_stop_brightness(priv);
mutex_lock(&priv->mutex);
if (priv->op_flags & OP_INVALID) {
@ -1226,11 +1028,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
return;
}
/* Cancel all the running timers/work .. */
cancel_work_sync(&priv->ps_work);
cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
ath9k_led_stop_brightness(priv);
ath9k_htc_ps_wakeup(priv);
htc_stop(priv->htc);
WMI_CMD(WMI_DISABLE_INTR_CMDID);
@ -1792,7 +1589,6 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
spin_lock_bh(&priv->beacon_lock);
priv->op_flags &= ~OP_SCANNING;
spin_unlock_bh(&priv->beacon_lock);
priv->op_flags |= OP_FULL_RESET;
if (priv->op_flags & OP_ASSOCIATED) {
ath9k_htc_beacon_config(priv, priv->vif);
ath_start_ani(priv);

Просмотреть файл

@ -1615,7 +1615,9 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
* simply keep the ATH_DBG_WARN_ON_ONCE() but make
* ath9k_hw_setpower() return type void.
*/
ATH_DBG_WARN_ON_ONCE(!status);
if (!(ah->ah_flags & AH_UNPLUGGED))
ATH_DBG_WARN_ON_ONCE(!status);
return status;
}

Просмотреть файл

@ -646,6 +646,10 @@ struct ath_nf_limits {
s16 nominal;
};
/* ah_flags */
#define AH_USE_EEPROM 0x1
#define AH_UNPLUGGED 0x2 /* The card has been physically removed. */
struct ath_hw {
struct ieee80211_hw *hw;
struct ath_common common;

Просмотреть файл

@ -29,8 +29,8 @@ static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
module_param_named(debug, ath9k_debug, uint, 0);
MODULE_PARM_DESC(debug, "Debugging mask");
int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
int ath9k_modparam_nohwcrypt;
module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
int led_blink;
@ -45,6 +45,7 @@ int ath9k_pm_qos_value = ATH9K_PM_QOS_DEFAULT_VALUE;
module_param_named(pmqos, ath9k_pm_qos_value, int, S_IRUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(pmqos, "User specified PM-QOS value");
bool is_ath9k_unloaded;
/* We use the hw_value as an index into our private channel structure */
#define CHAN2G(_freq, _idx) { \
@ -372,7 +373,7 @@ fail:
#undef DS2PHYS
}
static void ath9k_init_crypto(struct ath_softc *sc)
void ath9k_init_crypto(struct ath_softc *sc)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int i = 0;
@ -647,13 +648,12 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_NEED_DTIM_PERIOD;
IEEE80211_HW_REPORTS_TX_ACK_STATUS;
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt)
if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)
hw->flags |= IEEE80211_HW_MFP_CAPABLE;
hw->wiphy->interface_modes =
@ -899,6 +899,7 @@ module_init(ath9k_init);
static void __exit ath9k_exit(void)
{
is_ath9k_unloaded = true;
ath_ahb_exit();
ath_pci_exit();
ath_rate_control_unregister();

Просмотреть файл

@ -692,15 +692,16 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
if (ads.ds_rxstatus8 & AR_CRCErr)
rs->rs_status |= ATH9K_RXERR_CRC;
else if (ads.ds_rxstatus8 & AR_PHYErr) {
if (ads.ds_rxstatus8 & AR_PHYErr) {
rs->rs_status |= ATH9K_RXERR_PHY;
phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
rs->rs_phyerr = phyerr;
} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
}
if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
rs->rs_status |= ATH9K_RXERR_DECRYPT;
else if (ads.ds_rxstatus8 & AR_MichaelErr)
if (ads.ds_rxstatus8 & AR_MichaelErr)
rs->rs_status |= ATH9K_RXERR_MIC;
else if (ads.ds_rxstatus8 & AR_KeyMiss)
if (ads.ds_rxstatus8 & AR_KeyMiss)
rs->rs_status |= ATH9K_RXERR_DECRYPT;
}

Просмотреть файл

@ -285,7 +285,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
ath9k_hw_set_interrupts(ah, ah->imask);
if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
ath_beacon_config(sc, NULL);
if (sc->sc_flags & SC_OP_BEACONS)
ath_beacon_config(sc, NULL);
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
ath_start_ani(common);
}
@ -599,7 +600,7 @@ void ath9k_tasklet(unsigned long data)
return;
}
spin_lock_bh(&sc->sc_pcu_lock);
spin_lock(&sc->sc_pcu_lock);
if (!ath9k_hw_check_alive(ah))
ieee80211_queue_work(sc->hw, &sc->hw_check_work);
@ -643,7 +644,7 @@ void ath9k_tasklet(unsigned long data)
/* re-enable hardware interrupt */
ath9k_hw_enable_interrupts(ah);
spin_unlock_bh(&sc->sc_pcu_lock);
spin_unlock(&sc->sc_pcu_lock);
ath9k_ps_restore(sc);
}
@ -1328,6 +1329,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
ath9k_ps_restore(sc);
sc->ps_idle = true;
ath9k_set_wiphy_idle(aphy, true);
ath_radio_disable(sc, hw);
sc->sc_flags |= SC_OP_INVALID;
@ -1455,6 +1457,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int ret = 0;
ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n");
mutex_lock(&sc->mutex);
@ -1464,7 +1467,8 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
case NL80211_IFTYPE_ADHOC:
if (sc->nbcnvifs >= ATH_BCBUF) {
ath_err(common, "No beacon slot available\n");
return -ENOBUFS;
ret = -ENOBUFS;
goto out;
}
break;
case NL80211_IFTYPE_STATION:
@ -1478,14 +1482,15 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
default:
ath_err(common, "Interface type %d not yet supported\n",
vif->type);
mutex_unlock(&sc->mutex);
return -ENOTSUPP;
ret = -ENOTSUPP;
goto out;
}
vif->type = new_type;
vif->p2p = p2p;
out:
mutex_unlock(&sc->mutex);
return 0;
return ret;
}
static void ath9k_remove_interface(struct ieee80211_hw *hw,
@ -1824,7 +1829,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int ret = 0;
if (modparam_nohwcrypt)
if (ath9k_modparam_nohwcrypt)
return -ENOSPC;
mutex_lock(&sc->mutex);

Просмотреть файл

@ -96,7 +96,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common)
struct pci_dev *pdev = to_pci_dev(sc->dev);
u8 aspm;
if (!pdev->is_pcie)
if (!pci_is_pcie(pdev))
return;
pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm);
@ -264,6 +264,8 @@ static void ath_pci_remove(struct pci_dev *pdev)
struct ath_softc *sc = aphy->sc;
void __iomem *mem = sc->mem;
if (!is_ath9k_unloaded)
sc->sc_ah->ah_flags |= AH_UNPLUGGED;
ath9k_deinit_device(sc);
free_irq(sc->irq, sc);
ieee80211_free_hw(sc->hw);
@ -309,7 +311,16 @@ static int ath_pci_resume(struct device *device)
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
/*
* Reset key cache to sane defaults (all entries cleared) instead of
* semi-random values after suspend/resume.
*/
ath9k_ps_wakeup(sc);
ath9k_init_crypto(sc);
ath9k_ps_restore(sc);
sc->ps_idle = true;
ath9k_set_wiphy_idle(aphy, true);
ath_radio_disable(sc, hw);
return 0;

Просмотреть файл

@ -400,7 +400,7 @@ static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table,
}
}
static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv)
static void ath_rc_init_valid_rate_idx(struct ath_rate_priv *ath_rc_priv)
{
u8 i;
@ -408,7 +408,7 @@ static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv)
ath_rc_priv->valid_rate_index[i] = 0;
}
static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
static inline void ath_rc_set_valid_rate_idx(struct ath_rate_priv *ath_rc_priv,
u8 index, int valid_tx_rate)
{
BUG_ON(index > ath_rc_priv->rate_table_size);
@ -489,7 +489,7 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i;
ath_rc_priv->valid_phy_ratecnt[phy] += 1;
ath_rc_set_valid_txmask(ath_rc_priv, i, 1);
ath_rc_set_valid_rate_idx(ath_rc_priv, i, 1);
hi = i;
}
}
@ -532,7 +532,7 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
ath_rc_priv->valid_phy_rateidx[phy]
[valid_rate_count] = j;
ath_rc_priv->valid_phy_ratecnt[phy] += 1;
ath_rc_set_valid_txmask(ath_rc_priv, j, 1);
ath_rc_set_valid_rate_idx(ath_rc_priv, j, 1);
hi = A_MAX(hi, j);
}
}
@ -568,7 +568,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
ath_rc_priv->valid_phy_rateidx[phy]
[ath_rc_priv->valid_phy_ratecnt[phy]] = j;
ath_rc_priv->valid_phy_ratecnt[phy] += 1;
ath_rc_set_valid_txmask(ath_rc_priv, j, 1);
ath_rc_set_valid_rate_idx(ath_rc_priv, j, 1);
hi = A_MAX(hi, j);
}
}
@ -1210,7 +1210,7 @@ static void ath_rc_init(struct ath_softc *sc,
}
/* Determine the valid rates */
ath_rc_init_valid_txmask(ath_rc_priv);
ath_rc_init_valid_rate_idx(ath_rc_priv);
for (i = 0; i < WLAN_RC_PHY_MAX; i++) {
for (j = 0; j < MAX_TX_RATE_PHY; j++)
@ -1321,7 +1321,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
struct ath_rate_priv *ath_rc_priv = priv_sta;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
int final_ts_idx = 0, tx_status = 0, is_underrun = 0;
int final_ts_idx = 0, tx_status = 0;
int long_retry = 0;
__le16 fc;
int i;
@ -1358,7 +1358,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
tx_status = 1;
ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
(is_underrun) ? sc->hw->max_rate_tries : long_retry);
long_retry);
/* Check if aggregation has to be enabled for this tid */
if (conf_is_ht(&sc->hw->conf) &&

Просмотреть файл

@ -195,7 +195,6 @@ struct ath_rc_stats {
* @rate_max_phy: phy index for the max rate
* @per: PER for every valid rate in %
* @probe_interval: interval for ratectrl to probe for other rates
* @prev_data_rix: rate idx of last data frame
* @ht_cap: HT capabilities
* @neg_rates: Negotatied rates
* @neg_ht_rates: Negotiated HT rates
@ -214,10 +213,8 @@ struct ath_rate_priv {
u32 probe_time;
u32 per_down_time;
u32 probe_interval;
u32 prev_data_rix;
struct ath_rateset neg_rates;
struct ath_rateset neg_ht_rates;
struct ath_rate_softc *asc;
const struct ath_rate_table *rate_table;
struct dentry *debugfs_rcstats;

Просмотреть файл

@ -528,7 +528,8 @@ bool ath_stoprecv(struct ath_softc *sc)
sc->rx.rxlink = NULL;
spin_unlock_bh(&sc->rx.rxbuflock);
if (unlikely(!stopped)) {
if (!(ah->ah_flags & AH_UNPLUGGED) &&
unlikely(!stopped)) {
ath_err(ath9k_hw_common(sc->sc_ah),
"Could not stop RX, we could be "
"confusing the DMA engine when we start RX up\n");

Просмотреть файл

@ -120,7 +120,7 @@ void ath9k_deinit_wmi(struct ath9k_htc_priv *priv)
kfree(priv->wmi);
}
void ath9k_wmi_tasklet(unsigned long data)
void ath9k_swba_tasklet(unsigned long data)
{
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
struct ath_common *common = ath9k_hw_common(priv->ah);
@ -131,6 +131,16 @@ void ath9k_wmi_tasklet(unsigned long data)
}
void ath9k_fatal_work(struct work_struct *work)
{
struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
fatal_work);
struct ath_common *common = ath9k_hw_common(priv->ah);
ath_dbg(common, ATH_DBG_FATAL, "FATAL Event received, resetting device\n");
ath9k_htc_reset(priv);
}
static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
{
skb_pull(skb, sizeof(struct wmi_cmd_hdr));
@ -163,7 +173,11 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
switch (cmd_id) {
case WMI_SWBA_EVENTID:
wmi->beacon_pending = *(u8 *)wmi_event;
tasklet_schedule(&wmi->drv_priv->wmi_tasklet);
tasklet_schedule(&wmi->drv_priv->swba_tasklet);
break;
case WMI_FATAL_EVENTID:
ieee80211_queue_work(wmi->drv_priv->hw,
&wmi->drv_priv->fatal_work);
break;
case WMI_TXRATE_EVENTID:
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
@ -250,7 +264,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
int time_left, ret = 0;
unsigned long flags;
if (wmi->drv_priv->op_flags & OP_UNPLUGGED)
if (ah->ah_flags & AH_UNPLUGGED)
return 0;
skb = alloc_skb(headroom + cmd_len, GFP_ATOMIC);

Просмотреть файл

@ -117,7 +117,8 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
u8 *cmd_buf, u32 cmd_len,
u8 *rsp_buf, u32 rsp_len,
u32 timeout);
void ath9k_wmi_tasklet(unsigned long data);
void ath9k_swba_tasklet(unsigned long data);
void ath9k_fatal_work(struct work_struct *work);
#define WMI_CMD(_wmi_cmd) \
do { \

Просмотреть файл

@ -1029,8 +1029,6 @@ static int carl9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz,
if (err)
return err;
msleep(20);
return 0;
}
@ -1660,12 +1658,6 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
return err;
cmd = CARL9170_CMD_RF_INIT;
msleep(100);
err = carl9170_echo_test(ar, 0xaabbccdd);
if (err)
return err;
} else {
cmd = CARL9170_CMD_FREQUENCY;
}
@ -1676,6 +1668,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
err = carl9170_write_reg(ar, AR9170_PHY_REG_HEAVY_CLIP_ENABLE,
0x200);
if (err)
return err;
err = carl9170_init_rf_bank4_pwr(ar,
channel->band == IEEE80211_BAND_5GHZ,

Просмотреть файл

@ -834,7 +834,7 @@ static int carl9170_usb_load_firmware(struct ar9170 *ar)
if (err)
goto err_out;
/* firmware restarts cmd counter */
/* now, start the command response counter */
ar->cmd_seq = -1;
return 0;
@ -851,7 +851,12 @@ int carl9170_usb_restart(struct ar9170 *ar)
if (ar->intf->condition != USB_INTERFACE_BOUND)
return 0;
/* Disable command response sequence counter. */
/*
* Disable the command response sequence counter check.
* We already know that the device/firmware is in a bad state.
* So, no extra points are awarded to anyone who reminds the
* driver about that.
*/
ar->cmd_seq = -2;
err = carl9170_reboot(ar);
@ -903,6 +908,15 @@ static int carl9170_usb_init_device(struct ar9170 *ar)
{
int err;
/*
* The carl9170 firmware let's the driver know when it's
* ready for action. But we have to be prepared to gracefully
* handle all spurious [flushed] messages after each (re-)boot.
* Thus the command response counter remains disabled until it
* can be safely synchronized.
*/
ar->cmd_seq = -2;
err = carl9170_usb_send_rx_irq_urb(ar);
if (err)
goto err_out;
@ -911,14 +925,21 @@ static int carl9170_usb_init_device(struct ar9170 *ar)
if (err)
goto err_unrx;
err = carl9170_usb_open(ar);
if (err)
goto err_unrx;
mutex_lock(&ar->mutex);
err = carl9170_usb_load_firmware(ar);
mutex_unlock(&ar->mutex);
if (err)
goto err_unrx;
goto err_stop;
return 0;
err_stop:
carl9170_usb_stop(ar);
err_unrx:
carl9170_usb_cancel_urbs(ar);
@ -964,10 +985,6 @@ static void carl9170_usb_firmware_finish(struct ar9170 *ar)
if (err)
goto err_freefw;
err = carl9170_usb_open(ar);
if (err)
goto err_unrx;
err = carl9170_register(ar);
carl9170_usb_stop(ar);
@ -1043,7 +1060,6 @@ static int carl9170_usb_probe(struct usb_interface *intf,
atomic_set(&ar->rx_work_urbs, 0);
atomic_set(&ar->rx_anch_urbs, 0);
atomic_set(&ar->rx_pool_urbs, 0);
ar->cmd_seq = -2;
usb_get_dev(ar->udev);
@ -1090,10 +1106,6 @@ static int carl9170_usb_suspend(struct usb_interface *intf,
carl9170_usb_cancel_urbs(ar);
/*
* firmware automatically reboots for usb suspend.
*/
return 0;
}
@ -1106,15 +1118,23 @@ static int carl9170_usb_resume(struct usb_interface *intf)
return -ENODEV;
usb_unpoison_anchored_urbs(&ar->rx_anch);
carl9170_set_state(ar, CARL9170_STOPPED);
/*
* The USB documentation demands that [for suspend] all traffic
* to and from the device has to stop. This would be fine, but
* there's a catch: the device[usb phy] does not come back.
*
* Upon resume the firmware will "kill" itself and the
* boot-code sorts out the magic voodoo.
* Not very nice, but there's not much what could go wrong.
*/
msleep(1100);
err = carl9170_usb_init_device(ar);
if (err)
goto err_unrx;
err = carl9170_usb_open(ar);
if (err)
goto err_unrx;
return 0;
err_unrx:
@ -1133,6 +1153,7 @@ static struct usb_driver carl9170_driver = {
#ifdef CONFIG_PM
.suspend = carl9170_usb_suspend,
.resume = carl9170_usb_resume,
.reset_resume = carl9170_usb_resume,
#endif /* CONFIG_PM */
};

Просмотреть файл

@ -2121,8 +2121,10 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
filename = "ucode13";
else if (rev == 14)
filename = "ucode14";
else if (rev >= 15)
else if (rev == 15)
filename = "ucode15";
else if ((rev >= 16) && (rev <= 20))
filename = "ucode16_mimo";
else
goto err_no_ucode;
err = b43_do_request_fw(ctx, filename, &fw->ucode);
@ -2165,7 +2167,9 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
goto err_no_initvals;
break;
case B43_PHYTYPE_N:
if ((rev >= 11) && (rev <= 12))
if (rev >= 16)
filename = "n0initvals16";
else if ((rev >= 11) && (rev <= 12))
filename = "n0initvals11";
else
goto err_no_initvals;
@ -2209,7 +2213,9 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
goto err_no_initvals;
break;
case B43_PHYTYPE_N:
if ((rev >= 11) && (rev <= 12))
if (rev >= 16)
filename = "n0bsinitvals16";
else if ((rev >= 11) && (rev <= 12))
filename = "n0bsinitvals11";
else
goto err_no_initvals;
@ -4050,7 +4056,7 @@ static int b43_phy_versioning(struct b43_wldev *dev)
break;
#ifdef CONFIG_B43_PHY_N
case B43_PHYTYPE_N:
if (phy_rev > 2)
if (phy_rev > 9)
unsupported = 1;
break;
#endif

Просмотреть файл

@ -139,6 +139,99 @@ static void b43_chantab_radio_upload(struct b43_wldev *dev,
b43_radio_write(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
}
static void b43_chantab_radio_2056_upload(struct b43_wldev *dev,
const struct b43_nphy_channeltab_entry_rev3 *e)
{
b43_radio_write(dev, B2056_SYN_PLL_VCOCAL1, e->radio_syn_pll_vcocal1);
b43_radio_write(dev, B2056_SYN_PLL_VCOCAL2, e->radio_syn_pll_vcocal2);
b43_radio_write(dev, B2056_SYN_PLL_REFDIV, e->radio_syn_pll_refdiv);
b43_radio_write(dev, B2056_SYN_PLL_MMD2, e->radio_syn_pll_mmd2);
b43_radio_write(dev, B2056_SYN_PLL_MMD1, e->radio_syn_pll_mmd1);
b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1,
e->radio_syn_pll_loopfilter1);
b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2,
e->radio_syn_pll_loopfilter2);
b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER3,
e->radio_syn_pll_loopfilter3);
b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4,
e->radio_syn_pll_loopfilter4);
b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER5,
e->radio_syn_pll_loopfilter5);
b43_radio_write(dev, B2056_SYN_RESERVED_ADDR27,
e->radio_syn_reserved_addr27);
b43_radio_write(dev, B2056_SYN_RESERVED_ADDR28,
e->radio_syn_reserved_addr28);
b43_radio_write(dev, B2056_SYN_RESERVED_ADDR29,
e->radio_syn_reserved_addr29);
b43_radio_write(dev, B2056_SYN_LOGEN_VCOBUF1,
e->radio_syn_logen_vcobuf1);
b43_radio_write(dev, B2056_SYN_LOGEN_MIXER2, e->radio_syn_logen_mixer2);
b43_radio_write(dev, B2056_SYN_LOGEN_BUF3, e->radio_syn_logen_buf3);
b43_radio_write(dev, B2056_SYN_LOGEN_BUF4, e->radio_syn_logen_buf4);
b43_radio_write(dev, B2056_RX0 | B2056_RX_LNAA_TUNE,
e->radio_rx0_lnaa_tune);
b43_radio_write(dev, B2056_RX0 | B2056_RX_LNAG_TUNE,
e->radio_rx0_lnag_tune);
b43_radio_write(dev, B2056_TX0 | B2056_TX_INTPAA_BOOST_TUNE,
e->radio_tx0_intpaa_boost_tune);
b43_radio_write(dev, B2056_TX0 | B2056_TX_INTPAG_BOOST_TUNE,
e->radio_tx0_intpag_boost_tune);
b43_radio_write(dev, B2056_TX0 | B2056_TX_PADA_BOOST_TUNE,
e->radio_tx0_pada_boost_tune);
b43_radio_write(dev, B2056_TX0 | B2056_TX_PADG_BOOST_TUNE,
e->radio_tx0_padg_boost_tune);
b43_radio_write(dev, B2056_TX0 | B2056_TX_PGAA_BOOST_TUNE,
e->radio_tx0_pgaa_boost_tune);
b43_radio_write(dev, B2056_TX0 | B2056_TX_PGAG_BOOST_TUNE,
e->radio_tx0_pgag_boost_tune);
b43_radio_write(dev, B2056_TX0 | B2056_TX_MIXA_BOOST_TUNE,
e->radio_tx0_mixa_boost_tune);
b43_radio_write(dev, B2056_TX0 | B2056_TX_MIXG_BOOST_TUNE,
e->radio_tx0_mixg_boost_tune);
b43_radio_write(dev, B2056_RX1 | B2056_RX_LNAA_TUNE,
e->radio_rx1_lnaa_tune);
b43_radio_write(dev, B2056_RX1 | B2056_RX_LNAG_TUNE,
e->radio_rx1_lnag_tune);
b43_radio_write(dev, B2056_TX1 | B2056_TX_INTPAA_BOOST_TUNE,
e->radio_tx1_intpaa_boost_tune);
b43_radio_write(dev, B2056_TX1 | B2056_TX_INTPAG_BOOST_TUNE,
e->radio_tx1_intpag_boost_tune);
b43_radio_write(dev, B2056_TX1 | B2056_TX_PADA_BOOST_TUNE,
e->radio_tx1_pada_boost_tune);
b43_radio_write(dev, B2056_TX1 | B2056_TX_PADG_BOOST_TUNE,
e->radio_tx1_padg_boost_tune);
b43_radio_write(dev, B2056_TX1 | B2056_TX_PGAA_BOOST_TUNE,
e->radio_tx1_pgaa_boost_tune);
b43_radio_write(dev, B2056_TX1 | B2056_TX_PGAG_BOOST_TUNE,
e->radio_tx1_pgag_boost_tune);
b43_radio_write(dev, B2056_TX1 | B2056_TX_MIXA_BOOST_TUNE,
e->radio_tx1_mixa_boost_tune);
b43_radio_write(dev, B2056_TX1 | B2056_TX_MIXG_BOOST_TUNE,
e->radio_tx1_mixg_boost_tune);
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2056Setup */
static void b43_radio_2056_setup(struct b43_wldev *dev,
const struct b43_nphy_channeltab_entry_rev3 *e)
{
B43_WARN_ON(dev->phy.rev < 3);
b43_chantab_radio_2056_upload(dev, e);
/* TODO */
udelay(50);
/* VCO calibration */
b43_radio_write(dev, B2056_SYN_PLL_VCOCAL12, 0x00);
b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x38);
b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x18);
b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x38);
b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x39);
udelay(300);
}
static void b43_chantab_phy_upload(struct b43_wldev *dev,
const struct b43_phy_n_sfo_cfg *e)
{
@ -401,16 +494,45 @@ static void b43_radio_init2055(struct b43_wldev *dev)
b43_radio_init2055_post(dev);
}
static void b43_radio_init2056_pre(struct b43_wldev *dev)
{
b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
~B43_NPHY_RFCTL_CMD_CHIP0PU);
/* Maybe wl meant to reset and set (order?) RFCTL_CMD_OEPORFORCE? */
b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
B43_NPHY_RFCTL_CMD_OEPORFORCE);
b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
~B43_NPHY_RFCTL_CMD_OEPORFORCE);
b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
B43_NPHY_RFCTL_CMD_CHIP0PU);
}
static void b43_radio_init2056_post(struct b43_wldev *dev)
{
b43_radio_set(dev, B2056_SYN_COM_CTRL, 0xB);
b43_radio_set(dev, B2056_SYN_COM_PU, 0x2);
b43_radio_set(dev, B2056_SYN_COM_RESET, 0x2);
msleep(1);
b43_radio_mask(dev, B2056_SYN_COM_RESET, ~0x2);
b43_radio_mask(dev, B2056_SYN_PLL_MAST2, ~0xFC);
b43_radio_mask(dev, B2056_SYN_RCCAL_CTRL0, ~0x1);
/*
if (nphy->init_por)
Call Radio 2056 Recalibrate
*/
}
/*
* Initialize a Broadcom 2056 N-radio
* http://bcm-v4.sipsolutions.net/802.11/Radio/2056/Init
*/
static void b43_radio_init2056(struct b43_wldev *dev)
{
/* TODO */
b43_radio_init2056_pre(dev);
b2056_upload_inittabs(dev, 0, 0);
b43_radio_init2056_post(dev);
}
/*
* Upload the N-PHY tables.
* http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables
@ -3578,7 +3700,6 @@ static int b43_nphy_set_channel(struct b43_wldev *dev,
if (dev->phy.rev >= 3) {
tabent_r3 = b43_nphy_get_chantabent_rev3(dev,
channel->center_freq);
tabent_r3 = NULL;
if (!tabent_r3)
return -ESRCH;
} else {
@ -3607,7 +3728,7 @@ static int b43_nphy_set_channel(struct b43_wldev *dev,
if (dev->phy.rev >= 3) {
tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 4 : 0;
b43_radio_maskset(dev, 0x08, 0xFFFB, tmp);
/* TODO: PHY Radio2056 Setup (dev, tabent_r3); */
b43_radio_2056_setup(dev, tabent_r3);
b43_nphy_channel_setup(dev, &(tabent_r3->phy_regs), channel);
} else {
tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 0x0020 : 0x0050;
@ -3638,6 +3759,7 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
memset(nphy, 0, sizeof(*nphy));
nphy->hang_avoid = (phy->rev == 3 || phy->rev == 4);
nphy->gain_boost = true; /* this way we follow wl, assume it is true */
nphy->txrx_chain = 2; /* sth different than 0 and 1 for now */
nphy->phyrxchain = 3; /* to avoid b43_nphy_set_rx_core_state like wl */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1114,4 +1114,7 @@ struct b43_nphy_channeltab_entry_rev3 {
struct b43_phy_n_sfo_cfg phy_regs;
};
void b2056_upload_inittabs(struct b43_wldev *dev,
bool ghz5, bool ignore_uploadflag);
#endif /* B43_RADIO_2056_H_ */

Просмотреть файл

@ -596,12 +596,7 @@ struct iwl_cfg iwl6005_2bg_cfg = {
.need_dc_calib = true, \
.need_temp_offset_calib = true, \
.led_mode = IWL_LED_RF_STATE, \
.adv_pm = true, \
/* \
*Due to bluetooth, we transmit 2.4 GHz probes \
* only on antenna A \
*/ \
.scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A
.adv_pm = true \
struct iwl_cfg iwl6030_2agn_cfg = {
.name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",

Просмотреть файл

@ -1492,15 +1492,11 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
if (priv->cfg->scan_rx_antennas[band])
rx_ant = priv->cfg->scan_rx_antennas[band];
if (priv->cfg->scan_tx_antennas[band])
scan_tx_antennas = priv->cfg->scan_tx_antennas[band];
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist &&
priv->bt_full_concurrent) {
/* operated as 1x1 in full concurrency mode */
scan_tx_antennas = first_antenna(
priv->cfg->scan_tx_antennas[band]);
if (band == IEEE80211_BAND_2GHZ &&
priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist) {
/* transmit 2.4 GHz probes only on first antenna */
scan_tx_antennas = first_antenna(scan_tx_antennas);
}
priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band],

Просмотреть файл

@ -3280,9 +3280,10 @@ void iwlagn_mac_stop(struct ieee80211_hw *hw)
flush_workqueue(priv->workqueue);
/* enable interrupts again in order to receive rfkill changes */
/* User space software may expect getting rfkill changes
* even if interface is down */
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
iwl_enable_interrupts(priv);
iwl_enable_rfkill_int(priv);
IWL_DEBUG_MAC80211(priv, "leave\n");
}
@ -3634,7 +3635,8 @@ void iwlagn_configure_filter(struct ieee80211_hw *hw,
changed_flags, *total_flags);
CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK);
/* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
#undef CHK
@ -4190,14 +4192,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* 8. Enable interrupts and read RFKILL state
*********************************************/
/* enable interrupts if needed: hw bug w/a */
/* enable rfkill interrupt: hw bug w/a */
pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd);
if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd);
}
iwl_enable_interrupts(priv);
iwl_enable_rfkill_int(priv);
/* If platform's RF_KILL switch is NOT set to KILL */
if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
@ -4411,7 +4413,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
{IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
/* 6x00 Series Gen2a */
/* 6x05 Series */
{IWL_PCI_DEVICE(0x0082, 0x1301, iwl6005_2agn_cfg)},
{IWL_PCI_DEVICE(0x0082, 0x1306, iwl6005_2abg_cfg)},
{IWL_PCI_DEVICE(0x0082, 0x1307, iwl6005_2bg_cfg)},
@ -4420,7 +4422,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x0085, 0x1311, iwl6005_2agn_cfg)},
{IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)},
/* 6x00 Series Gen2b */
/* 6x30 Series */
{IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
{IWL_PCI_DEVICE(0x008A, 0x5307, iwl1030_bg_cfg)},
{IWL_PCI_DEVICE(0x008A, 0x5325, iwl1030_bgn_cfg)},
@ -4446,7 +4448,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
{IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
/* 6x50 WiFi/WiMax Series Gen2 */
/* 6150 WiFi/WiMax Series */
{IWL_PCI_DEVICE(0x0885, 0x1305, iwl6150_bgn_cfg)},
{IWL_PCI_DEVICE(0x0885, 0x1306, iwl6150_bgn_cfg)},
{IWL_PCI_DEVICE(0x0885, 0x1325, iwl6150_bgn_cfg)},

Просмотреть файл

@ -411,7 +411,6 @@ struct iwl_cfg {
const bool need_dc_calib; /* if used set to true */
const bool need_temp_offset_calib; /* if used set to true */
u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
enum iwl_led_mode led_mode;
const bool adv_pm;
const bool rx_with_siso_diversity;

Просмотреть файл

@ -148,6 +148,12 @@ static inline void iwl_disable_interrupts(struct iwl_priv *priv)
IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
}
static inline void iwl_enable_rfkill_int(struct iwl_priv *priv)
{
IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n");
iwl_write32(priv, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
}
static inline void iwl_enable_interrupts(struct iwl_priv *priv)
{
IWL_DEBUG_ISR(priv, "Enabling interrupts\n");

Просмотреть файл

@ -45,7 +45,7 @@
/* default: IWL_LED_BLINK(0) using blinking index table */
static int led_mode;
module_param(led_mode, int, S_IRUGO);
MODULE_PARM_DESC(led_mode, "led mode: 0=system default, "
MODULE_PARM_DESC(led_mode, "0=system default, "
"1=On(RF On)/Off(RF Off), 2=blinking");
static const struct {

Просмотреть файл

@ -784,7 +784,7 @@ static int lbs_spi_thread(void *data)
up(&card->spi_thread_terminated);
do_exit(0);
}
} while (err == EINTR);
} while (err == -EINTR);
/* Read the host interrupt status register to see what we
* can do. */

Просмотреть файл

@ -129,6 +129,7 @@ MODULE_PARM_DESC(workaround_interval,
#define OID_802_11_RTS_THRESHOLD cpu_to_le32(0x0d01020a)
#define OID_802_11_SUPPORTED_RATES cpu_to_le32(0x0d01020e)
#define OID_802_11_CONFIGURATION cpu_to_le32(0x0d010211)
#define OID_802_11_POWER_MODE cpu_to_le32(0x0d010216)
#define OID_802_11_BSSID_LIST cpu_to_le32(0x0d010217)
@ -239,6 +240,12 @@ enum ndis_80211_addwep_bits {
NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31)
};
enum ndis_80211_power_mode {
NDIS_80211_POWER_MODE_CAM,
NDIS_80211_POWER_MODE_MAX_PSP,
NDIS_80211_POWER_MODE_FAST_PSP,
};
struct ndis_80211_auth_request {
__le32 length;
u8 bssid[6];
@ -478,6 +485,9 @@ struct rndis_wlan_private {
struct mutex command_lock;
unsigned long work_pending;
int last_qual;
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
int last_cqm_event_rssi;
struct ieee80211_supported_band band;
struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)];
@ -500,10 +510,10 @@ struct rndis_wlan_private {
/* hardware state */
bool radio_on;
int power_mode;
int infra_mode;
bool connected;
u8 bssid[ETH_ALEN];
struct ndis_80211_ssid essid;
__le32 current_command_oid;
/* encryption stuff */
@ -570,7 +580,14 @@ static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev);
static struct cfg80211_ops rndis_config_ops = {
static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
bool enabled, int timeout);
static int rndis_set_cqm_rssi_config(struct wiphy *wiphy,
struct net_device *dev,
s32 rssi_thold, u32 rssi_hyst);
static const struct cfg80211_ops rndis_config_ops = {
.change_virtual_intf = rndis_change_virtual_intf,
.scan = rndis_scan,
.set_wiphy_params = rndis_set_wiphy_params,
@ -589,6 +606,8 @@ static struct cfg80211_ops rndis_config_ops = {
.set_pmksa = rndis_set_pmksa,
.del_pmksa = rndis_del_pmksa,
.flush_pmksa = rndis_flush_pmksa,
.set_power_mgmt = rndis_set_power_mgmt,
.set_cqm_rssi_config = rndis_set_cqm_rssi_config,
};
static void *rndis_wiphy_privid = &rndis_wiphy_privid;
@ -687,6 +706,7 @@ static const char *oid_to_string(__le32 oid)
OID_STR(OID_802_11_ADD_KEY);
OID_STR(OID_802_11_REMOVE_KEY);
OID_STR(OID_802_11_ASSOCIATION_INFORMATION);
OID_STR(OID_802_11_CAPABILITY);
OID_STR(OID_802_11_PMKID);
OID_STR(OID_802_11_NETWORK_TYPES_SUPPORTED);
OID_STR(OID_802_11_NETWORK_TYPE_IN_USE);
@ -697,6 +717,7 @@ static const char *oid_to_string(__le32 oid)
OID_STR(OID_802_11_RTS_THRESHOLD);
OID_STR(OID_802_11_SUPPORTED_RATES);
OID_STR(OID_802_11_CONFIGURATION);
OID_STR(OID_802_11_POWER_MODE);
OID_STR(OID_802_11_BSSID_LIST);
#undef OID_STR
}
@ -1026,7 +1047,6 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
return ret;
}
if (ret == 0) {
memcpy(&priv->essid, ssid, sizeof(priv->essid));
priv->radio_on = true;
netdev_dbg(usbdev->net, "%s(): radio_on = true\n", __func__);
}
@ -1967,8 +1987,8 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
int ie_len, bssid_len;
u8 *ie;
netdev_dbg(usbdev->net, " found bssid: '%.32s' [%pM]\n",
bssid->ssid.essid, bssid->mac);
netdev_dbg(usbdev->net, " found bssid: '%.32s' [%pM], len: %d\n",
bssid->ssid.essid, bssid->mac, le32_to_cpu(bssid->length));
/* parse bssid structure */
bssid_len = le32_to_cpu(bssid->length);
@ -2002,54 +2022,98 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
GFP_KERNEL);
}
static struct ndis_80211_bssid_ex *next_bssid_list_item(
struct ndis_80211_bssid_ex *bssid,
int *bssid_len, void *buf, int len)
{
void *buf_end, *bssid_end;
buf_end = (char *)buf + len;
bssid_end = (char *)bssid + *bssid_len;
if ((int)(buf_end - bssid_end) < sizeof(bssid->length)) {
*bssid_len = 0;
return NULL;
} else {
bssid = (void *)((char *)bssid + *bssid_len);
*bssid_len = le32_to_cpu(bssid->length);
return bssid;
}
}
static bool check_bssid_list_item(struct ndis_80211_bssid_ex *bssid,
int bssid_len, void *buf, int len)
{
void *buf_end, *bssid_end;
if (!bssid || bssid_len <= 0 || bssid_len > len)
return false;
buf_end = (char *)buf + len;
bssid_end = (char *)bssid + bssid_len;
return (int)(buf_end - bssid_end) >= 0 && (int)(bssid_end - buf) >= 0;
}
static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid,
bool *matched)
{
void *buf = NULL;
struct ndis_80211_bssid_list_ex *bssid_list;
struct ndis_80211_bssid_ex *bssid;
int ret = -EINVAL, len, count, bssid_len;
bool resized = false;
int ret = -EINVAL, len, count, bssid_len, real_count, new_len;
netdev_dbg(usbdev->net, "check_bssid_list\n");
netdev_dbg(usbdev->net, "%s()\n", __func__);
len = CONTROL_BUFFER_SIZE;
resize_buf:
buf = kmalloc(len, GFP_KERNEL);
buf = kzalloc(len, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto out;
}
ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len);
if (ret != 0)
/* BSSID-list might have got bigger last time we checked, keep
* resizing until it won't get any bigger.
*/
new_len = len;
ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &new_len);
if (ret != 0 || new_len < sizeof(struct ndis_80211_bssid_list_ex))
goto out;
if (!resized && len > CONTROL_BUFFER_SIZE) {
resized = true;
if (new_len > len) {
len = new_len;
kfree(buf);
goto resize_buf;
}
bssid_list = buf;
bssid = bssid_list->bssid;
bssid_len = le32_to_cpu(bssid->length);
count = le32_to_cpu(bssid_list->num_items);
netdev_dbg(usbdev->net, "check_bssid_list: %d BSSIDs found (buflen: %d)\n",
count, len);
len = new_len;
while (count && ((void *)bssid + bssid_len) <= (buf + len)) {
bssid_list = buf;
count = le32_to_cpu(bssid_list->num_items);
real_count = 0;
netdev_dbg(usbdev->net, "%s(): buflen: %d\n", __func__, len);
bssid_len = 0;
bssid = next_bssid_list_item(bssid_list->bssid, &bssid_len, buf, len);
/* Device returns incorrect 'num_items'. Workaround by ignoring the
* received 'num_items' and walking through full bssid buffer instead.
*/
while (check_bssid_list_item(bssid, bssid_len, buf, len)) {
if (rndis_bss_info_update(usbdev, bssid) && match_bssid &&
matched) {
if (compare_ether_addr(bssid->mac, match_bssid))
*matched = true;
}
bssid = (void *)bssid + bssid_len;
bssid_len = le32_to_cpu(bssid->length);
count--;
real_count++;
bssid = next_bssid_list_item(bssid, &bssid_len, buf, len);
}
netdev_dbg(usbdev->net, "%s(): num_items from device: %d, really found:"
" %d\n", __func__, count, real_count);
out:
kfree(buf);
return ret;
@ -2391,6 +2455,9 @@ static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
priv->encr_tx_key_index = key_index;
if (is_wpa_key(priv, key_index))
return 0;
key = priv->encr_keys[key_index];
return add_wep_key(usbdev, key.material, key.len, key_index);
@ -2521,6 +2588,51 @@ static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
return rndis_set_oid(usbdev, OID_802_11_PMKID, &pmkid, sizeof(pmkid));
}
static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
bool enabled, int timeout)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
int power_mode;
__le32 mode;
int ret;
netdev_dbg(usbdev->net, "%s(): %s, %d\n", __func__,
enabled ? "enabled" : "disabled",
timeout);
if (enabled)
power_mode = NDIS_80211_POWER_MODE_FAST_PSP;
else
power_mode = NDIS_80211_POWER_MODE_CAM;
if (power_mode == priv->power_mode)
return 0;
priv->power_mode = power_mode;
mode = cpu_to_le32(power_mode);
ret = rndis_set_oid(usbdev, OID_802_11_POWER_MODE, &mode, sizeof(mode));
netdev_dbg(usbdev->net, "%s(): OID_802_11_POWER_MODE -> %d\n",
__func__, ret);
return ret;
}
static int rndis_set_cqm_rssi_config(struct wiphy *wiphy,
struct net_device *dev,
s32 rssi_thold, u32 rssi_hyst)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
priv->cqm_rssi_thold = rssi_thold;
priv->cqm_rssi_hyst = rssi_hyst;
priv->last_cqm_event_rssi = 0;
return 0;
}
static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
struct ndis_80211_assoc_info *info)
{
@ -3050,6 +3162,32 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy)
return retval;
}
static void rndis_do_cqm(struct usbnet *usbdev, s32 rssi)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
enum nl80211_cqm_rssi_threshold_event event;
int thold, hyst, last_event;
if (priv->cqm_rssi_thold >= 0 || rssi >= 0)
return;
if (priv->infra_mode != NDIS_80211_INFRA_INFRA)
return;
last_event = priv->last_cqm_event_rssi;
thold = priv->cqm_rssi_thold;
hyst = priv->cqm_rssi_hyst;
if (rssi < thold && (last_event == 0 || rssi < last_event - hyst))
event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
else if (rssi > thold && (last_event == 0 || rssi > last_event + hyst))
event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
else
return;
priv->last_cqm_event_rssi = rssi;
cfg80211_cqm_rssi_notify(usbdev->net, event, GFP_KERNEL);
}
#define DEVICE_POLLER_JIFFIES (HZ)
static void rndis_device_poller(struct work_struct *work)
{
@ -3084,8 +3222,10 @@ static void rndis_device_poller(struct work_struct *work)
len = sizeof(rssi);
ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len);
if (ret == 0)
if (ret == 0) {
priv->last_qual = level_to_qual(le32_to_cpu(rssi));
rndis_do_cqm(usbdev, le32_to_cpu(rssi));
}
netdev_dbg(usbdev->net, "dev-poller: OID_802_11_RSSI -> %d, rssi:%d, qual: %d\n",
ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi)));
@ -3347,13 +3487,15 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
set_default_iw_params(usbdev);
priv->power_mode = -1;
/* set default rts/frag */
rndis_set_wiphy_params(wiphy,
WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD);
/* turn radio on */
priv->radio_on = true;
disassociate(usbdev, true);
/* turn radio off on init */
priv->radio_on = false;
disassociate(usbdev, false);
netif_carrier_off(usbdev->net);
return 0;

Просмотреть файл

@ -688,14 +688,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
u32 status;
u8 qid;
while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) {
/* Now remove the tx status from the FIFO */
if (kfifo_out(&rt2x00dev->txstatus_fifo, &status,
sizeof(status)) != sizeof(status)) {
WARN_ON(1);
break;
}
while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) {
qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE);
if (qid >= QID_RX) {
/*
@ -803,14 +796,7 @@ static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
break;
if (kfifo_is_full(&rt2x00dev->txstatus_fifo)) {
WARNING(rt2x00dev, "TX status FIFO overrun,"
" drop tx status report.\n");
break;
}
if (kfifo_in(&rt2x00dev->txstatus_fifo, &status,
sizeof(status)) != sizeof(status)) {
if (!kfifo_put(&rt2x00dev->txstatus_fifo, &status)) {
WARNING(rt2x00dev, "TX status FIFO overrun,"
"drop tx status report.\n");
break;

Просмотреть файл

@ -369,7 +369,10 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry,
static void rt2800usb_write_tx_data(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
u8 padding_len;
unsigned int len;
int err;
rt2800_write_tx_data(entry, txdesc);
/*
* pad(1~3 bytes) is added after each 802.11 payload.
@ -378,9 +381,14 @@ static void rt2800usb_write_tx_data(struct queue_entry *entry,
* | TXINFO | TXWI | 802.11 header | L2 pad | payload | pad | USB end pad |
* |<------------- tx_pkt_len ------------->|
*/
rt2800_write_tx_data(entry, txdesc);
padding_len = roundup(entry->skb->len + 4, 4) - entry->skb->len;
memset(skb_put(entry->skb, padding_len), 0, padding_len);
len = roundup(entry->skb->len, 4) + 4;
err = skb_padto(entry->skb, len);
if (unlikely(err)) {
WARNING(entry->queue->rt2x00dev, "TX SKB padding error, out of memory\n");
return;
}
entry->skb->len = len;
}
/*

Просмотреть файл

@ -347,28 +347,16 @@ struct link {
struct delayed_work watchdog_work;
};
enum rt2x00_delayed_flags {
DELAYED_UPDATE_BEACON,
};
/*
* Interface structure
* Per interface configuration details, this structure
* is allocated as the private data for ieee80211_vif.
*/
struct rt2x00_intf {
/*
* All fields within the rt2x00_intf structure
* must be protected with a spinlock.
*/
spinlock_t lock;
/*
* MAC of the device.
*/
u8 mac[ETH_ALEN];
/*
* BBSID of the AP to associate with.
*/
u8 bssid[ETH_ALEN];
/*
* beacon->skb must be protected with the mutex.
*/
@ -384,8 +372,7 @@ struct rt2x00_intf {
/*
* Actions that needed rescheduling.
*/
unsigned int delayed_flags;
#define DELAYED_UPDATE_BEACON 0x00000001
unsigned long delayed_flags;
/*
* Software sequence counter, this is only required
@ -908,7 +895,7 @@ struct rt2x00_dev {
/*
* FIFO for storing tx status reports between isr and tasklet.
*/
struct kfifo txstatus_fifo;
DECLARE_KFIFO_PTR(txstatus_fifo, u32);
/*
* Tasklet for processing tx status reports (rt2800pci).

Просмотреть файл

@ -62,13 +62,13 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
* This will prevent the device being confused when it wants
* to ACK frames or consideres itself associated.
*/
memset(&conf.mac, 0, sizeof(conf.mac));
memset(conf.mac, 0, sizeof(conf.mac));
if (mac)
memcpy(&conf.mac, mac, ETH_ALEN);
memcpy(conf.mac, mac, ETH_ALEN);
memset(&conf.bssid, 0, sizeof(conf.bssid));
memset(conf.bssid, 0, sizeof(conf.bssid));
if (bssid)
memcpy(&conf.bssid, bssid, ETH_ALEN);
memcpy(conf.bssid, bssid, ETH_ALEN);
flags |= CONFIG_UPDATE_TYPE;
if (mac || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count))

Просмотреть файл

@ -110,19 +110,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
{
struct rt2x00_dev *rt2x00dev = data;
struct rt2x00_intf *intf = vif_to_intf(vif);
int delayed_flags;
/*
* Copy all data we need during this action under the protection
* of a spinlock. Otherwise race conditions might occur which results
* into an invalid configuration.
*/
spin_lock(&intf->lock);
delayed_flags = intf->delayed_flags;
intf->delayed_flags = 0;
spin_unlock(&intf->lock);
/*
* It is possible the radio was disabled while the work had been
@ -133,7 +120,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
if (delayed_flags & DELAYED_UPDATE_BEACON)
if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags))
rt2x00queue_update_beacon(rt2x00dev, vif, true);
}
@ -813,8 +800,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Allocate tx status FIFO for driver use.
*/
if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags) &&
rt2x00dev->ops->lib->txstatus_tasklet) {
if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) {
/*
* Allocate txstatus fifo and tasklet, we use a size of 512
* for the kfifo which is big enough to store 512/4=128 tx
@ -828,9 +814,10 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
return status;
/* tasklet for processing the tx status reports. */
tasklet_init(&rt2x00dev->txstatus_tasklet,
rt2x00dev->ops->lib->txstatus_tasklet,
(unsigned long)rt2x00dev);
if (rt2x00dev->ops->lib->txstatus_tasklet)
tasklet_init(&rt2x00dev->txstatus_tasklet,
rt2x00dev->ops->lib->txstatus_tasklet,
(unsigned long)rt2x00dev);
}

Просмотреть файл

@ -40,8 +40,6 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
if (tx_info->control.sta)
txdesc->mpdu_density =
tx_info->control.sta->ht_cap.ampdu_density;
else
txdesc->mpdu_density = 0;
txdesc->ba_size = 7; /* FIXME: What value is needed? */

Просмотреть файл

@ -268,7 +268,6 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
else
rt2x00dev->intf_sta_count++;
spin_lock_init(&intf->lock);
spin_lock_init(&intf->seqlock);
mutex_init(&intf->beacon_skb_mutex);
intf->beacon = entry;
@ -282,9 +281,8 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
* STA interfaces at this time, since this can cause
* invalid behavior in the device.
*/
memcpy(&intf->mac, vif->addr, ETH_ALEN);
rt2x00lib_config_intf(rt2x00dev, intf, vif->type,
intf->mac, NULL);
vif->addr, NULL);
/*
* Some filters depend on the current working mode. We can force
@ -445,9 +443,7 @@ static void rt2x00mac_set_tim_iter(void *data, u8 *mac,
vif->type != NL80211_IFTYPE_WDS)
return;
spin_lock(&intf->lock);
intf->delayed_flags |= DELAYED_UPDATE_BEACON;
spin_unlock(&intf->lock);
set_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags);
}
int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
@ -472,17 +468,17 @@ EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
{
if (key_len > NL80211_TKIP_DATA_OFFSET_ENCR_KEY)
memcpy(&crypto->key,
memcpy(crypto->key,
&key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY],
sizeof(crypto->key));
if (key_len > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
memcpy(&crypto->tx_mic,
memcpy(crypto->tx_mic,
&key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
sizeof(crypto->tx_mic));
if (key_len > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY)
memcpy(&crypto->rx_mic,
memcpy(crypto->rx_mic,
&key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
sizeof(crypto->rx_mic));
}
@ -492,7 +488,6 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_key_conf *key)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(vif);
int (*set_key) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key);
@ -516,7 +511,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (rt2x00dev->intf_sta_count)
crypto.bssidx = 0;
else
crypto.bssidx = intf->mac[5] & (rt2x00dev->ops->max_ap_intf - 1);
crypto.bssidx = vif->addr[5] & (rt2x00dev->ops->max_ap_intf - 1);
crypto.cipher = rt2x00crypto_key_to_cipher(key);
if (crypto.cipher == CIPHER_NONE)
@ -534,7 +529,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (crypto.cipher == CIPHER_TKIP)
memcpy_tkip(&crypto, &key->key[0], key->keylen);
else
memcpy(&crypto.key, &key->key[0], key->keylen);
memcpy(crypto.key, &key->key[0], key->keylen);
/*
* Each BSS has a maximum of 4 shared keys.
* Shared key index values:
@ -614,22 +609,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return;
spin_lock(&intf->lock);
/*
* conf->bssid can be NULL if coming from the internal
* beacon update routine.
*/
if (changes & BSS_CHANGED_BSSID)
memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN);
spin_unlock(&intf->lock);
/*
* Call rt2x00_config_intf() outside of the spinlock context since
* the call will sleep for USB drivers. By using the ieee80211_if_conf
* values as arguments we make keep access to rt2x00_intf thread safe
* even without the lock.
* Update the BSSID.
*/
if (changes & BSS_CHANGED_BSSID)
rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,

Просмотреть файл

@ -286,7 +286,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
rt2x00dev->irq = pci_dev->irq;
rt2x00dev->name = pci_name(pci_dev);
if (pci_dev->is_pcie)
if (pci_is_pcie(pci_dev))
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
else
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);

Просмотреть файл

@ -1,7 +1,2 @@
rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o rtl8187_rfkill.o
obj-$(CONFIG_RTL8180) += rtl8180.o
obj-$(CONFIG_RTL8187) += rtl8187.o
obj-$(CONFIG_RTL8180) += rtl8180/
obj-$(CONFIG_RTL8187) += rtl8187/

Просмотреть файл

@ -0,0 +1,5 @@
rtl8180-objs := dev.o rtl8225.o sa2400.o max2820.o grf5101.o
obj-$(CONFIG_RTL8180) += rtl8180.o
ccflags-y += -Idrivers/net/wireless/rtl818x

Просмотреть файл

@ -24,10 +24,10 @@
#include <net/mac80211.h>
#include "rtl8180.h"
#include "rtl8180_rtl8225.h"
#include "rtl8180_sa2400.h"
#include "rtl8180_max2820.h"
#include "rtl8180_grf5101.h"
#include "rtl8225.h"
#include "sa2400.h"
#include "max2820.h"
#include "grf5101.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");

Просмотреть файл

@ -25,7 +25,7 @@
#include <net/mac80211.h>
#include "rtl8180.h"
#include "rtl8180_grf5101.h"
#include "grf5101.h"
static const int grf5101_encode[] = {
0x0, 0x8, 0x4, 0xC,

Просмотреть файл

@ -24,7 +24,7 @@
#include <net/mac80211.h>
#include "rtl8180.h"
#include "rtl8180_max2820.h"
#include "max2820.h"
static const u32 max2820_chan[] = {
12, /* CH 1 */

Просмотреть файл

@ -21,7 +21,7 @@
#include <net/mac80211.h>
#include "rtl8180.h"
#include "rtl8180_rtl8225.h"
#include "rtl8225.h"
static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
{

Просмотреть файл

@ -25,7 +25,7 @@
#include <net/mac80211.h>
#include "rtl8180.h"
#include "rtl8180_sa2400.h"
#include "sa2400.h"
static const u32 sa2400_chan[] = {
0x00096c, /* ch1 */

Просмотреть файл

@ -0,0 +1,5 @@
rtl8187-objs := dev.o rtl8225.o leds.o rfkill.o
obj-$(CONFIG_RTL8187) += rtl8187.o
ccflags-y += -Idrivers/net/wireless/rtl818x

Просмотреть файл

@ -29,11 +29,11 @@
#include <net/mac80211.h>
#include "rtl8187.h"
#include "rtl8187_rtl8225.h"
#include "rtl8225.h"
#ifdef CONFIG_RTL8187_LEDS
#include "rtl8187_leds.h"
#include "leds.h"
#endif
#include "rtl8187_rfkill.h"
#include "rfkill.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");

Просмотреть файл

@ -20,7 +20,7 @@
#include <linux/eeprom_93cx6.h>
#include "rtl8187.h"
#include "rtl8187_leds.h"
#include "leds.h"
static void led_turn_on(struct work_struct *work)
{

Просмотреть файл

@ -18,7 +18,7 @@
#include <net/mac80211.h>
#include "rtl8187.h"
#include "rtl8187_rfkill.h"
#include "rfkill.h"
static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv)
{

Просмотреть файл

@ -16,7 +16,7 @@
#define RTL8187_H
#include "rtl818x.h"
#include "rtl8187_leds.h"
#include "leds.h"
#define RTL8187_EEPROM_TXPWR_BASE 0x05
#define RTL8187_EEPROM_MAC_ADDR 0x07

Просмотреть файл

@ -21,7 +21,7 @@
#include <net/mac80211.h>
#include "rtl8187.h"
#include "rtl8187_rtl8225.h"
#include "rtl8225.h"
static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
{

Просмотреть файл

@ -251,16 +251,14 @@ void rtl_init_rfkill(struct ieee80211_hw *hw)
bool blocked;
u8 valid = 0;
/*set init state to rf on */
rtlpriv->rfkill.rfkill_state = 1;
radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid);
if (valid) {
RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
(KERN_INFO "wireless switch is %s\n",
rtlpriv->rfkill.rfkill_state ? "on" : "off"));
/*set init state to that of switch */
rtlpriv->rfkill.rfkill_state = radio_state;
printk(KERN_INFO "rtlwifi: wireless switch is %s\n",
rtlpriv->rfkill.rfkill_state ? "on" : "off");
if (valid) {
rtlpriv->rfkill.rfkill_state = radio_state;
blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1;

Просмотреть файл

@ -612,10 +612,22 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
num_rx_inperiod++;
}
if (unlikely(!rtl_action_proc(hw, skb, false)))
if (unlikely(!rtl_action_proc(hw, skb,
false))) {
dev_kfree_skb_any(skb);
else
ieee80211_rx_irqsafe(hw, skb);
} else {
struct sk_buff *uskb = NULL;
u8 *pdata;
uskb = dev_alloc_skb(skb->len + 128);
memcpy(IEEE80211_SKB_RXCB(uskb),
&rx_status,
sizeof(rx_status));
pdata = (u8 *)skb_put(uskb, skb->len);
memcpy(pdata, skb->data, skb->len);
dev_kfree_skb_any(skb);
ieee80211_rx_irqsafe(hw, uskb);
}
} else {
dev_kfree_skb_any(skb);
}
@ -1608,7 +1620,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
pcipriv->ndis_adapter.pcibridge_funcnum =
PCI_FUNC(bridge_pdev->devfn);
pcipriv->ndis_adapter.pcibridge_pciehdr_offset =
bridge_pdev->pcie_cap;
pci_pcie_cap(bridge_pdev);
pcipriv->ndis_adapter.pcicfg_addrport =
(pcipriv->ndis_adapter.pcibridge_busnum << 16) |
(pcipriv->ndis_adapter.pcibridge_devnum << 11) |

Просмотреть файл

@ -962,17 +962,6 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
rtl_cam_reset_all_entry(hw);
rtl92ce_enable_hw_security_config(hw);
ppsc->rfpwr_state = ERFON;
tmp_u1b = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG)&(~BIT(3));
rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, tmp_u1b);
tmp_u1b = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL);
ppsc->rfoff_reason |= (tmp_u1b & BIT(3)) ? 0 : RF_CHANGE_BY_HW;
if (ppsc->rfoff_reason > RF_CHANGE_BY_PS)
rtl_ps_set_rf_state(hw, ERFOFF, ppsc->rfoff_reason, true);
else {
ppsc->rfpwr_state = ERFON;
ppsc->rfoff_reason = 0;
rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON);
}
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
_rtl92ce_enable_aspm_back_door(hw);
rtlpriv->intf_ops->enable_aspm(hw);

Просмотреть файл

@ -19,7 +19,6 @@
*
*/
#include <linux/gpio.h>
#include <linux/slab.h>
#include "reg.h"

Просмотреть файл

@ -21,7 +21,6 @@
*
*/
#include <linux/gpio.h>
#include <linux/slab.h>
#include "acx.h"

Просмотреть файл

@ -405,10 +405,10 @@ int ssb_bus_scan(struct ssb_bus *bus,
/* Ignore PCI cores on PCI-E cards.
* Ignore PCI-E cores on PCI cards. */
if (dev->id.coreid == SSB_DEV_PCI) {
if (bus->host_pci->is_pcie)
if (pci_is_pcie(bus->host_pci))
continue;
} else {
if (!bus->host_pci->is_pcie)
if (!pci_is_pcie(bus->host_pci))
continue;
}
}

Просмотреть файл

@ -144,6 +144,7 @@ struct bt_skb_cb {
__u8 tx_seq;
__u8 retries;
__u8 sar;
unsigned short channel;
};
#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))

Просмотреть файл

@ -934,9 +934,13 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
struct sockaddr_hci {
sa_family_t hci_family;
unsigned short hci_dev;
unsigned short hci_channel;
};
#define HCI_DEV_NONE 0xffff
#define HCI_CHANNEL_RAW 0
#define HCI_CHANNEL_CONTROL 1
struct hci_filter {
unsigned long type_mask;
unsigned long event_mask[2];

Просмотреть файл

@ -129,6 +129,7 @@ struct hci_dev {
wait_queue_head_t req_wait_q;
__u32 req_status;
__u32 req_result;
__u16 req_last_cmd;
struct inquiry_cache inq_cache;
struct hci_conn_hash conn_hash;
@ -660,6 +661,11 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
/* ----- HCI Sockets ----- */
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
/* Management interface */
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
int mgmt_index_added(u16 index);
int mgmt_index_removed(u16 index);
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
@ -668,6 +674,7 @@ struct hci_pinfo {
struct hci_dev *hdev;
struct hci_filter filter;
__u32 cmsg_mask;
unsigned short channel;
};
/* HCI security filter */
@ -687,6 +694,6 @@ struct hci_sec_filter {
#define hci_req_lock(d) mutex_lock(&d->req_lock)
#define hci_req_unlock(d) mutex_unlock(&d->req_lock)
void hci_req_complete(struct hci_dev *hdev, int result);
void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result);
#endif /* __HCI_CORE_H */

Просмотреть файл

@ -0,0 +1,87 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2010 Nokia Corporation
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;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
struct mgmt_hdr {
__le16 opcode;
__le16 len;
} __packed;
#define MGMT_HDR_SIZE 4
#define MGMT_OP_READ_VERSION 0x0001
struct mgmt_rp_read_version {
__u8 version;
__le16 revision;
} __packed;
#define MGMT_OP_READ_INDEX_LIST 0x0003
struct mgmt_rp_read_index_list {
__le16 num_controllers;
__le16 index[0];
} __packed;
#define MGMT_OP_READ_INFO 0x0004
struct mgmt_cp_read_info {
__le16 index;
} __packed;
struct mgmt_rp_read_info {
__le16 index;
__u8 type;
__u8 powered;
__u8 discoverable;
__u8 pairable;
__u8 sec_mode;
bdaddr_t bdaddr;
__u8 dev_class[3];
__u8 features[8];
__u16 manufacturer;
__u8 hci_ver;
__u16 hci_rev;
} __packed;
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
__u8 data[0];
} __packed;
#define MGMT_EV_CMD_STATUS 0x0002
struct mgmt_ev_cmd_status {
__u8 status;
__le16 opcode;
} __packed;
#define MGMT_EV_CONTROLLER_ERROR 0x0003
struct mgmt_ev_controller_error {
__le16 index;
__u8 error_code;
} __packed;
#define MGMT_EV_INDEX_ADDED 0x0004
struct mgmt_ev_index_added {
__le16 index;
} __packed;
#define MGMT_EV_INDEX_REMOVED 0x0005
struct mgmt_ev_index_removed {
__le16 index;
} __packed;

Просмотреть файл

@ -365,6 +365,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21),
IEEE80211_TX_CTL_LDPC = BIT(22),
IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24),
IEEE80211_TX_CTL_TX_OFFCHAN = BIT(25),
};
#define IEEE80211_TX_CTL_STBC_SHIFT 23
@ -1824,6 +1825,12 @@ struct ieee80211_ops {
int (*napi_poll)(struct ieee80211_hw *hw, int budget);
int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
int (*remain_on_channel)(struct ieee80211_hw *hw,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
int duration);
int (*cancel_remain_on_channel)(struct ieee80211_hw *hw);
};
/**
@ -2729,6 +2736,18 @@ void ieee80211_request_smps(struct ieee80211_vif *vif,
*/
void ieee80211_key_removed(struct ieee80211_key_conf *key_conf);
/**
* ieee80211_ready_on_channel - notification of remain-on-channel start
* @hw: pointer as obtained from ieee80211_alloc_hw()
*/
void ieee80211_ready_on_channel(struct ieee80211_hw *hw);
/**
* ieee80211_remain_on_channel_expired - remain_on_channel duration expired
* @hw: pointer as obtained from ieee80211_alloc_hw()
*/
void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw);
/* Rate control API */
/**

Просмотреть файл

@ -10,4 +10,4 @@ obj-$(CONFIG_BT_BNEP) += bnep/
obj-$(CONFIG_BT_CMTP) += cmtp/
obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o

Просмотреть файл

@ -91,9 +91,16 @@ static void hci_notify(struct hci_dev *hdev, int event)
/* ---- HCI requests ---- */
void hci_req_complete(struct hci_dev *hdev, int result)
void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result)
{
BT_DBG("%s result 0x%2.2x", hdev->name, result);
BT_DBG("%s command 0x%04x result 0x%2.2x", hdev->name, cmd, result);
/* If the request has set req_last_cmd (typical for multi-HCI
* command requests) check if the completed command matches
* this, and if not just return. Single HCI command requests
* typically leave req_last_cmd as 0 */
if (hdev->req_last_cmd && cmd != hdev->req_last_cmd)
return;
if (hdev->req_status == HCI_REQ_PEND) {
hdev->req_result = result;
@ -149,7 +156,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
break;
}
hdev->req_status = hdev->req_result = 0;
hdev->req_last_cmd = hdev->req_status = hdev->req_result = 0;
BT_DBG("%s end: err %d", hdev->name, err);
@ -252,6 +259,8 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
/* Connection accept timeout ~20 secs */
param = cpu_to_le16(0x7d00);
hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
hdev->req_last_cmd = HCI_OP_WRITE_CA_TIMEOUT;
}
static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
@ -960,6 +969,7 @@ int hci_register_dev(struct hci_dev *hdev)
}
}
mgmt_index_added(hdev->id);
hci_notify(hdev, HCI_DEV_REG);
return id;
@ -989,6 +999,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
for (i = 0; i < NUM_REASSEMBLY; i++)
kfree_skb(hdev->reassembly[i]);
mgmt_index_removed(hdev->id);
hci_notify(hdev, HCI_DEV_UNREG);
if (hdev->rfkill) {

Просмотреть файл

@ -58,7 +58,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_INQUIRY, &hdev->flags);
hci_req_complete(hdev, status);
hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
hci_conn_check_pending(hdev);
}
@ -174,7 +174,7 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *s
if (!status)
hdev->link_policy = get_unaligned_le16(sent);
hci_req_complete(hdev, status);
hci_req_complete(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, status);
}
static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
@ -183,7 +183,7 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%x", hdev->name, status);
hci_req_complete(hdev, status);
hci_req_complete(hdev, HCI_OP_RESET, status);
}
static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@ -235,7 +235,7 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_AUTH, &hdev->flags);
}
hci_req_complete(hdev, status);
hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status);
}
static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
@ -258,7 +258,7 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_ENCRYPT, &hdev->flags);
}
hci_req_complete(hdev, status);
hci_req_complete(hdev, HCI_OP_WRITE_ENCRYPT_MODE, status);
}
static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
@ -285,7 +285,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
set_bit(HCI_PSCAN, &hdev->flags);
}
hci_req_complete(hdev, status);
hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
}
static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
@ -383,7 +383,7 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%x", hdev->name, status);
hci_req_complete(hdev, status);
hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
}
static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
@ -536,7 +536,16 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
if (!rp->status)
bacpy(&hdev->bdaddr, &rp->bdaddr);
hci_req_complete(hdev, rp->status);
hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status);
}
static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
BT_DBG("%s status 0x%x", hdev->name, status);
hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
}
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
@ -544,7 +553,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
BT_DBG("%s status 0x%x", hdev->name, status);
if (status) {
hci_req_complete(hdev, status);
hci_req_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev);
} else
@ -871,7 +880,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
clear_bit(HCI_INQUIRY, &hdev->flags);
hci_req_complete(hdev, status);
hci_req_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev);
}
@ -1379,6 +1388,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_read_bd_addr(hdev, skb);
break;
case HCI_OP_WRITE_CA_TIMEOUT:
hci_cc_write_ca_timeout(hdev, skb);
break;
default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break;

Просмотреть файл

@ -49,6 +49,8 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
static int enable_mgmt;
/* ----- HCI socket interface ----- */
static inline int hci_test_bit(int nr, void *addr)
@ -102,6 +104,12 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
if (skb->sk == sk)
continue;
if (bt_cb(skb)->channel != hci_pi(sk)->channel)
continue;
if (bt_cb(skb)->channel == HCI_CHANNEL_CONTROL)
goto clone;
/* Apply filter */
flt = &hci_pi(sk)->filter;
@ -125,12 +133,14 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
continue;
}
clone:
nskb = skb_clone(skb, GFP_ATOMIC);
if (!nskb)
continue;
/* Put type byte before the data */
memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1);
if (bt_cb(skb)->channel == HCI_CHANNEL_RAW)
memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1);
if (sock_queue_rcv_skb(sk, nskb))
kfree_skb(nskb);
@ -353,25 +363,38 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a
static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
{
struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
struct sockaddr_hci haddr;
struct sock *sk = sock->sk;
struct hci_dev *hdev = NULL;
int err = 0;
int len, err = 0;
BT_DBG("sock %p sk %p", sock, sk);
if (!haddr || haddr->hci_family != AF_BLUETOOTH)
if (!addr)
return -EINVAL;
memset(&haddr, 0, sizeof(haddr));
len = min_t(unsigned int, sizeof(haddr), addr_len);
memcpy(&haddr, addr, len);
if (haddr.hci_family != AF_BLUETOOTH)
return -EINVAL;
if (haddr.hci_channel > HCI_CHANNEL_CONTROL)
return -EINVAL;
if (haddr.hci_channel == HCI_CHANNEL_CONTROL && !enable_mgmt)
return -EINVAL;
lock_sock(sk);
if (hci_pi(sk)->hdev) {
if (sk->sk_state == BT_BOUND || hci_pi(sk)->hdev) {
err = -EALREADY;
goto done;
}
if (haddr->hci_dev != HCI_DEV_NONE) {
hdev = hci_dev_get(haddr->hci_dev);
if (haddr.hci_dev != HCI_DEV_NONE) {
hdev = hci_dev_get(haddr.hci_dev);
if (!hdev) {
err = -ENODEV;
goto done;
@ -380,6 +403,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
atomic_inc(&hdev->promisc);
}
hci_pi(sk)->channel = haddr.hci_channel;
hci_pi(sk)->hdev = hdev;
sk->sk_state = BT_BOUND;
@ -502,6 +526,17 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
lock_sock(sk);
switch (hci_pi(sk)->channel) {
case HCI_CHANNEL_RAW:
break;
case HCI_CHANNEL_CONTROL:
err = mgmt_control(sk, msg, len);
goto done;
default:
err = -EINVAL;
goto done;
}
hdev = hci_pi(sk)->hdev;
if (!hdev) {
err = -EBADFD;
@ -831,3 +866,6 @@ void __exit hci_sock_cleanup(void)
proto_unregister(&hci_sk_proto);
}
module_param(enable_mgmt, bool, 0644);
MODULE_PARM_DESC(enable_mgmt, "Enable Management interface");

Просмотреть файл

@ -3124,8 +3124,14 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if (!sk)
return -ENOENT;
if (sk->sk_state == BT_DISCONN)
if (sk->sk_state != BT_CONFIG) {
struct l2cap_cmd_rej rej;
rej.reason = cpu_to_le16(0x0002);
l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
sizeof(rej), &rej);
goto unlock;
}
/* Reject if config buffer is too small. */
len = cmd_len - sizeof(*req);

308
net/bluetooth/mgmt.c Normal file
Просмотреть файл

@ -0,0 +1,308 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2010 Nokia Corporation
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;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
/* Bluetooth HCI Management interface */
#include <asm/uaccess.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/mgmt.h>
#define MGMT_VERSION 0
#define MGMT_REVISION 1
static int cmd_status(struct sock *sk, u16 cmd, u8 status)
{
struct sk_buff *skb;
struct mgmt_hdr *hdr;
struct mgmt_ev_cmd_status *ev;
BT_DBG("sock %p", sk);
skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
if (!skb)
return -ENOMEM;
hdr = (void *) skb_put(skb, sizeof(*hdr));
hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
hdr->len = cpu_to_le16(sizeof(*ev));
ev = (void *) skb_put(skb, sizeof(*ev));
ev->status = status;
put_unaligned_le16(cmd, &ev->opcode);
if (sock_queue_rcv_skb(sk, skb) < 0)
kfree_skb(skb);
return 0;
}
static int read_version(struct sock *sk)
{
struct sk_buff *skb;
struct mgmt_hdr *hdr;
struct mgmt_ev_cmd_complete *ev;
struct mgmt_rp_read_version *rp;
BT_DBG("sock %p", sk);
skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
if (!skb)
return -ENOMEM;
hdr = (void *) skb_put(skb, sizeof(*hdr));
hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
ev = (void *) skb_put(skb, sizeof(*ev));
put_unaligned_le16(MGMT_OP_READ_VERSION, &ev->opcode);
rp = (void *) skb_put(skb, sizeof(*rp));
rp->version = MGMT_VERSION;
put_unaligned_le16(MGMT_REVISION, &rp->revision);
if (sock_queue_rcv_skb(sk, skb) < 0)
kfree_skb(skb);
return 0;
}
static int read_index_list(struct sock *sk)
{
struct sk_buff *skb;
struct mgmt_hdr *hdr;
struct mgmt_ev_cmd_complete *ev;
struct mgmt_rp_read_index_list *rp;
struct list_head *p;
size_t body_len;
u16 count;
int i;
BT_DBG("sock %p", sk);
read_lock(&hci_dev_list_lock);
count = 0;
list_for_each(p, &hci_dev_list) {
count++;
}
body_len = sizeof(*ev) + sizeof(*rp) + (2 * count);
skb = alloc_skb(sizeof(*hdr) + body_len, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
hdr = (void *) skb_put(skb, sizeof(*hdr));
hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
hdr->len = cpu_to_le16(body_len);
ev = (void *) skb_put(skb, sizeof(*ev));
put_unaligned_le16(MGMT_OP_READ_INDEX_LIST, &ev->opcode);
rp = (void *) skb_put(skb, sizeof(*rp) + (2 * count));
put_unaligned_le16(count, &rp->num_controllers);
i = 0;
list_for_each(p, &hci_dev_list) {
struct hci_dev *d = list_entry(p, struct hci_dev, list);
put_unaligned_le16(d->id, &rp->index[i++]);
BT_DBG("Added hci%u", d->id);
}
read_unlock(&hci_dev_list_lock);
if (sock_queue_rcv_skb(sk, skb) < 0)
kfree_skb(skb);
return 0;
}
static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
{
struct sk_buff *skb;
struct mgmt_hdr *hdr;
struct mgmt_ev_cmd_complete *ev;
struct mgmt_rp_read_info *rp;
struct mgmt_cp_read_info *cp;
struct hci_dev *hdev;
u16 dev_id;
BT_DBG("sock %p", sk);
if (len != 2)
return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
if (!skb)
return -ENOMEM;
hdr = (void *) skb_put(skb, sizeof(*hdr));
hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
ev = (void *) skb_put(skb, sizeof(*ev));
put_unaligned_le16(MGMT_OP_READ_INFO, &ev->opcode);
rp = (void *) skb_put(skb, sizeof(*rp));
cp = (void *) data;
dev_id = get_unaligned_le16(&cp->index);
BT_DBG("request for hci%u", dev_id);
hdev = hci_dev_get(dev_id);
if (!hdev) {
kfree_skb(skb);
return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
}
hci_dev_lock_bh(hdev);
put_unaligned_le16(hdev->id, &rp->index);
rp->type = hdev->dev_type;
rp->powered = test_bit(HCI_UP, &hdev->flags);
rp->discoverable = test_bit(HCI_ISCAN, &hdev->flags);
rp->pairable = test_bit(HCI_PSCAN, &hdev->flags);
if (test_bit(HCI_AUTH, &hdev->flags))
rp->sec_mode = 3;
else if (hdev->ssp_mode > 0)
rp->sec_mode = 4;
else
rp->sec_mode = 2;
bacpy(&rp->bdaddr, &hdev->bdaddr);
memcpy(rp->features, hdev->features, 8);
memcpy(rp->dev_class, hdev->dev_class, 3);
put_unaligned_le16(hdev->manufacturer, &rp->manufacturer);
rp->hci_ver = hdev->hci_ver;
put_unaligned_le16(hdev->hci_rev, &rp->hci_rev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
if (sock_queue_rcv_skb(sk, skb) < 0)
kfree_skb(skb);
return 0;
}
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
{
unsigned char *buf;
struct mgmt_hdr *hdr;
u16 opcode, len;
int err;
BT_DBG("got %zu bytes", msglen);
if (msglen < sizeof(*hdr))
return -EINVAL;
buf = kmalloc(msglen, GFP_ATOMIC);
if (!buf)
return -ENOMEM;
if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
err = -EFAULT;
goto done;
}
hdr = (struct mgmt_hdr *) buf;
opcode = get_unaligned_le16(&hdr->opcode);
len = get_unaligned_le16(&hdr->len);
if (len != msglen - sizeof(*hdr)) {
err = -EINVAL;
goto done;
}
switch (opcode) {
case MGMT_OP_READ_VERSION:
err = read_version(sk);
break;
case MGMT_OP_READ_INDEX_LIST:
err = read_index_list(sk);
break;
case MGMT_OP_READ_INFO:
err = read_controller_info(sk, buf + sizeof(*hdr), len);
break;
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, opcode, 0x01);
break;
}
if (err < 0)
goto done;
err = msglen;
done:
kfree(buf);
return err;
}
static int mgmt_event(u16 event, void *data, u16 data_len)
{
struct sk_buff *skb;
struct mgmt_hdr *hdr;
skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
hdr = (void *) skb_put(skb, sizeof(*hdr));
hdr->opcode = cpu_to_le16(event);
hdr->len = cpu_to_le16(data_len);
memcpy(skb_put(skb, data_len), data, data_len);
hci_send_to_sock(NULL, skb);
kfree_skb(skb);
return 0;
}
int mgmt_index_added(u16 index)
{
struct mgmt_ev_index_added ev;
put_unaligned_le16(index, &ev.index);
return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev));
}
int mgmt_index_removed(u16 index)
{
struct mgmt_ev_index_added ev;
put_unaligned_le16(index, &ev.index);
return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev));
}

Просмотреть файл

@ -1593,6 +1593,37 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
return 0;
}
static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local,
struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type chantype,
unsigned int duration, u64 *cookie)
{
int ret;
u32 random_cookie;
lockdep_assert_held(&local->mtx);
if (local->hw_roc_cookie)
return -EBUSY;
/* must be nonzero */
random_cookie = random32() | 1;
*cookie = random_cookie;
local->hw_roc_dev = dev;
local->hw_roc_cookie = random_cookie;
local->hw_roc_channel = chan;
local->hw_roc_channel_type = chantype;
local->hw_roc_duration = duration;
ret = drv_remain_on_channel(local, chan, chantype, duration);
if (ret) {
local->hw_roc_channel = NULL;
local->hw_roc_cookie = 0;
}
return ret;
}
static int ieee80211_remain_on_channel(struct wiphy *wiphy,
struct net_device *dev,
struct ieee80211_channel *chan,
@ -1601,16 +1632,63 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
u64 *cookie)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
if (local->ops->remain_on_channel) {
int ret;
mutex_lock(&local->mtx);
ret = ieee80211_remain_on_channel_hw(local, dev,
chan, channel_type,
duration, cookie);
local->hw_roc_for_tx = false;
mutex_unlock(&local->mtx);
return ret;
}
return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
duration, cookie);
}
static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local,
u64 cookie)
{
int ret;
lockdep_assert_held(&local->mtx);
if (local->hw_roc_cookie != cookie)
return -ENOENT;
ret = drv_cancel_remain_on_channel(local);
if (ret)
return ret;
local->hw_roc_cookie = 0;
local->hw_roc_channel = NULL;
ieee80211_recalc_idle(local);
return 0;
}
static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
struct net_device *dev,
u64 cookie)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
if (local->ops->cancel_remain_on_channel) {
int ret;
mutex_lock(&local->mtx);
ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
mutex_unlock(&local->mtx);
return ret;
}
return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
}
@ -1662,6 +1740,12 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
channel_type != local->_oper_channel_type))
is_offchan = true;
if (chan == local->hw_roc_channel) {
/* TODO: check channel type? */
is_offchan = false;
flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
}
if (is_offchan && !offchan)
return -EBUSY;
@ -1700,6 +1784,49 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
*cookie = (unsigned long) skb;
if (is_offchan && local->ops->remain_on_channel) {
unsigned int duration;
int ret;
mutex_lock(&local->mtx);
/*
* If the duration is zero, then the driver
* wouldn't actually do anything. Set it to
* 100 for now.
*
* TODO: cancel the off-channel operation
* when we get the SKB's TX status and
* the wait time was zero before.
*/
duration = 100;
if (wait)
duration = wait;
ret = ieee80211_remain_on_channel_hw(local, dev, chan,
channel_type,
duration, cookie);
if (ret) {
kfree_skb(skb);
mutex_unlock(&local->mtx);
return ret;
}
local->hw_roc_for_tx = true;
local->hw_roc_duration = wait;
/*
* queue up frame for transmission after
* ieee80211_ready_on_channel call
*/
/* modify cookie to prevent API mismatches */
*cookie ^= 2;
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
local->hw_roc_skb = skb;
mutex_unlock(&local->mtx);
return 0;
}
/*
* Can transmit right away if the channel was the
* right one and there's no wait involved... If a
@ -1740,6 +1867,21 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
int ret = -ENOENT;
mutex_lock(&local->mtx);
if (local->ops->cancel_remain_on_channel) {
cookie ^= 2;
ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
if (ret == 0) {
kfree_skb(local->hw_roc_skb);
local->hw_roc_skb = NULL;
}
mutex_unlock(&local->mtx);
return ret;
}
list_for_each_entry(wk, &local->work_list, list) {
if (wk->sdata != sdata)
continue;

Просмотреть файл

@ -465,4 +465,34 @@ static inline int drv_get_antenna(struct ieee80211_local *local,
return ret;
}
static inline int drv_remain_on_channel(struct ieee80211_local *local,
struct ieee80211_channel *chan,
enum nl80211_channel_type chantype,
unsigned int duration)
{
int ret;
might_sleep();
trace_drv_remain_on_channel(local, chan, chantype, duration);
ret = local->ops->remain_on_channel(&local->hw, chan, chantype,
duration);
trace_drv_return_int(local, ret);
return ret;
}
static inline int drv_cancel_remain_on_channel(struct ieee80211_local *local)
{
int ret;
might_sleep();
trace_drv_cancel_remain_on_channel(local);
ret = local->ops->cancel_remain_on_channel(&local->hw);
trace_drv_return_int(local, ret);
return ret;
}
#endif /* __MAC80211_DRIVER_OPS */

Просмотреть файл

@ -933,6 +933,50 @@ TRACE_EVENT(drv_get_antenna,
)
);
TRACE_EVENT(drv_remain_on_channel,
TP_PROTO(struct ieee80211_local *local, struct ieee80211_channel *chan,
enum nl80211_channel_type chantype, unsigned int duration),
TP_ARGS(local, chan, chantype, duration),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(int, center_freq)
__field(int, channel_type)
__field(unsigned int, duration)
),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->center_freq = chan->center_freq;
__entry->channel_type = chantype;
__entry->duration = duration;
),
TP_printk(
LOCAL_PR_FMT " freq:%dMHz duration:%dms",
LOCAL_PR_ARG, __entry->center_freq, __entry->duration
)
);
TRACE_EVENT(drv_cancel_remain_on_channel,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local),
TP_STRUCT__entry(
LOCAL_ENTRY
),
TP_fast_assign(
LOCAL_ASSIGN;
),
TP_printk(
LOCAL_PR_FMT, LOCAL_PR_ARG
)
);
/*
* Tracing for API calls that drivers call.
*/
@ -1170,6 +1214,42 @@ TRACE_EVENT(api_chswitch_done,
)
);
TRACE_EVENT(api_ready_on_channel,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local),
TP_STRUCT__entry(
LOCAL_ENTRY
),
TP_fast_assign(
LOCAL_ASSIGN;
),
TP_printk(
LOCAL_PR_FMT, LOCAL_PR_ARG
)
);
TRACE_EVENT(api_remain_on_channel_expired,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local),
TP_STRUCT__entry(
LOCAL_ENTRY
),
TP_fast_assign(
LOCAL_ASSIGN;
),
TP_printk(
LOCAL_PR_FMT, LOCAL_PR_ARG
)
);
/*
* Tracing for internal functions
* (which may also be called in response to driver calls)

Просмотреть файл

@ -168,6 +168,7 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
* @IEEE80211_RX_FRAGMENTED: fragmented frame
* @IEEE80211_RX_AMSDU: a-MSDU packet
* @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed
* @IEEE80211_RX_DEFERRED_RELEASE: frame was subjected to receive reordering
*
* These are per-frame flags that are attached to a frame in the
* @rx_flags field of &struct ieee80211_rx_status.
@ -178,6 +179,7 @@ enum ieee80211_packet_rx_flags {
IEEE80211_RX_FRAGMENTED = BIT(2),
IEEE80211_RX_AMSDU = BIT(3),
IEEE80211_RX_MALFORMED_ACTION_FRM = BIT(4),
IEEE80211_RX_DEFERRED_RELEASE = BIT(5),
};
/**
@ -774,6 +776,15 @@ struct ieee80211_local {
struct sk_buff_head skb_queue;
struct sk_buff_head skb_queue_unreliable;
/*
* Internal FIFO queue which is shared between multiple rx path
* stages. Its main task is to provide a serialization mechanism,
* so all rx handlers can enjoy having exclusive access to their
* private data structures.
*/
struct sk_buff_head rx_skb_queue;
bool running_rx_handler; /* protected by rx_skb_queue.lock */
/* Station data */
/*
* The mutex only protects the list and counter,
@ -940,6 +951,15 @@ struct ieee80211_local {
} debugfs;
#endif
struct ieee80211_channel *hw_roc_channel;
struct net_device *hw_roc_dev;
struct sk_buff *hw_roc_skb;
struct work_struct hw_roc_start, hw_roc_done;
enum nl80211_channel_type hw_roc_channel_type;
unsigned int hw_roc_duration;
u32 hw_roc_cookie;
bool hw_roc_for_tx;
/* dummy netdev for use w/ NAPI */
struct net_device napi_dev;
@ -1131,6 +1151,7 @@ void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local);
void ieee80211_offchannel_stop_station(struct ieee80211_local *local);
void ieee80211_offchannel_return(struct ieee80211_local *local,
bool enable_beaconing);
void ieee80211_hw_roc_setup(struct ieee80211_local *local);
/* interface handling */
int ieee80211_iface_init(void);

Просмотреть файл

@ -1264,7 +1264,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
int count = 0;
bool working = false, scanning = false;
bool working = false, scanning = false, hw_roc = false;
struct ieee80211_work *wk;
unsigned int led_trig_start = 0, led_trig_stop = 0;
@ -1308,6 +1308,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
local->scan_sdata->vif.bss_conf.idle = false;
}
if (local->hw_roc_channel)
hw_roc = true;
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->old_idle == sdata->vif.bss_conf.idle)
continue;
@ -1316,7 +1319,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
}
if (working || scanning)
if (working || scanning || hw_roc)
led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK;
else
led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK;
@ -1328,6 +1331,8 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
if (hw_roc)
return ieee80211_idle_off(local, "hw remain-on-channel");
if (working)
return ieee80211_idle_off(local, "working");
if (scanning)

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше