2010-12-08 11:12:31 -06:00
/******************************************************************************
*
* Copyright ( c ) 2009 - 2010 Realtek Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 , USA
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE .
*
* Contact Information :
* wlanfae < wlanfae @ realtek . com >
* Realtek Corporation , No . 2 , Innovation Road II , Hsinchu Science Park ,
* Hsinchu 300 , Taiwan .
*
* Larry Finger < Larry . Finger @ lwfinger . net >
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "wifi.h"
# include "core.h"
# include "cam.h"
# include "base.h"
# include "ps.h"
/*mutex for start & stop is must here. */
static int rtl_op_start ( struct ieee80211_hw * hw )
{
int err = 0 ;
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_hal * rtlhal = rtl_hal ( rtl_priv ( hw ) ) ;
if ( ! is_hal_stop ( rtlhal ) )
return 0 ;
if ( ! test_bit ( RTL_STATUS_INTERFACE_START , & rtlpriv - > status ) )
return 0 ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
err = rtlpriv - > intf_ops - > adapter_start ( hw ) ;
if ( err )
goto out ;
rtl_watch_dog_timer_callback ( ( unsigned long ) hw ) ;
out :
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
return err ;
}
static void rtl_op_stop ( struct ieee80211_hw * hw )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
struct rtl_hal * rtlhal = rtl_hal ( rtl_priv ( hw ) ) ;
struct rtl_ps_ctl * ppsc = rtl_psc ( rtl_priv ( hw ) ) ;
if ( is_hal_stop ( rtlhal ) )
return ;
if ( unlikely ( ppsc - > rfpwr_state = = ERFOFF ) ) {
rtl_ips_nic_on ( hw ) ;
mdelay ( 1 ) ;
}
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
mac - > link_state = MAC80211_NOLINK ;
memset ( mac - > bssid , 0 , 6 ) ;
/*reset sec info */
rtl_cam_reset_sec_info ( hw ) ;
rtl_deinit_deferred_work ( hw ) ;
rtlpriv - > intf_ops - > adapter_stop ( hw ) ;
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
}
static int rtl_op_tx ( struct ieee80211_hw * hw , struct sk_buff * skb )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_hal * rtlhal = rtl_hal ( rtl_priv ( hw ) ) ;
struct rtl_ps_ctl * ppsc = rtl_psc ( rtl_priv ( hw ) ) ;
if ( unlikely ( is_hal_stop ( rtlhal ) | | ppsc - > rfpwr_state ! = ERFON ) )
goto err_free ;
if ( ! test_bit ( RTL_STATUS_INTERFACE_START , & rtlpriv - > status ) )
goto err_free ;
rtlpriv - > intf_ops - > adapter_tx ( hw , skb ) ;
return NETDEV_TX_OK ;
err_free :
dev_kfree_skb_any ( skb ) ;
return NETDEV_TX_OK ;
}
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 ( rtlpriv , COMP_ERR , DBG_WARNING ,
( " vif has been set!! mac->vif = 0x%p \n " , mac - > vif ) ) ;
return - EOPNOTSUPP ;
}
rtl_ips_nic_on ( hw ) ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
switch ( vif - > type ) {
case NL80211_IFTYPE_STATION :
if ( mac - > beacon_enabled = = 1 ) {
RT_TRACE ( rtlpriv , 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 ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
( " NL80211_IFTYPE_ADHOC \n " ) ) ;
mac - > link_state = MAC80211_LINKED ;
rtlpriv - > cfg - > ops - > set_bcn_reg ( hw ) ;
break ;
case NL80211_IFTYPE_AP :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
( " NL80211_IFTYPE_AP \n " ) ) ;
break ;
default :
RT_TRACE ( rtlpriv , COMP_ERR , DBG_EMERG ,
( " operation mode %d is not support! \n " , vif - > type ) ) ;
err = - EOPNOTSUPP ;
goto out ;
}
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 :
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
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 ) ) ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
/* Free beacon resources */
if ( ( mac - > opmode = = NL80211_IFTYPE_AP ) | |
( mac - > opmode = = NL80211_IFTYPE_ADHOC ) | |
( mac - > opmode = = 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 - > vif = NULL ;
mac - > link_state = MAC80211_NOLINK ;
memset ( mac - > bssid , 0 , 6 ) ;
mac - > opmode = NL80211_IFTYPE_UNSPECIFIED ;
rtlpriv - > cfg - > ops - > set_network_type ( hw , mac - > opmode ) ;
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
}
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 ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
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 ) {
if ( conf - > flags & IEEE80211_CONF_PS )
rtl_lps_enter ( hw ) ;
else
rtl_lps_leave ( hw ) ;
}
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 . channel ;
u8 wide_chan = ( u8 ) channel - > hw_value ;
/*
* 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 ( hw - > conf . 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 ( rtlpriv , COMP_ERR , DBG_EMERG ,
( " switch case not processed \n " ) ) ;
break ;
}
if ( wide_chan < = 0 )
wide_chan = 1 ;
rtlphy - > current_channel = wide_chan ;
rtlpriv - > cfg - > ops - > set_channel_access ( hw ) ;
rtlpriv - > cfg - > ops - > switch_channel ( hw ) ;
rtlpriv - > cfg - > ops - > set_bw_mode ( hw ,
hw - > conf . channel_type ) ;
}
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
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 ( ! 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 ( rtlpriv , 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 ( rtlpriv , 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 ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
( " Enable receive FCS error frame. \n " ) ) ;
} else {
mac - > rx_conf & = ~ rtlpriv - > cfg - > maps [ MAC_RCR_ACRC32 ] ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
( " Disable receive FCS error frame. \n " ) ) ;
}
}
if ( changed_flags & FIF_BCN_PRBRESP_PROMISC ) {
/*
* TODO : BIT ( 5 ) is probe response BIT ( 8 ) is beacon
* TODO : Use define for BIT ( 5 ) and BIT ( 8 )
*/
if ( * new_flags & FIF_BCN_PRBRESP_PROMISC )
mac - > rx_mgt_filter | = ( BIT ( 5 ) | BIT ( 8 ) ) ;
else
mac - > rx_mgt_filter & = ~ ( BIT ( 5 ) | BIT ( 8 ) ) ;
}
if ( changed_flags & FIF_CONTROL ) {
if ( * new_flags & FIF_CONTROL ) {
mac - > rx_conf | = rtlpriv - > cfg - > maps [ MAC_RCR_ACF ] ;
mac - > rx_ctrl_filter | = RTL_SUPPORTED_CTRL_FILTER ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
( " Enable receive control frame. \n " ) ) ;
} else {
mac - > rx_conf & = ~ rtlpriv - > cfg - > maps [ MAC_RCR_ACF ] ;
mac - > rx_ctrl_filter & = ~ RTL_SUPPORTED_CTRL_FILTER ;
RT_TRACE ( rtlpriv , 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 ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
( " Enable receive other BSS's frame. \n " ) ) ;
} else {
mac - > rx_conf & = ~ rtlpriv - > cfg - > maps [ MAC_RCR_AAP ] ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
( " Disable receive other BSS's frame. \n " ) ) ;
}
}
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_RCR , ( u8 * ) ( & mac - > rx_conf ) ) ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_MGT_FILTER ,
( u8 * ) ( & mac - > rx_mgt_filter ) ) ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_CTRL_FILTER ,
( u8 * ) ( & mac - > rx_ctrl_filter ) ) ;
}
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 ;
}
/*
* for mac80211 VO = 0 , VI = 1 , BE = 2 , BK = 3
* for rtl819x BE = 0 , BK = 1 , VI = 2 , VO = 3
*/
static int rtl_op_conf_tx ( struct ieee80211_hw * hw , u16 queue ,
const struct ieee80211_tx_queue_params * param )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
int aci ;
if ( queue > = AC_MAX ) {
RT_TRACE ( rtlpriv , COMP_ERR , DBG_WARNING ,
( " queue number %d is incorrect! \n " , queue ) ) ;
return - EINVAL ;
}
aci = _rtl_get_hal_qnum ( queue ) ;
mac - > ac [ aci ] . aifs = param - > aifs ;
mac - > ac [ aci ] . cw_min = param - > cw_min ;
mac - > ac [ aci ] . cw_max = param - > cw_max ;
mac - > ac [ aci ] . tx_op = param - > txop ;
memcpy ( & mac - > edca_param [ aci ] , param , sizeof ( * param ) ) ;
rtlpriv - > cfg - > ops - > set_qos ( hw , aci ) ;
return 0 ;
}
static void rtl_op_bss_info_changed ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
struct ieee80211_bss_conf * bss_conf , u32 changed )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
struct rtl_ps_ctl * ppsc = rtl_psc ( rtl_priv ( hw ) ) ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
if ( ( vif - > type = = NL80211_IFTYPE_ADHOC ) | |
( vif - > type = = NL80211_IFTYPE_AP ) | |
( vif - > type = = NL80211_IFTYPE_MESH_POINT ) ) {
if ( ( changed & BSS_CHANGED_BEACON ) | |
( changed & BSS_CHANGED_BEACON_ENABLED & &
bss_conf - > enable_beacon ) ) {
if ( mac - > beacon_enabled = = 0 ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_DMESG ,
( " BSS_CHANGED_BEACON_ENABLED \n " ) ) ;
/*start hw beacon interrupt. */
/*rtlpriv->cfg->ops->set_bcn_reg(hw); */
mac - > beacon_enabled = 1 ;
rtlpriv - > cfg - > ops - > update_interrupt_mask ( hw ,
rtlpriv - > cfg - > maps
[ RTL_IBSS_INT_MASKS ] ,
0 ) ;
}
} else {
if ( mac - > beacon_enabled = = 1 ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_DMESG ,
( " ADHOC DISABLE BEACON \n " ) ) ;
mac - > beacon_enabled = 0 ;
rtlpriv - > cfg - > ops - > update_interrupt_mask ( hw , 0 ,
rtlpriv - > cfg - > maps
[ RTL_IBSS_INT_MASKS ] ) ;
}
}
if ( changed & BSS_CHANGED_BEACON_INT ) {
RT_TRACE ( rtlpriv , COMP_BEACON , DBG_TRACE ,
( " BSS_CHANGED_BEACON_INT \n " ) ) ;
mac - > beacon_interval = bss_conf - > beacon_int ;
rtlpriv - > cfg - > ops - > set_bcn_intv ( hw ) ;
}
}
/*TODO: reference to enum ieee80211_bss_change */
if ( changed & BSS_CHANGED_ASSOC ) {
if ( bss_conf - > assoc ) {
mac - > link_state = MAC80211_LINKED ;
mac - > cnt_after_linked = 0 ;
mac - > assoc_id = bss_conf - > aid ;
memcpy ( mac - > bssid , bss_conf - > bssid , 6 ) ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_DMESG ,
( " BSS_CHANGED_ASSOC \n " ) ) ;
} else {
if ( mac - > link_state = = MAC80211_LINKED )
rtl_lps_leave ( hw ) ;
mac - > link_state = MAC80211_NOLINK ;
memset ( mac - > bssid , 0 , 6 ) ;
/* reset sec info */
rtl_cam_reset_sec_info ( hw ) ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_DMESG ,
( " BSS_CHANGED_UN_ASSOC \n " ) ) ;
}
}
if ( changed & BSS_CHANGED_ERP_CTS_PROT ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
( " BSS_CHANGED_ERP_CTS_PROT \n " ) ) ;
mac - > use_cts_protect = bss_conf - > use_cts_prot ;
}
if ( changed & BSS_CHANGED_ERP_PREAMBLE ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
( " BSS_CHANGED_ERP_PREAMBLE use short preamble:%x \n " ,
bss_conf - > use_short_preamble ) ) ;
mac - > short_preamble = bss_conf - > use_short_preamble ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_ACK_PREAMBLE ,
( u8 * ) ( & mac - > short_preamble ) ) ;
}
if ( changed & BSS_CHANGED_ERP_SLOT ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
( " BSS_CHANGED_ERP_SLOT \n " ) ) ;
if ( bss_conf - > use_short_slot )
mac - > slot_time = RTL_SLOT_TIME_9 ;
else
mac - > slot_time = RTL_SLOT_TIME_20 ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_SLOT_TIME ,
( u8 * ) ( & mac - > slot_time ) ) ;
}
if ( changed & BSS_CHANGED_HT ) {
struct ieee80211_sta * sta = NULL ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
( " BSS_CHANGED_HT \n " ) ) ;
sta = ieee80211_find_sta ( mac - > vif , mac - > bssid ) ;
if ( sta ) {
if ( sta - > ht_cap . ampdu_density >
mac - > current_ampdu_density )
mac - > current_ampdu_density =
sta - > ht_cap . ampdu_density ;
if ( sta - > ht_cap . ampdu_factor <
mac - > current_ampdu_factor )
mac - > current_ampdu_factor =
sta - > ht_cap . ampdu_factor ;
}
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_SHORTGI_DENSITY ,
( u8 * ) ( & mac - > max_mss_density ) ) ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_AMPDU_FACTOR ,
& mac - > current_ampdu_factor ) ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_AMPDU_MIN_SPACE ,
& mac - > current_ampdu_density ) ;
}
if ( changed & BSS_CHANGED_BSSID ) {
struct ieee80211_sta * sta = NULL ;
u32 basic_rates ;
u8 i ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_BSSID ,
( u8 * ) bss_conf - > bssid ) ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_DMESG ,
( MAC_FMT " \n " , MAC_ARG ( bss_conf - > bssid ) ) ) ;
memcpy ( mac - > bssid , bss_conf - > bssid , 6 ) ;
if ( is_valid_ether_addr ( bss_conf - > bssid ) ) {
switch ( vif - > type ) {
case NL80211_IFTYPE_UNSPECIFIED :
break ;
case NL80211_IFTYPE_ADHOC :
break ;
case NL80211_IFTYPE_STATION :
break ;
case NL80211_IFTYPE_AP :
break ;
default :
RT_TRACE ( rtlpriv , COMP_ERR , DBG_EMERG ,
( " switch case not process \n " ) ) ;
break ;
}
rtlpriv - > cfg - > ops - > set_network_type ( hw , vif - > type ) ;
} else
rtlpriv - > cfg - > ops - > set_network_type ( hw ,
NL80211_IFTYPE_UNSPECIFIED ) ;
memset ( mac - > mcs , 0 , 16 ) ;
mac - > ht_enable = false ;
mac - > sgi_40 = false ;
mac - > sgi_20 = false ;
if ( ! bss_conf - > use_short_slot )
mac - > mode = WIRELESS_MODE_B ;
else
mac - > mode = WIRELESS_MODE_G ;
sta = ieee80211_find_sta ( mac - > vif , mac - > bssid ) ;
if ( sta ) {
if ( sta - > ht_cap . ht_supported ) {
mac - > mode = WIRELESS_MODE_N_24G ;
mac - > ht_enable = true ;
}
if ( mac - > ht_enable ) {
u16 ht_cap = sta - > ht_cap . cap ;
memcpy ( mac - > mcs , ( u8 * ) ( & sta - > ht_cap . mcs ) , 16 ) ;
for ( i = 0 ; i < 16 ; i + + )
RT_TRACE ( rtlpriv , COMP_MAC80211 ,
DBG_LOUD , ( " %x " ,
mac - > mcs [ i ] ) ) ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
( " \n " ) ) ;
if ( ht_cap & IEEE80211_HT_CAP_SGI_40 )
mac - > sgi_40 = true ;
if ( ht_cap & IEEE80211_HT_CAP_SGI_20 )
mac - > sgi_20 = true ;
/*
* for cisco 1252 bw20 it ' s wrong
* if ( ht_cap &
* IEEE80211_HT_CAP_SUP_WIDTH_20_40 ) {
* mac - > bw_40 = true ;
* }
*/
}
}
/*mac80211 just give us CCK rates any time
* So we add G rate in basic rates when
not in B mode */
if ( changed & BSS_CHANGED_BASIC_RATES ) {
if ( mac - > mode = = WIRELESS_MODE_B )
basic_rates = bss_conf - > basic_rates | 0x00f ;
else
basic_rates = bss_conf - > basic_rates | 0xff0 ;
if ( ! vif )
goto out ;
mac - > basic_rates = basic_rates ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_BASIC_RATE ,
( u8 * ) ( & basic_rates ) ) ;
if ( rtlpriv - > dm . b_useramask )
rtlpriv - > cfg - > ops - > update_rate_mask ( hw , 0 ) ;
else
rtlpriv - > cfg - > ops - > update_rate_table ( hw ) ;
}
}
/*
* For FW LPS :
* To tell firmware we have connected
* to an AP . For 92 SE / CE power save v2 .
*/
if ( changed & BSS_CHANGED_ASSOC ) {
if ( bss_conf - > assoc ) {
if ( ppsc - > b_fwctrl_lps ) {
u8 mstatus = RT_MEDIA_CONNECT ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw ,
HW_VAR_H2C_FW_JOINBSSRPT ,
( u8 * ) ( & mstatus ) ) ;
ppsc - > report_linked = true ;
}
} else {
if ( ppsc - > b_fwctrl_lps ) {
u8 mstatus = RT_MEDIA_DISCONNECT ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw ,
HW_VAR_H2C_FW_JOINBSSRPT ,
( u8 * ) ( & mstatus ) ) ;
ppsc - > report_linked = false ;
}
}
}
out :
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
}
static u64 rtl_op_get_tsf ( struct ieee80211_hw * hw )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
u64 tsf ;
rtlpriv - > cfg - > ops - > get_hw_reg ( hw , HW_VAR_CORRECT_TSF , ( u8 * ) ( & tsf ) ) ;
return tsf ;
}
static void rtl_op_set_tsf ( struct ieee80211_hw * hw , u64 tsf )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
u8 bibss = ( mac - > opmode = = NL80211_IFTYPE_ADHOC ) ? 1 : 0 ; ;
mac - > tsf = tsf ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_CORRECT_TSF , ( u8 * ) ( & bibss ) ) ;
}
static void rtl_op_reset_tsf ( struct ieee80211_hw * hw )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
u8 tmp = 0 ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_DUAL_TSF_RST , ( u8 * ) ( & tmp ) ) ;
}
static void rtl_op_sta_notify ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
enum sta_notify_cmd cmd ,
struct ieee80211_sta * sta )
{
switch ( cmd ) {
case STA_NOTIFY_SLEEP :
break ;
case STA_NOTIFY_AWAKE :
break ;
default :
break ;
}
}
static int rtl_op_ampdu_action ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
enum ieee80211_ampdu_mlme_action action ,
2011-01-18 13:51:05 +01:00
struct ieee80211_sta * sta , u16 tid , u16 * ssn ,
u8 buf_size )
2010-12-08 11:12:31 -06:00
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
switch ( action ) {
case IEEE80211_AMPDU_TX_START :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
( " IEEE80211_AMPDU_TX_START: TID:%d \n " , tid ) ) ;
return rtl_tx_agg_start ( hw , sta - > addr , tid , ssn ) ;
break ;
case IEEE80211_AMPDU_TX_STOP :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
( " IEEE80211_AMPDU_TX_STOP: TID:%d \n " , tid ) ) ;
return rtl_tx_agg_stop ( hw , sta - > addr , tid ) ;
break ;
case IEEE80211_AMPDU_TX_OPERATIONAL :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
( " IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d \n " , tid ) ) ;
break ;
case IEEE80211_AMPDU_RX_START :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
( " IEEE80211_AMPDU_RX_START:TID:%d \n " , tid ) ) ;
break ;
case IEEE80211_AMPDU_RX_STOP :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
( " IEEE80211_AMPDU_RX_STOP:TID:%d \n " , tid ) ) ;
break ;
default :
RT_TRACE ( rtlpriv , COMP_ERR , DBG_EMERG ,
( " IEEE80211_AMPDU_ERR!!!!: \n " ) ) ;
return - EOPNOTSUPP ;
}
return 0 ;
}
static void rtl_op_sw_scan_start ( struct ieee80211_hw * hw )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
mac - > act_scanning = true ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD , ( " \n " ) ) ;
if ( mac - > link_state = = MAC80211_LINKED ) {
rtl_lps_leave ( hw ) ;
mac - > link_state = MAC80211_LINKED_SCANNING ;
} else
rtl_ips_nic_on ( hw ) ;
rtlpriv - > cfg - > ops - > led_control ( hw , LED_CTL_SITE_SURVEY ) ;
rtlpriv - > cfg - > ops - > scan_operation_backup ( hw , SCAN_OPT_BACKUP ) ;
}
static void rtl_op_sw_scan_complete ( struct ieee80211_hw * hw )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD , ( " \n " ) ) ;
rtlpriv - > cfg - > ops - > scan_operation_backup ( hw , SCAN_OPT_RESTORE ) ;
mac - > act_scanning = false ;
if ( mac - > link_state = = MAC80211_LINKED_SCANNING ) {
mac - > link_state = MAC80211_LINKED ;
/* fix fwlps issue */
rtlpriv - > cfg - > ops - > set_network_type ( hw , mac - > opmode ) ;
if ( rtlpriv - > dm . b_useramask )
rtlpriv - > cfg - > ops - > update_rate_mask ( hw , 0 ) ;
else
rtlpriv - > cfg - > ops - > update_rate_table ( hw ) ;
}
}
static int rtl_op_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 rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
u8 key_type = NO_ENCRYPTION ;
u8 key_idx ;
bool group_key = false ;
bool wep_only = false ;
int err = 0 ;
u8 mac_addr [ ETH_ALEN ] ;
u8 bcast_addr [ ETH_ALEN ] = { 0xff , 0xff , 0xff , 0xff , 0xff , 0xff } ;
u8 zero_addr [ ETH_ALEN ] = { 0 } ;
if ( rtlpriv - > cfg - > mod_params - > sw_crypto | | rtlpriv - > sec . use_sw_sec ) {
RT_TRACE ( rtlpriv , COMP_ERR , DBG_WARNING ,
( " not open hw encryption \n " ) ) ;
return - ENOSPC ; /*User disabled HW-crypto */
}
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
( " %s hardware based encryption for keyidx: %d, mac: %pM \n " ,
cmd = = SET_KEY ? " Using " : " Disabling " , key - > keyidx ,
sta ? sta - > addr : bcast_addr ) ) ;
rtlpriv - > sec . being_setkey = true ;
rtl_ips_nic_on ( hw ) ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
/* <1> get encryption alg */
switch ( key - > cipher ) {
case WLAN_CIPHER_SUITE_WEP40 :
key_type = WEP40_ENCRYPTION ;
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG , ( " alg:WEP40 \n " ) ) ;
rtlpriv - > sec . use_defaultkey = true ;
break ;
case WLAN_CIPHER_SUITE_WEP104 :
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
( " alg:WEP104 \n " ) ) ;
key_type = WEP104_ENCRYPTION ;
rtlpriv - > sec . use_defaultkey = true ;
break ;
case WLAN_CIPHER_SUITE_TKIP :
key_type = TKIP_ENCRYPTION ;
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG , ( " alg:TKIP \n " ) ) ;
if ( mac - > opmode = = NL80211_IFTYPE_ADHOC )
rtlpriv - > sec . use_defaultkey = true ;
break ;
case WLAN_CIPHER_SUITE_CCMP :
key_type = AESCCMP_ENCRYPTION ;
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG , ( " alg:CCMP \n " ) ) ;
if ( mac - > opmode = = NL80211_IFTYPE_ADHOC )
rtlpriv - > sec . use_defaultkey = true ;
break ;
default :
RT_TRACE ( rtlpriv , COMP_ERR , DBG_EMERG ,
( " alg_err:%x!!!!: \n " , key - > cipher ) ) ;
goto out_unlock ;
}
/* <2> get key_idx */
key_idx = ( u8 ) ( key - > keyidx ) ;
if ( key_idx > 3 )
goto out_unlock ;
/* <3> if pairwise key enable_hw_sec */
group_key = ! ( key - > flags & IEEE80211_KEY_FLAG_PAIRWISE ) ;
if ( ( ! group_key ) | | ( mac - > opmode = = NL80211_IFTYPE_ADHOC ) | |
rtlpriv - > sec . pairwise_enc_algorithm = = NO_ENCRYPTION ) {
if ( rtlpriv - > sec . pairwise_enc_algorithm = = NO_ENCRYPTION & &
( key_type = = WEP40_ENCRYPTION | |
key_type = = WEP104_ENCRYPTION ) )
wep_only = true ;
rtlpriv - > sec . pairwise_enc_algorithm = key_type ;
rtlpriv - > cfg - > ops - > enable_hw_sec ( hw ) ;
}
/* <4> set key based on cmd */
switch ( cmd ) {
case SET_KEY :
if ( wep_only ) {
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
( " set WEP(group/pairwise) key \n " ) ) ;
/* Pairwise key with an assigned MAC address. */
rtlpriv - > sec . pairwise_enc_algorithm = key_type ;
rtlpriv - > sec . group_enc_algorithm = key_type ;
/*set local buf about wep key. */
memcpy ( rtlpriv - > sec . key_buf [ key_idx ] ,
key - > key , key - > keylen ) ;
rtlpriv - > sec . key_len [ key_idx ] = key - > keylen ;
memcpy ( mac_addr , zero_addr , ETH_ALEN ) ;
} else if ( group_key ) { /* group key */
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
( " set group key \n " ) ) ;
/* group key */
rtlpriv - > sec . group_enc_algorithm = key_type ;
/*set local buf about group key. */
memcpy ( rtlpriv - > sec . key_buf [ key_idx ] ,
key - > key , key - > keylen ) ;
rtlpriv - > sec . key_len [ key_idx ] = key - > keylen ;
memcpy ( mac_addr , bcast_addr , ETH_ALEN ) ;
} else { /* pairwise key */
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
( " set pairwise key \n " ) ) ;
if ( ! sta ) {
RT_ASSERT ( false , ( " pairwise key withnot "
" mac_addr \n " ) ) ;
err = - EOPNOTSUPP ;
goto out_unlock ;
}
/* Pairwise key with an assigned MAC address. */
rtlpriv - > sec . pairwise_enc_algorithm = key_type ;
/*set local buf about pairwise key. */
memcpy ( rtlpriv - > sec . key_buf [ PAIRWISE_KEYIDX ] ,
key - > key , key - > keylen ) ;
rtlpriv - > sec . key_len [ PAIRWISE_KEYIDX ] = key - > keylen ;
rtlpriv - > sec . pairwise_key =
rtlpriv - > sec . key_buf [ PAIRWISE_KEYIDX ] ;
memcpy ( mac_addr , sta - > addr , ETH_ALEN ) ;
}
rtlpriv - > cfg - > ops - > set_key ( hw , key_idx , mac_addr ,
group_key , key_type , wep_only ,
false ) ;
/* <5> tell mac80211 do something: */
/*must use sw generate IV, or can not work !!!!. */
key - > flags | = IEEE80211_KEY_FLAG_GENERATE_IV ;
key - > hw_key_idx = key_idx ;
if ( key_type = = TKIP_ENCRYPTION )
key - > flags | = IEEE80211_KEY_FLAG_GENERATE_MMIC ;
break ;
case DISABLE_KEY :
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
( " disable key delete one entry \n " ) ) ;
/*set local buf about wep key. */
memset ( rtlpriv - > sec . key_buf [ key_idx ] , 0 , key - > keylen ) ;
rtlpriv - > sec . key_len [ key_idx ] = 0 ;
memcpy ( mac_addr , zero_addr , ETH_ALEN ) ;
/*
* mac80211 will delete entrys one by one ,
* so don ' t use rtl_cam_reset_all_entry
* or clear all entry here .
*/
rtl_cam_delete_one_entry ( hw , mac_addr , key_idx ) ;
break ;
default :
RT_TRACE ( rtlpriv , COMP_ERR , DBG_EMERG ,
( " cmd_err:%x!!!!: \n " , cmd ) ) ;
}
out_unlock :
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
rtlpriv - > sec . being_setkey = false ;
return err ;
}
static void rtl_op_rfkill_poll ( struct ieee80211_hw * hw )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
bool radio_state ;
bool blocked ;
u8 valid = 0 ;
if ( ! test_bit ( RTL_STATUS_INTERFACE_START , & rtlpriv - > status ) )
return ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
/*if Radio On return true here */
radio_state = rtlpriv - > cfg - > ops - > radio_onoff_checking ( hw , & valid ) ;
if ( valid ) {
if ( unlikely ( radio_state ! = rtlpriv - > rfkill . rfkill_state ) ) {
rtlpriv - > rfkill . rfkill_state = radio_state ;
RT_TRACE ( rtlpriv , COMP_RF , DBG_DMESG ,
( KERN_INFO " wireless radio switch turned %s \n " ,
radio_state ? " on " : " off " ) ) ;
blocked = ( rtlpriv - > rfkill . rfkill_state = = 1 ) ? 0 : 1 ;
wiphy_rfkill_set_hw_state ( hw - > wiphy , blocked ) ;
}
}
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
}
const struct ieee80211_ops rtl_ops = {
. start = rtl_op_start ,
. stop = rtl_op_stop ,
. tx = rtl_op_tx ,
. add_interface = rtl_op_add_interface ,
. remove_interface = rtl_op_remove_interface ,
. config = rtl_op_config ,
. configure_filter = rtl_op_configure_filter ,
. set_key = rtl_op_set_key ,
. conf_tx = rtl_op_conf_tx ,
. bss_info_changed = rtl_op_bss_info_changed ,
. get_tsf = rtl_op_get_tsf ,
. set_tsf = rtl_op_set_tsf ,
. reset_tsf = rtl_op_reset_tsf ,
. sta_notify = rtl_op_sta_notify ,
. ampdu_action = rtl_op_ampdu_action ,
. sw_scan_start = rtl_op_sw_scan_start ,
. sw_scan_complete = rtl_op_sw_scan_complete ,
. rfkill_poll = rtl_op_rfkill_poll ,
} ;