diff options
author | Kalle Valo <kvalo@qca.qualcomm.com> | 2012-07-19 09:00:56 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2012-10-24 04:49:37 -0400 |
commit | 84841ba29b1f55fb09703408477f097c7f8952f8 (patch) | |
tree | 9bcf8de2def815dd2a4d3a0a534e76b9ccb7fdd2 | |
parent | 11f0bfcf73f4a90c8c0e0b244a272379b376adb1 (diff) |
ath6kl: add support for changing contry code
To make it possible to change the country code from user space via nl80211
add handler for reg_notifier. The feature is only enabled when built
time option CONFIG_ATH6KL_REGDOMAIN is enabled, which again depends on
CFG80211_CERTIFICATION_ONUS for certication purposes.
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/Kconfig | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 47 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/core.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/wmi.c | 17 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/wmi.h | 6 |
5 files changed, 82 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index d755a5e7ed20..26c4b7220859 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig | |||
@@ -30,3 +30,12 @@ config ATH6KL_DEBUG | |||
30 | depends on ATH6KL | 30 | depends on ATH6KL |
31 | ---help--- | 31 | ---help--- |
32 | Enables debug support | 32 | Enables debug support |
33 | |||
34 | config ATH6KL_REGDOMAIN | ||
35 | bool "Atheros ath6kl regdomain support" | ||
36 | depends on ATH6KL | ||
37 | depends on CFG80211_CERTIFICATION_ONUS | ||
38 | ---help--- | ||
39 | Enabling this makes it possible to change the regdomain in | ||
40 | the firmware. This can be only enabled if regulatory requirements | ||
41 | are taken into account. | ||
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 4f538f0027f2..f620af5e0dbb 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -3458,6 +3458,49 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) | |||
3458 | ath6kl_cfg80211_stop(vif); | 3458 | ath6kl_cfg80211_stop(vif); |
3459 | } | 3459 | } |
3460 | 3460 | ||
3461 | static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy, | ||
3462 | struct regulatory_request *request) | ||
3463 | { | ||
3464 | struct ath6kl *ar = wiphy_priv(wiphy); | ||
3465 | u32 rates[IEEE80211_NUM_BANDS]; | ||
3466 | int ret, i; | ||
3467 | |||
3468 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
3469 | "cfg reg_notify %c%c%s%s initiator %d\n", | ||
3470 | request->alpha2[0], request->alpha2[1], | ||
3471 | request->intersect ? " intersect" : "", | ||
3472 | request->processed ? " processed" : "", | ||
3473 | request->initiator); | ||
3474 | |||
3475 | ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2); | ||
3476 | if (ret) { | ||
3477 | ath6kl_err("failed to set regdomain: %d\n", ret); | ||
3478 | return ret; | ||
3479 | } | ||
3480 | |||
3481 | /* | ||
3482 | * Firmware will apply the regdomain change only after a scan is | ||
3483 | * issued and it will send a WMI_REGDOMAIN_EVENTID when it has been | ||
3484 | * changed. | ||
3485 | */ | ||
3486 | |||
3487 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
3488 | if (wiphy->bands[i]) | ||
3489 | rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; | ||
3490 | |||
3491 | |||
3492 | ret = ath6kl_wmi_beginscan_cmd(ar->wmi, 0, WMI_LONG_SCAN, false, | ||
3493 | false, 0, ATH6KL_FG_SCAN_INTERVAL, | ||
3494 | 0, NULL, false, rates); | ||
3495 | if (ret) { | ||
3496 | ath6kl_err("failed to start scan for a regdomain change: %d\n", | ||
3497 | ret); | ||
3498 | return ret; | ||
3499 | } | ||
3500 | |||
3501 | return 0; | ||
3502 | } | ||
3503 | |||
3461 | static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) | 3504 | static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) |
3462 | { | 3505 | { |
3463 | vif->aggr_cntxt = aggr_init(vif); | 3506 | vif->aggr_cntxt = aggr_init(vif); |
@@ -3590,6 +3633,10 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) | |||
3590 | BIT(NL80211_IFTYPE_P2P_CLIENT); | 3633 | BIT(NL80211_IFTYPE_P2P_CLIENT); |
3591 | } | 3634 | } |
3592 | 3635 | ||
3636 | if (config_enabled(CONFIG_ATH6KL_REGDOMAIN) && | ||
3637 | test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) | ||
3638 | wiphy->reg_notifier = ath6kl_cfg80211_reg_notify; | ||
3639 | |||
3593 | /* max num of ssids that can be probed during scanning */ | 3640 | /* max num of ssids that can be probed during scanning */ |
3594 | wiphy->max_scan_ssids = MAX_PROBED_SSIDS; | 3641 | wiphy->max_scan_ssids = MAX_PROBED_SSIDS; |
3595 | 3642 | ||
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index a754a153cc81..eb86b315adff 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h | |||
@@ -124,6 +124,9 @@ enum ath6kl_fw_capability { | |||
124 | /* Firmware supports TX error rate notification */ | 124 | /* Firmware supports TX error rate notification */ |
125 | ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, | 125 | ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, |
126 | 126 | ||
127 | /* supports WMI_SET_REGDOMAIN_CMDID command */ | ||
128 | ATH6KL_FW_CAPABILITY_REGDOMAIN, | ||
129 | |||
127 | /* this needs to be last */ | 130 | /* this needs to be last */ |
128 | ATH6KL_FW_CAPABILITY_MAX, | 131 | ATH6KL_FW_CAPABILITY_MAX, |
129 | }; | 132 | }; |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 05cc871f8244..cf91348fdbdb 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c | |||
@@ -3216,6 +3216,23 @@ int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance) | |||
3216 | return ret; | 3216 | return ret; |
3217 | } | 3217 | } |
3218 | 3218 | ||
3219 | int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2) | ||
3220 | { | ||
3221 | struct sk_buff *skb; | ||
3222 | struct wmi_set_regdomain_cmd *cmd; | ||
3223 | |||
3224 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
3225 | if (!skb) | ||
3226 | return -ENOMEM; | ||
3227 | |||
3228 | cmd = (struct wmi_set_regdomain_cmd *) skb->data; | ||
3229 | memcpy(cmd->iso_name, alpha2, 2); | ||
3230 | |||
3231 | return ath6kl_wmi_cmd_send(wmi, 0, skb, | ||
3232 | WMI_SET_REGDOMAIN_CMDID, | ||
3233 | NO_SYNC_WMIFLAG); | ||
3234 | } | ||
3235 | |||
3219 | s32 ath6kl_wmi_get_rate(s8 rate_index) | 3236 | s32 ath6kl_wmi_get_rate(s8 rate_index) |
3220 | { | 3237 | { |
3221 | if (rate_index == RATE_AUTO) | 3238 | if (rate_index == RATE_AUTO) |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 5166a8e64927..1d510bae1558 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h | |||
@@ -1042,6 +1042,11 @@ struct wmi_sta_bmiss_enhance_cmd { | |||
1042 | u8 enable; | 1042 | u8 enable; |
1043 | } __packed; | 1043 | } __packed; |
1044 | 1044 | ||
1045 | struct wmi_set_regdomain_cmd { | ||
1046 | u8 length; | ||
1047 | u8 iso_name[2]; | ||
1048 | } __packed; | ||
1049 | |||
1045 | /* WMI_SET_POWER_MODE_CMDID */ | 1050 | /* WMI_SET_POWER_MODE_CMDID */ |
1046 | enum wmi_power_mode { | 1051 | enum wmi_power_mode { |
1047 | REC_POWER = 0x01, | 1052 | REC_POWER = 0x01, |
@@ -2640,6 +2645,7 @@ int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, | |||
2640 | int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable); | 2645 | int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable); |
2641 | int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, | 2646 | int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, |
2642 | u32 rate, u32 pkts, u32 intvl); | 2647 | u32 rate, u32 pkts, u32 intvl); |
2648 | int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2); | ||
2643 | 2649 | ||
2644 | /* AP mode uAPSD */ | 2650 | /* AP mode uAPSD */ |
2645 | int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); | 2651 | int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); |