diff options
author | Kiran Divekar <dkiran@marvell.com> | 2010-06-04 23:20:42 -0700 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-06-23 15:14:00 -0400 |
commit | 1047d5edd4838f27dc86f24676178f2249c446ea (patch) | |
tree | 2cf140cd7ae14590367b8dccda3c8adaee754e06 /drivers/net/wireless/libertas/cfg.c | |
parent | e4fe4eafa41cf951fb8fe2b9725ae84c599668d8 (diff) | |
download | lwn-1047d5edd4838f27dc86f24676178f2249c446ea.tar.gz lwn-1047d5edd4838f27dc86f24676178f2249c446ea.zip |
Libertas: Added 11d support using cfg80211
Added 11d support for libertas driver using cfg80211. This is based on Holger
Shurig's initial work to add cfg80211 support libertas.
(https://patchwork.kernel.org/patch/64286/)
Please let us know, if there are any improvements comments.
Code is added to send 11d enable command to firmware while
initialisation and pass 11d specific information to firmware
when notifier handler is called by cfg80211.
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kiran Divekar <dkiran@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/cfg.c')
-rw-r--r-- | drivers/net/wireless/libertas/cfg.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 089f0722fa20..f36cc970ad1b 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -8,6 +8,7 @@ #include <linux/slab.h> #include <linux/if_arp.h> +#include <linux/ieee80211.h> #include <net/cfg80211.h> #include <asm/unaligned.h> @@ -2042,6 +2043,7 @@ int lbs_cfg_register(struct lbs_private *priv) */ wdev->wiphy->cipher_suites = cipher_suites; wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + wdev->wiphy->reg_notifier = lbs_reg_notifier; ret = wiphy_register(wdev->wiphy); if (ret < 0) @@ -2061,6 +2063,114 @@ int lbs_cfg_register(struct lbs_private *priv) return ret; } +/** + * @brief This function sets DOMAIN INFO to FW + * @param priv pointer to struct lbs_private + * @return 0; -1 +*/ +static int lbs_11d_set_domain_info(struct lbs_private *priv) +{ + int ret; + + ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, NULL); + if (ret) + lbs_deb_11d("fail to dnld domain info\n"); + + return ret; +} + +static void lbs_send_domain_info_cmd_fw(struct wiphy *wiphy, + struct regulatory_request *request) +{ + u8 no_of_triplet = 0; + u8 no_of_parsed_chan = 0; + u8 first_channel = 0, next_chan = 0, max_pwr = 0; + u8 i, flag = 0; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + struct lbs_private *priv = wiphy_priv(wiphy); + struct lbs_802_11d_domain_reg *domain_info = &priv->domain_reg; + int ret = 0; + + lbs_deb_enter(LBS_DEB_CFG80211); + + /* Set country code */ + domain_info->country_code[0] = request->alpha2[0]; + domain_info->country_code[1] = request->alpha2[1]; + domain_info->country_code[2] = ' '; + + for (band = 0; band < IEEE80211_NUM_BANDS ; band++) { + + if (!wiphy->bands[band]) + continue; + + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels ; i++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (!flag) { + flag = 1; + next_chan = first_channel = (u32) ch->hw_value; + max_pwr = ch->max_power; + no_of_parsed_chan = 1; + continue; + } + + if (ch->hw_value == next_chan + 1 && + ch->max_power == max_pwr) { + next_chan++; + no_of_parsed_chan++; + } else { + domain_info->triplet[no_of_triplet] + .chans.first_channel = first_channel; + domain_info->triplet[no_of_triplet] + .chans.num_channels = no_of_parsed_chan; + domain_info->triplet[no_of_triplet] + .chans.max_power = max_pwr; + no_of_triplet++; + flag = 0; + } + } + if (flag) { + domain_info->triplet[no_of_triplet] + .chans.first_channel = first_channel; + domain_info->triplet[no_of_triplet] + .chans.num_channels = no_of_parsed_chan; + domain_info->triplet[no_of_triplet] + .chans.max_power = max_pwr; + no_of_triplet++; + } + } + + domain_info->no_triplet = no_of_triplet; + + /* Set domain info */ + ret = lbs_11d_set_domain_info(priv); + if (ret) + lbs_pr_err("11D: error setting domain info in FW\n"); + + lbs_deb_leave(LBS_DEB_CFG80211); +} + +int lbs_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain " + "callback for domain %c%c\n", request->alpha2[0], + request->alpha2[1]); + + lbs_send_domain_info_cmd_fw(wiphy, request); + + lbs_deb_leave(LBS_DEB_CFG80211); + + return 0; +} void lbs_scan_deinit(struct lbs_private *priv) { |