diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/htc_drv_main.c')
| -rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 460 |
1 files changed, 128 insertions, 332 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index dd17909bd903..845b4c938d16 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
| @@ -24,7 +24,7 @@ static struct dentry *ath9k_debugfs_root; | |||
| 24 | /* Utilities */ | 24 | /* Utilities */ |
| 25 | /*************/ | 25 | /*************/ |
| 26 | 26 | ||
| 27 | static void ath_update_txpow(struct ath9k_htc_priv *priv) | 27 | void ath_update_txpow(struct ath9k_htc_priv *priv) |
| 28 | { | 28 | { |
| 29 | struct ath_hw *ah = priv->ah; | 29 | struct ath_hw *ah = priv->ah; |
| 30 | 30 | ||
| @@ -116,6 +116,60 @@ void ath9k_ps_work(struct work_struct *work) | |||
| 116 | ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); | 116 | ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | void ath9k_htc_reset(struct ath9k_htc_priv *priv) | ||
| 120 | { | ||
| 121 | struct ath_hw *ah = priv->ah; | ||
| 122 | struct ath_common *common = ath9k_hw_common(ah); | ||
| 123 | struct ieee80211_channel *channel = priv->hw->conf.channel; | ||
| 124 | struct ath9k_hw_cal_data *caldata; | ||
| 125 | enum htc_phymode mode; | ||
| 126 | __be16 htc_mode; | ||
| 127 | u8 cmd_rsp; | ||
| 128 | int ret; | ||
| 129 | |||
| 130 | mutex_lock(&priv->mutex); | ||
| 131 | ath9k_htc_ps_wakeup(priv); | ||
| 132 | |||
| 133 | if (priv->op_flags & OP_ASSOCIATED) | ||
| 134 | cancel_delayed_work_sync(&priv->ath9k_ani_work); | ||
| 135 | |||
| 136 | ieee80211_stop_queues(priv->hw); | ||
| 137 | htc_stop(priv->htc); | ||
| 138 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | ||
| 139 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | ||
| 140 | WMI_CMD(WMI_STOP_RECV_CMDID); | ||
| 141 | |||
| 142 | caldata = &priv->caldata[channel->hw_value]; | ||
| 143 | ret = ath9k_hw_reset(ah, ah->curchan, caldata, false); | ||
| 144 | if (ret) { | ||
| 145 | ath_err(common, | ||
| 146 | "Unable to reset device (%u Mhz) reset status %d\n", | ||
| 147 | channel->center_freq, ret); | ||
| 148 | } | ||
| 149 | |||
| 150 | ath_update_txpow(priv); | ||
| 151 | |||
| 152 | WMI_CMD(WMI_START_RECV_CMDID); | ||
| 153 | ath9k_host_rx_init(priv); | ||
| 154 | |||
| 155 | mode = ath9k_htc_get_curmode(priv, ah->curchan); | ||
| 156 | htc_mode = cpu_to_be16(mode); | ||
| 157 | WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); | ||
| 158 | |||
| 159 | WMI_CMD(WMI_ENABLE_INTR_CMDID); | ||
| 160 | htc_start(priv->htc); | ||
| 161 | |||
| 162 | if (priv->op_flags & OP_ASSOCIATED) { | ||
| 163 | ath9k_htc_beacon_config(priv, priv->vif); | ||
| 164 | ath_start_ani(priv); | ||
| 165 | } | ||
| 166 | |||
| 167 | ieee80211_wake_queues(priv->hw); | ||
| 168 | |||
| 169 | ath9k_htc_ps_restore(priv); | ||
| 170 | mutex_unlock(&priv->mutex); | ||
| 171 | } | ||
| 172 | |||
| 119 | static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | 173 | static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, |
| 120 | struct ieee80211_hw *hw, | 174 | struct ieee80211_hw *hw, |
| 121 | struct ath9k_channel *hchan) | 175 | struct ath9k_channel *hchan) |
| @@ -123,7 +177,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
| 123 | struct ath_hw *ah = priv->ah; | 177 | struct ath_hw *ah = priv->ah; |
| 124 | struct ath_common *common = ath9k_hw_common(ah); | 178 | struct ath_common *common = ath9k_hw_common(ah); |
| 125 | struct ieee80211_conf *conf = &common->hw->conf; | 179 | struct ieee80211_conf *conf = &common->hw->conf; |
| 126 | bool fastcc = true; | 180 | bool fastcc; |
| 127 | struct ieee80211_channel *channel = hw->conf.channel; | 181 | struct ieee80211_channel *channel = hw->conf.channel; |
| 128 | struct ath9k_hw_cal_data *caldata; | 182 | struct ath9k_hw_cal_data *caldata; |
| 129 | enum htc_phymode mode; | 183 | enum htc_phymode mode; |
| @@ -134,8 +188,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
| 134 | if (priv->op_flags & OP_INVALID) | 188 | if (priv->op_flags & OP_INVALID) |
| 135 | return -EIO; | 189 | return -EIO; |
| 136 | 190 | ||
| 137 | if (priv->op_flags & OP_FULL_RESET) | 191 | fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); |
| 138 | fastcc = false; | ||
| 139 | 192 | ||
| 140 | ath9k_htc_ps_wakeup(priv); | 193 | ath9k_htc_ps_wakeup(priv); |
| 141 | htc_stop(priv->htc); | 194 | htc_stop(priv->htc); |
| @@ -177,23 +230,43 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
| 177 | goto err; | 230 | goto err; |
| 178 | 231 | ||
| 179 | htc_start(priv->htc); | 232 | htc_start(priv->htc); |
| 180 | |||
| 181 | priv->op_flags &= ~OP_FULL_RESET; | ||
| 182 | err: | 233 | err: |
| 183 | ath9k_htc_ps_restore(priv); | 234 | ath9k_htc_ps_restore(priv); |
| 184 | return ret; | 235 | return ret; |
| 185 | } | 236 | } |
| 186 | 237 | ||
| 238 | static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | ||
| 239 | { | ||
| 240 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
| 241 | struct ath9k_htc_target_vif hvif; | ||
| 242 | int ret = 0; | ||
| 243 | u8 cmd_rsp; | ||
| 244 | |||
| 245 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | ||
| 246 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | ||
| 247 | hvif.index = 0; /* Should do for now */ | ||
| 248 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | ||
| 249 | priv->nvifs--; | ||
| 250 | } | ||
| 251 | |||
| 187 | static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) | 252 | static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) |
| 188 | { | 253 | { |
| 189 | struct ath_common *common = ath9k_hw_common(priv->ah); | 254 | struct ath_common *common = ath9k_hw_common(priv->ah); |
| 190 | struct ath9k_htc_target_vif hvif; | 255 | struct ath9k_htc_target_vif hvif; |
| 256 | struct ath9k_htc_target_sta tsta; | ||
| 191 | int ret = 0; | 257 | int ret = 0; |
| 192 | u8 cmd_rsp; | 258 | u8 cmd_rsp; |
| 193 | 259 | ||
| 194 | if (priv->nvifs > 0) | 260 | if (priv->nvifs > 0) |
| 195 | return -ENOBUFS; | 261 | return -ENOBUFS; |
| 196 | 262 | ||
| 263 | if (priv->nstations >= ATH9K_HTC_MAX_STA) | ||
| 264 | return -ENOBUFS; | ||
| 265 | |||
| 266 | /* | ||
| 267 | * Add an interface. | ||
| 268 | */ | ||
| 269 | |||
| 197 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | 270 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); |
| 198 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | 271 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); |
| 199 | 272 | ||
| @@ -206,23 +279,57 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) | |||
| 206 | return ret; | 279 | return ret; |
| 207 | 280 | ||
| 208 | priv->nvifs++; | 281 | priv->nvifs++; |
| 282 | |||
| 283 | /* | ||
| 284 | * Associate a station with the interface for packet injection. | ||
| 285 | */ | ||
| 286 | |||
| 287 | memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); | ||
| 288 | |||
| 289 | memcpy(&tsta.macaddr, common->macaddr, ETH_ALEN); | ||
| 290 | |||
| 291 | tsta.is_vif_sta = 1; | ||
| 292 | tsta.sta_index = priv->nstations; | ||
| 293 | tsta.vif_index = hvif.index; | ||
| 294 | tsta.maxampdu = 0xffff; | ||
| 295 | |||
| 296 | WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); | ||
| 297 | if (ret) { | ||
| 298 | ath_err(common, "Unable to add station entry for monitor mode\n"); | ||
| 299 | goto err_vif; | ||
| 300 | } | ||
| 301 | |||
| 302 | priv->nstations++; | ||
| 303 | |||
| 209 | return 0; | 304 | return 0; |
| 305 | |||
| 306 | err_vif: | ||
| 307 | /* | ||
| 308 | * Remove the interface from the target. | ||
| 309 | */ | ||
| 310 | __ath9k_htc_remove_monitor_interface(priv); | ||
| 311 | return ret; | ||
| 210 | } | 312 | } |
| 211 | 313 | ||
| 212 | static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | 314 | static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) |
| 213 | { | 315 | { |
| 214 | struct ath_common *common = ath9k_hw_common(priv->ah); | 316 | struct ath_common *common = ath9k_hw_common(priv->ah); |
| 215 | struct ath9k_htc_target_vif hvif; | ||
| 216 | int ret = 0; | 317 | int ret = 0; |
| 217 | u8 cmd_rsp; | 318 | u8 cmd_rsp, sta_idx; |
| 218 | 319 | ||
| 219 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | 320 | __ath9k_htc_remove_monitor_interface(priv); |
| 220 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | ||
| 221 | hvif.index = 0; /* Should do for now */ | ||
| 222 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | ||
| 223 | priv->nvifs--; | ||
| 224 | 321 | ||
| 225 | return ret; | 322 | sta_idx = 0; /* Only single interface, for now */ |
| 323 | |||
| 324 | WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); | ||
| 325 | if (ret) { | ||
| 326 | ath_err(common, "Unable to remove station entry for monitor mode\n"); | ||
| 327 | return ret; | ||
| 328 | } | ||
| 329 | |||
| 330 | priv->nstations--; | ||
| 331 | |||
| 332 | return 0; | ||
| 226 | } | 333 | } |
| 227 | 334 | ||
| 228 | static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, | 335 | static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, |
| @@ -690,7 +797,7 @@ void ath9k_htc_debug_remove_root(void) | |||
| 690 | /* ANI */ | 797 | /* ANI */ |
| 691 | /*******/ | 798 | /*******/ |
| 692 | 799 | ||
| 693 | static void ath_start_ani(struct ath9k_htc_priv *priv) | 800 | void ath_start_ani(struct ath9k_htc_priv *priv) |
| 694 | { | 801 | { |
| 695 | struct ath_common *common = ath9k_hw_common(priv->ah); | 802 | struct ath_common *common = ath9k_hw_common(priv->ah); |
| 696 | unsigned long timestamp = jiffies_to_msecs(jiffies); | 803 | unsigned long timestamp = jiffies_to_msecs(jiffies); |
| @@ -789,317 +896,6 @@ set_timer: | |||
| 789 | msecs_to_jiffies(cal_interval)); | 896 | msecs_to_jiffies(cal_interval)); |
| 790 | } | 897 | } |
| 791 | 898 | ||
| 792 | /*******/ | ||
| 793 | /* LED */ | ||
| 794 | /*******/ | ||
| 795 | |||
| 796 | static void ath9k_led_blink_work(struct work_struct *work) | ||
| 797 | { | ||
| 798 | struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv, | ||
| 799 | ath9k_led_blink_work.work); | ||
| 800 | |||
| 801 | if (!(priv->op_flags & OP_LED_ASSOCIATED)) | ||
| 802 | return; | ||
| 803 | |||
| 804 | if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) || | ||
| 805 | (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) | ||
| 806 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); | ||
| 807 | else | ||
| 808 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, | ||
| 809 | (priv->op_flags & OP_LED_ON) ? 1 : 0); | ||
| 810 | |||
| 811 | ieee80211_queue_delayed_work(priv->hw, | ||
| 812 | &priv->ath9k_led_blink_work, | ||
| 813 | (priv->op_flags & OP_LED_ON) ? | ||
| 814 | msecs_to_jiffies(priv->led_off_duration) : | ||
| 815 | msecs_to_jiffies(priv->led_on_duration)); | ||
| 816 | |||
| 817 | priv->led_on_duration = priv->led_on_cnt ? | ||
| 818 | max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) : | ||
| 819 | ATH_LED_ON_DURATION_IDLE; | ||
| 820 | priv->led_off_duration = priv->led_off_cnt ? | ||
| 821 | max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) : | ||
| 822 | ATH_LED_OFF_DURATION_IDLE; | ||
| 823 | priv->led_on_cnt = priv->led_off_cnt = 0; | ||
| 824 | |||
| 825 | if (priv->op_flags & OP_LED_ON) | ||
| 826 | priv->op_flags &= ~OP_LED_ON; | ||
| 827 | else | ||
| 828 | priv->op_flags |= OP_LED_ON; | ||
| 829 | } | ||
| 830 | |||
| 831 | static void ath9k_led_brightness_work(struct work_struct *work) | ||
| 832 | { | ||
| 833 | struct ath_led *led = container_of(work, struct ath_led, | ||
| 834 | brightness_work.work); | ||
| 835 | struct ath9k_htc_priv *priv = led->priv; | ||
| 836 | |||
| 837 | switch (led->brightness) { | ||
| 838 | case LED_OFF: | ||
| 839 | if (led->led_type == ATH_LED_ASSOC || | ||
| 840 | led->led_type == ATH_LED_RADIO) { | ||
| 841 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, | ||
| 842 | (led->led_type == ATH_LED_RADIO)); | ||
| 843 | priv->op_flags &= ~OP_LED_ASSOCIATED; | ||
| 844 | if (led->led_type == ATH_LED_RADIO) | ||
| 845 | priv->op_flags &= ~OP_LED_ON; | ||
| 846 | } else { | ||
| 847 | priv->led_off_cnt++; | ||
| 848 | } | ||
| 849 | break; | ||
| 850 | case LED_FULL: | ||
| 851 | if (led->led_type == ATH_LED_ASSOC) { | ||
| 852 | priv->op_flags |= OP_LED_ASSOCIATED; | ||
| 853 | ieee80211_queue_delayed_work(priv->hw, | ||
| 854 | &priv->ath9k_led_blink_work, 0); | ||
| 855 | } else if (led->led_type == ATH_LED_RADIO) { | ||
| 856 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); | ||
| 857 | priv->op_flags |= OP_LED_ON; | ||
| 858 | } else { | ||
| 859 | priv->led_on_cnt++; | ||
| 860 | } | ||
| 861 | break; | ||
| 862 | default: | ||
| 863 | break; | ||
| 864 | } | ||
| 865 | } | ||
| 866 | |||
| 867 | static void ath9k_led_brightness(struct led_classdev *led_cdev, | ||
| 868 | enum led_brightness brightness) | ||
| 869 | { | ||
| 870 | struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); | ||
| 871 | struct ath9k_htc_priv *priv = led->priv; | ||
| 872 | |||
| 873 | led->brightness = brightness; | ||
| 874 | if (!(priv->op_flags & OP_LED_DEINIT)) | ||
| 875 | ieee80211_queue_delayed_work(priv->hw, | ||
| 876 | &led->brightness_work, 0); | ||
| 877 | } | ||
| 878 | |||
| 879 | static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv) | ||
| 880 | { | ||
| 881 | cancel_delayed_work_sync(&priv->radio_led.brightness_work); | ||
| 882 | cancel_delayed_work_sync(&priv->assoc_led.brightness_work); | ||
| 883 | cancel_delayed_work_sync(&priv->tx_led.brightness_work); | ||
| 884 | cancel_delayed_work_sync(&priv->rx_led.brightness_work); | ||
| 885 | } | ||
| 886 | |||
| 887 | static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led, | ||
| 888 | char *trigger) | ||
| 889 | { | ||
| 890 | int ret; | ||
| 891 | |||
| 892 | led->priv = priv; | ||
| 893 | led->led_cdev.name = led->name; | ||
| 894 | led->led_cdev.default_trigger = trigger; | ||
| 895 | led->led_cdev.brightness_set = ath9k_led_brightness; | ||
| 896 | |||
| 897 | ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev); | ||
| 898 | if (ret) | ||
| 899 | ath_err(ath9k_hw_common(priv->ah), | ||
| 900 | "Failed to register led:%s", led->name); | ||
| 901 | else | ||
| 902 | led->registered = 1; | ||
| 903 | |||
| 904 | INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work); | ||
| 905 | |||
| 906 | return ret; | ||
| 907 | } | ||
| 908 | |||
| 909 | static void ath9k_unregister_led(struct ath_led *led) | ||
| 910 | { | ||
| 911 | if (led->registered) { | ||
| 912 | led_classdev_unregister(&led->led_cdev); | ||
| 913 | led->registered = 0; | ||
| 914 | } | ||
| 915 | } | ||
| 916 | |||
| 917 | void ath9k_deinit_leds(struct ath9k_htc_priv *priv) | ||
| 918 | { | ||
| 919 | priv->op_flags |= OP_LED_DEINIT; | ||
| 920 | ath9k_unregister_led(&priv->assoc_led); | ||
| 921 | priv->op_flags &= ~OP_LED_ASSOCIATED; | ||
| 922 | ath9k_unregister_led(&priv->tx_led); | ||
| 923 | ath9k_unregister_led(&priv->rx_led); | ||
| 924 | ath9k_unregister_led(&priv->radio_led); | ||
| 925 | } | ||
| 926 | |||
| 927 | void ath9k_init_leds(struct ath9k_htc_priv *priv) | ||
| 928 | { | ||
| 929 | char *trigger; | ||
| 930 | int ret; | ||
| 931 | |||
| 932 | if (AR_SREV_9287(priv->ah)) | ||
| 933 | priv->ah->led_pin = ATH_LED_PIN_9287; | ||
| 934 | else if (AR_SREV_9271(priv->ah)) | ||
| 935 | priv->ah->led_pin = ATH_LED_PIN_9271; | ||
| 936 | else if (AR_DEVID_7010(priv->ah)) | ||
| 937 | priv->ah->led_pin = ATH_LED_PIN_7010; | ||
| 938 | else | ||
| 939 | priv->ah->led_pin = ATH_LED_PIN_DEF; | ||
| 940 | |||
| 941 | /* Configure gpio 1 for output */ | ||
| 942 | ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin, | ||
| 943 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
| 944 | /* LED off, active low */ | ||
| 945 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); | ||
| 946 | |||
| 947 | INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work); | ||
| 948 | |||
| 949 | trigger = ieee80211_get_radio_led_name(priv->hw); | ||
| 950 | snprintf(priv->radio_led.name, sizeof(priv->radio_led.name), | ||
| 951 | "ath9k-%s::radio", wiphy_name(priv->hw->wiphy)); | ||
| 952 | ret = ath9k_register_led(priv, &priv->radio_led, trigger); | ||
| 953 | priv->radio_led.led_type = ATH_LED_RADIO; | ||
| 954 | if (ret) | ||
| 955 | goto fail; | ||
| 956 | |||
| 957 | trigger = ieee80211_get_assoc_led_name(priv->hw); | ||
| 958 | snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name), | ||
| 959 | "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy)); | ||
| 960 | ret = ath9k_register_led(priv, &priv->assoc_led, trigger); | ||
| 961 | priv->assoc_led.led_type = ATH_LED_ASSOC; | ||
| 962 | if (ret) | ||
| 963 | goto fail; | ||
| 964 | |||
| 965 | trigger = ieee80211_get_tx_led_name(priv->hw); | ||
| 966 | snprintf(priv->tx_led.name, sizeof(priv->tx_led.name), | ||
| 967 | "ath9k-%s::tx", wiphy_name(priv->hw->wiphy)); | ||
| 968 | ret = ath9k_register_led(priv, &priv->tx_led, trigger); | ||
| 969 | priv->tx_led.led_type = ATH_LED_TX; | ||
| 970 | if (ret) | ||
| 971 | goto fail; | ||
| 972 | |||
| 973 | trigger = ieee80211_get_rx_led_name(priv->hw); | ||
| 974 | snprintf(priv->rx_led.name, sizeof(priv->rx_led.name), | ||
| 975 | "ath9k-%s::rx", wiphy_name(priv->hw->wiphy)); | ||
| 976 | ret = ath9k_register_led(priv, &priv->rx_led, trigger); | ||
| 977 | priv->rx_led.led_type = ATH_LED_RX; | ||
| 978 | if (ret) | ||
| 979 | goto fail; | ||
| 980 | |||
| 981 | priv->op_flags &= ~OP_LED_DEINIT; | ||
| 982 | |||
| 983 | return; | ||
| 984 | |||
| 985 | fail: | ||
| 986 | cancel_delayed_work_sync(&priv->ath9k_led_blink_work); | ||
| 987 | ath9k_deinit_leds(priv); | ||
| 988 | } | ||
| 989 | |||
| 990 | /*******************/ | ||
| 991 | /* Rfkill */ | ||
| 992 | /*******************/ | ||
| 993 | |||
| 994 | static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv) | ||
| 995 | { | ||
| 996 | return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) == | ||
| 997 | priv->ah->rfkill_polarity; | ||
| 998 | } | ||
| 999 | |||
| 1000 | static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw) | ||
| 1001 | { | ||
| 1002 | struct ath9k_htc_priv *priv = hw->priv; | ||
| 1003 | bool blocked = !!ath_is_rfkill_set(priv); | ||
| 1004 | |||
| 1005 | wiphy_rfkill_set_hw_state(hw->wiphy, blocked); | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv) | ||
| 1009 | { | ||
| 1010 | if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
| 1011 | wiphy_rfkill_start_polling(priv->hw->wiphy); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | static void ath9k_htc_radio_enable(struct ieee80211_hw *hw) | ||
| 1015 | { | ||
| 1016 | struct ath9k_htc_priv *priv = hw->priv; | ||
| 1017 | struct ath_hw *ah = priv->ah; | ||
| 1018 | struct ath_common *common = ath9k_hw_common(ah); | ||
| 1019 | int ret; | ||
| 1020 | u8 cmd_rsp; | ||
| 1021 | |||
| 1022 | if (!ah->curchan) | ||
| 1023 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); | ||
| 1024 | |||
| 1025 | /* Reset the HW */ | ||
| 1026 | ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); | ||
| 1027 | if (ret) { | ||
| 1028 | ath_err(common, | ||
| 1029 | "Unable to reset hardware; reset status %d (freq %u MHz)\n", | ||
| 1030 | ret, ah->curchan->channel); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | ath_update_txpow(priv); | ||
| 1034 | |||
| 1035 | /* Start RX */ | ||
| 1036 | WMI_CMD(WMI_START_RECV_CMDID); | ||
| 1037 | ath9k_host_rx_init(priv); | ||
| 1038 | |||
| 1039 | /* Start TX */ | ||
| 1040 | htc_start(priv->htc); | ||
| 1041 | spin_lock_bh(&priv->tx_lock); | ||
| 1042 | priv->tx_queues_stop = false; | ||
| 1043 | spin_unlock_bh(&priv->tx_lock); | ||
| 1044 | ieee80211_wake_queues(hw); | ||
| 1045 | |||
| 1046 | WMI_CMD(WMI_ENABLE_INTR_CMDID); | ||
| 1047 | |||
| 1048 | /* Enable LED */ | ||
| 1049 | ath9k_hw_cfg_output(ah, ah->led_pin, | ||
| 1050 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
| 1051 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | static void ath9k_htc_radio_disable(struct ieee80211_hw *hw) | ||
| 1055 | { | ||
| 1056 | struct ath9k_htc_priv *priv = hw->priv; | ||
| 1057 | struct ath_hw *ah = priv->ah; | ||
| 1058 | struct ath_common *common = ath9k_hw_common(ah); | ||
| 1059 | int ret; | ||
| 1060 | u8 cmd_rsp; | ||
| 1061 | |||
| 1062 | ath9k_htc_ps_wakeup(priv); | ||
| 1063 | |||
| 1064 | /* Disable LED */ | ||
| 1065 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); | ||
| 1066 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); | ||
| 1067 | |||
| 1068 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | ||
| 1069 | |||
| 1070 | /* Stop TX */ | ||
| 1071 | ieee80211_stop_queues(hw); | ||
| 1072 | htc_stop(priv->htc); | ||
| 1073 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | ||
| 1074 | skb_queue_purge(&priv->tx_queue); | ||
| 1075 | |||
| 1076 | /* Stop RX */ | ||
| 1077 | WMI_CMD(WMI_STOP_RECV_CMDID); | ||
| 1078 | |||
| 1079 | /* | ||
| 1080 | * The MIB counters have to be disabled here, | ||
| 1081 | * since the target doesn't do it. | ||
| 1082 | */ | ||
| 1083 | ath9k_hw_disable_mib_counters(ah); | ||
| 1084 | |||
| 1085 | if (!ah->curchan) | ||
| 1086 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); | ||
| 1087 | |||
| 1088 | /* Reset the HW */ | ||
| 1089 | ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); | ||
| 1090 | if (ret) { | ||
| 1091 | ath_err(common, | ||
| 1092 | "Unable to reset hardware; reset status %d (freq %u MHz)\n", | ||
| 1093 | ret, ah->curchan->channel); | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | /* Disable the PHY */ | ||
| 1097 | ath9k_hw_phy_disable(ah); | ||
| 1098 | |||
| 1099 | ath9k_htc_ps_restore(priv); | ||
| 1100 | ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | /**********************/ | 899 | /**********************/ |
| 1104 | /* mac80211 Callbacks */ | 900 | /* mac80211 Callbacks */ |
| 1105 | /**********************/ | 901 | /**********************/ |
| @@ -1218,6 +1014,12 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) | |||
| 1218 | int ret = 0; | 1014 | int ret = 0; |
| 1219 | u8 cmd_rsp; | 1015 | u8 cmd_rsp; |
| 1220 | 1016 | ||
| 1017 | /* Cancel all the running timers/work .. */ | ||
| 1018 | cancel_work_sync(&priv->fatal_work); | ||
| 1019 | cancel_work_sync(&priv->ps_work); | ||
| 1020 | cancel_delayed_work_sync(&priv->ath9k_led_blink_work); | ||
| 1021 | ath9k_led_stop_brightness(priv); | ||
| 1022 | |||
| 1221 | mutex_lock(&priv->mutex); | 1023 | mutex_lock(&priv->mutex); |
| 1222 | 1024 | ||
| 1223 | if (priv->op_flags & OP_INVALID) { | 1025 | if (priv->op_flags & OP_INVALID) { |
| @@ -1226,11 +1028,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) | |||
| 1226 | return; | 1028 | return; |
| 1227 | } | 1029 | } |
| 1228 | 1030 | ||
| 1229 | /* Cancel all the running timers/work .. */ | ||
| 1230 | cancel_work_sync(&priv->ps_work); | ||
| 1231 | cancel_delayed_work_sync(&priv->ath9k_led_blink_work); | ||
| 1232 | ath9k_led_stop_brightness(priv); | ||
| 1233 | |||
| 1234 | ath9k_htc_ps_wakeup(priv); | 1031 | ath9k_htc_ps_wakeup(priv); |
| 1235 | htc_stop(priv->htc); | 1032 | htc_stop(priv->htc); |
| 1236 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | 1033 | WMI_CMD(WMI_DISABLE_INTR_CMDID); |
| @@ -1792,7 +1589,6 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) | |||
| 1792 | spin_lock_bh(&priv->beacon_lock); | 1589 | spin_lock_bh(&priv->beacon_lock); |
| 1793 | priv->op_flags &= ~OP_SCANNING; | 1590 | priv->op_flags &= ~OP_SCANNING; |
| 1794 | spin_unlock_bh(&priv->beacon_lock); | 1591 | spin_unlock_bh(&priv->beacon_lock); |
| 1795 | priv->op_flags |= OP_FULL_RESET; | ||
| 1796 | if (priv->op_flags & OP_ASSOCIATED) { | 1592 | if (priv->op_flags & OP_ASSOCIATED) { |
| 1797 | ath9k_htc_beacon_config(priv, priv->vif); | 1593 | ath9k_htc_beacon_config(priv, priv->vif); |
| 1798 | ath_start_ani(priv); | 1594 | ath_start_ani(priv); |
