static int b43_phy_ht_op_switch_channel(struct b43_wldev *dev, unsigned int new_channel) { struct ieee80211_channel *channel = dev->wl->hw->conf.chandef.chan; enum nl80211_channel_type channel_type = cfg80211_get_chandef_type(&dev->wl->hw->conf.chandef); if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) { if ((new_channel < 1) || (new_channel > 14)) return -EINVAL; } else { return -EINVAL; } return b43_phy_ht_set_channel(dev, channel, channel_type); }
static int orinoco_set_monitor_channel(struct wiphy *wiphy, struct cfg80211_chan_def *chandef) { struct orinoco_private *priv = wiphy_priv(wiphy); int err = 0; unsigned long flags; int channel; if (!chandef->chan) return -EINVAL; if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT) return -EINVAL; if (chandef->chan->band != IEEE80211_BAND_2GHZ) return -EINVAL; channel = ieee80211_frequency_to_channel(chandef->chan->center_freq); if ((channel < 1) || (channel > NUM_CHANNELS) || !(priv->channel_mask & (1 << (channel - 1)))) return -EINVAL; if (orinoco_lock(priv, &flags) != 0) return -EBUSY; priv->channel = channel; if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { /* Fast channel change - no commit if successful */ struct hermes *hw = &priv->hw; err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | HERMES_TEST_SET_CHANNEL, channel, NULL); } orinoco_unlock(priv, &flags); return err; }
static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) { struct ath9k_htc_priv *priv = hw->priv; struct ath_common *common = ath9k_hw_common(priv->ah); struct ieee80211_conf *conf = &hw->conf; bool chip_reset = false; int ret = 0; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); if (changed & IEEE80211_CONF_CHANGE_IDLE) { mutex_lock(&priv->htc_pm_lock); priv->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); if (!priv->ps_idle) chip_reset = true; mutex_unlock(&priv->htc_pm_lock); } /* * Monitor interface should be added before * IEEE80211_CONF_CHANGE_CHANNEL is handled. */ if (changed & IEEE80211_CONF_CHANGE_MONITOR) { if ((conf->flags & IEEE80211_CONF_MONITOR) && !priv->ah->is_monitoring) ath9k_htc_add_monitor_interface(priv); else if (priv->ah->is_monitoring) ath9k_htc_remove_monitor_interface(priv); } if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || chip_reset) { struct ieee80211_channel *curchan = hw->conf.chandef.chan; enum nl80211_channel_type channel_type = cfg80211_get_chandef_type(&hw->conf.chandef); int pos = curchan->hw_value; ath_dbg(common, CONFIG, "Set channel: %d MHz\n", curchan->center_freq); ath9k_cmn_update_ichannel(&priv->ah->channels[pos], hw->conf.chandef.chan, channel_type); if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) { ath_err(common, "Unable to set channel\n"); ret = -EINVAL; goto out; } } if (changed & IEEE80211_CONF_CHANGE_PS) { if (conf->flags & IEEE80211_CONF_PS) { ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); priv->ps_enabled = true; } else { priv->ps_enabled = false; cancel_work_sync(&priv->ps_work); ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); } } if (changed & IEEE80211_CONF_CHANGE_POWER) { priv->txpowlimit = 2 * conf->power_level; ath9k_cmn_update_txpow(priv->ah, priv->curtxpow, priv->txpowlimit, &priv->curtxpow); } out: ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); return ret; }
static int rtl_op_config( struct ieee80211_hw *hw, u32 changed ) { struct rtl_priv *rtlpriv = rtl_priv( hw ); struct rtl_phy *rtlphy = &( rtlpriv->phy ); struct rtl_mac *mac = rtl_mac( rtl_priv( hw ) ); struct rtl_ps_ctl *ppsc = rtl_psc( rtl_priv( hw ) ); struct ieee80211_conf *conf = &hw->conf; if ( mac->skip_scan ) return 1; mutex_lock( &rtlpriv->locks.conf_mutex ); if ( changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL ) { /*BIT( 2 )*/ RT_TRACE( rtlpriv, COMP_MAC80211, DBG_LOUD, "IEEE80211_CONF_CHANGE_LISTEN_INTERVAL\n" ); } /*For IPS */ if ( changed & IEEE80211_CONF_CHANGE_IDLE ) { if ( hw->conf.flags & IEEE80211_CONF_IDLE ) rtl_ips_nic_off( hw ); else rtl_ips_nic_on( hw ); } else { /* *although rfoff may not cause by ips, but we will *check the reason in set_rf_power_state function */ if ( unlikely( ppsc->rfpwr_state == ERFOFF ) ) rtl_ips_nic_on( hw ); } /*For LPS */ if ( changed & IEEE80211_CONF_CHANGE_PS ) { cancel_delayed_work( &rtlpriv->works.ps_work ); cancel_delayed_work( &rtlpriv->works.ps_rfon_wq ); if ( conf->flags & IEEE80211_CONF_PS ) { rtlpriv->psc.sw_ps_enabled = true; /* sleep here is must, or we may recv the beacon and * cause mac80211 into wrong ps state, this will cause * power save nullfunc send fail, and further cause * pkt loss, So sleep must quickly but not immediatly * because that will cause nullfunc send by mac80211 * fail, and cause pkt loss, we have tested that 5mA * is worked very well */ if ( !rtlpriv->psc.multi_buffered ) queue_delayed_work( rtlpriv->works.rtl_wq, &rtlpriv->works.ps_work, MSECS( 5 ) ); } else { rtl_swlps_rf_awake( hw ); rtlpriv->psc.sw_ps_enabled = false; } } if ( changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS ) { RT_TRACE( rtlpriv, COMP_MAC80211, DBG_LOUD, "IEEE80211_CONF_CHANGE_RETRY_LIMITS %x\n", hw->conf.long_frame_max_tx_count ); mac->retry_long = hw->conf.long_frame_max_tx_count; mac->retry_short = hw->conf.long_frame_max_tx_count; rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_RETRY_LIMIT, ( u8 * ) ( &hw->conf. long_frame_max_tx_count ) ); } if ( changed & IEEE80211_CONF_CHANGE_CHANNEL ) { struct ieee80211_channel *channel = hw->conf.chandef.chan; u8 wide_chan = ( u8 ) channel->hw_value; if ( mac->act_scanning ) mac->n_channels++; if ( rtlpriv->dm.supp_phymode_switch && mac->link_state < MAC80211_LINKED && !mac->act_scanning ) { if ( rtlpriv->cfg->ops->chk_switch_dmdp ) rtlpriv->cfg->ops->chk_switch_dmdp( hw ); } /* *because we should back channel to *current_network.chan in in scanning, *So if set_chan == current_network.chan *we should set it. *because mac80211 tell us wrong bw40 *info for cisco1253 bw20, so we modify *it here based on UPPER & LOWER */ switch ( cfg80211_get_chandef_type( &hw->conf.chandef ) ) { case NL80211_CHAN_HT20: case NL80211_CHAN_NO_HT: /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_DONT_CARE; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20; mac->bw_40 = false; break; case NL80211_CHAN_HT40MINUS: /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ wide_chan -= 2; break; case NL80211_CHAN_HT40PLUS: /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ wide_chan += 2; break; default: mac->bw_40 = false; RT_TRACE( rtlpriv, COMP_ERR, DBG_EMERG, "switch case not processed\n" ); break; } if ( wide_chan <= 0 ) wide_chan = 1; /* In scanning, before we go offchannel we may send a ps = 1 * null to AP, and then we may send a ps = 0 null to AP quickly, * but first null may have caused AP to put lots of packet to * hw tx buffer. These packets must be tx'd before we go off * channel so we must delay more time to let AP flush these * packets before going offchannel, or dis-association or * delete BA will be caused by AP */ if ( rtlpriv->mac80211.offchan_delay ) { rtlpriv->mac80211.offchan_delay = false; mdelay( 50 ); } rtlphy->current_channel = wide_chan; rtlpriv->cfg->ops->switch_channel( hw ); rtlpriv->cfg->ops->set_channel_access( hw ); rtlpriv->cfg->ops->set_bw_mode( hw, cfg80211_get_chandef_type( &hw->conf.chandef ) ); } mutex_unlock( &rtlpriv->locks.conf_mutex ); return 0; }
/* returns 1 if this was a spectral frame, even if not handled. */ int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, struct ath_rx_status *rs, u64 tsf) { struct ath_hw *ah = sc->sc_ah; u8 num_bins, *bins, *vdata = (u8 *)hdr; struct fft_sample_ht20 fft_sample_20; struct fft_sample_ht20_40 fft_sample_40; struct fft_sample_tlv *tlv; struct ath_radar_info *radar_info; int len = rs->rs_datalen; int dc_pos; u16 fft_len, length, freq = ah->curchan->chan->center_freq; enum nl80211_channel_type chan_type; /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT * yet, but this is supposed to be possible as well. */ if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) return 0; /* check if spectral scan bit is set. This does not have to be checked * if received through a SPECTRAL phy error, but shouldn't hurt. */ radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) return 0; chan_type = cfg80211_get_chandef_type(&sc->hw->conf.chandef); if ((chan_type == NL80211_CHAN_HT40MINUS) || (chan_type == NL80211_CHAN_HT40PLUS)) { fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN; num_bins = SPECTRAL_HT20_40_NUM_BINS; bins = (u8 *)fft_sample_40.data; } else { fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN; num_bins = SPECTRAL_HT20_NUM_BINS; bins = (u8 *)fft_sample_20.data; } /* Variation in the data length is possible and will be fixed later */ if ((len > fft_len + 2) || (len < fft_len - 1)) return 1; switch (len - fft_len) { case 0: /* length correct, nothing to do. */ memcpy(bins, vdata, num_bins); break; case -1: /* first byte missing, duplicate it. */ memcpy(&bins[1], vdata, num_bins - 1); bins[0] = vdata[0]; break; case 2: /* MAC added 2 extra bytes at bin 30 and 32, remove them. */ memcpy(bins, vdata, 30); bins[30] = vdata[31]; memcpy(&bins[31], &vdata[33], num_bins - 31); break; case 1: /* MAC added 2 extra bytes AND first byte is missing. */ bins[0] = vdata[0]; memcpy(&bins[1], vdata, 30); bins[31] = vdata[31]; memcpy(&bins[32], &vdata[33], num_bins - 32); break; default: return 1; } /* DC value (value in the middle) is the blind spot of the spectral * sample and invalid, interpolate it. */ dc_pos = num_bins / 2; bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2; if ((chan_type == NL80211_CHAN_HT40MINUS) || (chan_type == NL80211_CHAN_HT40PLUS)) { s8 lower_rssi, upper_rssi; s16 ext_nf; u8 lower_max_index, upper_max_index; u8 lower_bitmap_w, upper_bitmap_w; u16 lower_mag, upper_mag; struct ath9k_hw_cal_data *caldata = ah->caldata; struct ath_ht20_40_mag_info *mag_info; if (caldata) ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan, caldata->nfCalHist[3].privNF); else ext_nf = ATH_DEFAULT_NOISE_FLOOR; length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv); fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40; fft_sample_40.tlv.length = __cpu_to_be16(length); fft_sample_40.freq = __cpu_to_be16(freq); fft_sample_40.channel_type = chan_type; if (chan_type == NL80211_CHAN_HT40PLUS) { lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]); upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]); fft_sample_40.lower_noise = ah->noise; fft_sample_40.upper_noise = ext_nf; } else { lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]); upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]); fft_sample_40.lower_noise = ext_nf; fft_sample_40.upper_noise = ah->noise; } fft_sample_40.lower_rssi = lower_rssi; fft_sample_40.upper_rssi = upper_rssi; mag_info = ((struct ath_ht20_40_mag_info *)radar_info) - 1; lower_mag = spectral_max_magnitude(mag_info->lower_bins); upper_mag = spectral_max_magnitude(mag_info->upper_bins); fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag); fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag); lower_max_index = spectral_max_index(mag_info->lower_bins); upper_max_index = spectral_max_index(mag_info->upper_bins); fft_sample_40.lower_max_index = lower_max_index; fft_sample_40.upper_max_index = upper_max_index; lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins); upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins); fft_sample_40.lower_bitmap_weight = lower_bitmap_w; fft_sample_40.upper_bitmap_weight = upper_bitmap_w; fft_sample_40.max_exp = mag_info->max_exp & 0xf; fft_sample_40.tsf = __cpu_to_be64(tsf); tlv = (struct fft_sample_tlv *)&fft_sample_40; } else { u8 max_index, bitmap_w; u16 magnitude; struct ath_ht20_mag_info *mag_info; length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv); fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20; fft_sample_20.tlv.length = __cpu_to_be16(length); fft_sample_20.freq = __cpu_to_be16(freq); fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]); fft_sample_20.noise = ah->noise; mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; magnitude = spectral_max_magnitude(mag_info->all_bins); fft_sample_20.max_magnitude = __cpu_to_be16(magnitude); max_index = spectral_max_index(mag_info->all_bins); fft_sample_20.max_index = max_index; bitmap_w = spectral_bitmap_weight(mag_info->all_bins); fft_sample_20.bitmap_weight = bitmap_w; fft_sample_20.max_exp = mag_info->max_exp & 0xf; fft_sample_20.tsf = __cpu_to_be64(tsf); tlv = (struct fft_sample_tlv *)&fft_sample_20; } ath_debug_send_fft_sample(sc, tlv); return 1; }
static int rtl_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); int err = 0; if (mac->vif) { RT_TRACE(COMP_ERR, DBG_WARNING, ("vif has been set!! mac->vif = 0x%p\n", mac->vif)); return -EOPNOTSUPP; } /*This flag is not defined before kernel 3.4*/ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; #endif rtl_ips_nic_on(hw); mutex_lock(&rtlpriv->locks.conf_mutex); /*<delete in kernel start>*/ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) switch (ieee80211_vif_type_p2p(vif)) { case NL80211_IFTYPE_P2P_CLIENT: mac->p2p = P2P_ROLE_CLIENT; /*fall through*/ #else /*<delete in kernel end>*/ switch (vif->type) { /*<delete in kernel start>*/ #endif /*<delete in kernel end>*/ case NL80211_IFTYPE_STATION: if (mac->beacon_enabled == 1) { RT_TRACE(COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_STATION \n")); mac->beacon_enabled = 0; rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]); } break; case NL80211_IFTYPE_ADHOC: RT_TRACE(COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_ADHOC \n")); mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg(hw); if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) mac->basic_rates = 0xfff; else mac->basic_rates = 0xff0; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&mac->basic_rates)); break; /*<delete in kernel start>*/ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) case NL80211_IFTYPE_P2P_GO: mac->p2p = P2P_ROLE_GO; /*fall through*/ #endif /*<delete in kernel end>*/ case NL80211_IFTYPE_AP: RT_TRACE(COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_AP \n")); mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg(hw); if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) mac->basic_rates = 0xfff; else mac->basic_rates = 0xff0; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&mac->basic_rates)); break; case NL80211_IFTYPE_MESH_POINT: RT_TRACE(COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_MESH_POINT \n")); mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg(hw); if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) mac->basic_rates = 0xfff; else mac->basic_rates = 0xff0; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&mac->basic_rates)); break; default: RT_TRACE(COMP_ERR, DBG_EMERG, ("operation mode %d is not support!\n", vif->type)); err = -EOPNOTSUPP; goto out; } #ifdef VIF_TODO if (!rtl_set_vif_info(hw, vif)) goto out; #endif if (mac->p2p) { RT_TRACE(COMP_MAC80211, DBG_LOUD, ("p2p role %x \n",vif->type)); mac->basic_rates = 0xff0;/*disable cck rate for p2p*/ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&mac->basic_rates)); } mac->vif = vif; mac->opmode = vif->type; rtlpriv->cfg->ops->set_network_type(hw, vif->type); memcpy(mac->mac_addr, vif->addr, ETH_ALEN); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); out: mutex_unlock(&rtlpriv->locks.conf_mutex); return err; } static void rtl_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); mutex_lock(&rtlpriv->locks.conf_mutex); /* Free beacon resources */ if ((vif->type == NL80211_IFTYPE_AP) || (vif->type == NL80211_IFTYPE_ADHOC) || (vif->type == NL80211_IFTYPE_MESH_POINT)) { if (mac->beacon_enabled == 1) { mac->beacon_enabled = 0; rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]); } } /* *Note: We assume NL80211_IFTYPE_UNSPECIFIED as *NO LINK for our hardware. */ mac->p2p = 0; mac->vif = NULL; mac->link_state = MAC80211_NOLINK; memset(mac->bssid, 0, 6); mac->vendor = PEER_UNKNOWN; mac->opmode = NL80211_IFTYPE_UNSPECIFIED; rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); mutex_unlock(&rtlpriv->locks.conf_mutex); } /*<delete in kernel start>*/ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) /*<delete in kernel end>*/ static int rtl_op_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum nl80211_iftype new_type, bool p2p) { struct rtl_priv *rtlpriv = rtl_priv(hw); int ret; rtl_op_remove_interface(hw, vif); vif->type = new_type; vif->p2p = p2p; ret = rtl_op_add_interface(hw, vif); RT_TRACE(COMP_MAC80211, DBG_LOUD, (" p2p %x\n",p2p)); return ret; } /*<delete in kernel start>*/ #endif /*<delete in kernel end>*/ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct ieee80211_conf *conf = &hw->conf; if (mac->skip_scan) return 1; mutex_lock(&rtlpriv->locks.conf_mutex); if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /* BIT(2) */ RT_TRACE(COMP_MAC80211, DBG_LOUD, ("IEEE80211_CONF_CHANGE_LISTEN_INTERVAL\n")); } /*For IPS */ if (changed & IEEE80211_CONF_CHANGE_IDLE) { if (hw->conf.flags & IEEE80211_CONF_IDLE) rtl_ips_nic_off(hw); else rtl_ips_nic_on(hw); } else { /* *although rfoff may not cause by ips, but we will *check the reason in set_rf_power_state function */ if (unlikely(ppsc->rfpwr_state == ERFOFF)) rtl_ips_nic_on(hw); } /*For LPS */ if (changed & IEEE80211_CONF_CHANGE_PS) { cancel_delayed_work(&rtlpriv->works.ps_work); cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); if (conf->flags & IEEE80211_CONF_PS) { rtlpriv->psc.sw_ps_enabled = true; /* sleep here is must, or we may recv the beacon and * cause mac80211 into wrong ps state, this will cause * power save nullfunc send fail, and further cause * pkt loss, So sleep must quickly but not immediatly * because that will cause nullfunc send by mac80211 * fail, and cause pkt loss, we have tested that 5mA * is worked very well */ if (!rtlpriv->psc.multi_buffered) queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_work, MSECS(5)); } else { rtl_swlps_rf_awake(hw); rtlpriv->psc.sw_ps_enabled = false; } } if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { RT_TRACE(COMP_MAC80211, DBG_LOUD, ("IEEE80211_CONF_CHANGE_RETRY_LIMITS %x\n", hw->conf.long_frame_max_tx_count)); mac->retry_long = hw->conf.long_frame_max_tx_count; mac->retry_short = hw->conf.long_frame_max_tx_count; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, (u8 *) (&hw->conf.long_frame_max_tx_count)); } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) struct ieee80211_channel *channel = hw->conf.chandef.chan; enum nl80211_channel_type channel_type = cfg80211_get_chandef_type(&(hw->conf.chandef)); #else struct ieee80211_channel *channel = hw->conf.channel; enum nl80211_channel_type channel_type = hw->conf.channel_type; #endif u8 wide_chan = (u8) channel->hw_value; if (mac->act_scanning) mac->n_channels++; if (rtlpriv->dm.supp_phymode_switch && mac->link_state < MAC80211_LINKED && !mac->act_scanning) { if (rtlpriv->cfg->ops->check_switch_to_dmdp) rtlpriv->cfg->ops->check_switch_to_dmdp(hw); } /* *because we should back channel to *current_network.chan in in scanning, *So if set_chan == current_network.chan *we should set it. *because mac80211 tell us wrong bw40 *info for cisco1253 bw20, so we modify *it here based on UPPER & LOWER */ switch (channel_type) { case NL80211_CHAN_HT20: case NL80211_CHAN_NO_HT: /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_DONT_CARE; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20; mac->bw_40 = false; break; case NL80211_CHAN_HT40MINUS: /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ wide_chan -= 2; break; case NL80211_CHAN_HT40PLUS: /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ wide_chan += 2; break; default: mac->bw_40 = false; RT_TRACE(COMP_ERR, DBG_EMERG, ("switch case not processed \n")); break; } if (wide_chan <= 0) wide_chan = 1; /* in scanning, when before we offchannel we may send a ps=1 * null to AP, and then we may send a ps = 0 null to AP quickly, * but first null have cause AP's put lots of packet to hw tx * buffer, these packet must be tx before off channel so we must * delay more time to let AP flush these packets before * offchannel, or dis-association or delete BA will happen by AP */ if (rtlpriv->mac80211.offchan_deley) { rtlpriv->mac80211.offchan_deley = false; mdelay(50); } rtlphy->current_channel = wide_chan; rtlpriv->cfg->ops->switch_channel(hw); rtlpriv->cfg->ops->set_channel_access(hw); rtlpriv->cfg->ops->set_bw_mode(hw, channel_type); } mutex_unlock(&rtlpriv->locks.conf_mutex); return 0; } static void rtl_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, u64 multicast) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); *new_flags &= RTL_SUPPORTED_FILTERS; if (0 == changed_flags) return; /*TODO: we disable broadcase now, so enable here */ if (changed_flags & FIF_ALLMULTI) { if (*new_flags & FIF_ALLMULTI) { mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] | rtlpriv->cfg->maps[MAC_RCR_AB]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Enable receive multicast frame.\n")); } else { mac->rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] | rtlpriv->cfg->maps[MAC_RCR_AB]); RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Disable receive multicast frame.\n")); } } if (changed_flags & FIF_FCSFAIL) { if (*new_flags & FIF_FCSFAIL) { mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Enable receive FCS error frame.\n")); } else { mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Disable receive FCS error frame.\n")); } } /* if ssid not set to hw don't check bssid * here just used for linked scanning, & linked * and nolink check bssid is set in set network_type */ if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) && (mac->link_state >= MAC80211_LINKED)) { if (mac->opmode != NL80211_IFTYPE_AP && mac->opmode != NL80211_IFTYPE_MESH_POINT) { if (*new_flags & FIF_BCN_PRBRESP_PROMISC) { rtlpriv->cfg->ops->set_chk_bssid(hw, false); } else { rtlpriv->cfg->ops->set_chk_bssid(hw, true); } } } if (changed_flags & FIF_CONTROL) { if (*new_flags & FIF_CONTROL) { mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Enable receive control frame.\n")); } else { mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Disable receive control frame.\n")); } } if (changed_flags & FIF_OTHER_BSS) { if (*new_flags & FIF_OTHER_BSS) { mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Enable receive other BSS's frame.\n")); } else { mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP]; RT_TRACE(COMP_MAC80211, DBG_LOUD, ("Disable receive other BSS's frame.\n")); } } } static int rtl_op_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal= rtl_hal(rtl_priv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_sta_info *sta_entry; if (sta) { sta_entry = (struct rtl_sta_info *) sta->drv_priv; spin_lock_bh(&rtlpriv->locks.entry_list_lock); list_add_tail(&sta_entry->list, &rtlpriv->entry_list); spin_unlock_bh(&rtlpriv->locks.entry_list_lock); if (rtlhal->current_bandtype == BAND_ON_2_4G) { sta_entry->wireless_mode = WIRELESS_MODE_G; if (sta->supp_rates[0] <= 0xf) sta_entry->wireless_mode = WIRELESS_MODE_B; if (sta->ht_cap.ht_supported == true) sta_entry->wireless_mode = WIRELESS_MODE_N_24G; if (vif->type == NL80211_IFTYPE_ADHOC) sta_entry->wireless_mode = WIRELESS_MODE_G; } else if (rtlhal->current_bandtype == BAND_ON_5G) { sta_entry->wireless_mode = WIRELESS_MODE_A; if (sta->ht_cap.ht_supported == true) sta_entry->wireless_mode = WIRELESS_MODE_N_24G; if (vif->type == NL80211_IFTYPE_ADHOC) sta_entry->wireless_mode = WIRELESS_MODE_A; } /*disable cck rate for p2p*/ if (mac->p2p) sta->supp_rates[0] &= 0xfffffff0; memcpy(sta_entry->mac_addr, sta->addr, ETH_ALEN); RT_TRACE(COMP_MAC80211, DBG_DMESG, ("Add sta addr is %pM\n",sta->addr)); rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); } return 0; } static int rtl_op_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_sta_info *sta_entry; if (sta) { RT_TRACE(COMP_MAC80211, DBG_DMESG, ("Remove sta addr is %pM\n",sta->addr)); sta_entry = (struct rtl_sta_info *) sta->drv_priv; sta_entry->wireless_mode = 0; sta_entry->ratr_index = 0; spin_lock_bh(&rtlpriv->locks.entry_list_lock); list_del(&sta_entry->list); spin_unlock_bh(&rtlpriv->locks.entry_list_lock); } return 0; } static int _rtl_get_hal_qnum(u16 queue) { int qnum; switch (queue) { case 0: qnum = AC3_VO; break; case 1: qnum = AC2_VI; break; case 2: qnum = AC0_BE; break; case 3: qnum = AC1_BK; break; default: qnum = AC0_BE; break; } return qnum; }