aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/libertas/cfg.c110
-rw-r--r--drivers/net/wireless/libertas/cfg.h5
-rw-r--r--drivers/net/wireless/libertas/cmd.c65
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c50
-rw-r--r--drivers/net/wireless/libertas/decl.h5
-rw-r--r--drivers/net/wireless/libertas/dev.h3
-rw-r--r--drivers/net/wireless/libertas/host.h28
-rw-r--r--drivers/net/wireless/libertas/main.c3
8 files changed, 268 insertions, 1 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 @@
8 8
9#include <linux/slab.h> 9#include <linux/slab.h>
10#include <linux/if_arp.h> 10#include <linux/if_arp.h>
11#include <linux/ieee80211.h>
11#include <net/cfg80211.h> 12#include <net/cfg80211.h>
12#include <asm/unaligned.h> 13#include <asm/unaligned.h>
13 14
@@ -2042,6 +2043,7 @@ int lbs_cfg_register(struct lbs_private *priv)
2042 */ 2043 */
2043 wdev->wiphy->cipher_suites = cipher_suites; 2044 wdev->wiphy->cipher_suites = cipher_suites;
2044 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); 2045 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2046 wdev->wiphy->reg_notifier = lbs_reg_notifier;
2045 2047
2046 ret = wiphy_register(wdev->wiphy); 2048 ret = wiphy_register(wdev->wiphy);
2047 if (ret < 0) 2049 if (ret < 0)
@@ -2061,6 +2063,114 @@ int lbs_cfg_register(struct lbs_private *priv)
2061 return ret; 2063 return ret;
2062} 2064}
2063 2065
2066/**
2067 * @brief This function sets DOMAIN INFO to FW
2068 * @param priv pointer to struct lbs_private
2069 * @return 0; -1
2070*/
2071static int lbs_11d_set_domain_info(struct lbs_private *priv)
2072{
2073 int ret;
2074
2075 ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
2076 CMD_ACT_SET,
2077 CMD_OPTION_WAITFORRSP, 0, NULL);
2078 if (ret)
2079 lbs_deb_11d("fail to dnld domain info\n");
2080
2081 return ret;
2082}
2083
2084static void lbs_send_domain_info_cmd_fw(struct wiphy *wiphy,
2085 struct regulatory_request *request)
2086{
2087 u8 no_of_triplet = 0;
2088 u8 no_of_parsed_chan = 0;
2089 u8 first_channel = 0, next_chan = 0, max_pwr = 0;
2090 u8 i, flag = 0;
2091 enum ieee80211_band band;
2092 struct ieee80211_supported_band *sband;
2093 struct ieee80211_channel *ch;
2094 struct lbs_private *priv = wiphy_priv(wiphy);
2095 struct lbs_802_11d_domain_reg *domain_info = &priv->domain_reg;
2096 int ret = 0;
2097
2098 lbs_deb_enter(LBS_DEB_CFG80211);
2099
2100 /* Set country code */
2101 domain_info->country_code[0] = request->alpha2[0];
2102 domain_info->country_code[1] = request->alpha2[1];
2103 domain_info->country_code[2] = ' ';
2104
2105 for (band = 0; band < IEEE80211_NUM_BANDS ; band++) {
2106
2107 if (!wiphy->bands[band])
2108 continue;
2109
2110 sband = wiphy->bands[band];
2111
2112 for (i = 0; i < sband->n_channels ; i++) {
2113 ch = &sband->channels[i];
2114 if (ch->flags & IEEE80211_CHAN_DISABLED)
2115 continue;
2116
2117 if (!flag) {
2118 flag = 1;
2119 next_chan = first_channel = (u32) ch->hw_value;
2120 max_pwr = ch->max_power;
2121 no_of_parsed_chan = 1;
2122 continue;
2123 }
2124
2125 if (ch->hw_value == next_chan + 1 &&
2126 ch->max_power == max_pwr) {
2127 next_chan++;
2128 no_of_parsed_chan++;
2129 } else {
2130 domain_info->triplet[no_of_triplet]
2131 .chans.first_channel = first_channel;
2132 domain_info->triplet[no_of_triplet]
2133 .chans.num_channels = no_of_parsed_chan;
2134 domain_info->triplet[no_of_triplet]
2135 .chans.max_power = max_pwr;
2136 no_of_triplet++;
2137 flag = 0;
2138 }
2139 }
2140 if (flag) {
2141 domain_info->triplet[no_of_triplet]
2142 .chans.first_channel = first_channel;
2143 domain_info->triplet[no_of_triplet]
2144 .chans.num_channels = no_of_parsed_chan;
2145 domain_info->triplet[no_of_triplet]
2146 .chans.max_power = max_pwr;
2147 no_of_triplet++;
2148 }
2149 }
2150
2151 domain_info->no_triplet = no_of_triplet;
2152
2153 /* Set domain info */
2154 ret = lbs_11d_set_domain_info(priv);
2155 if (ret)
2156 lbs_pr_err("11D: error setting domain info in FW\n");
2157
2158 lbs_deb_leave(LBS_DEB_CFG80211);
2159}
2160
2161int lbs_reg_notifier(struct wiphy *wiphy,
2162 struct regulatory_request *request)
2163{
2164 lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
2165 "callback for domain %c%c\n", request->alpha2[0],
2166 request->alpha2[1]);
2167
2168 lbs_send_domain_info_cmd_fw(wiphy, request);
2169
2170 lbs_deb_leave(LBS_DEB_CFG80211);
2171
2172 return 0;
2173}
2064 2174
2065void lbs_scan_deinit(struct lbs_private *priv) 2175void lbs_scan_deinit(struct lbs_private *priv)
2066{ 2176{
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index eae3fd911abb..756fb98f9f05 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -3,11 +3,16 @@
3 3
4struct device; 4struct device;
5struct lbs_private; 5struct lbs_private;
6struct regulatory_request;
7struct wiphy;
6 8
7struct wireless_dev *lbs_cfg_alloc(struct device *dev); 9struct wireless_dev *lbs_cfg_alloc(struct device *dev);
8int lbs_cfg_register(struct lbs_private *priv); 10int lbs_cfg_register(struct lbs_private *priv);
9void lbs_cfg_free(struct lbs_private *priv); 11void lbs_cfg_free(struct lbs_private *priv);
10 12
13int lbs_reg_notifier(struct wiphy *wiphy,
14 struct regulatory_request *request);
15
11/* All of those are TODOs: */ 16/* All of those are TODOs: */
12#define lbs_cmd_802_11_rssi(priv, cmdptr) (0) 17#define lbs_cmd_802_11_rssi(priv, cmdptr) (0)
13#define lbs_ret_802_11_rssi(priv, resp) (0) 18#define lbs_ret_802_11_rssi(priv, resp) (0)
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index d8838461e596..6c8a9d952a01 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -899,6 +899,66 @@ void lbs_set_mac_control(struct lbs_private *priv)
899} 899}
900 900
901/** 901/**
902 * @brief This function implements command CMD_802_11D_DOMAIN_INFO
903 * @param priv pointer to struct lbs_private
904 * @param cmd pointer to cmd buffer
905 * @param cmdno cmd ID
906 * @param cmdOption cmd action
907 * @return 0
908*/
909int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
910 struct cmd_ds_command *cmd,
911 u16 cmdoption)
912{
913 struct cmd_ds_802_11d_domain_info *pdomaininfo =
914 &cmd->params.domaininfo;
915 struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
916 u8 nr_triplet = priv->domain_reg.no_triplet;
917
918 lbs_deb_enter(LBS_DEB_11D);
919
920 lbs_deb_11d("nr_triplet=%x\n", nr_triplet);
921
922 pdomaininfo->action = cpu_to_le16(cmdoption);
923 if (cmdoption == CMD_ACT_GET) {
924 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
925 sizeof(struct cmd_header));
926 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
927 le16_to_cpu(cmd->size));
928 goto done;
929 }
930
931 domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
932 memcpy(domain->countrycode, priv->domain_reg.country_code,
933 sizeof(domain->countrycode));
934
935 domain->header.len = cpu_to_le16(nr_triplet
936 * sizeof(struct ieee80211_country_ie_triplet)
937 + sizeof(domain->countrycode));
938
939 if (nr_triplet) {
940 memcpy(domain->triplet, priv->domain_reg.triplet,
941 nr_triplet *
942 sizeof(struct ieee80211_country_ie_triplet));
943
944 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
945 le16_to_cpu(domain->header.len) +
946 sizeof(struct mrvl_ie_header) +
947 sizeof(struct cmd_header));
948 } else {
949 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
950 sizeof(struct cmd_header));
951 }
952
953 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
954 le16_to_cpu(cmd->size));
955
956done:
957 lbs_deb_enter(LBS_DEB_11D);
958 return 0;
959}
960
961/**
902 * @brief This function prepare the command before send to firmware. 962 * @brief This function prepare the command before send to firmware.
903 * 963 *
904 * @param priv A pointer to struct lbs_private structure 964 * @param priv A pointer to struct lbs_private structure
@@ -996,6 +1056,11 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
996 ret = 0; 1056 ret = 0;
997 goto done; 1057 goto done;
998 1058
1059 case CMD_802_11D_DOMAIN_INFO:
1060 cmdptr->command = cpu_to_le16(cmd_no);
1061 ret = lbs_cmd_802_11d_domain_info(priv, cmdptr, cmd_action);
1062 break;
1063
999 case CMD_802_11_TPC_CFG: 1064 case CMD_802_11_TPC_CFG:
1000 cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG); 1065 cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1001 cmdptr->size = 1066 cmdptr->size =
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 52b543c52a93..b4bc103d7970 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -97,6 +97,52 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
97 return ret; 97 return ret;
98} 98}
99 99
100/**
101 * @brief This function parses countryinfo from AP and download country info to FW
102 * @param priv pointer to struct lbs_private
103 * @param resp pointer to command response buffer
104 * @return 0; -1
105 */
106int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
107{
108 struct cmd_ds_802_11d_domain_info *domaininfo =
109 &resp->params.domaininforesp;
110 struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
111 u16 action = le16_to_cpu(domaininfo->action);
112 s16 ret = 0;
113 u8 nr_triplet = 0;
114
115 lbs_deb_enter(LBS_DEB_11D);
116
117 lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
118 (int)le16_to_cpu(resp->size));
119
120 nr_triplet = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
121 sizeof(struct ieee80211_country_ie_triplet);
122
123 lbs_deb_11d("domain info resp: nr_triplet %d\n", nr_triplet);
124
125 if (nr_triplet > MRVDRV_MAX_TRIPLET_802_11D) {
126 lbs_deb_11d("invalid number of triplets returned!!\n");
127 return -1;
128 }
129
130 switch (action) {
131 case CMD_ACT_SET: /*Proc set action */
132 break;
133
134 case CMD_ACT_GET:
135 break;
136 default:
137 lbs_deb_11d("invalid action:%d\n", domaininfo->action);
138 ret = -1;
139 break;
140 }
141
142 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
143 return ret;
144}
145
100static inline int handle_cmd_response(struct lbs_private *priv, 146static inline int handle_cmd_response(struct lbs_private *priv,
101 struct cmd_header *cmd_response) 147 struct cmd_header *cmd_response)
102{ 148{
@@ -130,6 +176,10 @@ static inline int handle_cmd_response(struct lbs_private *priv,
130 ret = lbs_ret_802_11_rssi(priv, resp); 176 ret = lbs_ret_802_11_rssi(priv, resp);
131 break; 177 break;
132 178
179 case CMD_RET(CMD_802_11D_DOMAIN_INFO):
180 ret = lbs_ret_802_11d_domain_info(resp);
181 break;
182
133 case CMD_RET(CMD_802_11_TPC_CFG): 183 case CMD_RET(CMD_802_11_TPC_CFG):
134 spin_lock_irqsave(&priv->driver_lock, flags); 184 spin_lock_irqsave(&priv->driver_lock, flags);
135 memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg, 185 memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 85c97d3ed88d..ba5438a7ba17 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -13,6 +13,7 @@
13struct lbs_private; 13struct lbs_private;
14struct sk_buff; 14struct sk_buff;
15struct net_device; 15struct net_device;
16struct cmd_ds_command;
16 17
17 18
18/* ethtool.c */ 19/* ethtool.c */
@@ -52,5 +53,9 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
52u32 lbs_fw_index_to_data_rate(u8 index); 53u32 lbs_fw_index_to_data_rate(u8 index);
53u8 lbs_data_rate_to_fw_index(u32 rate); 54u8 lbs_data_rate_to_fw_index(u32 rate);
54 55
56int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
57 struct cmd_ds_command *cmd, u16 cmdoption);
58
59int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp);
55 60
56#endif 61#endif
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index be263acf19c4..4536d9c0ad87 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -60,6 +60,9 @@ struct lbs_private {
60 struct dentry *regs_dir; 60 struct dentry *regs_dir;
61 struct dentry *debugfs_regs_files[6]; 61 struct dentry *debugfs_regs_files[6];
62 62
63 /** 11D and domain regulatory data */
64 struct lbs_802_11d_domain_reg domain_reg;
65
63 /* Hardware debugging */ 66 /* Hardware debugging */
64 u32 mac_offset; 67 u32 mac_offset;
65 u32 bbp_offset; 68 u32 bbp_offset;
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 3809c0b49464..112fbf167dc8 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -389,6 +389,30 @@ struct lbs_offset_value {
389 u32 value; 389 u32 value;
390} __attribute__ ((packed)); 390} __attribute__ ((packed));
391 391
392#define MRVDRV_MAX_TRIPLET_802_11D 83
393
394#define COUNTRY_CODE_LEN 3
395
396struct mrvl_ie_domain_param_set {
397 struct mrvl_ie_header header;
398
399 u8 countrycode[COUNTRY_CODE_LEN];
400 struct ieee80211_country_ie_triplet triplet[1];
401} __attribute__ ((packed));
402
403struct cmd_ds_802_11d_domain_info {
404 __le16 action;
405 struct mrvl_ie_domain_param_set domain;
406} __attribute__ ((packed));
407
408struct lbs_802_11d_domain_reg {
409 /** Country code*/
410 u8 country_code[COUNTRY_CODE_LEN];
411 /** No. of triplet*/
412 u8 no_triplet;
413 struct ieee80211_country_ie_triplet triplet[MRVDRV_MAX_TRIPLET_802_11D];
414} __attribute__ ((packed));
415
392/* 416/*
393 * Define data structure for CMD_GET_HW_SPEC 417 * Define data structure for CMD_GET_HW_SPEC
394 * This structure defines the response for the GET_HW_SPEC command 418 * This structure defines the response for the GET_HW_SPEC command
@@ -949,6 +973,9 @@ struct cmd_ds_command {
949 struct cmd_ds_bbp_reg_access bbpreg; 973 struct cmd_ds_bbp_reg_access bbpreg;
950 struct cmd_ds_rf_reg_access rfreg; 974 struct cmd_ds_rf_reg_access rfreg;
951 975
976 struct cmd_ds_802_11d_domain_info domaininfo;
977 struct cmd_ds_802_11d_domain_info domaininforesp;
978
952 struct cmd_ds_802_11_tpc_cfg tpccfg; 979 struct cmd_ds_802_11_tpc_cfg tpccfg;
953 struct cmd_ds_802_11_afc afc; 980 struct cmd_ds_802_11_afc afc;
954 struct cmd_ds_802_11_led_ctrl ledgpio; 981 struct cmd_ds_802_11_led_ctrl ledgpio;
@@ -958,5 +985,4 @@ struct cmd_ds_command {
958 struct cmd_ds_802_11_beacon_control bcn_ctrl; 985 struct cmd_ds_802_11_beacon_control bcn_ctrl;
959 } params; 986 } params;
960} __attribute__ ((packed)); 987} __attribute__ ((packed));
961
962#endif 988#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 58b031c52410..b519fc70f04f 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -652,6 +652,9 @@ static int lbs_setup_firmware(struct lbs_private *priv)
652 priv->txpower_max = maxlevel; 652 priv->txpower_max = maxlevel;
653 } 653 }
654 654
655 /* Send cmd to FW to enable 11D function */
656 ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1);
657
655 lbs_set_mac_control(priv); 658 lbs_set_mac_control(priv);
656done: 659done:
657 lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); 660 lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);