libertas: fix use-after-free error
[deliverable/linux.git] / drivers / net / wireless / libertas / cmd.c
CommitLineData
876c9d3a
MT
1/**
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"
876c9d3a
MT
9#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);
0d61d042
HS
16struct 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
876c9d3a
MT
21
22static u16 commands_allowed_in_ps[] = {
0aef64d7 23 CMD_802_11_RSSI,
876c9d3a
MT
24};
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 */
981f187b 33static u8 is_command_allowed_in_ps(__le16 command)
876c9d3a 34{
876c9d3a
MT
35 int i;
36
981f187b 37 for (i = 0; i < ARRAY_SIZE(commands_allowed_in_ps); i++) {
876c9d3a
MT
38 if (command == cpu_to_le16(commands_allowed_in_ps[i]))
39 return 1;
40 }
41
42 return 0;
43}
44
69f9032d 45static int lbs_cmd_hw_spec(struct lbs_private *priv, struct cmd_ds_command *cmd)
876c9d3a
MT
46{
47 struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec;
48
9012b28a 49 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 50
0aef64d7 51 cmd->command = cpu_to_le16(CMD_GET_HW_SPEC);
981f187b 52 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
aa21c004 53 memcpy(hwspec->permanentaddr, priv->current_addr, ETH_ALEN);
876c9d3a 54
9012b28a 55 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
56 return 0;
57}
58
69f9032d 59static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv,
876c9d3a
MT
60 struct cmd_ds_command *cmd,
61 u16 cmd_action)
62{
63 struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
876c9d3a 64
9012b28a 65 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 66
0aef64d7 67 cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
981f187b
DW
68 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
69 S_DS_GEN);
876c9d3a
MT
70 psm->action = cpu_to_le16(cmd_action);
71 psm->multipledtim = 0;
981f187b 72 switch (cmd_action) {
0aef64d7 73 case CMD_SUBCMD_ENTER_PS:
9012b28a 74 lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
876c9d3a 75
252cf0d1 76 psm->locallisteninterval = 0;
97605c3e 77 psm->nullpktinterval = 0;
876c9d3a 78 psm->multipledtim =
56c4656e 79 cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
876c9d3a
MT
80 break;
81
0aef64d7 82 case CMD_SUBCMD_EXIT_PS:
9012b28a 83 lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
876c9d3a
MT
84 break;
85
0aef64d7 86 case CMD_SUBCMD_SLEEP_CONFIRMED:
9012b28a 87 lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
876c9d3a
MT
88 break;
89
90 default:
91 break;
92 }
93
9012b28a 94 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
95 return 0;
96}
97
69f9032d 98static int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
876c9d3a
MT
99 struct cmd_ds_command *cmd,
100 u16 cmd_action, void *pdata_buf)
101{
102 u16 *timeout = pdata_buf;
103
8ff12da1
HS
104 lbs_deb_enter(LBS_DEB_CMD);
105
0aef64d7 106 cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
876c9d3a
MT
107 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)
981f187b 114 cmd->params.inactivity_timeout.timeout = cpu_to_le16(*timeout);
876c9d3a
MT
115 else
116 cmd->params.inactivity_timeout.timeout = 0;
117
8ff12da1 118 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
119 return 0;
120}
121
69f9032d 122static int lbs_cmd_802_11_sleep_params(struct lbs_private *priv,
876c9d3a
MT
123 struct cmd_ds_command *cmd,
124 u16 cmd_action)
125{
876c9d3a
MT
126 struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;
127
9012b28a 128 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 129
981f187b
DW
130 cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
131 S_DS_GEN);
0aef64d7 132 cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS);
876c9d3a 133
0aef64d7 134 if (cmd_action == CMD_ACT_GET) {
aa21c004 135 memset(&priv->sp, 0, sizeof(struct sleep_params));
876c9d3a
MT
136 memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
137 sp->action = cpu_to_le16(cmd_action);
0aef64d7 138 } else if (cmd_action == CMD_ACT_SET) {
876c9d3a 139 sp->action = cpu_to_le16(cmd_action);
aa21c004
DW
140 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);
876c9d3a
MT
146 }
147
9012b28a 148 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
149 return 0;
150}
151
69f9032d 152static int lbs_cmd_802_11_set_wep(struct lbs_private *priv,
876c9d3a
MT
153 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;
876c9d3a
MT
158 int ret = 0;
159 struct assoc_request * assoc_req = pdata_buf;
160
9012b28a 161 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 162
0aef64d7 163 cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
981f187b 164 cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
876c9d3a 165
0aef64d7 166 if (cmd_act == CMD_ACT_ADD) {
876c9d3a
MT
167 int i;
168
169 if (!assoc_req) {
9012b28a 170 lbs_deb_cmd("Invalid association request!");
876c9d3a
MT
171 ret = -1;
172 goto done;
173 }
174
0aef64d7 175 wep->action = cpu_to_le16(CMD_ACT_ADD);
876c9d3a
MT
176
177 /* default tx key index */
981f187b 178 wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
0aef64d7 179 (u32)CMD_WEP_KEY_INDEX_MASK));
876c9d3a 180
876c9d3a
MT
181 /* Copy key types and material to host command structure */
182 for (i = 0; i < 4; i++) {
1443b653 183 struct enc_key * pkey = &assoc_req->wep_keys[i];
876c9d3a
MT
184
185 switch (pkey->len) {
186 case KEY_LEN_WEP_40:
6470a89d 187 wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
876c9d3a
MT
188 memmove(&wep->keymaterial[i], pkey->key,
189 pkey->len);
8ff12da1 190 lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
876c9d3a
MT
191 break;
192 case KEY_LEN_WEP_104:
6470a89d 193 wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
876c9d3a
MT
194 memmove(&wep->keymaterial[i], pkey->key,
195 pkey->len);
8ff12da1 196 lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
876c9d3a
MT
197 break;
198 case 0:
199 break;
200 default:
8ff12da1 201 lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
876c9d3a
MT
202 i, pkey->len);
203 ret = -1;
204 goto done;
205 break;
206 }
207 }
0aef64d7 208 } else if (cmd_act == CMD_ACT_REMOVE) {
876c9d3a 209 /* ACT_REMOVE clears _all_ WEP keys */
0aef64d7 210 wep->action = cpu_to_le16(CMD_ACT_REMOVE);
876c9d3a
MT
211
212 /* default tx key index */
aa21c004 213 wep->keyindex = cpu_to_le16((u16)(priv->wep_tx_keyidx &
0aef64d7 214 (u32)CMD_WEP_KEY_INDEX_MASK));
aa21c004 215 lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
876c9d3a
MT
216 }
217
218 ret = 0;
219
220done:
9012b28a 221 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
222 return ret;
223}
224
69f9032d 225static int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv,
876c9d3a 226 struct cmd_ds_command *cmd,
90a42210
DW
227 u16 cmd_action,
228 void * pdata_buf)
876c9d3a
MT
229{
230 struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
18c96c34 231 u32 * enable = pdata_buf;
90a42210
DW
232
233 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 234
0aef64d7 235 cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
981f187b 236 cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
876c9d3a 237 penableRSN->action = cpu_to_le16(cmd_action);
18c96c34 238
0aef64d7 239 if (cmd_action == CMD_ACT_SET) {
18c96c34 240 if (*enable)
0aef64d7 241 penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
18c96c34 242 else
0aef64d7 243 penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
8ff12da1 244 lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
876c9d3a
MT
245 }
246
90a42210 247 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
248 return 0;
249}
250
251
3a188649
HS
252static 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
876c9d3a 298static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
1443b653 299 struct enc_key * pkey)
876c9d3a 300{
8ff12da1
HS
301 lbs_deb_enter(LBS_DEB_CMD);
302
876c9d3a 303 if (pkey->flags & KEY_INFO_WPA_ENABLED) {
90a42210 304 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
876c9d3a 305 }
876c9d3a
MT
306 if (pkey->flags & KEY_INFO_WPA_UNICAST) {
307 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
90a42210
DW
308 }
309 if (pkey->flags & KEY_INFO_WPA_MCAST) {
876c9d3a
MT
310 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
311 }
312
313 pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
1443b653 314 pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
876c9d3a
MT
315 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));
8ff12da1 321 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
322}
323
69f9032d 324static int lbs_cmd_802_11_key_material(struct lbs_private *priv,
876c9d3a
MT
325 struct cmd_ds_command *cmd,
326 u16 cmd_action,
327 u32 cmd_oid, void *pdata_buf)
328{
876c9d3a
MT
329 struct cmd_ds_802_11_key_material *pkeymaterial =
330 &cmd->params.keymaterial;
90a42210 331 struct assoc_request * assoc_req = pdata_buf;
876c9d3a
MT
332 int ret = 0;
333 int index = 0;
334
9012b28a 335 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 336
0aef64d7 337 cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
876c9d3a
MT
338 pkeymaterial->action = cpu_to_le16(cmd_action);
339
0aef64d7 340 if (cmd_action == CMD_ACT_GET) {
90a42210 341 cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
876c9d3a
MT
342 ret = 0;
343 goto done;
344 }
345
346 memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
347
90a42210 348 if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
876c9d3a 349 set_one_wpa_key(&pkeymaterial->keyParamSet[index],
90a42210 350 &assoc_req->wpa_unicast_key);
876c9d3a
MT
351 index++;
352 }
353
90a42210 354 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
876c9d3a 355 set_one_wpa_key(&pkeymaterial->keyParamSet[index],
90a42210 356 &assoc_req->wpa_mcast_key);
876c9d3a
MT
357 index++;
358 }
359
360 cmd->size = cpu_to_le16( S_DS_GEN
90a42210
DW
361 + sizeof (pkeymaterial->action)
362 + (index * sizeof(struct MrvlIEtype_keyParamSet)));
876c9d3a
MT
363
364 ret = 0;
365
366done:
9012b28a 367 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
368 return ret;
369}
370
69f9032d 371static int lbs_cmd_802_11_reset(struct lbs_private *priv,
876c9d3a
MT
372 struct cmd_ds_command *cmd, int cmd_action)
373{
374 struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
375
8ff12da1
HS
376 lbs_deb_enter(LBS_DEB_CMD);
377
0aef64d7 378 cmd->command = cpu_to_le16(CMD_802_11_RESET);
876c9d3a
MT
379 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
380 reset->action = cpu_to_le16(cmd_action);
381
8ff12da1 382 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
383 return 0;
384}
385
69f9032d 386static int lbs_cmd_802_11_get_log(struct lbs_private *priv,
876c9d3a
MT
387 struct cmd_ds_command *cmd)
388{
8ff12da1 389 lbs_deb_enter(LBS_DEB_CMD);
0aef64d7 390 cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
876c9d3a
MT
391 cmd->size =
392 cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
393
8ff12da1 394 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
395 return 0;
396}
397
69f9032d 398static int lbs_cmd_802_11_get_stat(struct lbs_private *priv,
876c9d3a
MT
399 struct cmd_ds_command *cmd)
400{
8ff12da1 401 lbs_deb_enter(LBS_DEB_CMD);
0aef64d7 402 cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
876c9d3a 403 cmd->size =
981f187b 404 cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
876c9d3a 405
8ff12da1 406 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
407 return 0;
408}
409
69f9032d 410static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
876c9d3a
MT
411 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;
876c9d3a
MT
416 u8 ucTemp;
417
9012b28a 418 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 419
9012b28a 420 lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
876c9d3a 421
0aef64d7 422 cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
981f187b 423 cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
876c9d3a
MT
424
425 switch (cmd_oid) {
426 case OID_802_11_INFRASTRUCTURE_MODE:
427 {
0dc5a290 428 u8 mode = (u8) (size_t) pdata_buf;
0aef64d7
DW
429 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
430 pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
c2df2efe 431 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8));
0dc5a290 432 if (mode == IW_MODE_ADHOC) {
876c9d3a 433 ucTemp = SNMP_MIB_VALUE_ADHOC;
0dc5a290
DW
434 } else {
435 /* Infra and Auto modes */
436 ucTemp = SNMP_MIB_VALUE_INFRA;
437 }
876c9d3a
MT
438
439 memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));
440
441 break;
442 }
443
444 case OID_802_11D_ENABLE:
445 {
446 u32 ulTemp;
447
0aef64d7 448 pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
876c9d3a 449
0aef64d7 450 if (cmd_action == CMD_ACT_SET) {
c2df2efe
HS
451 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
452 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
876c9d3a 453 ulTemp = *(u32 *)pdata_buf;
981f187b 454 *((__le16 *)(pSNMPMIB->value)) =
876c9d3a
MT
455 cpu_to_le16((u16) ulTemp);
456 }
457 break;
458 }
459
460 case OID_802_11_FRAGMENTATION_THRESHOLD:
461 {
462 u32 ulTemp;
463
0aef64d7 464 pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
876c9d3a 465
0aef64d7
DW
466 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);
981f187b 470 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
876c9d3a 471 ulTemp = *((u32 *) pdata_buf);
981f187b 472 *((__le16 *)(pSNMPMIB->value)) =
876c9d3a
MT
473 cpu_to_le16((u16) ulTemp);
474
475 }
476
477 break;
478 }
479
480 case OID_802_11_RTS_THRESHOLD:
481 {
482
483 u32 ulTemp;
c2df2efe 484 pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I);
876c9d3a 485
0aef64d7
DW
486 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);
981f187b
DW
490 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
491 ulTemp = *((u32 *)pdata_buf);
492 *(__le16 *)(pSNMPMIB->value) =
876c9d3a
MT
493 cpu_to_le16((u16) ulTemp);
494
495 }
496 break;
497 }
498 case OID_802_11_TX_RETRYCOUNT:
0aef64d7 499 pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);
876c9d3a 500
0aef64d7
DW
501 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);
876c9d3a 505 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
981f187b 506 *((__le16 *)(pSNMPMIB->value)) =
aa21c004 507 cpu_to_le16((u16) priv->txretrycount);
876c9d3a
MT
508 }
509
510 break;
511 default:
512 break;
513 }
514
9012b28a 515 lbs_deb_cmd(
876c9d3a 516 "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
981f187b
DW
517 le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
518 le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
876c9d3a 519
9012b28a 520 lbs_deb_cmd(
8ff12da1 521 "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
981f187b
DW
522 le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
523 le16_to_cpu(pSNMPMIB->bufsize),
524 le16_to_cpu(*(__le16 *) pSNMPMIB->value));
876c9d3a 525
9012b28a 526 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
527 return 0;
528}
529
69f9032d 530static int lbs_cmd_802_11_radio_control(struct lbs_private *priv,
876c9d3a
MT
531 struct cmd_ds_command *cmd,
532 int cmd_action)
533{
981f187b 534 struct cmd_ds_802_11_radio_control *pradiocontrol = &cmd->params.radio;
876c9d3a 535
9012b28a 536 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
537
538 cmd->size =
539 cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
540 S_DS_GEN);
0aef64d7 541 cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL);
876c9d3a
MT
542
543 pradiocontrol->action = cpu_to_le16(cmd_action);
544
aa21c004 545 switch (priv->preamble) {
0aef64d7 546 case CMD_TYPE_SHORT_PREAMBLE:
876c9d3a
MT
547 pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
548 break;
549
0aef64d7 550 case CMD_TYPE_LONG_PREAMBLE:
876c9d3a
MT
551 pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
552 break;
553
0aef64d7 554 case CMD_TYPE_AUTO_PREAMBLE:
876c9d3a
MT
555 default:
556 pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
557 break;
558 }
559
aa21c004 560 if (priv->radioon)
876c9d3a
MT
561 pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
562 else
563 pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);
564
9012b28a 565 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
566 return 0;
567}
568
69f9032d 569static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv,
876c9d3a
MT
570 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
9012b28a 576 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
577
578 cmd->size =
981f187b 579 cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
0aef64d7 580 cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
981f187b 581 prtp->action = cpu_to_le16(cmd_action);
876c9d3a 582
981f187b
DW
583 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));
876c9d3a
MT
586
587 switch (cmd_action) {
0aef64d7
DW
588 case CMD_ACT_TX_POWER_OPT_GET:
589 prtp->action = cpu_to_le16(CMD_ACT_GET);
876c9d3a
MT
590 prtp->currentlevel = 0;
591 break;
592
0aef64d7
DW
593 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);
876c9d3a
MT
596 break;
597
0aef64d7
DW
598 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);
876c9d3a
MT
601 break;
602
0aef64d7
DW
603 case CMD_ACT_TX_POWER_OPT_SET_LOW:
604 prtp->action = cpu_to_le16(CMD_ACT_SET);
876c9d3a
MT
605 prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
606 break;
607 }
9012b28a
HS
608
609 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
610 return 0;
611}
612
69f9032d 613static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv,
965f8bbc
LCC
614 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
69f9032d 633static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
876c9d3a
MT
634 struct cmd_ds_command *cmd,
635 u16 cmd_action)
636{
637 struct cmd_ds_802_11_rate_adapt_rateset
638 *rateadapt = &cmd->params.rateset;
876c9d3a 639
8ff12da1 640 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
641 cmd->size =
642 cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
643 + S_DS_GEN);
0aef64d7 644 cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
876c9d3a 645
981f187b 646 rateadapt->action = cpu_to_le16(cmd_action);
aa21c004
DW
647 rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
648 rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
876c9d3a 649
9012b28a 650 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
651 return 0;
652}
653
69f9032d 654static int lbs_cmd_802_11_data_rate(struct lbs_private *priv,
876c9d3a
MT
655 struct cmd_ds_command *cmd,
656 u16 cmd_action)
657{
658 struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;
876c9d3a 659
9012b28a 660 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 661
981f187b 662 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
876c9d3a 663 S_DS_GEN);
0aef64d7 664 cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE);
876c9d3a 665 memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
876c9d3a
MT
666 pdatarate->action = cpu_to_le16(cmd_action);
667
ffcae953 668 if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) {
aa21c004 669 pdatarate->rates[0] = lbs_data_rate_to_fw_index(priv->cur_rate);
8ff12da1 670 lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n",
aa21c004 671 priv->cur_rate);
ffcae953 672 } else if (cmd_action == CMD_ACT_SET_TX_AUTO) {
8ff12da1 673 lbs_deb_cmd("DATA_RATE: setting auto\n");
876c9d3a
MT
674 }
675
9012b28a 676 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
677 return 0;
678}
679
69f9032d 680static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
876c9d3a
MT
681 struct cmd_ds_command *cmd,
682 u16 cmd_action)
683{
684 struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
876c9d3a 685
8ff12da1 686 lbs_deb_enter(LBS_DEB_CMD);
981f187b 687 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
876c9d3a 688 S_DS_GEN);
0aef64d7 689 cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
876c9d3a 690
8ff12da1 691 lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
876c9d3a
MT
692 pMCastAdr->action = cpu_to_le16(cmd_action);
693 pMCastAdr->nr_of_adrs =
aa21c004
DW
694 cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
695 memcpy(pMCastAdr->maclist, priv->multicastlist,
696 priv->nr_of_multicastmacaddr * ETH_ALEN);
876c9d3a 697
8ff12da1 698 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
699 return 0;
700}
701
69f9032d 702static int lbs_cmd_802_11_rf_channel(struct lbs_private *priv,
876c9d3a
MT
703 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
8ff12da1 708 lbs_deb_enter(LBS_DEB_CMD);
0aef64d7 709 cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL);
981f187b
DW
710 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) +
711 S_DS_GEN);
876c9d3a 712
0aef64d7 713 if (option == CMD_OPT_802_11_RF_CHANNEL_SET) {
876c9d3a
MT
714 rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
715 }
716
717 rfchan->action = cpu_to_le16(option);
718
8ff12da1 719 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
720 return 0;
721}
722
69f9032d 723static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
876c9d3a
MT
724 struct cmd_ds_command *cmd)
725{
876c9d3a 726
8ff12da1 727 lbs_deb_enter(LBS_DEB_CMD);
0aef64d7 728 cmd->command = cpu_to_le16(CMD_802_11_RSSI);
981f187b 729 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
a783f1ee 730 cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
876c9d3a
MT
731
732 /* reset Beacon SNR/NF/RSSI values */
aa21c004
DW
733 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;
876c9d3a 739
8ff12da1 740 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
741 return 0;
742}
743
69f9032d 744static int lbs_cmd_reg_access(struct lbs_private *priv,
876c9d3a
MT
745 struct cmd_ds_command *cmdptr,
746 u8 cmd_action, void *pdata_buf)
747{
10078321 748 struct lbs_offset_value *offval;
876c9d3a 749
9012b28a 750 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 751
10078321 752 offval = (struct lbs_offset_value *)pdata_buf;
876c9d3a 753
c2df2efe 754 switch (le16_to_cpu(cmdptr->command)) {
0aef64d7 755 case CMD_MAC_REG_ACCESS:
876c9d3a
MT
756 {
757 struct cmd_ds_mac_reg_access *macreg;
758
759 cmdptr->size =
981f187b
DW
760 cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
761 + S_DS_GEN);
876c9d3a
MT
762 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
0aef64d7 773 case CMD_BBP_REG_ACCESS:
876c9d3a
MT
774 {
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
0aef64d7 792 case CMD_RF_REG_ACCESS:
876c9d3a
MT
793 {
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
9012b28a 815 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
816 return 0;
817}
818
69f9032d 819static int lbs_cmd_802_11_mac_address(struct lbs_private *priv,
876c9d3a
MT
820 struct cmd_ds_command *cmd,
821 u16 cmd_action)
822{
876c9d3a 823
8ff12da1 824 lbs_deb_enter(LBS_DEB_CMD);
0aef64d7 825 cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
981f187b 826 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
876c9d3a
MT
827 S_DS_GEN);
828 cmd->result = 0;
829
830 cmd->params.macadd.action = cpu_to_le16(cmd_action);
831
0aef64d7 832 if (cmd_action == CMD_ACT_SET) {
876c9d3a 833 memcpy(cmd->params.macadd.macadd,
aa21c004
DW
834 priv->current_addr, ETH_ALEN);
835 lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6);
876c9d3a
MT
836 }
837
8ff12da1 838 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
839 return 0;
840}
841
69f9032d 842static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv,
876c9d3a
MT
843 struct cmd_ds_command *cmd,
844 int cmd_action, void *pdata_buf)
845{
10078321 846 struct lbs_ioctl_regrdwr *ea = pdata_buf;
876c9d3a 847
9012b28a 848 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 849
0aef64d7 850 cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
981f187b
DW
851 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
852 S_DS_GEN);
876c9d3a
MT
853 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
8ff12da1 860 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
861 return 0;
862}
863
69f9032d 864static int lbs_cmd_bt_access(struct lbs_private *priv,
876c9d3a
MT
865 struct cmd_ds_command *cmd,
866 u16 cmd_action, void *pdata_buf)
867{
868 struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
8ff12da1 869 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
876c9d3a 870
0aef64d7 871 cmd->command = cpu_to_le16(CMD_BT_ACCESS);
981f187b 872 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
876c9d3a
MT
873 cmd->result = 0;
874 bt_access->action = cpu_to_le16(cmd_action);
875
876 switch (cmd_action) {
0aef64d7 877 case CMD_ACT_BT_ACCESS_ADD:
876c9d3a 878 memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
ece56191 879 lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
876c9d3a 880 break;
0aef64d7 881 case CMD_ACT_BT_ACCESS_DEL:
876c9d3a 882 memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
ece56191 883 lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
876c9d3a 884 break;
0aef64d7 885 case CMD_ACT_BT_ACCESS_LIST:
876c9d3a
MT
886 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
887 break;
0aef64d7 888 case CMD_ACT_BT_ACCESS_RESET:
876c9d3a 889 break;
0aef64d7 890 case CMD_ACT_BT_ACCESS_SET_INVERT:
90e8eafc
LCC
891 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
892 break;
0aef64d7 893 case CMD_ACT_BT_ACCESS_GET_INVERT:
90e8eafc 894 break;
876c9d3a
MT
895 default:
896 break;
897 }
8ff12da1 898 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
899 return 0;
900}
901
69f9032d 902static int lbs_cmd_fwt_access(struct lbs_private *priv,
876c9d3a
MT
903 struct cmd_ds_command *cmd,
904 u16 cmd_action, void *pdata_buf)
905{
906 struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
8ff12da1 907 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
876c9d3a 908
0aef64d7 909 cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
981f187b 910 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
876c9d3a
MT
911 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
8ff12da1 920 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
921 return 0;
922}
923
69f9032d 924static int lbs_cmd_mesh_access(struct lbs_private *priv,
876c9d3a
MT
925 struct cmd_ds_command *cmd,
926 u16 cmd_action, void *pdata_buf)
927{
928 struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
8ff12da1 929 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
876c9d3a 930
0aef64d7 931 cmd->command = cpu_to_le16(CMD_MESH_ACCESS);
981f187b 932 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN);
876c9d3a
MT
933 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
8ff12da1 942 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
943 return 0;
944}
945
96287ac4
BD
946static 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;
96287ac4
BD
952
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);
aa21c004
DW
960 bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
961 bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
96287ac4
BD
962
963 lbs_deb_leave(LBS_DEB_CMD);
964 return 0;
965}
966
29f5f2a1 967/*
10078321 968 * Note: NEVER use lbs_queue_cmd() with addtail==0 other than for
29f5f2a1
MT
969 * the command timer, because it does not account for queued commands.
970 */
aa21c004 971void lbs_queue_cmd(struct lbs_private *priv,
69f9032d
HS
972 struct cmd_ctrl_node *cmdnode,
973 u8 addtail)
876c9d3a
MT
974{
975 unsigned long flags;
976 struct cmd_ds_command *cmdptr;
977
8ff12da1 978 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a
MT
979
980 if (!cmdnode) {
8ff12da1 981 lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
876c9d3a
MT
982 goto done;
983 }
984
985 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
986 if (!cmdptr) {
8ff12da1 987 lbs_deb_host("QUEUE_CMD: cmdptr is NULL\n");
876c9d3a
MT
988 goto done;
989 }
990
991 /* Exit_PS command needs to be queued in the header always. */
c2df2efe 992 if (le16_to_cpu(cmdptr->command) == CMD_802_11_PS_MODE) {
876c9d3a 993 struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
0aef64d7 994 if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
aa21c004 995 if (priv->psstate != PS_STATE_FULL_POWER)
876c9d3a
MT
996 addtail = 0;
997 }
998 }
999
aa21c004 1000 spin_lock_irqsave(&priv->driver_lock, flags);
876c9d3a 1001
ac47246e 1002 if (addtail)
aa21c004 1003 list_add_tail(&cmdnode->list, &priv->cmdpendingq);
ac47246e 1004 else
aa21c004 1005 list_add(&cmdnode->list, &priv->cmdpendingq);
876c9d3a 1006
aa21c004 1007 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 1008
8ff12da1 1009 lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
981f187b 1010 le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command));
876c9d3a
MT
1011
1012done:
8ff12da1 1013 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1014}
1015
1016/*
1017 * TODO: Fix the issue when DownloadcommandToStation is being called the
8ff12da1 1018 * second time when the command times out. All the cmdptr->xxx are in little
876c9d3a
MT
1019 * 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 */
69f9032d 1023static int DownloadcommandToStation(struct lbs_private *priv,
876c9d3a
MT
1024 struct cmd_ctrl_node *cmdnode)
1025{
1026 unsigned long flags;
1027 struct cmd_ds_command *cmdptr;
b031ac10 1028 int ret = -1;
876c9d3a
MT
1029 u16 cmdsize;
1030 u16 command;
1031
8ff12da1 1032 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 1033
aa21c004
DW
1034 if (!priv || !cmdnode) {
1035 lbs_deb_host("DNLD_CMD: priv or cmdmode is NULL\n");
876c9d3a
MT
1036 goto done;
1037 }
1038
1039 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
1040
aa21c004 1041 spin_lock_irqsave(&priv->driver_lock, flags);
876c9d3a 1042 if (!cmdptr || !cmdptr->size) {
8ff12da1 1043 lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n");
10078321 1044 __lbs_cleanup_and_insert_cmd(priv, cmdnode);
aa21c004 1045 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1046 goto done;
1047 }
1048
aa21c004
DW
1049 priv->cur_cmd = cmdnode;
1050 priv->cur_cmd_retcode = 0;
1051 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 1052
c2df2efe
HS
1053 cmdsize = le16_to_cpu(cmdptr->size);
1054 command = le16_to_cpu(cmdptr->command);
876c9d3a 1055
8ff12da1 1056 lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n",
c2df2efe 1057 command, cmdsize, jiffies);
8ff12da1
HS
1058 lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize);
1059
876c9d3a 1060 cmdnode->cmdwaitqwoken = 0;
876c9d3a 1061
208fdd2f 1062 ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
876c9d3a
MT
1063
1064 if (ret != 0) {
8ff12da1 1065 lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n");
aa21c004
DW
1066 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);
876c9d3a
MT
1071 goto done;
1072 }
1073
8ff12da1 1074 lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
876c9d3a
MT
1075
1076 /* Setup the timer after transmit command */
0aef64d7
DW
1077 if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
1078 || command == CMD_802_11_ASSOCIATE)
aa21c004 1079 mod_timer(&priv->command_timer, jiffies + (10*HZ));
876c9d3a 1080 else
aa21c004 1081 mod_timer(&priv->command_timer, jiffies + (5*HZ));
876c9d3a
MT
1082
1083 ret = 0;
1084
9012b28a 1085done:
8ff12da1 1086 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
876c9d3a
MT
1087 return ret;
1088}
1089
69f9032d 1090static int lbs_cmd_mac_control(struct lbs_private *priv,
876c9d3a
MT
1091 struct cmd_ds_command *cmd)
1092{
1093 struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
1094
9012b28a 1095 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 1096
0aef64d7 1097 cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
981f187b 1098 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
aa21c004 1099 mac->action = cpu_to_le16(priv->currentpacketfilter);
876c9d3a 1100
8ff12da1 1101 lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
981f187b 1102 le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
876c9d3a 1103
9012b28a 1104 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
1105 return 0;
1106}
1107
1108/**
1109 * This function inserts command node to cmdfreeq
aa21c004 1110 * after cleans it. Requires priv->driver_lock held.
876c9d3a 1111 */
69f9032d
HS
1112void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1113 struct cmd_ctrl_node *ptempcmd)
876c9d3a 1114{
876c9d3a
MT
1115
1116 if (!ptempcmd)
8ff12da1 1117 return;
876c9d3a
MT
1118
1119 cleanup_cmdnode(ptempcmd);
aa21c004 1120 list_add_tail(&ptempcmd->list, &priv->cmdfreeq);
876c9d3a
MT
1121}
1122
69f9032d
HS
1123static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1124 struct cmd_ctrl_node *ptempcmd)
876c9d3a
MT
1125{
1126 unsigned long flags;
1127
aa21c004 1128 spin_lock_irqsave(&priv->driver_lock, flags);
10078321 1129 __lbs_cleanup_and_insert_cmd(priv, ptempcmd);
aa21c004 1130 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1131}
1132
69f9032d 1133int lbs_set_radio_control(struct lbs_private *priv)
876c9d3a
MT
1134{
1135 int ret = 0;
1136
9012b28a 1137 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 1138
10078321 1139 ret = lbs_prepare_and_send_command(priv,
0aef64d7
DW
1140 CMD_802_11_RADIO_CONTROL,
1141 CMD_ACT_SET,
1142 CMD_OPTION_WAITFORRSP, 0, NULL);
876c9d3a 1143
8ff12da1 1144 lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n",
aa21c004 1145 priv->radioon, priv->preamble);
876c9d3a 1146
9012b28a 1147 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
1148 return ret;
1149}
1150
69f9032d 1151int lbs_set_mac_packet_filter(struct lbs_private *priv)
876c9d3a
MT
1152{
1153 int ret = 0;
1154
9012b28a 1155 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 1156
876c9d3a 1157 /* Send MAC control command to station */
10078321 1158 ret = lbs_prepare_and_send_command(priv,
0aef64d7 1159 CMD_MAC_CONTROL, 0, 0, 0, NULL);
876c9d3a 1160
9012b28a 1161 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
1162 return ret;
1163}
1164
1165/**
1166 * @brief This function prepare the command before send to firmware.
1167 *
69f9032d 1168 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1169 * @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 */
69f9032d 1176int lbs_prepare_and_send_command(struct lbs_private *priv,
876c9d3a
MT
1177 u16 cmd_no,
1178 u16 cmd_action,
1179 u16 wait_option, u32 cmd_oid, void *pdata_buf)
1180{
1181 int ret = 0;
876c9d3a
MT
1182 struct cmd_ctrl_node *cmdnode;
1183 struct cmd_ds_command *cmdptr;
1184 unsigned long flags;
1185
8ff12da1 1186 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 1187
aa21c004
DW
1188 if (!priv) {
1189 lbs_deb_host("PREP_CMD: priv is NULL\n");
876c9d3a
MT
1190 ret = -1;
1191 goto done;
1192 }
1193
aa21c004 1194 if (priv->surpriseremoved) {
8ff12da1 1195 lbs_deb_host("PREP_CMD: card removed\n");
876c9d3a
MT
1196 ret = -1;
1197 goto done;
1198 }
1199
0d61d042 1200 cmdnode = lbs_get_cmd_ctrl_node(priv);
876c9d3a
MT
1201
1202 if (cmdnode == NULL) {
8ff12da1 1203 lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
876c9d3a
MT
1204
1205 /* Wake up main thread to execute next command */
fe336150 1206 wake_up_interruptible(&priv->waitq);
876c9d3a
MT
1207 ret = -1;
1208 goto done;
1209 }
1210
f5ece8fc 1211 lbs_set_cmd_ctrl_node(priv, cmdnode, wait_option, pdata_buf);
876c9d3a
MT
1212
1213 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
1214
8ff12da1 1215 lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
876c9d3a
MT
1216
1217 if (!cmdptr) {
8ff12da1 1218 lbs_deb_host("PREP_CMD: cmdptr is NULL\n");
10078321 1219 lbs_cleanup_and_insert_cmd(priv, cmdnode);
876c9d3a
MT
1220 ret = -1;
1221 goto done;
1222 }
1223
1224 /* Set sequence number, command and INT option */
aa21c004
DW
1225 priv->seqnum++;
1226 cmdptr->seqnum = cpu_to_le16(priv->seqnum);
876c9d3a 1227
981f187b 1228 cmdptr->command = cpu_to_le16(cmd_no);
876c9d3a
MT
1229 cmdptr->result = 0;
1230
1231 switch (cmd_no) {
0aef64d7 1232 case CMD_GET_HW_SPEC:
10078321 1233 ret = lbs_cmd_hw_spec(priv, cmdptr);
876c9d3a 1234 break;
0aef64d7 1235 case CMD_802_11_PS_MODE:
10078321 1236 ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
876c9d3a
MT
1237 break;
1238
0aef64d7 1239 case CMD_802_11_SCAN:
10078321 1240 ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
876c9d3a
MT
1241 break;
1242
0aef64d7 1243 case CMD_MAC_CONTROL:
10078321 1244 ret = lbs_cmd_mac_control(priv, cmdptr);
876c9d3a
MT
1245 break;
1246
0aef64d7
DW
1247 case CMD_802_11_ASSOCIATE:
1248 case CMD_802_11_REASSOCIATE:
10078321 1249 ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
876c9d3a
MT
1250 break;
1251
0aef64d7 1252 case CMD_802_11_DEAUTHENTICATE:
10078321 1253 ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
876c9d3a
MT
1254 break;
1255
0aef64d7 1256 case CMD_802_11_SET_WEP:
10078321 1257 ret = lbs_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
876c9d3a
MT
1258 break;
1259
0aef64d7 1260 case CMD_802_11_AD_HOC_START:
10078321 1261 ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
876c9d3a 1262 break;
0aef64d7 1263 case CMD_CODE_DNLD:
876c9d3a
MT
1264 break;
1265
0aef64d7 1266 case CMD_802_11_RESET:
10078321 1267 ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
876c9d3a
MT
1268 break;
1269
0aef64d7 1270 case CMD_802_11_GET_LOG:
10078321 1271 ret = lbs_cmd_802_11_get_log(priv, cmdptr);
876c9d3a
MT
1272 break;
1273
0aef64d7 1274 case CMD_802_11_AUTHENTICATE:
10078321 1275 ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
876c9d3a
MT
1276 break;
1277
0aef64d7 1278 case CMD_802_11_GET_STAT:
10078321 1279 ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
876c9d3a
MT
1280 break;
1281
0aef64d7 1282 case CMD_802_11_SNMP_MIB:
10078321 1283 ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
876c9d3a
MT
1284 cmd_action, cmd_oid, pdata_buf);
1285 break;
1286
0aef64d7
DW
1287 case CMD_MAC_REG_ACCESS:
1288 case CMD_BBP_REG_ACCESS:
1289 case CMD_RF_REG_ACCESS:
10078321 1290 ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
876c9d3a
MT
1291 break;
1292
0aef64d7 1293 case CMD_802_11_RF_CHANNEL:
10078321 1294 ret = lbs_cmd_802_11_rf_channel(priv, cmdptr,
876c9d3a
MT
1295 cmd_action, pdata_buf);
1296 break;
1297
0aef64d7 1298 case CMD_802_11_RF_TX_POWER:
10078321 1299 ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
876c9d3a
MT
1300 cmd_action, pdata_buf);
1301 break;
1302
0aef64d7 1303 case CMD_802_11_RADIO_CONTROL:
10078321 1304 ret = lbs_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
876c9d3a
MT
1305 break;
1306
0aef64d7 1307 case CMD_802_11_DATA_RATE:
10078321 1308 ret = lbs_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
876c9d3a 1309 break;
0aef64d7 1310 case CMD_802_11_RATE_ADAPT_RATESET:
10078321 1311 ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
876c9d3a
MT
1312 cmdptr, cmd_action);
1313 break;
1314
0aef64d7 1315 case CMD_MAC_MULTICAST_ADR:
10078321 1316 ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
876c9d3a
MT
1317 break;
1318
965f8bbc 1319 case CMD_802_11_MONITOR_MODE:
10078321 1320 ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
965f8bbc
LCC
1321 cmd_action, pdata_buf);
1322 break;
1323
0aef64d7 1324 case CMD_802_11_AD_HOC_JOIN:
10078321 1325 ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
876c9d3a
MT
1326 break;
1327
0aef64d7 1328 case CMD_802_11_RSSI:
10078321 1329 ret = lbs_cmd_802_11_rssi(priv, cmdptr);
876c9d3a
MT
1330 break;
1331
0aef64d7 1332 case CMD_802_11_AD_HOC_STOP:
10078321 1333 ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
876c9d3a
MT
1334 break;
1335
0aef64d7 1336 case CMD_802_11_ENABLE_RSN:
10078321 1337 ret = lbs_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
90a42210 1338 pdata_buf);
876c9d3a
MT
1339 break;
1340
0aef64d7 1341 case CMD_802_11_KEY_MATERIAL:
10078321 1342 ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
90a42210 1343 cmd_oid, pdata_buf);
876c9d3a
MT
1344 break;
1345
0aef64d7 1346 case CMD_802_11_PAIRWISE_TSC:
876c9d3a 1347 break;
0aef64d7 1348 case CMD_802_11_GROUP_TSC:
876c9d3a
MT
1349 break;
1350
0aef64d7 1351 case CMD_802_11_MAC_ADDRESS:
10078321 1352 ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
876c9d3a
MT
1353 break;
1354
0aef64d7 1355 case CMD_802_11_EEPROM_ACCESS:
10078321 1356 ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
876c9d3a
MT
1357 cmd_action, pdata_buf);
1358 break;
1359
0aef64d7
DW
1360 case CMD_802_11_SET_AFC:
1361 case CMD_802_11_GET_AFC:
876c9d3a
MT
1362
1363 cmdptr->command = cpu_to_le16(cmd_no);
981f187b
DW
1364 cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
1365 S_DS_GEN);
876c9d3a
MT
1366
1367 memmove(&cmdptr->params.afc,
1368 pdata_buf, sizeof(struct cmd_ds_802_11_afc));
1369
1370 ret = 0;
1371 goto done;
1372
0aef64d7 1373 case CMD_802_11D_DOMAIN_INFO:
10078321 1374 ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
876c9d3a
MT
1375 cmd_no, cmd_action);
1376 break;
1377
0aef64d7 1378 case CMD_802_11_SLEEP_PARAMS:
10078321 1379 ret = lbs_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
876c9d3a 1380 break;
0aef64d7 1381 case CMD_802_11_INACTIVITY_TIMEOUT:
10078321 1382 ret = lbs_cmd_802_11_inactivity_timeout(priv, cmdptr,
876c9d3a 1383 cmd_action, pdata_buf);
f5ece8fc 1384 lbs_set_cmd_ctrl_node(priv, cmdnode, 0, pdata_buf);
876c9d3a
MT
1385 break;
1386
0aef64d7
DW
1387 case CMD_802_11_TPC_CFG:
1388 cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
876c9d3a
MT
1389 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;
0aef64d7 1398 case CMD_802_11_LED_GPIO_CTRL:
876c9d3a
MT
1399 {
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 =
0aef64d7 1409 cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
876c9d3a
MT
1410
1411#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
1412 cmdptr->size =
c2df2efe
HS
1413 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;
876c9d3a
MT
1417
1418 ret = 0;
1419 break;
1420 }
3a188649
HS
1421 case CMD_802_11_SUBSCRIBE_EVENT:
1422 lbs_cmd_802_11_subscribe_event(priv, cmdptr,
1423 cmd_action, pdata_buf);
1424 break;
0aef64d7
DW
1425 case CMD_802_11_PWR_CFG:
1426 cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
876c9d3a
MT
1427 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;
0aef64d7 1435 case CMD_BT_ACCESS:
10078321 1436 ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
876c9d3a
MT
1437 break;
1438
0aef64d7 1439 case CMD_FWT_ACCESS:
10078321 1440 ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
876c9d3a
MT
1441 break;
1442
0aef64d7 1443 case CMD_MESH_ACCESS:
10078321 1444 ret = lbs_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
876c9d3a
MT
1445 break;
1446
0aef64d7
DW
1447 case CMD_GET_TSF:
1448 cmdptr->command = cpu_to_le16(CMD_GET_TSF);
981f187b
DW
1449 cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
1450 S_DS_GEN);
876c9d3a
MT
1451 ret = 0;
1452 break;
96287ac4
BD
1453 case CMD_802_11_BEACON_CTRL:
1454 ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
1455 break;
876c9d3a 1456 default:
8ff12da1 1457 lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
876c9d3a
MT
1458 ret = -1;
1459 break;
1460 }
1461
1462 /* return error, since the command preparation failed */
1463 if (ret != 0) {
8ff12da1 1464 lbs_deb_host("PREP_CMD: command preparation failed\n");
10078321 1465 lbs_cleanup_and_insert_cmd(priv, cmdnode);
876c9d3a
MT
1466 ret = -1;
1467 goto done;
1468 }
1469
1470 cmdnode->cmdwaitqwoken = 0;
1471
aa21c004 1472 lbs_queue_cmd(priv, cmdnode, 1);
fe336150 1473 wake_up_interruptible(&priv->waitq);
876c9d3a 1474
0aef64d7 1475 if (wait_option & CMD_OPTION_WAITFORRSP) {
8ff12da1 1476 lbs_deb_host("PREP_CMD: wait for response\n");
876c9d3a
MT
1477 might_sleep();
1478 wait_event_interruptible(cmdnode->cmdwait_q,
1479 cmdnode->cmdwaitqwoken);
1480 }
1481
aa21c004
DW
1482 spin_lock_irqsave(&priv->driver_lock, flags);
1483 if (priv->cur_cmd_retcode) {
8ff12da1 1484 lbs_deb_host("PREP_CMD: command failed with return code %d\n",
aa21c004
DW
1485 priv->cur_cmd_retcode);
1486 priv->cur_cmd_retcode = 0;
876c9d3a
MT
1487 ret = -1;
1488 }
aa21c004 1489 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1490
1491done:
8ff12da1 1492 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
876c9d3a
MT
1493 return ret;
1494}
10078321 1495EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
876c9d3a
MT
1496
1497/**
1498 * @brief This function allocates the command buffer and link
1499 * it to command free queue.
1500 *
69f9032d 1501 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1502 * @return 0 or -1
1503 */
69f9032d 1504int lbs_allocate_cmd_buffer(struct lbs_private *priv)
876c9d3a
MT
1505{
1506 int ret = 0;
1507 u32 ulbufsize;
1508 u32 i;
1509 struct cmd_ctrl_node *tempcmd_array;
1510 u8 *ptempvirtualaddr;
876c9d3a 1511
8ff12da1 1512 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a
MT
1513
1514 /* Allocate and initialize cmdCtrlNode */
1515 ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
1516
fb3dddf2 1517 if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) {
8ff12da1 1518 lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
876c9d3a
MT
1519 ret = -1;
1520 goto done;
1521 }
aa21c004 1522 priv->cmd_array = tempcmd_array;
876c9d3a
MT
1523
1524 /* Allocate and initialize command buffers */
1525 ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
1526 for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
fb3dddf2 1527 if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) {
8ff12da1 1528 lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
876c9d3a
MT
1529 ret = -1;
1530 goto done;
1531 }
1532
876c9d3a
MT
1533 /* 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);
10078321 1539 lbs_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
876c9d3a
MT
1540 }
1541
1542 ret = 0;
9012b28a
HS
1543
1544done:
8ff12da1 1545 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
876c9d3a
MT
1546 return ret;
1547}
1548
1549/**
1550 * @brief This function frees the command buffer.
1551 *
69f9032d 1552 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1553 * @return 0 or -1
1554 */
69f9032d 1555int lbs_free_cmd_buffer(struct lbs_private *priv)
876c9d3a 1556{
981f187b 1557 u32 ulbufsize; /* Someone needs to die for this. Slowly and painfully */
876c9d3a
MT
1558 unsigned int i;
1559 struct cmd_ctrl_node *tempcmd_array;
876c9d3a 1560
8ff12da1 1561 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a
MT
1562
1563 /* need to check if cmd array is allocated or not */
aa21c004 1564 if (priv->cmd_array == NULL) {
8ff12da1 1565 lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
876c9d3a
MT
1566 goto done;
1567 }
1568
aa21c004 1569 tempcmd_array = priv->cmd_array;
876c9d3a
MT
1570
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) {
876c9d3a
MT
1575 kfree(tempcmd_array[i].bufvirtualaddr);
1576 tempcmd_array[i].bufvirtualaddr = NULL;
1577 }
1578 }
1579
1580 /* Release cmd_ctrl_node */
aa21c004
DW
1581 if (priv->cmd_array) {
1582 kfree(priv->cmd_array);
1583 priv->cmd_array = NULL;
876c9d3a
MT
1584 }
1585
1586done:
8ff12da1 1587 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1588 return 0;
1589}
1590
1591/**
1592 * @brief This function gets a free command node if available in
1593 * command free queue.
1594 *
69f9032d 1595 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1596 * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
1597 */
0d61d042 1598struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
876c9d3a
MT
1599{
1600 struct cmd_ctrl_node *tempnode;
876c9d3a
MT
1601 unsigned long flags;
1602
8ff12da1
HS
1603 lbs_deb_enter(LBS_DEB_HOST);
1604
aa21c004 1605 if (!priv)
876c9d3a
MT
1606 return NULL;
1607
aa21c004 1608 spin_lock_irqsave(&priv->driver_lock, flags);
876c9d3a 1609
aa21c004
DW
1610 if (!list_empty(&priv->cmdfreeq)) {
1611 tempnode = list_first_entry(&priv->cmdfreeq,
abe3ed14
LZ
1612 struct cmd_ctrl_node, list);
1613 list_del(&tempnode->list);
876c9d3a 1614 } else {
8ff12da1 1615 lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
876c9d3a
MT
1616 tempnode = NULL;
1617 }
1618
aa21c004 1619 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 1620
8ff12da1 1621 if (tempnode)
876c9d3a 1622 cleanup_cmdnode(tempnode);
876c9d3a 1623
8ff12da1 1624 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1625 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{
8ff12da1
HS
1636 lbs_deb_enter(LBS_DEB_HOST);
1637
876c9d3a
MT
1638 if (!ptempnode)
1639 return;
1640 ptempnode->cmdwaitqwoken = 1;
1641 wake_up_interruptible(&ptempnode->cmdwait_q);
876c9d3a
MT
1642 ptempnode->wait_option = 0;
1643 ptempnode->pdata_buf = NULL;
1723047d 1644 ptempnode->callback = NULL;
876c9d3a
MT
1645
1646 if (ptempnode->bufvirtualaddr != NULL)
1647 memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
8ff12da1
HS
1648
1649 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1650}
1651
1652/**
1653 * @brief This function initializes the command node.
1654 *
69f9032d 1655 * @param priv A pointer to struct lbs_private structure
876c9d3a 1656 * @param ptempnode A pointer to cmd_ctrl_node structure
876c9d3a
MT
1657 * @param wait_option wait option: wait response or not
1658 * @param pdata_buf A pointer to informaion buffer
1659 * @return 0 or -1
1660 */
69f9032d 1661void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
876c9d3a 1662 struct cmd_ctrl_node *ptempnode,
f5ece8fc 1663 u16 wait_option, void *pdata_buf)
876c9d3a 1664{
8ff12da1 1665 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a
MT
1666
1667 if (!ptempnode)
1668 return;
1669
876c9d3a
MT
1670 ptempnode->wait_option = wait_option;
1671 ptempnode->pdata_buf = pdata_buf;
1723047d 1672 ptempnode->callback = NULL;
876c9d3a 1673
8ff12da1 1674 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1675}
1676
1677/**
1678 * @brief This function executes next command in command
1679 * pending queue. It will put fimware back to PS mode
1680 * if applicable.
1681 *
69f9032d 1682 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1683 * @return 0 or -1
1684 */
69f9032d 1685int lbs_execute_next_command(struct lbs_private *priv)
876c9d3a 1686{
876c9d3a
MT
1687 struct cmd_ctrl_node *cmdnode = NULL;
1688 struct cmd_ds_command *cmdptr;
1689 unsigned long flags;
1690 int ret = 0;
1691
8ff12da1 1692 // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
10078321 1693 // only caller to us is lbs_thread() and we get even when a
8ff12da1
HS
1694 // data packet is received
1695 lbs_deb_enter(LBS_DEB_THREAD);
876c9d3a 1696
aa21c004 1697 spin_lock_irqsave(&priv->driver_lock, flags);
876c9d3a 1698
aa21c004 1699 if (priv->cur_cmd) {
8ff12da1 1700 lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
aa21c004 1701 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1702 ret = -1;
1703 goto done;
1704 }
1705
aa21c004
DW
1706 if (!list_empty(&priv->cmdpendingq)) {
1707 cmdnode = list_first_entry(&priv->cmdpendingq,
abe3ed14 1708 struct cmd_ctrl_node, list);
876c9d3a
MT
1709 }
1710
aa21c004 1711 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1712
1713 if (cmdnode) {
876c9d3a
MT
1714 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
1715
1716 if (is_command_allowed_in_ps(cmdptr->command)) {
aa21c004
DW
1717 if ((priv->psstate == PS_STATE_SLEEP) ||
1718 (priv->psstate == PS_STATE_PRE_SLEEP)) {
8ff12da1
HS
1719 lbs_deb_host(
1720 "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
981f187b 1721 le16_to_cpu(cmdptr->command),
aa21c004 1722 priv->psstate);
876c9d3a
MT
1723 ret = -1;
1724 goto done;
1725 }
8ff12da1
HS
1726 lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
1727 "0x%04x in psstate %d\n",
981f187b 1728 le16_to_cpu(cmdptr->command),
aa21c004
DW
1729 priv->psstate);
1730 } else if (priv->psstate != PS_STATE_FULL_POWER) {
876c9d3a
MT
1731 /*
1732 * 1. Non-PS command:
1733 * Queue it. set needtowakeup to TRUE if current state
10078321 1734 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
876c9d3a
MT
1735 * 2. PS command but not Exit_PS:
1736 * Ignore it.
1737 * 3. PS command Exit_PS:
1738 * Set needtowakeup to TRUE if current state is SLEEP,
1739 * otherwise send this command down to firmware
1740 * immediately.
1741 */
1742 if (cmdptr->command !=
0aef64d7 1743 cpu_to_le16(CMD_802_11_PS_MODE)) {
876c9d3a
MT
1744 /* Prepare to send Exit PS,
1745 * this non PS command will be sent later */
aa21c004
DW
1746 if ((priv->psstate == PS_STATE_SLEEP)
1747 || (priv->psstate == PS_STATE_PRE_SLEEP)
876c9d3a
MT
1748 ) {
1749 /* w/ new scheme, it will not reach here.
1750 since it is blocked in main_thread. */
aa21c004 1751 priv->needtowakeup = 1;
876c9d3a 1752 } else
10078321 1753 lbs_ps_wakeup(priv, 0);
876c9d3a
MT
1754
1755 ret = 0;
1756 goto done;
1757 } else {
1758 /*
1759 * PS command. Ignore it if it is not Exit_PS.
1760 * otherwise send it down immediately.
1761 */
1762 struct cmd_ds_802_11_ps_mode *psm =
1763 &cmdptr->params.psmode;
1764
8ff12da1
HS
1765 lbs_deb_host(
1766 "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
876c9d3a
MT
1767 psm->action);
1768 if (psm->action !=
0aef64d7 1769 cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
8ff12da1
HS
1770 lbs_deb_host(
1771 "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
abe3ed14 1772 list_del(&cmdnode->list);
10078321 1773 lbs_cleanup_and_insert_cmd(priv, cmdnode);
876c9d3a
MT
1774
1775 ret = 0;
1776 goto done;
1777 }
1778
aa21c004
DW
1779 if ((priv->psstate == PS_STATE_SLEEP) ||
1780 (priv->psstate == PS_STATE_PRE_SLEEP)) {
8ff12da1
HS
1781 lbs_deb_host(
1782 "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
abe3ed14 1783 list_del(&cmdnode->list);
10078321 1784 lbs_cleanup_and_insert_cmd(priv, cmdnode);
aa21c004 1785 priv->needtowakeup = 1;
876c9d3a
MT
1786
1787 ret = 0;
1788 goto done;
1789 }
1790
8ff12da1
HS
1791 lbs_deb_host(
1792 "EXEC_NEXT_CMD: sending EXIT_PS\n");
876c9d3a
MT
1793 }
1794 }
abe3ed14 1795 list_del(&cmdnode->list);
8ff12da1 1796 lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
981f187b 1797 le16_to_cpu(cmdptr->command));
876c9d3a
MT
1798 DownloadcommandToStation(priv, cmdnode);
1799 } else {
1800 /*
1801 * check if in power save mode, if yes, put the device back
1802 * to PS mode
1803 */
aa21c004
DW
1804 if ((priv->psmode != LBS802_11POWERMODECAM) &&
1805 (priv->psstate == PS_STATE_FULL_POWER) &&
1806 ((priv->connect_status == LBS_CONNECTED) ||
1807 (priv->mesh_connect_status == LBS_CONNECTED))) {
1808 if (priv->secinfo.WPAenabled ||
1809 priv->secinfo.WPA2enabled) {
876c9d3a 1810 /* check for valid WPA group keys */
aa21c004
DW
1811 if (priv->wpa_mcast_key.len ||
1812 priv->wpa_unicast_key.len) {
8ff12da1 1813 lbs_deb_host(
876c9d3a
MT
1814 "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
1815 " go back to PS_SLEEP");
10078321 1816 lbs_ps_sleep(priv, 0);
876c9d3a
MT
1817 }
1818 } else {
8ff12da1
HS
1819 lbs_deb_host(
1820 "EXEC_NEXT_CMD: cmdpendingq empty, "
1821 "go back to PS_SLEEP");
10078321 1822 lbs_ps_sleep(priv, 0);
876c9d3a
MT
1823 }
1824 }
1825 }
1826
1827 ret = 0;
1828done:
8ff12da1 1829 lbs_deb_leave(LBS_DEB_THREAD);
876c9d3a
MT
1830 return ret;
1831}
1832
69f9032d 1833void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
876c9d3a
MT
1834{
1835 union iwreq_data iwrq;
1836 u8 buf[50];
1837
8ff12da1 1838 lbs_deb_enter(LBS_DEB_WEXT);
876c9d3a
MT
1839
1840 memset(&iwrq, 0, sizeof(union iwreq_data));
1841 memset(buf, 0, sizeof(buf));
1842
1843 snprintf(buf, sizeof(buf) - 1, "%s", str);
1844
1845 iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
1846
1847 /* Send Event to upper layer */
8ff12da1
HS
1848 lbs_deb_wext("event indication string %s\n", (char *)buf);
1849 lbs_deb_wext("event indication length %d\n", iwrq.data.length);
1850 lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
876c9d3a 1851
634b8f49 1852 wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
876c9d3a 1853
8ff12da1 1854 lbs_deb_leave(LBS_DEB_WEXT);
876c9d3a
MT
1855}
1856
69f9032d 1857static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
876c9d3a
MT
1858{
1859 unsigned long flags;
876c9d3a
MT
1860 int ret = 0;
1861
8ff12da1 1862 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 1863
8ff12da1 1864 lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
876c9d3a
MT
1865 size);
1866
8ff12da1 1867 lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
876c9d3a 1868
208fdd2f 1869 ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
634b8f49 1870 priv->dnld_sent = DNLD_RES_RECEIVED;
876c9d3a 1871
aa21c004
DW
1872 spin_lock_irqsave(&priv->driver_lock, flags);
1873 if (priv->intcounter || priv->currenttxskb)
8ff12da1 1874 lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
aa21c004
DW
1875 priv->intcounter, priv->currenttxskb);
1876 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1877
1878 if (ret) {
1879 lbs_pr_alert(
1880 "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
1881 } else {
aa21c004
DW
1882 spin_lock_irqsave(&priv->driver_lock, flags);
1883 if (!priv->intcounter) {
1884 priv->psstate = PS_STATE_SLEEP;
876c9d3a 1885 } else {
8ff12da1 1886 lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
aa21c004 1887 priv->intcounter);
876c9d3a 1888 }
aa21c004 1889 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 1890
8ff12da1 1891 lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
876c9d3a
MT
1892 }
1893
8ff12da1 1894 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
876c9d3a
MT
1895 return ret;
1896}
1897
69f9032d 1898void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
876c9d3a 1899{
8ff12da1 1900 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a
MT
1901
1902 /*
1903 * PS is currently supported only in Infrastructure mode
1904 * Remove this check if it is to be supported in IBSS mode also
1905 */
1906
10078321 1907 lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
0aef64d7 1908 CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
876c9d3a 1909
8ff12da1 1910 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1911}
1912
1913/**
8ff12da1 1914 * @brief This function sends Exit_PS command to firmware.
876c9d3a 1915 *
69f9032d 1916 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1917 * @param wait_option wait response or not
1918 * @return n/a
1919 */
69f9032d 1920void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
876c9d3a 1921{
981f187b 1922 __le32 Localpsmode;
876c9d3a 1923
8ff12da1 1924 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 1925
10078321 1926 Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
876c9d3a 1927
10078321 1928 lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
0aef64d7 1929 CMD_SUBCMD_EXIT_PS,
876c9d3a
MT
1930 wait_option, 0, &Localpsmode);
1931
8ff12da1 1932 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1933}
1934
1935/**
1936 * @brief This function checks condition and prepares to
1937 * send sleep confirm command to firmware if ok.
1938 *
69f9032d 1939 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1940 * @param psmode Power Saving mode
1941 * @return n/a
1942 */
69f9032d 1943void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode)
876c9d3a
MT
1944{
1945 unsigned long flags =0;
876c9d3a
MT
1946 u8 allowed = 1;
1947
8ff12da1 1948 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 1949
634b8f49 1950 if (priv->dnld_sent) {
876c9d3a 1951 allowed = 0;
8ff12da1 1952 lbs_deb_host("dnld_sent was set");
876c9d3a
MT
1953 }
1954
aa21c004
DW
1955 spin_lock_irqsave(&priv->driver_lock, flags);
1956 if (priv->cur_cmd) {
876c9d3a 1957 allowed = 0;
8ff12da1 1958 lbs_deb_host("cur_cmd was set");
876c9d3a 1959 }
aa21c004 1960 if (priv->intcounter > 0) {
876c9d3a 1961 allowed = 0;
aa21c004 1962 lbs_deb_host("intcounter %d", priv->intcounter);
876c9d3a 1963 }
aa21c004 1964 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1965
1966 if (allowed) {
10078321 1967 lbs_deb_host("sending lbs_ps_confirm_sleep\n");
aa21c004 1968 sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep,
876c9d3a
MT
1969 sizeof(struct PS_CMD_ConfirmSleep));
1970 } else {
8ff12da1 1971 lbs_deb_host("sleep confirm has been delayed\n");
876c9d3a
MT
1972 }
1973
8ff12da1 1974 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a 1975}
675787e2
HS
1976
1977
1978/**
1979 * @brief Simple way to call firmware functions
1980 *
1981 * @param priv A pointer to struct lbs_private structure
1982 * @param psmode one of the many CMD_802_11_xxxx
1983 * @param cmd pointer to the parameters structure for above command
1984 * (this should not include the command, size, sequence
1985 * and result fields from struct cmd_ds_gen)
1986 * @param cmd_size size structure pointed to by cmd
1987 * @param rsp pointer to an area where the result should be placed
1988 * @param rsp_size pointer to the size of the rsp area. If the firmware
1989 * returns fewer bytes, then this *rsp_size will be
1990 * changed to the actual size.
1991 * @return -1 in case of a higher level error, otherwise
1992 * the result code from the firmware
1993 */
1723047d 1994
448a51ae
DW
1995int lbs_cmd(struct lbs_private *priv, uint16_t command, void *cmd, int cmd_size,
1996 int (*callback)(uint16_t, struct cmd_ds_command *, struct lbs_private *))
675787e2 1997{
675787e2
HS
1998 struct cmd_ctrl_node *cmdnode;
1999 struct cmd_ds_gen *cmdptr;
2000 unsigned long flags;
2001 int ret = 0;
2002
2003 lbs_deb_enter(LBS_DEB_HOST);
675787e2 2004
aa21c004
DW
2005 if (!priv) {
2006 lbs_deb_host("PREP_CMD: priv is NULL\n");
675787e2
HS
2007 ret = -1;
2008 goto done;
2009 }
2010
aa21c004 2011 if (priv->surpriseremoved) {
675787e2
HS
2012 lbs_deb_host("PREP_CMD: card removed\n");
2013 ret = -1;
2014 goto done;
2015 }
2016
2017 cmdnode = lbs_get_cmd_ctrl_node(priv);
2018
2019 if (cmdnode == NULL) {
2020 lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
2021
2022 /* Wake up main thread to execute next command */
2023 wake_up_interruptible(&priv->waitq);
2024 ret = -1;
2025 goto done;
2026 }
2027
2028 cmdptr = (struct cmd_ds_gen *)cmdnode->bufvirtualaddr;
2029 cmdnode->wait_option = CMD_OPTION_WAITFORRSP;
448a51ae 2030 cmdnode->callback = callback;
675787e2
HS
2031
2032 /* Set sequence number, clean result, move to buffer */
aa21c004 2033 priv->seqnum++;
675787e2 2034 cmdptr->command = cpu_to_le16(command);
6228c0ae 2035 cmdptr->size = cpu_to_le16(cmd_size + S_DS_GEN);
aa21c004 2036 cmdptr->seqnum = cpu_to_le16(priv->seqnum);
675787e2
HS
2037 cmdptr->result = 0;
2038 memcpy(cmdptr->cmdresp, cmd, cmd_size);
2039
2040 lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
2041
2042 /* here was the big old switch() statement, which is now obsolete,
2043 * because the caller of lbs_cmd() sets up all of *cmd for us. */
2044
2045 cmdnode->cmdwaitqwoken = 0;
aa21c004 2046 lbs_queue_cmd(priv, cmdnode, 1);
675787e2
HS
2047 wake_up_interruptible(&priv->waitq);
2048
2049 might_sleep();
2050 wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
2051
aa21c004
DW
2052 spin_lock_irqsave(&priv->driver_lock, flags);
2053 if (priv->cur_cmd_retcode) {
675787e2 2054 lbs_deb_host("PREP_CMD: command failed with return code %d\n",
aa21c004
DW
2055 priv->cur_cmd_retcode);
2056 priv->cur_cmd_retcode = 0;
675787e2
HS
2057 ret = -1;
2058 }
aa21c004 2059 spin_unlock_irqrestore(&priv->driver_lock, flags);
675787e2
HS
2060
2061done:
2062 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
2063 return ret;
2064}
2065EXPORT_SYMBOL_GPL(lbs_cmd);
2066
2067
This page took 0.29681 seconds and 5 git commands to generate.