summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/libertas/cfg.c
diff options
context:
space:
mode:
authorKiran Divekar <dkiran@marvell.com>2010-06-04 23:20:42 -0700
committerJohn W. Linville <linville@tuxdriver.com>2010-06-23 15:14:00 -0400
commit1047d5edd4838f27dc86f24676178f2249c446ea (patch)
tree2cf140cd7ae14590367b8dccda3c8adaee754e06 /drivers/net/wireless/libertas/cfg.c
parente4fe4eafa41cf951fb8fe2b9725ae84c599668d8 (diff)
downloadlwn-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.c110
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)
{