aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2010-07-27 15:56:05 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-07-27 15:07:30 -0400
commitcc4b9d3928d682c4a15690c2bd9ed11c2eac5921 (patch)
tree36bb70576b32bbdd148f4c71e54c09a0ed500042 /drivers/net/wireless
parent9fb7663d2b832183ec7558a19426666819636a64 (diff)
libertas: convert 11D_DOMAIN_INFO to a direct command
Signed-off-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/libertas/cfg.c103
-rw-r--r--drivers/net/wireless/libertas/cmd.c188
-rw-r--r--drivers/net/wireless/libertas/cmd.h6
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c51
-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.h21
7 files changed, 139 insertions, 238 deletions
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index e90c56030e39..25f902760980 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -1979,113 +1979,20 @@ int lbs_cfg_register(struct lbs_private *priv)
1979 return ret; 1979 return ret;
1980} 1980}
1981 1981
1982/**
1983 * @brief This function sets DOMAIN INFO to FW
1984 * @param priv pointer to struct lbs_private
1985 * @return 0; -1
1986*/
1987static int lbs_11d_set_domain_info(struct lbs_private *priv)
1988{
1989 int ret;
1990
1991 ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
1992 CMD_ACT_SET,
1993 CMD_OPTION_WAITFORRSP, 0, NULL);
1994 if (ret)
1995 lbs_deb_11d("fail to dnld domain info\n");
1996
1997 return ret;
1998}
1999
2000static void lbs_send_domain_info_cmd_fw(struct wiphy *wiphy,
2001 struct regulatory_request *request)
2002{
2003 u8 no_of_triplet = 0;
2004 u8 no_of_parsed_chan = 0;
2005 u8 first_channel = 0, next_chan = 0, max_pwr = 0;
2006 u8 i, flag = 0;
2007 enum ieee80211_band band;
2008 struct ieee80211_supported_band *sband;
2009 struct ieee80211_channel *ch;
2010 struct lbs_private *priv = wiphy_priv(wiphy);
2011 struct lbs_802_11d_domain_reg *domain_info = &priv->domain_reg;
2012 int ret = 0;
2013
2014 lbs_deb_enter(LBS_DEB_CFG80211);
2015
2016 /* Set country code */
2017 domain_info->country_code[0] = request->alpha2[0];
2018 domain_info->country_code[1] = request->alpha2[1];
2019 domain_info->country_code[2] = ' ';
2020
2021 for (band = 0; band < IEEE80211_NUM_BANDS ; band++) {
2022
2023 if (!wiphy->bands[band])
2024 continue;
2025
2026 sband = wiphy->bands[band];
2027
2028 for (i = 0; i < sband->n_channels ; i++) {
2029 ch = &sband->channels[i];
2030 if (ch->flags & IEEE80211_CHAN_DISABLED)
2031 continue;
2032
2033 if (!flag) {
2034 flag = 1;
2035 next_chan = first_channel = (u32) ch->hw_value;
2036 max_pwr = ch->max_power;
2037 no_of_parsed_chan = 1;
2038 continue;
2039 }
2040
2041 if (ch->hw_value == next_chan + 1 &&
2042 ch->max_power == max_pwr) {
2043 next_chan++;
2044 no_of_parsed_chan++;
2045 } else {
2046 domain_info->triplet[no_of_triplet]
2047 .chans.first_channel = first_channel;
2048 domain_info->triplet[no_of_triplet]
2049 .chans.num_channels = no_of_parsed_chan;
2050 domain_info->triplet[no_of_triplet]
2051 .chans.max_power = max_pwr;
2052 no_of_triplet++;
2053 flag = 0;
2054 }
2055 }
2056 if (flag) {
2057 domain_info->triplet[no_of_triplet]
2058 .chans.first_channel = first_channel;
2059 domain_info->triplet[no_of_triplet]
2060 .chans.num_channels = no_of_parsed_chan;
2061 domain_info->triplet[no_of_triplet]
2062 .chans.max_power = max_pwr;
2063 no_of_triplet++;
2064 }
2065 }
2066
2067 domain_info->no_triplet = no_of_triplet;
2068
2069 /* Set domain info */
2070 ret = lbs_11d_set_domain_info(priv);
2071 if (ret)
2072 lbs_pr_err("11D: error setting domain info in FW\n");
2073
2074 lbs_deb_leave(LBS_DEB_CFG80211);
2075}
2076
2077int lbs_reg_notifier(struct wiphy *wiphy, 1982int lbs_reg_notifier(struct wiphy *wiphy,
2078 struct regulatory_request *request) 1983 struct regulatory_request *request)
2079{ 1984{
1985 struct lbs_private *priv = wiphy_priv(wiphy);
1986 int ret;
1987
2080 lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain " 1988 lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
2081 "callback for domain %c%c\n", request->alpha2[0], 1989 "callback for domain %c%c\n", request->alpha2[0],
2082 request->alpha2[1]); 1990 request->alpha2[1]);
2083 1991
2084 lbs_send_domain_info_cmd_fw(wiphy, request); 1992 ret = lbs_set_11d_domain_info(priv, request, wiphy->bands);
2085 1993
2086 lbs_deb_leave(LBS_DEB_CFG80211); 1994 lbs_deb_leave(LBS_DEB_CFG80211);
2087 1995 return ret;
2088 return 0;
2089} 1996}
2090 1997
2091void lbs_scan_deinit(struct lbs_private *priv) 1998void lbs_scan_deinit(struct lbs_private *priv)
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index e95f80de7c50..2aa362fd1a96 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -725,6 +725,129 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
725 return ret; 725 return ret;
726} 726}
727 727
728/**
729 * @brief Send regulatory and 802.11d domain information to the firmware
730 *
731 * @param priv pointer to struct lbs_private
732 * @param request cfg80211 regulatory request structure
733 * @param bands the device's supported bands and channels
734 *
735 * @return 0 on success, error code on failure
736*/
737int lbs_set_11d_domain_info(struct lbs_private *priv,
738 struct regulatory_request *request,
739 struct ieee80211_supported_band **bands)
740{
741 struct cmd_ds_802_11d_domain_info cmd;
742 struct mrvl_ie_domain_param_set *domain = &cmd.domain;
743 struct ieee80211_country_ie_triplet *t;
744 enum ieee80211_band band;
745 struct ieee80211_channel *ch;
746 u8 num_triplet = 0;
747 u8 num_parsed_chan = 0;
748 u8 first_channel = 0, next_chan = 0, max_pwr = 0;
749 u8 i, flag = 0;
750 size_t triplet_size;
751 int ret;
752
753 lbs_deb_enter(LBS_DEB_11D);
754
755 memset(&cmd, 0, sizeof(cmd));
756 cmd.action = cpu_to_le16(CMD_ACT_SET);
757
758 lbs_deb_11d("Setting country code '%c%c'\n",
759 request->alpha2[0], request->alpha2[1]);
760
761 domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
762
763 /* Set country code */
764 domain->country_code[0] = request->alpha2[0];
765 domain->country_code[1] = request->alpha2[1];
766 domain->country_code[2] = ' ';
767
768 /* Now set up the channel triplets; firmware is somewhat picky here
769 * and doesn't validate channel numbers and spans; hence it would
770 * interpret a triplet of (36, 4, 20) as channels 36, 37, 38, 39. Since
771 * the last 3 aren't valid channels, the driver is responsible for
772 * splitting that up into 4 triplet pairs of (36, 1, 20) + (40, 1, 20)
773 * etc.
774 */
775 for (band = 0;
776 (band < IEEE80211_NUM_BANDS) && (num_triplet < MAX_11D_TRIPLETS);
777 band++) {
778
779 if (!bands[band])
780 continue;
781
782 for (i = 0;
783 (i < bands[band]->n_channels) && (num_triplet < MAX_11D_TRIPLETS);
784 i++) {
785 ch = &bands[band]->channels[i];
786 if (ch->flags & IEEE80211_CHAN_DISABLED)
787 continue;
788
789 if (!flag) {
790 flag = 1;
791 next_chan = first_channel = (u32) ch->hw_value;
792 max_pwr = ch->max_power;
793 num_parsed_chan = 1;
794 continue;
795 }
796
797 if ((ch->hw_value == next_chan + 1) &&
798 (ch->max_power == max_pwr)) {
799 /* Consolidate adjacent channels */
800 next_chan++;
801 num_parsed_chan++;
802 } else {
803 /* Add this triplet */
804 lbs_deb_11d("11D triplet (%d, %d, %d)\n",
805 first_channel, num_parsed_chan,
806 max_pwr);
807 t = &domain->triplet[num_triplet];
808 t->chans.first_channel = first_channel;
809 t->chans.num_channels = num_parsed_chan;
810 t->chans.max_power = max_pwr;
811 num_triplet++;
812 flag = 0;
813 }
814 }
815
816 if (flag) {
817 /* Add last triplet */
818 lbs_deb_11d("11D triplet (%d, %d, %d)\n", first_channel,
819 num_parsed_chan, max_pwr);
820 t = &domain->triplet[num_triplet];
821 t->chans.first_channel = first_channel;
822 t->chans.num_channels = num_parsed_chan;
823 t->chans.max_power = max_pwr;
824 num_triplet++;
825 }
826 }
827
828 lbs_deb_11d("# triplets %d\n", num_triplet);
829
830 /* Set command header sizes */
831 triplet_size = num_triplet * sizeof(struct ieee80211_country_ie_triplet);
832 domain->header.len = cpu_to_le16(sizeof(domain->country_code) +
833 triplet_size);
834
835 lbs_deb_hex(LBS_DEB_11D, "802.11D domain param set",
836 (u8 *) &cmd.domain.country_code,
837 le16_to_cpu(domain->header.len));
838
839 cmd.hdr.size = cpu_to_le16(sizeof(cmd.hdr) +
840 sizeof(cmd.action) +
841 sizeof(cmd.domain.header) +
842 sizeof(cmd.domain.country_code) +
843 triplet_size);
844
845 ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);
846
847 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
848 return ret;
849}
850
728static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr, 851static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
729 u8 cmd_action, void *pdata_buf) 852 u8 cmd_action, void *pdata_buf)
730{ 853{
@@ -1006,66 +1129,6 @@ void lbs_set_mac_control(struct lbs_private *priv)
1006} 1129}
1007 1130
1008/** 1131/**
1009 * @brief This function implements command CMD_802_11D_DOMAIN_INFO
1010 * @param priv pointer to struct lbs_private
1011 * @param cmd pointer to cmd buffer
1012 * @param cmdno cmd ID
1013 * @param cmdOption cmd action
1014 * @return 0
1015*/
1016int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
1017 struct cmd_ds_command *cmd,
1018 u16 cmdoption)
1019{
1020 struct cmd_ds_802_11d_domain_info *pdomaininfo =
1021 &cmd->params.domaininfo;
1022 struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
1023 u8 nr_triplet = priv->domain_reg.no_triplet;
1024
1025 lbs_deb_enter(LBS_DEB_11D);
1026
1027 lbs_deb_11d("nr_triplet=%x\n", nr_triplet);
1028
1029 pdomaininfo->action = cpu_to_le16(cmdoption);
1030 if (cmdoption == CMD_ACT_GET) {
1031 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
1032 sizeof(struct cmd_header));
1033 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
1034 le16_to_cpu(cmd->size));
1035 goto done;
1036 }
1037
1038 domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
1039 memcpy(domain->countrycode, priv->domain_reg.country_code,
1040 sizeof(domain->countrycode));
1041
1042 domain->header.len = cpu_to_le16(nr_triplet
1043 * sizeof(struct ieee80211_country_ie_triplet)
1044 + sizeof(domain->countrycode));
1045
1046 if (nr_triplet) {
1047 memcpy(domain->triplet, priv->domain_reg.triplet,
1048 nr_triplet *
1049 sizeof(struct ieee80211_country_ie_triplet));
1050
1051 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
1052 le16_to_cpu(domain->header.len) +
1053 sizeof(struct mrvl_ie_header) +
1054 sizeof(struct cmd_header));
1055 } else {
1056 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
1057 sizeof(struct cmd_header));
1058 }
1059
1060 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
1061 le16_to_cpu(cmd->size));
1062
1063done:
1064 lbs_deb_enter(LBS_DEB_11D);
1065 return 0;
1066}
1067
1068/**
1069 * @brief This function prepare the command before send to firmware. 1132 * @brief This function prepare the command before send to firmware.
1070 * 1133 *
1071 * @param priv A pointer to struct lbs_private structure 1134 * @param priv A pointer to struct lbs_private structure
@@ -1154,11 +1217,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
1154 ret = 0; 1217 ret = 0;
1155 goto done; 1218 goto done;
1156 1219
1157 case CMD_802_11D_DOMAIN_INFO:
1158 cmdptr->command = cpu_to_le16(cmd_no);
1159 ret = lbs_cmd_802_11d_domain_info(priv, cmdptr, cmd_action);
1160 break;
1161
1162 case CMD_802_11_TPC_CFG: 1220 case CMD_802_11_TPC_CFG:
1163 cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG); 1221 cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1164 cmdptr->size = 1222 cmdptr->size =
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index ec41380c4b29..2c24c1978e82 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -3,6 +3,8 @@
3#ifndef _LBS_CMD_H_ 3#ifndef _LBS_CMD_H_
4#define _LBS_CMD_H_ 4#define _LBS_CMD_H_
5 5
6#include <net/cfg80211.h>
7
6#include "host.h" 8#include "host.h"
7#include "dev.h" 9#include "dev.h"
8 10
@@ -133,4 +135,8 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable);
133 135
134int lbs_get_rssi(struct lbs_private *priv, s8 *snr, s8 *nf); 136int lbs_get_rssi(struct lbs_private *priv, s8 *snr, s8 *nf);
135 137
138int lbs_set_11d_domain_info(struct lbs_private *priv,
139 struct regulatory_request *request,
140 struct ieee80211_supported_band **bands);
141
136#endif /* _LBS_CMD_H */ 142#endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index e51957c3ae4b..35b8ceb4f09d 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -96,53 +96,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
96 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); 96 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
97 return ret; 97 return ret;
98} 98}
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 */
106static int 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
146static inline int handle_cmd_response(struct lbs_private *priv, 99static inline int handle_cmd_response(struct lbs_private *priv,
147 struct cmd_header *cmd_response) 100 struct cmd_header *cmd_response)
148{ 101{
@@ -172,10 +125,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
172 case CMD_RET(CMD_802_11_BEACON_STOP): 125 case CMD_RET(CMD_802_11_BEACON_STOP):
173 break; 126 break;
174 127
175 case CMD_RET(CMD_802_11D_DOMAIN_INFO):
176 ret = lbs_ret_802_11d_domain_info(resp);
177 break;
178
179 case CMD_RET(CMD_802_11_TPC_CFG): 128 case CMD_RET(CMD_802_11_TPC_CFG):
180 spin_lock_irqsave(&priv->driver_lock, flags); 129 spin_lock_irqsave(&priv->driver_lock, flags);
181 memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg, 130 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 ba5438a7ba17..1d141fefd767 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -53,9 +53,4 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
53u32 lbs_fw_index_to_data_rate(u8 index); 53u32 lbs_fw_index_to_data_rate(u8 index);
54u8 lbs_data_rate_to_fw_index(u32 rate); 54u8 lbs_data_rate_to_fw_index(u32 rate);
55 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);
60
61#endif 56#endif
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 4536d9c0ad87..be263acf19c4 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -60,9 +60,6 @@ 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
66 /* Hardware debugging */ 63 /* Hardware debugging */
67 u32 mac_offset; 64 u32 mac_offset;
68 u32 bbp_offset; 65 u32 bbp_offset;
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 0517ec3d4ba3..ff42a08bb2d5 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -389,30 +389,22 @@ struct lbs_offset_value {
389 u32 value; 389 u32 value;
390} __packed; 390} __packed;
391 391
392#define MRVDRV_MAX_TRIPLET_802_11D 83 392#define MAX_11D_TRIPLETS 83
393
394#define COUNTRY_CODE_LEN 3
395 393
396struct mrvl_ie_domain_param_set { 394struct mrvl_ie_domain_param_set {
397 struct mrvl_ie_header header; 395 struct mrvl_ie_header header;
398 396
399 u8 countrycode[COUNTRY_CODE_LEN]; 397 u8 country_code[3];
400 struct ieee80211_country_ie_triplet triplet[1]; 398 struct ieee80211_country_ie_triplet triplet[MAX_11D_TRIPLETS];
401} __packed; 399} __packed;
402 400
403struct cmd_ds_802_11d_domain_info { 401struct cmd_ds_802_11d_domain_info {
402 struct cmd_header hdr;
403
404 __le16 action; 404 __le16 action;
405 struct mrvl_ie_domain_param_set domain; 405 struct mrvl_ie_domain_param_set domain;
406} __packed; 406} __packed;
407 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} __packed;
415
416/* 408/*
417 * Define data structure for CMD_GET_HW_SPEC 409 * Define data structure for CMD_GET_HW_SPEC
418 * This structure defines the response for the GET_HW_SPEC command 410 * This structure defines the response for the GET_HW_SPEC command
@@ -973,9 +965,6 @@ struct cmd_ds_command {
973 struct cmd_ds_bbp_reg_access bbpreg; 965 struct cmd_ds_bbp_reg_access bbpreg;
974 struct cmd_ds_rf_reg_access rfreg; 966 struct cmd_ds_rf_reg_access rfreg;
975 967
976 struct cmd_ds_802_11d_domain_info domaininfo;
977 struct cmd_ds_802_11d_domain_info domaininforesp;
978
979 struct cmd_ds_802_11_tpc_cfg tpccfg; 968 struct cmd_ds_802_11_tpc_cfg tpccfg;
980 struct cmd_ds_802_11_afc afc; 969 struct cmd_ds_802_11_afc afc;
981 struct cmd_ds_802_11_led_ctrl ledgpio; 970 struct cmd_ds_802_11_led_ctrl ledgpio;