blob: 228e3fee20fb4d9dbc18d3a8b001df2a5982eb0d [file] [log] [blame]
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001/**
2 * This file contains the handling of command.
3 * It prepares command and sends it to firmware when it is ready.
4 */
5
6#include <net/iw_handler.h>
7#include "host.h"
8#include "hostcmd.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02009#include "decl.h"
10#include "defs.h"
11#include "dev.h"
12#include "join.h"
13#include "wext.h"
14
15static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
Holger Schurig0d61d042007-12-05 17:58:06 +010016struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
17void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
18 struct cmd_ctrl_node *ptempnode,
19 u16 wait_option, void *pdata_buf);
20
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020021
22static u16 commands_allowed_in_ps[] = {
Dan Williams0aef64d2007-08-02 11:31:18 -040023 CMD_802_11_RSSI,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020024};
25
26/**
27 * @brief This function checks if the commans is allowed
28 * in PS mode not.
29 *
30 * @param command the command ID
31 * @return TRUE or FALSE
32 */
David Woodhouse981f1872007-05-25 23:36:54 -040033static u8 is_command_allowed_in_ps(__le16 command)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020034{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020035 int i;
36
David Woodhouse981f1872007-05-25 23:36:54 -040037 for (i = 0; i < ARRAY_SIZE(commands_allowed_in_ps); i++) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020038 if (command == cpu_to_le16(commands_allowed_in_ps[i]))
39 return 1;
40 }
41
42 return 0;
43}
44
Holger Schurig69f90322007-11-23 15:43:44 +010045static int lbs_cmd_hw_spec(struct lbs_private *priv, struct cmd_ds_command *cmd)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020046{
47 struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec;
48
Holger Schurig9012b282007-05-25 11:27:16 -040049 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020050
Dan Williams0aef64d2007-08-02 11:31:18 -040051 cmd->command = cpu_to_le16(CMD_GET_HW_SPEC);
David Woodhouse981f1872007-05-25 23:36:54 -040052 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
David Woodhouseaa21c002007-12-08 20:04:36 +000053 memcpy(hwspec->permanentaddr, priv->current_addr, ETH_ALEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020054
Holger Schurig9012b282007-05-25 11:27:16 -040055 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020056 return 0;
57}
58
Holger Schurig69f90322007-11-23 15:43:44 +010059static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020060 struct cmd_ds_command *cmd,
61 u16 cmd_action)
62{
63 struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020064
Holger Schurig9012b282007-05-25 11:27:16 -040065 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020066
Dan Williams0aef64d2007-08-02 11:31:18 -040067 cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
David Woodhouse981f1872007-05-25 23:36:54 -040068 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
69 S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020070 psm->action = cpu_to_le16(cmd_action);
71 psm->multipledtim = 0;
David Woodhouse981f1872007-05-25 23:36:54 -040072 switch (cmd_action) {
Dan Williams0aef64d2007-08-02 11:31:18 -040073 case CMD_SUBCMD_ENTER_PS:
Holger Schurig9012b282007-05-25 11:27:16 -040074 lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020075
Holger Schurig252cf0d2007-08-02 13:09:34 -040076 psm->locallisteninterval = 0;
Holger Schurig97605c32007-08-02 13:09:15 -040077 psm->nullpktinterval = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020078 psm->multipledtim =
Holger Schurig56c46562007-08-02 13:09:49 -040079 cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020080 break;
81
Dan Williams0aef64d2007-08-02 11:31:18 -040082 case CMD_SUBCMD_EXIT_PS:
Holger Schurig9012b282007-05-25 11:27:16 -040083 lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020084 break;
85
Dan Williams0aef64d2007-08-02 11:31:18 -040086 case CMD_SUBCMD_SLEEP_CONFIRMED:
Holger Schurig9012b282007-05-25 11:27:16 -040087 lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020088 break;
89
90 default:
91 break;
92 }
93
Holger Schurig9012b282007-05-25 11:27:16 -040094 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020095 return 0;
96}
97
Holger Schurig69f90322007-11-23 15:43:44 +010098static int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020099 struct cmd_ds_command *cmd,
100 u16 cmd_action, void *pdata_buf)
101{
102 u16 *timeout = pdata_buf;
103
Holger Schurig8ff12da2007-08-02 11:54:31 -0400104 lbs_deb_enter(LBS_DEB_CMD);
105
Dan Williams0aef64d2007-08-02 11:31:18 -0400106 cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200107 cmd->size =
108 cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
109 + S_DS_GEN);
110
111 cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action);
112
113 if (cmd_action)
David Woodhouse981f1872007-05-25 23:36:54 -0400114 cmd->params.inactivity_timeout.timeout = cpu_to_le16(*timeout);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200115 else
116 cmd->params.inactivity_timeout.timeout = 0;
117
Holger Schurig8ff12da2007-08-02 11:54:31 -0400118 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200119 return 0;
120}
121
Holger Schurig69f90322007-11-23 15:43:44 +0100122static int lbs_cmd_802_11_sleep_params(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200123 struct cmd_ds_command *cmd,
124 u16 cmd_action)
125{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200126 struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;
127
Holger Schurig9012b282007-05-25 11:27:16 -0400128 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200129
David Woodhouse981f1872007-05-25 23:36:54 -0400130 cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
131 S_DS_GEN);
Dan Williams0aef64d2007-08-02 11:31:18 -0400132 cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200133
Dan Williams0aef64d2007-08-02 11:31:18 -0400134 if (cmd_action == CMD_ACT_GET) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000135 memset(&priv->sp, 0, sizeof(struct sleep_params));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200136 memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
137 sp->action = cpu_to_le16(cmd_action);
Dan Williams0aef64d2007-08-02 11:31:18 -0400138 } else if (cmd_action == CMD_ACT_SET) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200139 sp->action = cpu_to_le16(cmd_action);
David Woodhouseaa21c002007-12-08 20:04:36 +0000140 sp->error = cpu_to_le16(priv->sp.sp_error);
141 sp->offset = cpu_to_le16(priv->sp.sp_offset);
142 sp->stabletime = cpu_to_le16(priv->sp.sp_stabletime);
143 sp->calcontrol = (u8) priv->sp.sp_calcontrol;
144 sp->externalsleepclk = (u8) priv->sp.sp_extsleepclk;
145 sp->reserved = cpu_to_le16(priv->sp.sp_reserved);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200146 }
147
Holger Schurig9012b282007-05-25 11:27:16 -0400148 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200149 return 0;
150}
151
Holger Schurig69f90322007-11-23 15:43:44 +0100152static int lbs_cmd_802_11_set_wep(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200153 struct cmd_ds_command *cmd,
154 u32 cmd_act,
155 void * pdata_buf)
156{
157 struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200158 int ret = 0;
159 struct assoc_request * assoc_req = pdata_buf;
160
Holger Schurig9012b282007-05-25 11:27:16 -0400161 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200162
Dan Williams0aef64d2007-08-02 11:31:18 -0400163 cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
David Woodhouse981f1872007-05-25 23:36:54 -0400164 cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200165
Dan Williams0aef64d2007-08-02 11:31:18 -0400166 if (cmd_act == CMD_ACT_ADD) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200167 int i;
168
169 if (!assoc_req) {
Holger Schurig9012b282007-05-25 11:27:16 -0400170 lbs_deb_cmd("Invalid association request!");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200171 ret = -1;
172 goto done;
173 }
174
Dan Williams0aef64d2007-08-02 11:31:18 -0400175 wep->action = cpu_to_le16(CMD_ACT_ADD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200176
177 /* default tx key index */
David Woodhouse981f1872007-05-25 23:36:54 -0400178 wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
Dan Williams0aef64d2007-08-02 11:31:18 -0400179 (u32)CMD_WEP_KEY_INDEX_MASK));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200180
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200181 /* Copy key types and material to host command structure */
182 for (i = 0; i < 4; i++) {
Dan Williams1443b652007-08-02 10:45:55 -0400183 struct enc_key * pkey = &assoc_req->wep_keys[i];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200184
185 switch (pkey->len) {
186 case KEY_LEN_WEP_40:
Holger Schurig6470a892007-10-08 11:07:27 +0200187 wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200188 memmove(&wep->keymaterial[i], pkey->key,
189 pkey->len);
Holger Schurig8ff12da2007-08-02 11:54:31 -0400190 lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200191 break;
192 case KEY_LEN_WEP_104:
Holger Schurig6470a892007-10-08 11:07:27 +0200193 wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200194 memmove(&wep->keymaterial[i], pkey->key,
195 pkey->len);
Holger Schurig8ff12da2007-08-02 11:54:31 -0400196 lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200197 break;
198 case 0:
199 break;
200 default:
Holger Schurig8ff12da2007-08-02 11:54:31 -0400201 lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200202 i, pkey->len);
203 ret = -1;
204 goto done;
205 break;
206 }
207 }
Dan Williams0aef64d2007-08-02 11:31:18 -0400208 } else if (cmd_act == CMD_ACT_REMOVE) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200209 /* ACT_REMOVE clears _all_ WEP keys */
Dan Williams0aef64d2007-08-02 11:31:18 -0400210 wep->action = cpu_to_le16(CMD_ACT_REMOVE);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200211
212 /* default tx key index */
David Woodhouseaa21c002007-12-08 20:04:36 +0000213 wep->keyindex = cpu_to_le16((u16)(priv->wep_tx_keyidx &
Dan Williams0aef64d2007-08-02 11:31:18 -0400214 (u32)CMD_WEP_KEY_INDEX_MASK));
David Woodhouseaa21c002007-12-08 20:04:36 +0000215 lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200216 }
217
218 ret = 0;
219
220done:
Holger Schurig9012b282007-05-25 11:27:16 -0400221 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200222 return ret;
223}
224
Holger Schurig69f90322007-11-23 15:43:44 +0100225static int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200226 struct cmd_ds_command *cmd,
Dan Williams90a42212007-05-25 23:01:24 -0400227 u16 cmd_action,
228 void * pdata_buf)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200229{
230 struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
Dan Williams18c96c342007-06-18 12:01:12 -0400231 u32 * enable = pdata_buf;
Dan Williams90a42212007-05-25 23:01:24 -0400232
233 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200234
Dan Williams0aef64d2007-08-02 11:31:18 -0400235 cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
David Woodhouse981f1872007-05-25 23:36:54 -0400236 cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200237 penableRSN->action = cpu_to_le16(cmd_action);
Dan Williams18c96c342007-06-18 12:01:12 -0400238
Dan Williams0aef64d2007-08-02 11:31:18 -0400239 if (cmd_action == CMD_ACT_SET) {
Dan Williams18c96c342007-06-18 12:01:12 -0400240 if (*enable)
Dan Williams0aef64d2007-08-02 11:31:18 -0400241 penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
Dan Williams18c96c342007-06-18 12:01:12 -0400242 else
Dan Williams0aef64d2007-08-02 11:31:18 -0400243 penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
Holger Schurig8ff12da2007-08-02 11:54:31 -0400244 lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200245 }
246
Dan Williams90a42212007-05-25 23:01:24 -0400247 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200248 return 0;
249}
250
251
Holger Schurig3a188642007-11-26 10:07:14 +0100252static ssize_t lbs_tlv_size(const u8 *tlv, u16 size)
253{
254 ssize_t pos = 0;
255 struct mrvlietypesheader *tlv_h;
256 while (pos < size) {
257 u16 length;
258 tlv_h = (struct mrvlietypesheader *) tlv;
259 if (tlv_h->len == 0)
260 return pos;
261 length = le16_to_cpu(tlv_h->len) +
262 sizeof(struct mrvlietypesheader);
263 pos += length;
264 tlv += length;
265 }
266 return pos;
267}
268
269
270static void lbs_cmd_802_11_subscribe_event(struct lbs_private *priv,
271 struct cmd_ds_command *cmd, u16 cmd_action,
272 void *pdata_buf)
273{
274 struct cmd_ds_802_11_subscribe_event *events =
275 (struct cmd_ds_802_11_subscribe_event *) pdata_buf;
276
277 /* pdata_buf points to a struct cmd_ds_802_11_subscribe_event and room
278 * for various Marvell TLVs */
279
280 lbs_deb_enter(LBS_DEB_CMD);
281
282 cmd->size = cpu_to_le16(sizeof(*events)
283 - sizeof(events->tlv)
284 + S_DS_GEN);
285 cmd->params.subscribe_event.action = cpu_to_le16(cmd_action);
286 if (cmd_action == CMD_ACT_GET) {
287 cmd->params.subscribe_event.events = 0;
288 } else {
289 ssize_t sz = lbs_tlv_size(events->tlv, sizeof(events->tlv));
290 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + sz);
291 cmd->params.subscribe_event.events = events->events;
292 memcpy(cmd->params.subscribe_event.tlv, events->tlv, sz);
293 }
294
295 lbs_deb_leave(LBS_DEB_CMD);
296}
297
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200298static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
Dan Williams1443b652007-08-02 10:45:55 -0400299 struct enc_key * pkey)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200300{
Holger Schurig8ff12da2007-08-02 11:54:31 -0400301 lbs_deb_enter(LBS_DEB_CMD);
302
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200303 if (pkey->flags & KEY_INFO_WPA_ENABLED) {
Dan Williams90a42212007-05-25 23:01:24 -0400304 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200305 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200306 if (pkey->flags & KEY_INFO_WPA_UNICAST) {
307 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
Dan Williams90a42212007-05-25 23:01:24 -0400308 }
309 if (pkey->flags & KEY_INFO_WPA_MCAST) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200310 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
311 }
312
313 pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
Dan Williams1443b652007-08-02 10:45:55 -0400314 pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200315 pkeyparamset->keylen = cpu_to_le16(pkey->len);
316 memcpy(pkeyparamset->key, pkey->key, pkey->len);
317 pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid)
318 + sizeof(pkeyparamset->keyinfo)
319 + sizeof(pkeyparamset->keylen)
320 + sizeof(pkeyparamset->key));
Holger Schurig8ff12da2007-08-02 11:54:31 -0400321 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200322}
323
Holger Schurig69f90322007-11-23 15:43:44 +0100324static int lbs_cmd_802_11_key_material(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200325 struct cmd_ds_command *cmd,
326 u16 cmd_action,
327 u32 cmd_oid, void *pdata_buf)
328{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200329 struct cmd_ds_802_11_key_material *pkeymaterial =
330 &cmd->params.keymaterial;
Dan Williams90a42212007-05-25 23:01:24 -0400331 struct assoc_request * assoc_req = pdata_buf;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200332 int ret = 0;
333 int index = 0;
334
Holger Schurig9012b282007-05-25 11:27:16 -0400335 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200336
Dan Williams0aef64d2007-08-02 11:31:18 -0400337 cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200338 pkeymaterial->action = cpu_to_le16(cmd_action);
339
Dan Williams0aef64d2007-08-02 11:31:18 -0400340 if (cmd_action == CMD_ACT_GET) {
Dan Williams90a42212007-05-25 23:01:24 -0400341 cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200342 ret = 0;
343 goto done;
344 }
345
346 memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
347
Dan Williams90a42212007-05-25 23:01:24 -0400348 if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200349 set_one_wpa_key(&pkeymaterial->keyParamSet[index],
Dan Williams90a42212007-05-25 23:01:24 -0400350 &assoc_req->wpa_unicast_key);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200351 index++;
352 }
353
Dan Williams90a42212007-05-25 23:01:24 -0400354 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200355 set_one_wpa_key(&pkeymaterial->keyParamSet[index],
Dan Williams90a42212007-05-25 23:01:24 -0400356 &assoc_req->wpa_mcast_key);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200357 index++;
358 }
359
360 cmd->size = cpu_to_le16( S_DS_GEN
Dan Williams90a42212007-05-25 23:01:24 -0400361 + sizeof (pkeymaterial->action)
362 + (index * sizeof(struct MrvlIEtype_keyParamSet)));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200363
364 ret = 0;
365
366done:
Holger Schurig9012b282007-05-25 11:27:16 -0400367 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200368 return ret;
369}
370
Holger Schurig69f90322007-11-23 15:43:44 +0100371static int lbs_cmd_802_11_reset(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200372 struct cmd_ds_command *cmd, int cmd_action)
373{
374 struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
375
Holger Schurig8ff12da2007-08-02 11:54:31 -0400376 lbs_deb_enter(LBS_DEB_CMD);
377
Dan Williams0aef64d2007-08-02 11:31:18 -0400378 cmd->command = cpu_to_le16(CMD_802_11_RESET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200379 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
380 reset->action = cpu_to_le16(cmd_action);
381
Holger Schurig8ff12da2007-08-02 11:54:31 -0400382 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200383 return 0;
384}
385
Holger Schurig69f90322007-11-23 15:43:44 +0100386static int lbs_cmd_802_11_get_log(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200387 struct cmd_ds_command *cmd)
388{
Holger Schurig8ff12da2007-08-02 11:54:31 -0400389 lbs_deb_enter(LBS_DEB_CMD);
Dan Williams0aef64d2007-08-02 11:31:18 -0400390 cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200391 cmd->size =
392 cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
393
Holger Schurig8ff12da2007-08-02 11:54:31 -0400394 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200395 return 0;
396}
397
Holger Schurig69f90322007-11-23 15:43:44 +0100398static int lbs_cmd_802_11_get_stat(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200399 struct cmd_ds_command *cmd)
400{
Holger Schurig8ff12da2007-08-02 11:54:31 -0400401 lbs_deb_enter(LBS_DEB_CMD);
Dan Williams0aef64d2007-08-02 11:31:18 -0400402 cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200403 cmd->size =
David Woodhouse981f1872007-05-25 23:36:54 -0400404 cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200405
Holger Schurig8ff12da2007-08-02 11:54:31 -0400406 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200407 return 0;
408}
409
Holger Schurig69f90322007-11-23 15:43:44 +0100410static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200411 struct cmd_ds_command *cmd,
412 int cmd_action,
413 int cmd_oid, void *pdata_buf)
414{
415 struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200416 u8 ucTemp;
417
Holger Schurig9012b282007-05-25 11:27:16 -0400418 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200419
Holger Schurig9012b282007-05-25 11:27:16 -0400420 lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200421
Dan Williams0aef64d2007-08-02 11:31:18 -0400422 cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
David Woodhouse981f1872007-05-25 23:36:54 -0400423 cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200424
425 switch (cmd_oid) {
426 case OID_802_11_INFRASTRUCTURE_MODE:
427 {
Dan Williams0dc5a292007-05-10 22:58:02 -0400428 u8 mode = (u8) (size_t) pdata_buf;
Dan Williams0aef64d2007-08-02 11:31:18 -0400429 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
430 pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000431 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8));
Dan Williams0dc5a292007-05-10 22:58:02 -0400432 if (mode == IW_MODE_ADHOC) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200433 ucTemp = SNMP_MIB_VALUE_ADHOC;
Dan Williams0dc5a292007-05-10 22:58:02 -0400434 } else {
435 /* Infra and Auto modes */
436 ucTemp = SNMP_MIB_VALUE_INFRA;
437 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200438
439 memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));
440
441 break;
442 }
443
444 case OID_802_11D_ENABLE:
445 {
446 u32 ulTemp;
447
Dan Williams0aef64d2007-08-02 11:31:18 -0400448 pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200449
Dan Williams0aef64d2007-08-02 11:31:18 -0400450 if (cmd_action == CMD_ACT_SET) {
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000451 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
452 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200453 ulTemp = *(u32 *)pdata_buf;
David Woodhouse981f1872007-05-25 23:36:54 -0400454 *((__le16 *)(pSNMPMIB->value)) =
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200455 cpu_to_le16((u16) ulTemp);
456 }
457 break;
458 }
459
460 case OID_802_11_FRAGMENTATION_THRESHOLD:
461 {
462 u32 ulTemp;
463
Dan Williams0aef64d2007-08-02 11:31:18 -0400464 pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200465
Dan Williams0aef64d2007-08-02 11:31:18 -0400466 if (cmd_action == CMD_ACT_GET) {
467 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
468 } else if (cmd_action == CMD_ACT_SET) {
469 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
David Woodhouse981f1872007-05-25 23:36:54 -0400470 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200471 ulTemp = *((u32 *) pdata_buf);
David Woodhouse981f1872007-05-25 23:36:54 -0400472 *((__le16 *)(pSNMPMIB->value)) =
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200473 cpu_to_le16((u16) ulTemp);
474
475 }
476
477 break;
478 }
479
480 case OID_802_11_RTS_THRESHOLD:
481 {
482
483 u32 ulTemp;
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000484 pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200485
Dan Williams0aef64d2007-08-02 11:31:18 -0400486 if (cmd_action == CMD_ACT_GET) {
487 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
488 } else if (cmd_action == CMD_ACT_SET) {
489 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
David Woodhouse981f1872007-05-25 23:36:54 -0400490 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
491 ulTemp = *((u32 *)pdata_buf);
492 *(__le16 *)(pSNMPMIB->value) =
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200493 cpu_to_le16((u16) ulTemp);
494
495 }
496 break;
497 }
498 case OID_802_11_TX_RETRYCOUNT:
Dan Williams0aef64d2007-08-02 11:31:18 -0400499 pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200500
Dan Williams0aef64d2007-08-02 11:31:18 -0400501 if (cmd_action == CMD_ACT_GET) {
502 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
503 } else if (cmd_action == CMD_ACT_SET) {
504 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200505 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
David Woodhouse981f1872007-05-25 23:36:54 -0400506 *((__le16 *)(pSNMPMIB->value)) =
David Woodhouseaa21c002007-12-08 20:04:36 +0000507 cpu_to_le16((u16) priv->txretrycount);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200508 }
509
510 break;
511 default:
512 break;
513 }
514
Holger Schurig9012b282007-05-25 11:27:16 -0400515 lbs_deb_cmd(
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200516 "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
David Woodhouse981f1872007-05-25 23:36:54 -0400517 le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
518 le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200519
Holger Schurig9012b282007-05-25 11:27:16 -0400520 lbs_deb_cmd(
Holger Schurig8ff12da2007-08-02 11:54:31 -0400521 "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
David Woodhouse981f1872007-05-25 23:36:54 -0400522 le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
523 le16_to_cpu(pSNMPMIB->bufsize),
524 le16_to_cpu(*(__le16 *) pSNMPMIB->value));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200525
Holger Schurig9012b282007-05-25 11:27:16 -0400526 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200527 return 0;
528}
529
Holger Schurig69f90322007-11-23 15:43:44 +0100530static int lbs_cmd_802_11_radio_control(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200531 struct cmd_ds_command *cmd,
532 int cmd_action)
533{
David Woodhouse981f1872007-05-25 23:36:54 -0400534 struct cmd_ds_802_11_radio_control *pradiocontrol = &cmd->params.radio;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200535
Holger Schurig9012b282007-05-25 11:27:16 -0400536 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200537
538 cmd->size =
539 cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
540 S_DS_GEN);
Dan Williams0aef64d2007-08-02 11:31:18 -0400541 cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200542
543 pradiocontrol->action = cpu_to_le16(cmd_action);
544
David Woodhouseaa21c002007-12-08 20:04:36 +0000545 switch (priv->preamble) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400546 case CMD_TYPE_SHORT_PREAMBLE:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200547 pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
548 break;
549
Dan Williams0aef64d2007-08-02 11:31:18 -0400550 case CMD_TYPE_LONG_PREAMBLE:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200551 pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
552 break;
553
Dan Williams0aef64d2007-08-02 11:31:18 -0400554 case CMD_TYPE_AUTO_PREAMBLE:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200555 default:
556 pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
557 break;
558 }
559
David Woodhouseaa21c002007-12-08 20:04:36 +0000560 if (priv->radioon)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200561 pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
562 else
563 pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);
564
Holger Schurig9012b282007-05-25 11:27:16 -0400565 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200566 return 0;
567}
568
Holger Schurig69f90322007-11-23 15:43:44 +0100569static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200570 struct cmd_ds_command *cmd,
571 u16 cmd_action, void *pdata_buf)
572{
573
574 struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
575
Holger Schurig9012b282007-05-25 11:27:16 -0400576 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200577
578 cmd->size =
David Woodhouse981f1872007-05-25 23:36:54 -0400579 cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
Dan Williams0aef64d2007-08-02 11:31:18 -0400580 cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
David Woodhouse981f1872007-05-25 23:36:54 -0400581 prtp->action = cpu_to_le16(cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200582
David Woodhouse981f1872007-05-25 23:36:54 -0400583 lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n",
584 le16_to_cpu(cmd->size), le16_to_cpu(cmd->command),
585 le16_to_cpu(prtp->action));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200586
587 switch (cmd_action) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400588 case CMD_ACT_TX_POWER_OPT_GET:
589 prtp->action = cpu_to_le16(CMD_ACT_GET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200590 prtp->currentlevel = 0;
591 break;
592
Dan Williams0aef64d2007-08-02 11:31:18 -0400593 case CMD_ACT_TX_POWER_OPT_SET_HIGH:
594 prtp->action = cpu_to_le16(CMD_ACT_SET);
595 prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200596 break;
597
Dan Williams0aef64d2007-08-02 11:31:18 -0400598 case CMD_ACT_TX_POWER_OPT_SET_MID:
599 prtp->action = cpu_to_le16(CMD_ACT_SET);
600 prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200601 break;
602
Dan Williams0aef64d2007-08-02 11:31:18 -0400603 case CMD_ACT_TX_POWER_OPT_SET_LOW:
604 prtp->action = cpu_to_le16(CMD_ACT_SET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200605 prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
606 break;
607 }
Holger Schurig9012b282007-05-25 11:27:16 -0400608
609 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200610 return 0;
611}
612
Holger Schurig69f90322007-11-23 15:43:44 +0100613static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv,
Luis Carlos Cobo965f8bbc2007-08-02 13:16:55 -0400614 struct cmd_ds_command *cmd,
615 u16 cmd_action, void *pdata_buf)
616{
617 struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;
618
619 cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
620 cmd->size =
621 cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
622 S_DS_GEN);
623
624 monitor->action = cpu_to_le16(cmd_action);
625 if (cmd_action == CMD_ACT_SET) {
626 monitor->mode =
627 cpu_to_le16((u16) (*(u32 *) pdata_buf));
628 }
629
630 return 0;
631}
632
Holger Schurig69f90322007-11-23 15:43:44 +0100633static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200634 struct cmd_ds_command *cmd,
635 u16 cmd_action)
636{
637 struct cmd_ds_802_11_rate_adapt_rateset
638 *rateadapt = &cmd->params.rateset;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200639
Holger Schurig8ff12da2007-08-02 11:54:31 -0400640 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200641 cmd->size =
642 cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
643 + S_DS_GEN);
Dan Williams0aef64d2007-08-02 11:31:18 -0400644 cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200645
David Woodhouse981f1872007-05-25 23:36:54 -0400646 rateadapt->action = cpu_to_le16(cmd_action);
David Woodhouseaa21c002007-12-08 20:04:36 +0000647 rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
648 rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200649
Holger Schurig9012b282007-05-25 11:27:16 -0400650 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200651 return 0;
652}
653
Holger Schurig69f90322007-11-23 15:43:44 +0100654static int lbs_cmd_802_11_data_rate(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200655 struct cmd_ds_command *cmd,
656 u16 cmd_action)
657{
658 struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200659
Holger Schurig9012b282007-05-25 11:27:16 -0400660 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200661
David Woodhouse981f1872007-05-25 23:36:54 -0400662 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200663 S_DS_GEN);
Dan Williams0aef64d2007-08-02 11:31:18 -0400664 cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200665 memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200666 pdatarate->action = cpu_to_le16(cmd_action);
667
Dan Williamsffcae952007-08-02 11:35:46 -0400668 if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000669 pdatarate->rates[0] = lbs_data_rate_to_fw_index(priv->cur_rate);
Holger Schurig8ff12da2007-08-02 11:54:31 -0400670 lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n",
David Woodhouseaa21c002007-12-08 20:04:36 +0000671 priv->cur_rate);
Dan Williamsffcae952007-08-02 11:35:46 -0400672 } else if (cmd_action == CMD_ACT_SET_TX_AUTO) {
Holger Schurig8ff12da2007-08-02 11:54:31 -0400673 lbs_deb_cmd("DATA_RATE: setting auto\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200674 }
675
Holger Schurig9012b282007-05-25 11:27:16 -0400676 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200677 return 0;
678}
679
Holger Schurig69f90322007-11-23 15:43:44 +0100680static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200681 struct cmd_ds_command *cmd,
682 u16 cmd_action)
683{
684 struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200685
Holger Schurig8ff12da2007-08-02 11:54:31 -0400686 lbs_deb_enter(LBS_DEB_CMD);
David Woodhouse981f1872007-05-25 23:36:54 -0400687 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200688 S_DS_GEN);
Dan Williams0aef64d2007-08-02 11:31:18 -0400689 cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200690
Holger Schurig8ff12da2007-08-02 11:54:31 -0400691 lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200692 pMCastAdr->action = cpu_to_le16(cmd_action);
693 pMCastAdr->nr_of_adrs =
David Woodhouseaa21c002007-12-08 20:04:36 +0000694 cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
695 memcpy(pMCastAdr->maclist, priv->multicastlist,
696 priv->nr_of_multicastmacaddr * ETH_ALEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200697
Holger Schurig8ff12da2007-08-02 11:54:31 -0400698 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200699 return 0;
700}
701
Holger Schurig69f90322007-11-23 15:43:44 +0100702static int lbs_cmd_802_11_rf_channel(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200703 struct cmd_ds_command *cmd,
704 int option, void *pdata_buf)
705{
706 struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
707
Holger Schurig8ff12da2007-08-02 11:54:31 -0400708 lbs_deb_enter(LBS_DEB_CMD);
Dan Williams0aef64d2007-08-02 11:31:18 -0400709 cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL);
David Woodhouse981f1872007-05-25 23:36:54 -0400710 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) +
711 S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200712
Dan Williams0aef64d2007-08-02 11:31:18 -0400713 if (option == CMD_OPT_802_11_RF_CHANNEL_SET) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200714 rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
715 }
716
717 rfchan->action = cpu_to_le16(option);
718
Holger Schurig8ff12da2007-08-02 11:54:31 -0400719 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200720 return 0;
721}
722
Holger Schurig69f90322007-11-23 15:43:44 +0100723static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200724 struct cmd_ds_command *cmd)
725{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200726
Holger Schurig8ff12da2007-08-02 11:54:31 -0400727 lbs_deb_enter(LBS_DEB_CMD);
Dan Williams0aef64d2007-08-02 11:31:18 -0400728 cmd->command = cpu_to_le16(CMD_802_11_RSSI);
David Woodhouse981f1872007-05-25 23:36:54 -0400729 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
Holger Schuriga783f1e2007-08-02 13:08:24 -0400730 cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200731
732 /* reset Beacon SNR/NF/RSSI values */
David Woodhouseaa21c002007-12-08 20:04:36 +0000733 priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
734 priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
735 priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
736 priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
737 priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
738 priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200739
Holger Schurig8ff12da2007-08-02 11:54:31 -0400740 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200741 return 0;
742}
743
Holger Schurig69f90322007-11-23 15:43:44 +0100744static int lbs_cmd_reg_access(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200745 struct cmd_ds_command *cmdptr,
746 u8 cmd_action, void *pdata_buf)
747{
Holger Schurig10078322007-11-15 18:05:47 -0500748 struct lbs_offset_value *offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200749
Holger Schurig9012b282007-05-25 11:27:16 -0400750 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200751
Holger Schurig10078322007-11-15 18:05:47 -0500752 offval = (struct lbs_offset_value *)pdata_buf;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200753
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000754 switch (le16_to_cpu(cmdptr->command)) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400755 case CMD_MAC_REG_ACCESS:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200756 {
757 struct cmd_ds_mac_reg_access *macreg;
758
759 cmdptr->size =
David Woodhouse981f1872007-05-25 23:36:54 -0400760 cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
761 + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200762 macreg =
763 (struct cmd_ds_mac_reg_access *)&cmdptr->params.
764 macreg;
765
766 macreg->action = cpu_to_le16(cmd_action);
767 macreg->offset = cpu_to_le16((u16) offval->offset);
768 macreg->value = cpu_to_le32(offval->value);
769
770 break;
771 }
772
Dan Williams0aef64d2007-08-02 11:31:18 -0400773 case CMD_BBP_REG_ACCESS:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200774 {
775 struct cmd_ds_bbp_reg_access *bbpreg;
776
777 cmdptr->size =
778 cpu_to_le16(sizeof
779 (struct cmd_ds_bbp_reg_access)
780 + S_DS_GEN);
781 bbpreg =
782 (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
783 bbpreg;
784
785 bbpreg->action = cpu_to_le16(cmd_action);
786 bbpreg->offset = cpu_to_le16((u16) offval->offset);
787 bbpreg->value = (u8) offval->value;
788
789 break;
790 }
791
Dan Williams0aef64d2007-08-02 11:31:18 -0400792 case CMD_RF_REG_ACCESS:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200793 {
794 struct cmd_ds_rf_reg_access *rfreg;
795
796 cmdptr->size =
797 cpu_to_le16(sizeof
798 (struct cmd_ds_rf_reg_access) +
799 S_DS_GEN);
800 rfreg =
801 (struct cmd_ds_rf_reg_access *)&cmdptr->params.
802 rfreg;
803
804 rfreg->action = cpu_to_le16(cmd_action);
805 rfreg->offset = cpu_to_le16((u16) offval->offset);
806 rfreg->value = (u8) offval->value;
807
808 break;
809 }
810
811 default:
812 break;
813 }
814
Holger Schurig9012b282007-05-25 11:27:16 -0400815 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200816 return 0;
817}
818
Holger Schurig69f90322007-11-23 15:43:44 +0100819static int lbs_cmd_802_11_mac_address(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200820 struct cmd_ds_command *cmd,
821 u16 cmd_action)
822{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200823
Holger Schurig8ff12da2007-08-02 11:54:31 -0400824 lbs_deb_enter(LBS_DEB_CMD);
Dan Williams0aef64d2007-08-02 11:31:18 -0400825 cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
David Woodhouse981f1872007-05-25 23:36:54 -0400826 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200827 S_DS_GEN);
828 cmd->result = 0;
829
830 cmd->params.macadd.action = cpu_to_le16(cmd_action);
831
Dan Williams0aef64d2007-08-02 11:31:18 -0400832 if (cmd_action == CMD_ACT_SET) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200833 memcpy(cmd->params.macadd.macadd,
David Woodhouseaa21c002007-12-08 20:04:36 +0000834 priv->current_addr, ETH_ALEN);
835 lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200836 }
837
Holger Schurig8ff12da2007-08-02 11:54:31 -0400838 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200839 return 0;
840}
841
Holger Schurig69f90322007-11-23 15:43:44 +0100842static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200843 struct cmd_ds_command *cmd,
844 int cmd_action, void *pdata_buf)
845{
Holger Schurig10078322007-11-15 18:05:47 -0500846 struct lbs_ioctl_regrdwr *ea = pdata_buf;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200847
Holger Schurig9012b282007-05-25 11:27:16 -0400848 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200849
Dan Williams0aef64d2007-08-02 11:31:18 -0400850 cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
David Woodhouse981f1872007-05-25 23:36:54 -0400851 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
852 S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200853 cmd->result = 0;
854
855 cmd->params.rdeeprom.action = cpu_to_le16(ea->action);
856 cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset);
857 cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
858 cmd->params.rdeeprom.value = 0;
859
Holger Schurig8ff12da2007-08-02 11:54:31 -0400860 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200861 return 0;
862}
863
Holger Schurig69f90322007-11-23 15:43:44 +0100864static int lbs_cmd_bt_access(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200865 struct cmd_ds_command *cmd,
866 u16 cmd_action, void *pdata_buf)
867{
868 struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
Holger Schurig8ff12da2007-08-02 11:54:31 -0400869 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200870
Dan Williams0aef64d2007-08-02 11:31:18 -0400871 cmd->command = cpu_to_le16(CMD_BT_ACCESS);
David Woodhouse981f1872007-05-25 23:36:54 -0400872 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200873 cmd->result = 0;
874 bt_access->action = cpu_to_le16(cmd_action);
875
876 switch (cmd_action) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400877 case CMD_ACT_BT_ACCESS_ADD:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200878 memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
Holger Schurigece56192007-08-02 11:53:06 -0400879 lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200880 break;
Dan Williams0aef64d2007-08-02 11:31:18 -0400881 case CMD_ACT_BT_ACCESS_DEL:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200882 memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
Holger Schurigece56192007-08-02 11:53:06 -0400883 lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200884 break;
Dan Williams0aef64d2007-08-02 11:31:18 -0400885 case CMD_ACT_BT_ACCESS_LIST:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200886 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
887 break;
Dan Williams0aef64d2007-08-02 11:31:18 -0400888 case CMD_ACT_BT_ACCESS_RESET:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200889 break;
Dan Williams0aef64d2007-08-02 11:31:18 -0400890 case CMD_ACT_BT_ACCESS_SET_INVERT:
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -0400891 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
892 break;
Dan Williams0aef64d2007-08-02 11:31:18 -0400893 case CMD_ACT_BT_ACCESS_GET_INVERT:
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -0400894 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200895 default:
896 break;
897 }
Holger Schurig8ff12da2007-08-02 11:54:31 -0400898 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200899 return 0;
900}
901
Holger Schurig69f90322007-11-23 15:43:44 +0100902static int lbs_cmd_fwt_access(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200903 struct cmd_ds_command *cmd,
904 u16 cmd_action, void *pdata_buf)
905{
906 struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
Holger Schurig8ff12da2007-08-02 11:54:31 -0400907 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200908
Dan Williams0aef64d2007-08-02 11:31:18 -0400909 cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
David Woodhouse981f1872007-05-25 23:36:54 -0400910 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200911 cmd->result = 0;
912
913 if (pdata_buf)
914 memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
915 else
916 memset(fwt_access, 0, sizeof(*fwt_access));
917
918 fwt_access->action = cpu_to_le16(cmd_action);
919
Holger Schurig8ff12da2007-08-02 11:54:31 -0400920 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200921 return 0;
922}
923
Holger Schurig69f90322007-11-23 15:43:44 +0100924static int lbs_cmd_mesh_access(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200925 struct cmd_ds_command *cmd,
926 u16 cmd_action, void *pdata_buf)
927{
928 struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
Holger Schurig8ff12da2007-08-02 11:54:31 -0400929 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200930
Dan Williams0aef64d2007-08-02 11:31:18 -0400931 cmd->command = cpu_to_le16(CMD_MESH_ACCESS);
David Woodhouse981f1872007-05-25 23:36:54 -0400932 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200933 cmd->result = 0;
934
935 if (pdata_buf)
936 memcpy(mesh_access, pdata_buf, sizeof(*mesh_access));
937 else
938 memset(mesh_access, 0, sizeof(*mesh_access));
939
940 mesh_access->action = cpu_to_le16(cmd_action);
941
Holger Schurig8ff12da2007-08-02 11:54:31 -0400942 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200943 return 0;
944}
945
Brajesh Dave96287ac2007-11-20 17:44:28 -0500946static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
947 struct cmd_ds_command *cmd,
948 u16 cmd_action)
949{
950 struct cmd_ds_802_11_beacon_control
951 *bcn_ctrl = &cmd->params.bcn_ctrl;
Brajesh Dave96287ac2007-11-20 17:44:28 -0500952
953 lbs_deb_enter(LBS_DEB_CMD);
954 cmd->size =
955 cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
956 + S_DS_GEN);
957 cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
958
959 bcn_ctrl->action = cpu_to_le16(cmd_action);
David Woodhouseaa21c002007-12-08 20:04:36 +0000960 bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
961 bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
Brajesh Dave96287ac2007-11-20 17:44:28 -0500962
963 lbs_deb_leave(LBS_DEB_CMD);
964 return 0;
965}
966
Marcelo Tosatti29f5f2a2007-10-30 10:52:46 -0400967/*
Holger Schurig10078322007-11-15 18:05:47 -0500968 * Note: NEVER use lbs_queue_cmd() with addtail==0 other than for
Marcelo Tosatti29f5f2a2007-10-30 10:52:46 -0400969 * the command timer, because it does not account for queued commands.
970 */
David Woodhouseaa21c002007-12-08 20:04:36 +0000971void lbs_queue_cmd(struct lbs_private *priv,
Holger Schurig69f90322007-11-23 15:43:44 +0100972 struct cmd_ctrl_node *cmdnode,
973 u8 addtail)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200974{
975 unsigned long flags;
976 struct cmd_ds_command *cmdptr;
977
Holger Schurig8ff12da2007-08-02 11:54:31 -0400978 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200979
980 if (!cmdnode) {
Holger Schurig8ff12da2007-08-02 11:54:31 -0400981 lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200982 goto done;
983 }
984
985 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
986 if (!cmdptr) {
Holger Schurig8ff12da2007-08-02 11:54:31 -0400987 lbs_deb_host("QUEUE_CMD: cmdptr is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200988 goto done;
989 }
990
991 /* Exit_PS command needs to be queued in the header always. */
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000992 if (le16_to_cpu(cmdptr->command) == CMD_802_11_PS_MODE) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200993 struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
Dan Williams0aef64d2007-08-02 11:31:18 -0400994 if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000995 if (priv->psstate != PS_STATE_FULL_POWER)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200996 addtail = 0;
997 }
998 }
999
David Woodhouseaa21c002007-12-08 20:04:36 +00001000 spin_lock_irqsave(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001001
David Woodhouseac472462007-12-08 00:35:00 +00001002 if (addtail)
David Woodhouseaa21c002007-12-08 20:04:36 +00001003 list_add_tail(&cmdnode->list, &priv->cmdpendingq);
David Woodhouseac472462007-12-08 00:35:00 +00001004 else
David Woodhouseaa21c002007-12-08 20:04:36 +00001005 list_add(&cmdnode->list, &priv->cmdpendingq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001006
David Woodhouseaa21c002007-12-08 20:04:36 +00001007 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001008
Holger Schurig8ff12da2007-08-02 11:54:31 -04001009 lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
David Woodhouse981f1872007-05-25 23:36:54 -04001010 le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001011
1012done:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001013 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001014}
1015
1016/*
1017 * TODO: Fix the issue when DownloadcommandToStation is being called the
Holger Schurig8ff12da2007-08-02 11:54:31 -04001018 * second time when the command times out. All the cmdptr->xxx are in little
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001019 * endian and therefore all the comparissions will fail.
1020 * For now - we are not performing the endian conversion the second time - but
1021 * for PS and DEEP_SLEEP we need to worry
1022 */
Holger Schurig69f90322007-11-23 15:43:44 +01001023static int DownloadcommandToStation(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001024 struct cmd_ctrl_node *cmdnode)
1025{
1026 unsigned long flags;
1027 struct cmd_ds_command *cmdptr;
Eugene Teob031ac12007-08-02 13:18:07 -04001028 int ret = -1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001029 u16 cmdsize;
1030 u16 command;
1031
Holger Schurig8ff12da2007-08-02 11:54:31 -04001032 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001033
David Woodhouseaa21c002007-12-08 20:04:36 +00001034 if (!priv || !cmdnode) {
1035 lbs_deb_host("DNLD_CMD: priv or cmdmode is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001036 goto done;
1037 }
1038
1039 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
1040
David Woodhouseaa21c002007-12-08 20:04:36 +00001041 spin_lock_irqsave(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001042 if (!cmdptr || !cmdptr->size) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001043 lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n");
Holger Schurig10078322007-11-15 18:05:47 -05001044 __lbs_cleanup_and_insert_cmd(priv, cmdnode);
David Woodhouseaa21c002007-12-08 20:04:36 +00001045 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001046 goto done;
1047 }
1048
David Woodhouseaa21c002007-12-08 20:04:36 +00001049 priv->cur_cmd = cmdnode;
1050 priv->cur_cmd_retcode = 0;
1051 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001052
Holger Schurigc2df2ef2007-12-07 15:30:44 +00001053 cmdsize = le16_to_cpu(cmdptr->size);
1054 command = le16_to_cpu(cmdptr->command);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001055
Holger Schurig8ff12da2007-08-02 11:54:31 -04001056 lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n",
Holger Schurigc2df2ef2007-12-07 15:30:44 +00001057 command, cmdsize, jiffies);
Holger Schurig8ff12da2007-08-02 11:54:31 -04001058 lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize);
1059
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001060 cmdnode->cmdwaitqwoken = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001061
Holger Schurig208fdd22007-05-25 12:17:06 -04001062 ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001063
1064 if (ret != 0) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001065 lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n");
David Woodhouseaa21c002007-12-08 20:04:36 +00001066 spin_lock_irqsave(&priv->driver_lock, flags);
1067 priv->cur_cmd_retcode = ret;
1068 __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
1069 priv->cur_cmd = NULL;
1070 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001071 goto done;
1072 }
1073
Holger Schurig8ff12da2007-08-02 11:54:31 -04001074 lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001075
1076 /* Setup the timer after transmit command */
Dan Williams0aef64d2007-08-02 11:31:18 -04001077 if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
1078 || command == CMD_802_11_ASSOCIATE)
David Woodhouseaa21c002007-12-08 20:04:36 +00001079 mod_timer(&priv->command_timer, jiffies + (10*HZ));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001080 else
David Woodhouseaa21c002007-12-08 20:04:36 +00001081 mod_timer(&priv->command_timer, jiffies + (5*HZ));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001082
1083 ret = 0;
1084
Holger Schurig9012b282007-05-25 11:27:16 -04001085done:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001086 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001087 return ret;
1088}
1089
Holger Schurig69f90322007-11-23 15:43:44 +01001090static int lbs_cmd_mac_control(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001091 struct cmd_ds_command *cmd)
1092{
1093 struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
1094
Holger Schurig9012b282007-05-25 11:27:16 -04001095 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001096
Dan Williams0aef64d2007-08-02 11:31:18 -04001097 cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
David Woodhouse981f1872007-05-25 23:36:54 -04001098 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
David Woodhouseaa21c002007-12-08 20:04:36 +00001099 mac->action = cpu_to_le16(priv->currentpacketfilter);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001100
Holger Schurig8ff12da2007-08-02 11:54:31 -04001101 lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
David Woodhouse981f1872007-05-25 23:36:54 -04001102 le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001103
Holger Schurig9012b282007-05-25 11:27:16 -04001104 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001105 return 0;
1106}
1107
1108/**
1109 * This function inserts command node to cmdfreeq
David Woodhouseaa21c002007-12-08 20:04:36 +00001110 * after cleans it. Requires priv->driver_lock held.
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001111 */
Holger Schurig69f90322007-11-23 15:43:44 +01001112void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1113 struct cmd_ctrl_node *ptempcmd)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001114{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001115
1116 if (!ptempcmd)
Holger Schurig8ff12da2007-08-02 11:54:31 -04001117 return;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001118
1119 cleanup_cmdnode(ptempcmd);
David Woodhouseaa21c002007-12-08 20:04:36 +00001120 list_add_tail(&ptempcmd->list, &priv->cmdfreeq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001121}
1122
Holger Schurig69f90322007-11-23 15:43:44 +01001123static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1124 struct cmd_ctrl_node *ptempcmd)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001125{
1126 unsigned long flags;
1127
David Woodhouseaa21c002007-12-08 20:04:36 +00001128 spin_lock_irqsave(&priv->driver_lock, flags);
Holger Schurig10078322007-11-15 18:05:47 -05001129 __lbs_cleanup_and_insert_cmd(priv, ptempcmd);
David Woodhouseaa21c002007-12-08 20:04:36 +00001130 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001131}
1132
Holger Schurig69f90322007-11-23 15:43:44 +01001133int lbs_set_radio_control(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001134{
1135 int ret = 0;
1136
Holger Schurig9012b282007-05-25 11:27:16 -04001137 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001138
Holger Schurig10078322007-11-15 18:05:47 -05001139 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -04001140 CMD_802_11_RADIO_CONTROL,
1141 CMD_ACT_SET,
1142 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001143
Holger Schurig8ff12da2007-08-02 11:54:31 -04001144 lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +00001145 priv->radioon, priv->preamble);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001146
Holger Schurig9012b282007-05-25 11:27:16 -04001147 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001148 return ret;
1149}
1150
Holger Schurig69f90322007-11-23 15:43:44 +01001151int lbs_set_mac_packet_filter(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001152{
1153 int ret = 0;
1154
Holger Schurig9012b282007-05-25 11:27:16 -04001155 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001156
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001157 /* Send MAC control command to station */
Holger Schurig10078322007-11-15 18:05:47 -05001158 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -04001159 CMD_MAC_CONTROL, 0, 0, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001160
Holger Schurig9012b282007-05-25 11:27:16 -04001161 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001162 return ret;
1163}
1164
1165/**
1166 * @brief This function prepare the command before send to firmware.
1167 *
Holger Schurig69f90322007-11-23 15:43:44 +01001168 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001169 * @param cmd_no command number
1170 * @param cmd_action command action: GET or SET
1171 * @param wait_option wait option: wait response or not
1172 * @param cmd_oid cmd oid: treated as sub command
1173 * @param pdata_buf A pointer to informaion buffer
1174 * @return 0 or -1
1175 */
Holger Schurig69f90322007-11-23 15:43:44 +01001176int lbs_prepare_and_send_command(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001177 u16 cmd_no,
1178 u16 cmd_action,
1179 u16 wait_option, u32 cmd_oid, void *pdata_buf)
1180{
1181 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001182 struct cmd_ctrl_node *cmdnode;
1183 struct cmd_ds_command *cmdptr;
1184 unsigned long flags;
1185
Holger Schurig8ff12da2007-08-02 11:54:31 -04001186 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001187
David Woodhouseaa21c002007-12-08 20:04:36 +00001188 if (!priv) {
1189 lbs_deb_host("PREP_CMD: priv is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001190 ret = -1;
1191 goto done;
1192 }
1193
David Woodhouseaa21c002007-12-08 20:04:36 +00001194 if (priv->surpriseremoved) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001195 lbs_deb_host("PREP_CMD: card removed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001196 ret = -1;
1197 goto done;
1198 }
1199
Holger Schurig0d61d042007-12-05 17:58:06 +01001200 cmdnode = lbs_get_cmd_ctrl_node(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001201
1202 if (cmdnode == NULL) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001203 lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001204
1205 /* Wake up main thread to execute next command */
Dan Williamsfe336152007-08-02 11:32:25 -04001206 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001207 ret = -1;
1208 goto done;
1209 }
1210
David Woodhousef5ece8f2007-12-01 15:15:41 +00001211 lbs_set_cmd_ctrl_node(priv, cmdnode, wait_option, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001212
1213 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
1214
Holger Schurig8ff12da2007-08-02 11:54:31 -04001215 lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001216
1217 if (!cmdptr) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001218 lbs_deb_host("PREP_CMD: cmdptr is NULL\n");
Holger Schurig10078322007-11-15 18:05:47 -05001219 lbs_cleanup_and_insert_cmd(priv, cmdnode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001220 ret = -1;
1221 goto done;
1222 }
1223
1224 /* Set sequence number, command and INT option */
David Woodhouseaa21c002007-12-08 20:04:36 +00001225 priv->seqnum++;
1226 cmdptr->seqnum = cpu_to_le16(priv->seqnum);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001227
David Woodhouse981f1872007-05-25 23:36:54 -04001228 cmdptr->command = cpu_to_le16(cmd_no);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001229 cmdptr->result = 0;
1230
1231 switch (cmd_no) {
Dan Williams0aef64d2007-08-02 11:31:18 -04001232 case CMD_GET_HW_SPEC:
Holger Schurig10078322007-11-15 18:05:47 -05001233 ret = lbs_cmd_hw_spec(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001234 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001235 case CMD_802_11_PS_MODE:
Holger Schurig10078322007-11-15 18:05:47 -05001236 ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001237 break;
1238
Dan Williams0aef64d2007-08-02 11:31:18 -04001239 case CMD_802_11_SCAN:
Holger Schurig10078322007-11-15 18:05:47 -05001240 ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001241 break;
1242
Dan Williams0aef64d2007-08-02 11:31:18 -04001243 case CMD_MAC_CONTROL:
Holger Schurig10078322007-11-15 18:05:47 -05001244 ret = lbs_cmd_mac_control(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001245 break;
1246
Dan Williams0aef64d2007-08-02 11:31:18 -04001247 case CMD_802_11_ASSOCIATE:
1248 case CMD_802_11_REASSOCIATE:
Holger Schurig10078322007-11-15 18:05:47 -05001249 ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001250 break;
1251
Dan Williams0aef64d2007-08-02 11:31:18 -04001252 case CMD_802_11_DEAUTHENTICATE:
Holger Schurig10078322007-11-15 18:05:47 -05001253 ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001254 break;
1255
Dan Williams0aef64d2007-08-02 11:31:18 -04001256 case CMD_802_11_SET_WEP:
Holger Schurig10078322007-11-15 18:05:47 -05001257 ret = lbs_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001258 break;
1259
Dan Williams0aef64d2007-08-02 11:31:18 -04001260 case CMD_802_11_AD_HOC_START:
Holger Schurig10078322007-11-15 18:05:47 -05001261 ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001262 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001263 case CMD_CODE_DNLD:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001264 break;
1265
Dan Williams0aef64d2007-08-02 11:31:18 -04001266 case CMD_802_11_RESET:
Holger Schurig10078322007-11-15 18:05:47 -05001267 ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001268 break;
1269
Dan Williams0aef64d2007-08-02 11:31:18 -04001270 case CMD_802_11_GET_LOG:
Holger Schurig10078322007-11-15 18:05:47 -05001271 ret = lbs_cmd_802_11_get_log(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001272 break;
1273
Dan Williams0aef64d2007-08-02 11:31:18 -04001274 case CMD_802_11_AUTHENTICATE:
Holger Schurig10078322007-11-15 18:05:47 -05001275 ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001276 break;
1277
Dan Williams0aef64d2007-08-02 11:31:18 -04001278 case CMD_802_11_GET_STAT:
Holger Schurig10078322007-11-15 18:05:47 -05001279 ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001280 break;
1281
Dan Williams0aef64d2007-08-02 11:31:18 -04001282 case CMD_802_11_SNMP_MIB:
Holger Schurig10078322007-11-15 18:05:47 -05001283 ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001284 cmd_action, cmd_oid, pdata_buf);
1285 break;
1286
Dan Williams0aef64d2007-08-02 11:31:18 -04001287 case CMD_MAC_REG_ACCESS:
1288 case CMD_BBP_REG_ACCESS:
1289 case CMD_RF_REG_ACCESS:
Holger Schurig10078322007-11-15 18:05:47 -05001290 ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001291 break;
1292
Dan Williams0aef64d2007-08-02 11:31:18 -04001293 case CMD_802_11_RF_CHANNEL:
Holger Schurig10078322007-11-15 18:05:47 -05001294 ret = lbs_cmd_802_11_rf_channel(priv, cmdptr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001295 cmd_action, pdata_buf);
1296 break;
1297
Dan Williams0aef64d2007-08-02 11:31:18 -04001298 case CMD_802_11_RF_TX_POWER:
Holger Schurig10078322007-11-15 18:05:47 -05001299 ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001300 cmd_action, pdata_buf);
1301 break;
1302
Dan Williams0aef64d2007-08-02 11:31:18 -04001303 case CMD_802_11_RADIO_CONTROL:
Holger Schurig10078322007-11-15 18:05:47 -05001304 ret = lbs_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001305 break;
1306
Dan Williams0aef64d2007-08-02 11:31:18 -04001307 case CMD_802_11_DATA_RATE:
Holger Schurig10078322007-11-15 18:05:47 -05001308 ret = lbs_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001309 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001310 case CMD_802_11_RATE_ADAPT_RATESET:
Holger Schurig10078322007-11-15 18:05:47 -05001311 ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001312 cmdptr, cmd_action);
1313 break;
1314
Dan Williams0aef64d2007-08-02 11:31:18 -04001315 case CMD_MAC_MULTICAST_ADR:
Holger Schurig10078322007-11-15 18:05:47 -05001316 ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001317 break;
1318
Luis Carlos Cobo965f8bbc2007-08-02 13:16:55 -04001319 case CMD_802_11_MONITOR_MODE:
Holger Schurig10078322007-11-15 18:05:47 -05001320 ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
Luis Carlos Cobo965f8bbc2007-08-02 13:16:55 -04001321 cmd_action, pdata_buf);
1322 break;
1323
Dan Williams0aef64d2007-08-02 11:31:18 -04001324 case CMD_802_11_AD_HOC_JOIN:
Holger Schurig10078322007-11-15 18:05:47 -05001325 ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001326 break;
1327
Dan Williams0aef64d2007-08-02 11:31:18 -04001328 case CMD_802_11_RSSI:
Holger Schurig10078322007-11-15 18:05:47 -05001329 ret = lbs_cmd_802_11_rssi(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001330 break;
1331
Dan Williams0aef64d2007-08-02 11:31:18 -04001332 case CMD_802_11_AD_HOC_STOP:
Holger Schurig10078322007-11-15 18:05:47 -05001333 ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001334 break;
1335
Dan Williams0aef64d2007-08-02 11:31:18 -04001336 case CMD_802_11_ENABLE_RSN:
Holger Schurig10078322007-11-15 18:05:47 -05001337 ret = lbs_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
Dan Williams90a42212007-05-25 23:01:24 -04001338 pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001339 break;
1340
Dan Williams0aef64d2007-08-02 11:31:18 -04001341 case CMD_802_11_KEY_MATERIAL:
Holger Schurig10078322007-11-15 18:05:47 -05001342 ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
Dan Williams90a42212007-05-25 23:01:24 -04001343 cmd_oid, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001344 break;
1345
Dan Williams0aef64d2007-08-02 11:31:18 -04001346 case CMD_802_11_PAIRWISE_TSC:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001347 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001348 case CMD_802_11_GROUP_TSC:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001349 break;
1350
Dan Williams0aef64d2007-08-02 11:31:18 -04001351 case CMD_802_11_MAC_ADDRESS:
Holger Schurig10078322007-11-15 18:05:47 -05001352 ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001353 break;
1354
Dan Williams0aef64d2007-08-02 11:31:18 -04001355 case CMD_802_11_EEPROM_ACCESS:
Holger Schurig10078322007-11-15 18:05:47 -05001356 ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001357 cmd_action, pdata_buf);
1358 break;
1359
Dan Williams0aef64d2007-08-02 11:31:18 -04001360 case CMD_802_11_SET_AFC:
1361 case CMD_802_11_GET_AFC:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001362
1363 cmdptr->command = cpu_to_le16(cmd_no);
David Woodhouse981f1872007-05-25 23:36:54 -04001364 cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
1365 S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001366
1367 memmove(&cmdptr->params.afc,
1368 pdata_buf, sizeof(struct cmd_ds_802_11_afc));
1369
1370 ret = 0;
1371 goto done;
1372
Dan Williams0aef64d2007-08-02 11:31:18 -04001373 case CMD_802_11D_DOMAIN_INFO:
Holger Schurig10078322007-11-15 18:05:47 -05001374 ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001375 cmd_no, cmd_action);
1376 break;
1377
Dan Williams0aef64d2007-08-02 11:31:18 -04001378 case CMD_802_11_SLEEP_PARAMS:
Holger Schurig10078322007-11-15 18:05:47 -05001379 ret = lbs_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001380 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001381 case CMD_802_11_INACTIVITY_TIMEOUT:
Holger Schurig10078322007-11-15 18:05:47 -05001382 ret = lbs_cmd_802_11_inactivity_timeout(priv, cmdptr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001383 cmd_action, pdata_buf);
David Woodhousef5ece8f2007-12-01 15:15:41 +00001384 lbs_set_cmd_ctrl_node(priv, cmdnode, 0, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001385 break;
1386
Dan Williams0aef64d2007-08-02 11:31:18 -04001387 case CMD_802_11_TPC_CFG:
1388 cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001389 cmdptr->size =
1390 cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
1391 S_DS_GEN);
1392
1393 memmove(&cmdptr->params.tpccfg,
1394 pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
1395
1396 ret = 0;
1397 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001398 case CMD_802_11_LED_GPIO_CTRL:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001399 {
1400 struct mrvlietypes_ledgpio *gpio =
1401 (struct mrvlietypes_ledgpio*)
1402 cmdptr->params.ledgpio.data;
1403
1404 memmove(&cmdptr->params.ledgpio,
1405 pdata_buf,
1406 sizeof(struct cmd_ds_802_11_led_ctrl));
1407
1408 cmdptr->command =
Dan Williams0aef64d2007-08-02 11:31:18 -04001409 cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001410
1411#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
1412 cmdptr->size =
Holger Schurigc2df2ef2007-12-07 15:30:44 +00001413 cpu_to_le16(le16_to_cpu(gpio->header.len)
1414 + S_DS_GEN
1415 + ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
1416 gpio->header.len = gpio->header.len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001417
1418 ret = 0;
1419 break;
1420 }
Holger Schurig3a188642007-11-26 10:07:14 +01001421 case CMD_802_11_SUBSCRIBE_EVENT:
1422 lbs_cmd_802_11_subscribe_event(priv, cmdptr,
1423 cmd_action, pdata_buf);
1424 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001425 case CMD_802_11_PWR_CFG:
1426 cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001427 cmdptr->size =
1428 cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
1429 S_DS_GEN);
1430 memmove(&cmdptr->params.pwrcfg, pdata_buf,
1431 sizeof(struct cmd_ds_802_11_pwr_cfg));
1432
1433 ret = 0;
1434 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001435 case CMD_BT_ACCESS:
Holger Schurig10078322007-11-15 18:05:47 -05001436 ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001437 break;
1438
Dan Williams0aef64d2007-08-02 11:31:18 -04001439 case CMD_FWT_ACCESS:
Holger Schurig10078322007-11-15 18:05:47 -05001440 ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001441 break;
1442
Dan Williams0aef64d2007-08-02 11:31:18 -04001443 case CMD_MESH_ACCESS:
Holger Schurig10078322007-11-15 18:05:47 -05001444 ret = lbs_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001445 break;
1446
Dan Williams0aef64d2007-08-02 11:31:18 -04001447 case CMD_GET_TSF:
1448 cmdptr->command = cpu_to_le16(CMD_GET_TSF);
David Woodhouse981f1872007-05-25 23:36:54 -04001449 cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
1450 S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001451 ret = 0;
1452 break;
Brajesh Dave96287ac2007-11-20 17:44:28 -05001453 case CMD_802_11_BEACON_CTRL:
1454 ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
1455 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001456 default:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001457 lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001458 ret = -1;
1459 break;
1460 }
1461
1462 /* return error, since the command preparation failed */
1463 if (ret != 0) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001464 lbs_deb_host("PREP_CMD: command preparation failed\n");
Holger Schurig10078322007-11-15 18:05:47 -05001465 lbs_cleanup_and_insert_cmd(priv, cmdnode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001466 ret = -1;
1467 goto done;
1468 }
1469
1470 cmdnode->cmdwaitqwoken = 0;
1471
David Woodhouseaa21c002007-12-08 20:04:36 +00001472 lbs_queue_cmd(priv, cmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -04001473 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001474
Dan Williams0aef64d2007-08-02 11:31:18 -04001475 if (wait_option & CMD_OPTION_WAITFORRSP) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001476 lbs_deb_host("PREP_CMD: wait for response\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001477 might_sleep();
1478 wait_event_interruptible(cmdnode->cmdwait_q,
1479 cmdnode->cmdwaitqwoken);
1480 }
1481
David Woodhouseaa21c002007-12-08 20:04:36 +00001482 spin_lock_irqsave(&priv->driver_lock, flags);
1483 if (priv->cur_cmd_retcode) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001484 lbs_deb_host("PREP_CMD: command failed with return code %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +00001485 priv->cur_cmd_retcode);
1486 priv->cur_cmd_retcode = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001487 ret = -1;
1488 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001489 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001490
1491done:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001492 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001493 return ret;
1494}
Holger Schurig10078322007-11-15 18:05:47 -05001495EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001496
1497/**
1498 * @brief This function allocates the command buffer and link
1499 * it to command free queue.
1500 *
Holger Schurig69f90322007-11-23 15:43:44 +01001501 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001502 * @return 0 or -1
1503 */
Holger Schurig69f90322007-11-23 15:43:44 +01001504int lbs_allocate_cmd_buffer(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001505{
1506 int ret = 0;
1507 u32 ulbufsize;
1508 u32 i;
1509 struct cmd_ctrl_node *tempcmd_array;
1510 u8 *ptempvirtualaddr;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001511
Holger Schurig8ff12da2007-08-02 11:54:31 -04001512 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001513
1514 /* Allocate and initialize cmdCtrlNode */
1515 ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
1516
Holger Schurigfb3dddf2007-05-25 11:58:22 -04001517 if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001518 lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001519 ret = -1;
1520 goto done;
1521 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001522 priv->cmd_array = tempcmd_array;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001523
1524 /* Allocate and initialize command buffers */
1525 ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
1526 for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
Holger Schurigfb3dddf2007-05-25 11:58:22 -04001527 if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001528 lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001529 ret = -1;
1530 goto done;
1531 }
1532
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001533 /* Update command buffer virtual */
1534 tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr;
1535 }
1536
1537 for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
1538 init_waitqueue_head(&tempcmd_array[i].cmdwait_q);
Holger Schurig10078322007-11-15 18:05:47 -05001539 lbs_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001540 }
1541
1542 ret = 0;
Holger Schurig9012b282007-05-25 11:27:16 -04001543
1544done:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001545 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001546 return ret;
1547}
1548
1549/**
1550 * @brief This function frees the command buffer.
1551 *
Holger Schurig69f90322007-11-23 15:43:44 +01001552 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001553 * @return 0 or -1
1554 */
Holger Schurig69f90322007-11-23 15:43:44 +01001555int lbs_free_cmd_buffer(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001556{
David Woodhouse981f1872007-05-25 23:36:54 -04001557 u32 ulbufsize; /* Someone needs to die for this. Slowly and painfully */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001558 unsigned int i;
1559 struct cmd_ctrl_node *tempcmd_array;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001560
Holger Schurig8ff12da2007-08-02 11:54:31 -04001561 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001562
1563 /* need to check if cmd array is allocated or not */
David Woodhouseaa21c002007-12-08 20:04:36 +00001564 if (priv->cmd_array == NULL) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001565 lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001566 goto done;
1567 }
1568
David Woodhouseaa21c002007-12-08 20:04:36 +00001569 tempcmd_array = priv->cmd_array;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001570
1571 /* Release shared memory buffers */
1572 ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
1573 for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
1574 if (tempcmd_array[i].bufvirtualaddr) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001575 kfree(tempcmd_array[i].bufvirtualaddr);
1576 tempcmd_array[i].bufvirtualaddr = NULL;
1577 }
1578 }
1579
1580 /* Release cmd_ctrl_node */
David Woodhouseaa21c002007-12-08 20:04:36 +00001581 if (priv->cmd_array) {
1582 kfree(priv->cmd_array);
1583 priv->cmd_array = NULL;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001584 }
1585
1586done:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001587 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001588 return 0;
1589}
1590
1591/**
1592 * @brief This function gets a free command node if available in
1593 * command free queue.
1594 *
Holger Schurig69f90322007-11-23 15:43:44 +01001595 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001596 * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
1597 */
Holger Schurig0d61d042007-12-05 17:58:06 +01001598struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001599{
1600 struct cmd_ctrl_node *tempnode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001601 unsigned long flags;
1602
Holger Schurig8ff12da2007-08-02 11:54:31 -04001603 lbs_deb_enter(LBS_DEB_HOST);
1604
David Woodhouseaa21c002007-12-08 20:04:36 +00001605 if (!priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001606 return NULL;
1607
David Woodhouseaa21c002007-12-08 20:04:36 +00001608 spin_lock_irqsave(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001609
David Woodhouseaa21c002007-12-08 20:04:36 +00001610 if (!list_empty(&priv->cmdfreeq)) {
1611 tempnode = list_first_entry(&priv->cmdfreeq,
Li Zefanabe3ed12007-12-06 13:01:21 +01001612 struct cmd_ctrl_node, list);
1613 list_del(&tempnode->list);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001614 } else {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001615 lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001616 tempnode = NULL;
1617 }
1618
David Woodhouseaa21c002007-12-08 20:04:36 +00001619 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001620
Holger Schurig8ff12da2007-08-02 11:54:31 -04001621 if (tempnode)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001622 cleanup_cmdnode(tempnode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001623
Holger Schurig8ff12da2007-08-02 11:54:31 -04001624 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001625 return tempnode;
1626}
1627
1628/**
1629 * @brief This function cleans command node.
1630 *
1631 * @param ptempnode A pointer to cmdCtrlNode structure
1632 * @return n/a
1633 */
1634static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
1635{
Holger Schurig8ff12da2007-08-02 11:54:31 -04001636 lbs_deb_enter(LBS_DEB_HOST);
1637
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001638 if (!ptempnode)
1639 return;
1640 ptempnode->cmdwaitqwoken = 1;
1641 wake_up_interruptible(&ptempnode->cmdwait_q);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001642 ptempnode->wait_option = 0;
1643 ptempnode->pdata_buf = NULL;
David Woodhouse17230472007-12-07 15:13:05 +00001644 ptempnode->callback = NULL;
David Woodhouse1309b552007-12-10 13:36:10 -05001645 ptempnode->callback_arg = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001646
1647 if (ptempnode->bufvirtualaddr != NULL)
1648 memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
Holger Schurig8ff12da2007-08-02 11:54:31 -04001649
1650 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001651}
1652
1653/**
1654 * @brief This function initializes the command node.
1655 *
Holger Schurig69f90322007-11-23 15:43:44 +01001656 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001657 * @param ptempnode A pointer to cmd_ctrl_node structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001658 * @param wait_option wait option: wait response or not
1659 * @param pdata_buf A pointer to informaion buffer
1660 * @return 0 or -1
1661 */
Holger Schurig69f90322007-11-23 15:43:44 +01001662void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001663 struct cmd_ctrl_node *ptempnode,
David Woodhousef5ece8f2007-12-01 15:15:41 +00001664 u16 wait_option, void *pdata_buf)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001665{
Holger Schurig8ff12da2007-08-02 11:54:31 -04001666 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001667
1668 if (!ptempnode)
1669 return;
1670
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001671 ptempnode->wait_option = wait_option;
1672 ptempnode->pdata_buf = pdata_buf;
David Woodhouse17230472007-12-07 15:13:05 +00001673 ptempnode->callback = NULL;
David Woodhouse1309b552007-12-10 13:36:10 -05001674 ptempnode->callback_arg = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001675
Holger Schurig8ff12da2007-08-02 11:54:31 -04001676 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001677}
1678
1679/**
1680 * @brief This function executes next command in command
1681 * pending queue. It will put fimware back to PS mode
1682 * if applicable.
1683 *
Holger Schurig69f90322007-11-23 15:43:44 +01001684 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001685 * @return 0 or -1
1686 */
Holger Schurig69f90322007-11-23 15:43:44 +01001687int lbs_execute_next_command(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001688{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001689 struct cmd_ctrl_node *cmdnode = NULL;
1690 struct cmd_ds_command *cmdptr;
1691 unsigned long flags;
1692 int ret = 0;
1693
Holger Schurig8ff12da2007-08-02 11:54:31 -04001694 // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
Holger Schurig10078322007-11-15 18:05:47 -05001695 // only caller to us is lbs_thread() and we get even when a
Holger Schurig8ff12da2007-08-02 11:54:31 -04001696 // data packet is received
1697 lbs_deb_enter(LBS_DEB_THREAD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001698
David Woodhouseaa21c002007-12-08 20:04:36 +00001699 spin_lock_irqsave(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001700
David Woodhouseaa21c002007-12-08 20:04:36 +00001701 if (priv->cur_cmd) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001702 lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
David Woodhouseaa21c002007-12-08 20:04:36 +00001703 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001704 ret = -1;
1705 goto done;
1706 }
1707
David Woodhouseaa21c002007-12-08 20:04:36 +00001708 if (!list_empty(&priv->cmdpendingq)) {
1709 cmdnode = list_first_entry(&priv->cmdpendingq,
Li Zefanabe3ed12007-12-06 13:01:21 +01001710 struct cmd_ctrl_node, list);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001711 }
1712
David Woodhouseaa21c002007-12-08 20:04:36 +00001713 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001714
1715 if (cmdnode) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001716 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
1717
1718 if (is_command_allowed_in_ps(cmdptr->command)) {
David Woodhouseaa21c002007-12-08 20:04:36 +00001719 if ((priv->psstate == PS_STATE_SLEEP) ||
1720 (priv->psstate == PS_STATE_PRE_SLEEP)) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001721 lbs_deb_host(
1722 "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
David Woodhouse981f1872007-05-25 23:36:54 -04001723 le16_to_cpu(cmdptr->command),
David Woodhouseaa21c002007-12-08 20:04:36 +00001724 priv->psstate);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001725 ret = -1;
1726 goto done;
1727 }
Holger Schurig8ff12da2007-08-02 11:54:31 -04001728 lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
1729 "0x%04x in psstate %d\n",
David Woodhouse981f1872007-05-25 23:36:54 -04001730 le16_to_cpu(cmdptr->command),
David Woodhouseaa21c002007-12-08 20:04:36 +00001731 priv->psstate);
1732 } else if (priv->psstate != PS_STATE_FULL_POWER) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001733 /*
1734 * 1. Non-PS command:
1735 * Queue it. set needtowakeup to TRUE if current state
Holger Schurig10078322007-11-15 18:05:47 -05001736 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001737 * 2. PS command but not Exit_PS:
1738 * Ignore it.
1739 * 3. PS command Exit_PS:
1740 * Set needtowakeup to TRUE if current state is SLEEP,
1741 * otherwise send this command down to firmware
1742 * immediately.
1743 */
1744 if (cmdptr->command !=
Dan Williams0aef64d2007-08-02 11:31:18 -04001745 cpu_to_le16(CMD_802_11_PS_MODE)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001746 /* Prepare to send Exit PS,
1747 * this non PS command will be sent later */
David Woodhouseaa21c002007-12-08 20:04:36 +00001748 if ((priv->psstate == PS_STATE_SLEEP)
1749 || (priv->psstate == PS_STATE_PRE_SLEEP)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001750 ) {
1751 /* w/ new scheme, it will not reach here.
1752 since it is blocked in main_thread. */
David Woodhouseaa21c002007-12-08 20:04:36 +00001753 priv->needtowakeup = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001754 } else
Holger Schurig10078322007-11-15 18:05:47 -05001755 lbs_ps_wakeup(priv, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001756
1757 ret = 0;
1758 goto done;
1759 } else {
1760 /*
1761 * PS command. Ignore it if it is not Exit_PS.
1762 * otherwise send it down immediately.
1763 */
1764 struct cmd_ds_802_11_ps_mode *psm =
1765 &cmdptr->params.psmode;
1766
Holger Schurig8ff12da2007-08-02 11:54:31 -04001767 lbs_deb_host(
1768 "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001769 psm->action);
1770 if (psm->action !=
Dan Williams0aef64d2007-08-02 11:31:18 -04001771 cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001772 lbs_deb_host(
1773 "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
Li Zefanabe3ed12007-12-06 13:01:21 +01001774 list_del(&cmdnode->list);
Holger Schurig10078322007-11-15 18:05:47 -05001775 lbs_cleanup_and_insert_cmd(priv, cmdnode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001776
1777 ret = 0;
1778 goto done;
1779 }
1780
David Woodhouseaa21c002007-12-08 20:04:36 +00001781 if ((priv->psstate == PS_STATE_SLEEP) ||
1782 (priv->psstate == PS_STATE_PRE_SLEEP)) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001783 lbs_deb_host(
1784 "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
Li Zefanabe3ed12007-12-06 13:01:21 +01001785 list_del(&cmdnode->list);
Holger Schurig10078322007-11-15 18:05:47 -05001786 lbs_cleanup_and_insert_cmd(priv, cmdnode);
David Woodhouseaa21c002007-12-08 20:04:36 +00001787 priv->needtowakeup = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001788
1789 ret = 0;
1790 goto done;
1791 }
1792
Holger Schurig8ff12da2007-08-02 11:54:31 -04001793 lbs_deb_host(
1794 "EXEC_NEXT_CMD: sending EXIT_PS\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001795 }
1796 }
Li Zefanabe3ed12007-12-06 13:01:21 +01001797 list_del(&cmdnode->list);
Holger Schurig8ff12da2007-08-02 11:54:31 -04001798 lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
David Woodhouse981f1872007-05-25 23:36:54 -04001799 le16_to_cpu(cmdptr->command));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001800 DownloadcommandToStation(priv, cmdnode);
1801 } else {
1802 /*
1803 * check if in power save mode, if yes, put the device back
1804 * to PS mode
1805 */
David Woodhouseaa21c002007-12-08 20:04:36 +00001806 if ((priv->psmode != LBS802_11POWERMODECAM) &&
1807 (priv->psstate == PS_STATE_FULL_POWER) &&
1808 ((priv->connect_status == LBS_CONNECTED) ||
1809 (priv->mesh_connect_status == LBS_CONNECTED))) {
1810 if (priv->secinfo.WPAenabled ||
1811 priv->secinfo.WPA2enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001812 /* check for valid WPA group keys */
David Woodhouseaa21c002007-12-08 20:04:36 +00001813 if (priv->wpa_mcast_key.len ||
1814 priv->wpa_unicast_key.len) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001815 lbs_deb_host(
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001816 "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
1817 " go back to PS_SLEEP");
Holger Schurig10078322007-11-15 18:05:47 -05001818 lbs_ps_sleep(priv, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001819 }
1820 } else {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001821 lbs_deb_host(
1822 "EXEC_NEXT_CMD: cmdpendingq empty, "
1823 "go back to PS_SLEEP");
Holger Schurig10078322007-11-15 18:05:47 -05001824 lbs_ps_sleep(priv, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001825 }
1826 }
1827 }
1828
1829 ret = 0;
1830done:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001831 lbs_deb_leave(LBS_DEB_THREAD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001832 return ret;
1833}
1834
Holger Schurig69f90322007-11-23 15:43:44 +01001835void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001836{
1837 union iwreq_data iwrq;
1838 u8 buf[50];
1839
Holger Schurig8ff12da2007-08-02 11:54:31 -04001840 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001841
1842 memset(&iwrq, 0, sizeof(union iwreq_data));
1843 memset(buf, 0, sizeof(buf));
1844
1845 snprintf(buf, sizeof(buf) - 1, "%s", str);
1846
1847 iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
1848
1849 /* Send Event to upper layer */
Holger Schurig8ff12da2007-08-02 11:54:31 -04001850 lbs_deb_wext("event indication string %s\n", (char *)buf);
1851 lbs_deb_wext("event indication length %d\n", iwrq.data.length);
1852 lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001853
Holger Schurig634b8f42007-05-25 13:05:16 -04001854 wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001855
Holger Schurig8ff12da2007-08-02 11:54:31 -04001856 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001857}
1858
Holger Schurig69f90322007-11-23 15:43:44 +01001859static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001860{
1861 unsigned long flags;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001862 int ret = 0;
1863
Holger Schurig8ff12da2007-08-02 11:54:31 -04001864 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001865
Holger Schurig8ff12da2007-08-02 11:54:31 -04001866 lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001867 size);
1868
Holger Schurig8ff12da2007-08-02 11:54:31 -04001869 lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001870
Holger Schurig208fdd22007-05-25 12:17:06 -04001871 ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
Holger Schurig634b8f42007-05-25 13:05:16 -04001872 priv->dnld_sent = DNLD_RES_RECEIVED;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001873
David Woodhouseaa21c002007-12-08 20:04:36 +00001874 spin_lock_irqsave(&priv->driver_lock, flags);
1875 if (priv->intcounter || priv->currenttxskb)
Holger Schurig8ff12da2007-08-02 11:54:31 -04001876 lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
David Woodhouseaa21c002007-12-08 20:04:36 +00001877 priv->intcounter, priv->currenttxskb);
1878 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001879
1880 if (ret) {
1881 lbs_pr_alert(
1882 "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
1883 } else {
David Woodhouseaa21c002007-12-08 20:04:36 +00001884 spin_lock_irqsave(&priv->driver_lock, flags);
1885 if (!priv->intcounter) {
1886 priv->psstate = PS_STATE_SLEEP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001887 } else {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001888 lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +00001889 priv->intcounter);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001890 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001891 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001892
Holger Schurig8ff12da2007-08-02 11:54:31 -04001893 lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001894 }
1895
Holger Schurig8ff12da2007-08-02 11:54:31 -04001896 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001897 return ret;
1898}
1899
Holger Schurig69f90322007-11-23 15:43:44 +01001900void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001901{
Holger Schurig8ff12da2007-08-02 11:54:31 -04001902 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001903
1904 /*
1905 * PS is currently supported only in Infrastructure mode
1906 * Remove this check if it is to be supported in IBSS mode also
1907 */
1908
Holger Schurig10078322007-11-15 18:05:47 -05001909 lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
Dan Williams0aef64d2007-08-02 11:31:18 -04001910 CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001911
Holger Schurig8ff12da2007-08-02 11:54:31 -04001912 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001913}
1914
1915/**
Holger Schurig8ff12da2007-08-02 11:54:31 -04001916 * @brief This function sends Exit_PS command to firmware.
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001917 *
Holger Schurig69f90322007-11-23 15:43:44 +01001918 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001919 * @param wait_option wait response or not
1920 * @return n/a
1921 */
Holger Schurig69f90322007-11-23 15:43:44 +01001922void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001923{
David Woodhouse981f1872007-05-25 23:36:54 -04001924 __le32 Localpsmode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001925
Holger Schurig8ff12da2007-08-02 11:54:31 -04001926 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001927
Holger Schurig10078322007-11-15 18:05:47 -05001928 Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001929
Holger Schurig10078322007-11-15 18:05:47 -05001930 lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
Dan Williams0aef64d2007-08-02 11:31:18 -04001931 CMD_SUBCMD_EXIT_PS,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001932 wait_option, 0, &Localpsmode);
1933
Holger Schurig8ff12da2007-08-02 11:54:31 -04001934 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001935}
1936
1937/**
1938 * @brief This function checks condition and prepares to
1939 * send sleep confirm command to firmware if ok.
1940 *
Holger Schurig69f90322007-11-23 15:43:44 +01001941 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001942 * @param psmode Power Saving mode
1943 * @return n/a
1944 */
Holger Schurig69f90322007-11-23 15:43:44 +01001945void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001946{
1947 unsigned long flags =0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001948 u8 allowed = 1;
1949
Holger Schurig8ff12da2007-08-02 11:54:31 -04001950 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001951
Holger Schurig634b8f42007-05-25 13:05:16 -04001952 if (priv->dnld_sent) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001953 allowed = 0;
Holger Schurig8ff12da2007-08-02 11:54:31 -04001954 lbs_deb_host("dnld_sent was set");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001955 }
1956
David Woodhouseaa21c002007-12-08 20:04:36 +00001957 spin_lock_irqsave(&priv->driver_lock, flags);
1958 if (priv->cur_cmd) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001959 allowed = 0;
Holger Schurig8ff12da2007-08-02 11:54:31 -04001960 lbs_deb_host("cur_cmd was set");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001961 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001962 if (priv->intcounter > 0) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001963 allowed = 0;
David Woodhouseaa21c002007-12-08 20:04:36 +00001964 lbs_deb_host("intcounter %d", priv->intcounter);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001965 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001966 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001967
1968 if (allowed) {
Holger Schurig10078322007-11-15 18:05:47 -05001969 lbs_deb_host("sending lbs_ps_confirm_sleep\n");
David Woodhouseaa21c002007-12-08 20:04:36 +00001970 sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001971 sizeof(struct PS_CMD_ConfirmSleep));
1972 } else {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001973 lbs_deb_host("sleep confirm has been delayed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001974 }
1975
Holger Schurig8ff12da2007-08-02 11:54:31 -04001976 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001977}
Holger Schurig675787e2007-12-05 17:58:11 +01001978
1979
1980/**
1981 * @brief Simple way to call firmware functions
1982 *
1983 * @param priv A pointer to struct lbs_private structure
1984 * @param psmode one of the many CMD_802_11_xxxx
1985 * @param cmd pointer to the parameters structure for above command
1986 * (this should not include the command, size, sequence
1987 * and result fields from struct cmd_ds_gen)
1988 * @param cmd_size size structure pointed to by cmd
1989 * @param rsp pointer to an area where the result should be placed
1990 * @param rsp_size pointer to the size of the rsp area. If the firmware
1991 * returns fewer bytes, then this *rsp_size will be
1992 * changed to the actual size.
1993 * @return -1 in case of a higher level error, otherwise
1994 * the result code from the firmware
1995 */
David Woodhouse17230472007-12-07 15:13:05 +00001996
David Woodhouse448a51a2007-12-08 00:59:54 +00001997int lbs_cmd(struct lbs_private *priv, uint16_t command, void *cmd, int cmd_size,
David Woodhouse1309b552007-12-10 13:36:10 -05001998 int (*callback)(struct lbs_private *, unsigned long, struct cmd_ds_command *),
1999 unsigned long callback_arg)
Holger Schurig675787e2007-12-05 17:58:11 +01002000{
Holger Schurig675787e2007-12-05 17:58:11 +01002001 struct cmd_ctrl_node *cmdnode;
2002 struct cmd_ds_gen *cmdptr;
2003 unsigned long flags;
2004 int ret = 0;
2005
2006 lbs_deb_enter(LBS_DEB_HOST);
Holger Schurig675787e2007-12-05 17:58:11 +01002007
David Woodhouseaa21c002007-12-08 20:04:36 +00002008 if (!priv) {
2009 lbs_deb_host("PREP_CMD: priv is NULL\n");
Holger Schurig675787e2007-12-05 17:58:11 +01002010 ret = -1;
2011 goto done;
2012 }
2013
David Woodhouseaa21c002007-12-08 20:04:36 +00002014 if (priv->surpriseremoved) {
Holger Schurig675787e2007-12-05 17:58:11 +01002015 lbs_deb_host("PREP_CMD: card removed\n");
2016 ret = -1;
2017 goto done;
2018 }
2019
2020 cmdnode = lbs_get_cmd_ctrl_node(priv);
2021
2022 if (cmdnode == NULL) {
2023 lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
2024
2025 /* Wake up main thread to execute next command */
2026 wake_up_interruptible(&priv->waitq);
2027 ret = -1;
2028 goto done;
2029 }
2030
2031 cmdptr = (struct cmd_ds_gen *)cmdnode->bufvirtualaddr;
2032 cmdnode->wait_option = CMD_OPTION_WAITFORRSP;
David Woodhouse448a51a2007-12-08 00:59:54 +00002033 cmdnode->callback = callback;
David Woodhouse1309b552007-12-10 13:36:10 -05002034 cmdnode->callback_arg = callback_arg;
Holger Schurig675787e2007-12-05 17:58:11 +01002035
2036 /* Set sequence number, clean result, move to buffer */
David Woodhouseaa21c002007-12-08 20:04:36 +00002037 priv->seqnum++;
Holger Schurig675787e2007-12-05 17:58:11 +01002038 cmdptr->command = cpu_to_le16(command);
David Woodhouse6228c0a2007-12-06 12:38:31 +00002039 cmdptr->size = cpu_to_le16(cmd_size + S_DS_GEN);
David Woodhouseaa21c002007-12-08 20:04:36 +00002040 cmdptr->seqnum = cpu_to_le16(priv->seqnum);
Holger Schurig675787e2007-12-05 17:58:11 +01002041 cmdptr->result = 0;
2042 memcpy(cmdptr->cmdresp, cmd, cmd_size);
2043
2044 lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
2045
2046 /* here was the big old switch() statement, which is now obsolete,
2047 * because the caller of lbs_cmd() sets up all of *cmd for us. */
2048
2049 cmdnode->cmdwaitqwoken = 0;
David Woodhouseaa21c002007-12-08 20:04:36 +00002050 lbs_queue_cmd(priv, cmdnode, 1);
Holger Schurig675787e2007-12-05 17:58:11 +01002051 wake_up_interruptible(&priv->waitq);
2052
2053 might_sleep();
2054 wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
2055
David Woodhouseaa21c002007-12-08 20:04:36 +00002056 spin_lock_irqsave(&priv->driver_lock, flags);
2057 if (priv->cur_cmd_retcode) {
Holger Schurig675787e2007-12-05 17:58:11 +01002058 lbs_deb_host("PREP_CMD: command failed with return code %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +00002059 priv->cur_cmd_retcode);
2060 priv->cur_cmd_retcode = 0;
Holger Schurig675787e2007-12-05 17:58:11 +01002061 ret = -1;
2062 }
David Woodhouseaa21c002007-12-08 20:04:36 +00002063 spin_unlock_irqrestore(&priv->driver_lock, flags);
Holger Schurig675787e2007-12-05 17:58:11 +01002064
2065done:
2066 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
2067 return ret;
2068}
2069EXPORT_SYMBOL_GPL(lbs_cmd);
2070
2071