libertas: convert SLEEP_PARAMS to a direct command
[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"
6e66f03f 14#include "cmd.h"
876c9d3a 15
2fd6cfe3
DW
16static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
17static void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
0d61d042 18 struct cmd_ctrl_node *ptempnode,
8e5b6b2d 19 void *pdata_buf);
0d61d042 20
876c9d3a 21
876c9d3a 22/**
852e1f2a 23 * @brief Checks whether a command is allowed in Power Save mode
876c9d3a
MT
24 *
25 * @param command the command ID
852e1f2a 26 * @return 1 if allowed, 0 if not allowed
876c9d3a 27 */
852e1f2a 28static u8 is_command_allowed_in_ps(u16 cmd)
876c9d3a 29{
852e1f2a
DW
30 switch (cmd) {
31 case CMD_802_11_RSSI:
32 return 1;
33 default:
34 break;
876c9d3a 35 }
876c9d3a
MT
36 return 0;
37}
38
6e66f03f
DW
39/**
40 * @brief Updates the hardware details like MAC address and regulatory region
41 *
42 * @param priv A pointer to struct lbs_private structure
43 *
44 * @return 0 on success, error on failure
45 */
46int lbs_update_hw_spec(struct lbs_private *priv)
876c9d3a 47{
6e66f03f
DW
48 struct cmd_ds_get_hw_spec cmd;
49 int ret = -1;
50 u32 i;
51 DECLARE_MAC_BUF(mac);
876c9d3a 52
9012b28a 53 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 54
6e66f03f
DW
55 memset(&cmd, 0, sizeof(cmd));
56 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
57 memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
689442dc 58 ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
6e66f03f
DW
59 if (ret)
60 goto out;
61
62 priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
63 memcpy(priv->fwreleasenumber, cmd.fwreleasenumber, 4);
64
65 lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n",
66 priv->fwreleasenumber[2], priv->fwreleasenumber[1],
67 priv->fwreleasenumber[0], priv->fwreleasenumber[3]);
68 lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n",
69 print_mac(mac, cmd.permanentaddr));
70 lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
71 cmd.hwifversion, cmd.version);
72
73 /* Clamp region code to 8-bit since FW spec indicates that it should
74 * only ever be 8-bit, even though the field size is 16-bit. Some firmware
75 * returns non-zero high 8 bits here.
76 */
77 priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
78
79 for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
80 /* use the region code to search for the index */
81 if (priv->regioncode == lbs_region_code_to_index[i])
82 break;
83 }
84
85 /* if it's unidentified region code, use the default (USA) */
86 if (i >= MRVDRV_MAX_REGION_CODE) {
87 priv->regioncode = 0x10;
88 lbs_pr_info("unidentified region code; using the default (USA)\n");
89 }
90
91 if (priv->current_addr[0] == 0xff)
92 memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
876c9d3a 93
6e66f03f
DW
94 memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN);
95 if (priv->mesh_dev)
96 memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
97
98 if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
99 ret = -1;
100 goto out;
101 }
102
103 if (lbs_set_universaltable(priv, 0)) {
104 ret = -1;
105 goto out;
106 }
107
108out:
9012b28a 109 lbs_deb_leave(LBS_DEB_CMD);
6e66f03f 110 return ret;
876c9d3a
MT
111}
112
506e9025 113int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria)
6ce4fd2a
DW
114{
115 struct cmd_ds_host_sleep cmd_config;
116 int ret;
117
9fae899c 118 cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
6ce4fd2a 119 cmd_config.criteria = cpu_to_le32(criteria);
506e9025
DW
120 cmd_config.gpio = priv->wol_gpio;
121 cmd_config.gap = priv->wol_gap;
6ce4fd2a 122
689442dc 123 ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
506e9025
DW
124 if (!ret) {
125 lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
126 priv->wol_criteria = criteria;
127 } else {
6ce4fd2a 128 lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
6ce4fd2a 129 }
506e9025 130
6ce4fd2a
DW
131 return ret;
132}
133EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
134
69f9032d 135static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv,
876c9d3a
MT
136 struct cmd_ds_command *cmd,
137 u16 cmd_action)
138{
139 struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
876c9d3a 140
9012b28a 141 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 142
0aef64d7 143 cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
981f187b
DW
144 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
145 S_DS_GEN);
876c9d3a
MT
146 psm->action = cpu_to_le16(cmd_action);
147 psm->multipledtim = 0;
981f187b 148 switch (cmd_action) {
0aef64d7 149 case CMD_SUBCMD_ENTER_PS:
9012b28a 150 lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
876c9d3a 151
252cf0d1 152 psm->locallisteninterval = 0;
97605c3e 153 psm->nullpktinterval = 0;
876c9d3a 154 psm->multipledtim =
56c4656e 155 cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
876c9d3a
MT
156 break;
157
0aef64d7 158 case CMD_SUBCMD_EXIT_PS:
9012b28a 159 lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
876c9d3a
MT
160 break;
161
0aef64d7 162 case CMD_SUBCMD_SLEEP_CONFIRMED:
9012b28a 163 lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
876c9d3a
MT
164 break;
165
166 default:
167 break;
168 }
169
9012b28a 170 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
171 return 0;
172}
173
6e5cc4fb
DW
174int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
175 uint16_t cmd_action, uint16_t *timeout)
876c9d3a 176{
6e5cc4fb
DW
177 struct cmd_ds_802_11_inactivity_timeout cmd;
178 int ret;
876c9d3a 179
8ff12da1
HS
180 lbs_deb_enter(LBS_DEB_CMD);
181
6e5cc4fb
DW
182 cmd.hdr.command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
183 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
876c9d3a 184
6e5cc4fb 185 cmd.action = cpu_to_le16(cmd_action);
876c9d3a 186
6e5cc4fb
DW
187 if (cmd_action == CMD_ACT_SET)
188 cmd.timeout = cpu_to_le16(*timeout);
876c9d3a 189 else
6e5cc4fb 190 cmd.timeout = 0;
876c9d3a 191
6e5cc4fb
DW
192 ret = lbs_cmd_with_response(priv, CMD_802_11_INACTIVITY_TIMEOUT, &cmd);
193
194 if (!ret)
195 *timeout = le16_to_cpu(cmd.timeout);
196
197 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
198 return 0;
199}
200
3fbe104c
DW
201int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
202 struct sleep_params *sp)
876c9d3a 203{
3fbe104c
DW
204 struct cmd_ds_802_11_sleep_params cmd;
205 int ret;
876c9d3a 206
9012b28a 207 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 208
0aef64d7 209 if (cmd_action == CMD_ACT_GET) {
3fbe104c
DW
210 memset(&cmd, 0, sizeof(cmd));
211 } else {
212 cmd.error = cpu_to_le16(sp->sp_error);
213 cmd.offset = cpu_to_le16(sp->sp_offset);
214 cmd.stabletime = cpu_to_le16(sp->sp_stabletime);
215 cmd.calcontrol = sp->sp_calcontrol;
216 cmd.externalsleepclk = sp->sp_extsleepclk;
217 cmd.reserved = cpu_to_le16(sp->sp_reserved);
876c9d3a 218 }
3fbe104c
DW
219 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
220 cmd.action = cpu_to_le16(cmd_action);
876c9d3a 221
3fbe104c
DW
222 ret = lbs_cmd_with_response(priv, CMD_802_11_SLEEP_PARAMS, &cmd);
223
224 if (!ret) {
225 lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, "
226 "calcontrol 0x%x extsleepclk 0x%x\n",
227 le16_to_cpu(cmd.error), le16_to_cpu(cmd.offset),
228 le16_to_cpu(cmd.stabletime), cmd.calcontrol,
229 cmd.externalsleepclk);
230
231 sp->sp_error = le16_to_cpu(cmd.error);
232 sp->sp_offset = le16_to_cpu(cmd.offset);
233 sp->sp_stabletime = le16_to_cpu(cmd.stabletime);
234 sp->sp_calcontrol = cmd.calcontrol;
235 sp->sp_extsleepclk = cmd.externalsleepclk;
236 sp->sp_reserved = le16_to_cpu(cmd.reserved);
237 }
238
239 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
240 return 0;
241}
242
69f9032d 243static int lbs_cmd_802_11_set_wep(struct lbs_private *priv,
876c9d3a
MT
244 struct cmd_ds_command *cmd,
245 u32 cmd_act,
246 void * pdata_buf)
247{
248 struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
876c9d3a
MT
249 int ret = 0;
250 struct assoc_request * assoc_req = pdata_buf;
251
9012b28a 252 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 253
0aef64d7 254 cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
981f187b 255 cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
876c9d3a 256
0aef64d7 257 if (cmd_act == CMD_ACT_ADD) {
876c9d3a
MT
258 int i;
259
260 if (!assoc_req) {
23d36eec 261 lbs_deb_cmd("Invalid association request!\n");
876c9d3a
MT
262 ret = -1;
263 goto done;
264 }
265
0aef64d7 266 wep->action = cpu_to_le16(CMD_ACT_ADD);
876c9d3a
MT
267
268 /* default tx key index */
981f187b 269 wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
0aef64d7 270 (u32)CMD_WEP_KEY_INDEX_MASK));
876c9d3a 271
876c9d3a
MT
272 /* Copy key types and material to host command structure */
273 for (i = 0; i < 4; i++) {
1443b653 274 struct enc_key * pkey = &assoc_req->wep_keys[i];
876c9d3a
MT
275
276 switch (pkey->len) {
277 case KEY_LEN_WEP_40:
6470a89d 278 wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
876c9d3a
MT
279 memmove(&wep->keymaterial[i], pkey->key,
280 pkey->len);
8ff12da1 281 lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
876c9d3a
MT
282 break;
283 case KEY_LEN_WEP_104:
6470a89d 284 wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
876c9d3a
MT
285 memmove(&wep->keymaterial[i], pkey->key,
286 pkey->len);
8ff12da1 287 lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
876c9d3a
MT
288 break;
289 case 0:
290 break;
291 default:
8ff12da1 292 lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
876c9d3a
MT
293 i, pkey->len);
294 ret = -1;
295 goto done;
296 break;
297 }
298 }
0aef64d7 299 } else if (cmd_act == CMD_ACT_REMOVE) {
876c9d3a 300 /* ACT_REMOVE clears _all_ WEP keys */
0aef64d7 301 wep->action = cpu_to_le16(CMD_ACT_REMOVE);
876c9d3a
MT
302
303 /* default tx key index */
aa21c004 304 wep->keyindex = cpu_to_le16((u16)(priv->wep_tx_keyidx &
0aef64d7 305 (u32)CMD_WEP_KEY_INDEX_MASK));
aa21c004 306 lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
876c9d3a
MT
307 }
308
309 ret = 0;
310
311done:
9012b28a 312 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
313 return ret;
314}
315
69f9032d 316static int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv,
876c9d3a 317 struct cmd_ds_command *cmd,
90a42210
DW
318 u16 cmd_action,
319 void * pdata_buf)
876c9d3a
MT
320{
321 struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
18c96c34 322 u32 * enable = pdata_buf;
90a42210
DW
323
324 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 325
0aef64d7 326 cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
981f187b 327 cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
876c9d3a 328 penableRSN->action = cpu_to_le16(cmd_action);
18c96c34 329
0aef64d7 330 if (cmd_action == CMD_ACT_SET) {
18c96c34 331 if (*enable)
0aef64d7 332 penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
18c96c34 333 else
0aef64d7 334 penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
8ff12da1 335 lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
876c9d3a
MT
336 }
337
90a42210 338 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
339 return 0;
340}
341
342
3a188649
HS
343static ssize_t lbs_tlv_size(const u8 *tlv, u16 size)
344{
345 ssize_t pos = 0;
346 struct mrvlietypesheader *tlv_h;
347 while (pos < size) {
348 u16 length;
349 tlv_h = (struct mrvlietypesheader *) tlv;
350 if (tlv_h->len == 0)
351 return pos;
352 length = le16_to_cpu(tlv_h->len) +
353 sizeof(struct mrvlietypesheader);
354 pos += length;
355 tlv += length;
356 }
357 return pos;
358}
359
360
361static void lbs_cmd_802_11_subscribe_event(struct lbs_private *priv,
362 struct cmd_ds_command *cmd, u16 cmd_action,
363 void *pdata_buf)
364{
365 struct cmd_ds_802_11_subscribe_event *events =
366 (struct cmd_ds_802_11_subscribe_event *) pdata_buf;
367
368 /* pdata_buf points to a struct cmd_ds_802_11_subscribe_event and room
369 * for various Marvell TLVs */
370
371 lbs_deb_enter(LBS_DEB_CMD);
372
373 cmd->size = cpu_to_le16(sizeof(*events)
374 - sizeof(events->tlv)
375 + S_DS_GEN);
376 cmd->params.subscribe_event.action = cpu_to_le16(cmd_action);
377 if (cmd_action == CMD_ACT_GET) {
378 cmd->params.subscribe_event.events = 0;
379 } else {
380 ssize_t sz = lbs_tlv_size(events->tlv, sizeof(events->tlv));
381 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + sz);
382 cmd->params.subscribe_event.events = events->events;
383 memcpy(cmd->params.subscribe_event.tlv, events->tlv, sz);
384 }
385
386 lbs_deb_leave(LBS_DEB_CMD);
387}
388
876c9d3a 389static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
1443b653 390 struct enc_key * pkey)
876c9d3a 391{
8ff12da1
HS
392 lbs_deb_enter(LBS_DEB_CMD);
393
876c9d3a 394 if (pkey->flags & KEY_INFO_WPA_ENABLED) {
90a42210 395 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
876c9d3a 396 }
876c9d3a
MT
397 if (pkey->flags & KEY_INFO_WPA_UNICAST) {
398 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
90a42210
DW
399 }
400 if (pkey->flags & KEY_INFO_WPA_MCAST) {
876c9d3a
MT
401 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
402 }
403
404 pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
1443b653 405 pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
876c9d3a
MT
406 pkeyparamset->keylen = cpu_to_le16(pkey->len);
407 memcpy(pkeyparamset->key, pkey->key, pkey->len);
408 pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid)
409 + sizeof(pkeyparamset->keyinfo)
410 + sizeof(pkeyparamset->keylen)
411 + sizeof(pkeyparamset->key));
8ff12da1 412 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
413}
414
69f9032d 415static int lbs_cmd_802_11_key_material(struct lbs_private *priv,
876c9d3a
MT
416 struct cmd_ds_command *cmd,
417 u16 cmd_action,
418 u32 cmd_oid, void *pdata_buf)
419{
876c9d3a
MT
420 struct cmd_ds_802_11_key_material *pkeymaterial =
421 &cmd->params.keymaterial;
90a42210 422 struct assoc_request * assoc_req = pdata_buf;
876c9d3a
MT
423 int ret = 0;
424 int index = 0;
425
9012b28a 426 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 427
0aef64d7 428 cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
876c9d3a
MT
429 pkeymaterial->action = cpu_to_le16(cmd_action);
430
0aef64d7 431 if (cmd_action == CMD_ACT_GET) {
90a42210 432 cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
876c9d3a
MT
433 ret = 0;
434 goto done;
435 }
436
437 memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
438
90a42210 439 if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
876c9d3a 440 set_one_wpa_key(&pkeymaterial->keyParamSet[index],
90a42210 441 &assoc_req->wpa_unicast_key);
876c9d3a
MT
442 index++;
443 }
444
90a42210 445 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
876c9d3a 446 set_one_wpa_key(&pkeymaterial->keyParamSet[index],
90a42210 447 &assoc_req->wpa_mcast_key);
876c9d3a
MT
448 index++;
449 }
450
451 cmd->size = cpu_to_le16( S_DS_GEN
90a42210
DW
452 + sizeof (pkeymaterial->action)
453 + (index * sizeof(struct MrvlIEtype_keyParamSet)));
876c9d3a
MT
454
455 ret = 0;
456
457done:
9012b28a 458 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
459 return ret;
460}
461
69f9032d 462static int lbs_cmd_802_11_reset(struct lbs_private *priv,
876c9d3a
MT
463 struct cmd_ds_command *cmd, int cmd_action)
464{
465 struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
466
8ff12da1
HS
467 lbs_deb_enter(LBS_DEB_CMD);
468
0aef64d7 469 cmd->command = cpu_to_le16(CMD_802_11_RESET);
876c9d3a
MT
470 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
471 reset->action = cpu_to_le16(cmd_action);
472
8ff12da1 473 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
474 return 0;
475}
476
69f9032d 477static int lbs_cmd_802_11_get_log(struct lbs_private *priv,
876c9d3a
MT
478 struct cmd_ds_command *cmd)
479{
8ff12da1 480 lbs_deb_enter(LBS_DEB_CMD);
0aef64d7 481 cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
876c9d3a
MT
482 cmd->size =
483 cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
484
8ff12da1 485 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
486 return 0;
487}
488
69f9032d 489static int lbs_cmd_802_11_get_stat(struct lbs_private *priv,
876c9d3a
MT
490 struct cmd_ds_command *cmd)
491{
8ff12da1 492 lbs_deb_enter(LBS_DEB_CMD);
0aef64d7 493 cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
876c9d3a 494 cmd->size =
981f187b 495 cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
876c9d3a 496
8ff12da1 497 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
498 return 0;
499}
500
69f9032d 501static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
876c9d3a
MT
502 struct cmd_ds_command *cmd,
503 int cmd_action,
504 int cmd_oid, void *pdata_buf)
505{
506 struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
876c9d3a
MT
507 u8 ucTemp;
508
9012b28a 509 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 510
9012b28a 511 lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
876c9d3a 512
0aef64d7 513 cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
981f187b 514 cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
876c9d3a
MT
515
516 switch (cmd_oid) {
517 case OID_802_11_INFRASTRUCTURE_MODE:
518 {
0dc5a290 519 u8 mode = (u8) (size_t) pdata_buf;
0aef64d7
DW
520 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
521 pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
c2df2efe 522 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8));
0dc5a290 523 if (mode == IW_MODE_ADHOC) {
876c9d3a 524 ucTemp = SNMP_MIB_VALUE_ADHOC;
0dc5a290
DW
525 } else {
526 /* Infra and Auto modes */
527 ucTemp = SNMP_MIB_VALUE_INFRA;
528 }
876c9d3a
MT
529
530 memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));
531
532 break;
533 }
534
535 case OID_802_11D_ENABLE:
536 {
537 u32 ulTemp;
538
0aef64d7 539 pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
876c9d3a 540
0aef64d7 541 if (cmd_action == CMD_ACT_SET) {
c2df2efe
HS
542 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
543 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
876c9d3a 544 ulTemp = *(u32 *)pdata_buf;
981f187b 545 *((__le16 *)(pSNMPMIB->value)) =
876c9d3a
MT
546 cpu_to_le16((u16) ulTemp);
547 }
548 break;
549 }
550
551 case OID_802_11_FRAGMENTATION_THRESHOLD:
552 {
553 u32 ulTemp;
554
0aef64d7 555 pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
876c9d3a 556
0aef64d7
DW
557 if (cmd_action == CMD_ACT_GET) {
558 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
559 } else if (cmd_action == CMD_ACT_SET) {
560 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
981f187b 561 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
876c9d3a 562 ulTemp = *((u32 *) pdata_buf);
981f187b 563 *((__le16 *)(pSNMPMIB->value)) =
876c9d3a
MT
564 cpu_to_le16((u16) ulTemp);
565
566 }
567
568 break;
569 }
570
571 case OID_802_11_RTS_THRESHOLD:
572 {
573
574 u32 ulTemp;
c2df2efe 575 pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I);
876c9d3a 576
0aef64d7
DW
577 if (cmd_action == CMD_ACT_GET) {
578 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
579 } else if (cmd_action == CMD_ACT_SET) {
580 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
981f187b
DW
581 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
582 ulTemp = *((u32 *)pdata_buf);
583 *(__le16 *)(pSNMPMIB->value) =
876c9d3a
MT
584 cpu_to_le16((u16) ulTemp);
585
586 }
587 break;
588 }
589 case OID_802_11_TX_RETRYCOUNT:
0aef64d7 590 pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);
876c9d3a 591
0aef64d7
DW
592 if (cmd_action == CMD_ACT_GET) {
593 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
594 } else if (cmd_action == CMD_ACT_SET) {
595 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
876c9d3a 596 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
981f187b 597 *((__le16 *)(pSNMPMIB->value)) =
aa21c004 598 cpu_to_le16((u16) priv->txretrycount);
876c9d3a
MT
599 }
600
601 break;
602 default:
603 break;
604 }
605
9012b28a 606 lbs_deb_cmd(
876c9d3a 607 "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
981f187b
DW
608 le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
609 le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
876c9d3a 610
9012b28a 611 lbs_deb_cmd(
8ff12da1 612 "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
981f187b
DW
613 le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
614 le16_to_cpu(pSNMPMIB->bufsize),
615 le16_to_cpu(*(__le16 *) pSNMPMIB->value));
876c9d3a 616
9012b28a 617 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
618 return 0;
619}
620
69f9032d 621static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv,
876c9d3a
MT
622 struct cmd_ds_command *cmd,
623 u16 cmd_action, void *pdata_buf)
624{
625
626 struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
627
9012b28a 628 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
629
630 cmd->size =
981f187b 631 cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
0aef64d7 632 cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
981f187b 633 prtp->action = cpu_to_le16(cmd_action);
876c9d3a 634
981f187b
DW
635 lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n",
636 le16_to_cpu(cmd->size), le16_to_cpu(cmd->command),
637 le16_to_cpu(prtp->action));
876c9d3a
MT
638
639 switch (cmd_action) {
0aef64d7
DW
640 case CMD_ACT_TX_POWER_OPT_GET:
641 prtp->action = cpu_to_le16(CMD_ACT_GET);
876c9d3a
MT
642 prtp->currentlevel = 0;
643 break;
644
0aef64d7
DW
645 case CMD_ACT_TX_POWER_OPT_SET_HIGH:
646 prtp->action = cpu_to_le16(CMD_ACT_SET);
647 prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH);
876c9d3a
MT
648 break;
649
0aef64d7
DW
650 case CMD_ACT_TX_POWER_OPT_SET_MID:
651 prtp->action = cpu_to_le16(CMD_ACT_SET);
652 prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID);
876c9d3a
MT
653 break;
654
0aef64d7
DW
655 case CMD_ACT_TX_POWER_OPT_SET_LOW:
656 prtp->action = cpu_to_le16(CMD_ACT_SET);
876c9d3a
MT
657 prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
658 break;
659 }
9012b28a
HS
660
661 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
662 return 0;
663}
664
69f9032d 665static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv,
965f8bbc
LCC
666 struct cmd_ds_command *cmd,
667 u16 cmd_action, void *pdata_buf)
668{
669 struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;
670
671 cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
672 cmd->size =
673 cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
674 S_DS_GEN);
675
676 monitor->action = cpu_to_le16(cmd_action);
677 if (cmd_action == CMD_ACT_SET) {
678 monitor->mode =
679 cpu_to_le16((u16) (*(u32 *) pdata_buf));
680 }
681
682 return 0;
683}
684
69f9032d 685static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
876c9d3a
MT
686 struct cmd_ds_command *cmd,
687 u16 cmd_action)
688{
689 struct cmd_ds_802_11_rate_adapt_rateset
690 *rateadapt = &cmd->params.rateset;
876c9d3a 691
8ff12da1 692 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
693 cmd->size =
694 cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
695 + S_DS_GEN);
0aef64d7 696 cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
876c9d3a 697
981f187b 698 rateadapt->action = cpu_to_le16(cmd_action);
aa21c004
DW
699 rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
700 rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
876c9d3a 701
9012b28a 702 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
703 return 0;
704}
705
8e3c91bb
DW
706/**
707 * @brief Get the current data rate
708 *
709 * @param priv A pointer to struct lbs_private structure
710 *
711 * @return The data rate on success, error on failure
712 */
713int lbs_get_data_rate(struct lbs_private *priv)
876c9d3a 714{
8e3c91bb
DW
715 struct cmd_ds_802_11_data_rate cmd;
716 int ret = -1;
876c9d3a 717
9012b28a 718 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 719
8e3c91bb
DW
720 memset(&cmd, 0, sizeof(cmd));
721 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
722 cmd.action = cpu_to_le16(CMD_ACT_GET_TX_RATE);
723
689442dc 724 ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
8e3c91bb
DW
725 if (ret)
726 goto out;
727
728 lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
729
730 ret = (int) lbs_fw_index_to_data_rate(cmd.rates[0]);
731 lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", ret);
732
733out:
734 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
735 return ret;
736}
737
738/**
739 * @brief Set the data rate
740 *
741 * @param priv A pointer to struct lbs_private structure
742 * @param rate The desired data rate, or 0 to clear a locked rate
743 *
744 * @return 0 on success, error on failure
745 */
746int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
747{
748 struct cmd_ds_802_11_data_rate cmd;
749 int ret = 0;
750
751 lbs_deb_enter(LBS_DEB_CMD);
752
753 memset(&cmd, 0, sizeof(cmd));
754 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
755
756 if (rate > 0) {
757 cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
758 cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
759 if (cmd.rates[0] == 0) {
760 lbs_deb_cmd("DATA_RATE: invalid requested rate of"
761 " 0x%02X\n", rate);
762 ret = 0;
763 goto out;
764 }
765 lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
766 } else {
767 cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
8ff12da1 768 lbs_deb_cmd("DATA_RATE: setting auto\n");
876c9d3a
MT
769 }
770
689442dc 771 ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
8e3c91bb
DW
772 if (ret)
773 goto out;
774
775 lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
776
777 /* FIXME: get actual rates FW can do if this command actually returns
778 * all data rates supported.
779 */
780 priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
781 lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
782
783out:
784 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
785 return ret;
876c9d3a
MT
786}
787
69f9032d 788static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
876c9d3a
MT
789 struct cmd_ds_command *cmd,
790 u16 cmd_action)
791{
792 struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
876c9d3a 793
8ff12da1 794 lbs_deb_enter(LBS_DEB_CMD);
981f187b 795 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
876c9d3a 796 S_DS_GEN);
0aef64d7 797 cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
876c9d3a 798
8ff12da1 799 lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
876c9d3a
MT
800 pMCastAdr->action = cpu_to_le16(cmd_action);
801 pMCastAdr->nr_of_adrs =
aa21c004
DW
802 cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
803 memcpy(pMCastAdr->maclist, priv->multicastlist,
804 priv->nr_of_multicastmacaddr * ETH_ALEN);
876c9d3a 805
8ff12da1 806 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
807 return 0;
808}
809
2dd4b262
DW
810/**
811 * @brief Get the radio channel
812 *
813 * @param priv A pointer to struct lbs_private structure
814 *
815 * @return The channel on success, error on failure
816 */
817int lbs_get_channel(struct lbs_private *priv)
876c9d3a 818{
2dd4b262
DW
819 struct cmd_ds_802_11_rf_channel cmd;
820 int ret = 0;
876c9d3a 821
8ff12da1 822 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 823
2dd4b262
DW
824 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
825 cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
876c9d3a 826
689442dc 827 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
2dd4b262
DW
828 if (ret)
829 goto out;
876c9d3a 830
cb182a60
DW
831 ret = le16_to_cpu(cmd.channel);
832 lbs_deb_cmd("current radio channel is %d\n", ret);
2dd4b262
DW
833
834out:
835 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
836 return ret;
837}
838
839/**
840 * @brief Set the radio channel
841 *
842 * @param priv A pointer to struct lbs_private structure
843 * @param channel The desired channel, or 0 to clear a locked channel
844 *
845 * @return 0 on success, error on failure
846 */
847int lbs_set_channel(struct lbs_private *priv, u8 channel)
848{
849 struct cmd_ds_802_11_rf_channel cmd;
850 u8 old_channel = priv->curbssparams.channel;
851 int ret = 0;
852
853 lbs_deb_enter(LBS_DEB_CMD);
854
855 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
856 cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
857 cmd.channel = cpu_to_le16(channel);
858
689442dc 859 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
2dd4b262
DW
860 if (ret)
861 goto out;
862
cb182a60
DW
863 priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel);
864 lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
865 priv->curbssparams.channel);
2dd4b262
DW
866
867out:
868 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
869 return ret;
876c9d3a
MT
870}
871
69f9032d 872static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
876c9d3a
MT
873 struct cmd_ds_command *cmd)
874{
876c9d3a 875
8ff12da1 876 lbs_deb_enter(LBS_DEB_CMD);
0aef64d7 877 cmd->command = cpu_to_le16(CMD_802_11_RSSI);
981f187b 878 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
a783f1ee 879 cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
876c9d3a
MT
880
881 /* reset Beacon SNR/NF/RSSI values */
aa21c004
DW
882 priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
883 priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
884 priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
885 priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
886 priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
887 priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
876c9d3a 888
8ff12da1 889 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
890 return 0;
891}
892
69f9032d 893static int lbs_cmd_reg_access(struct lbs_private *priv,
876c9d3a
MT
894 struct cmd_ds_command *cmdptr,
895 u8 cmd_action, void *pdata_buf)
896{
10078321 897 struct lbs_offset_value *offval;
876c9d3a 898
9012b28a 899 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 900
10078321 901 offval = (struct lbs_offset_value *)pdata_buf;
876c9d3a 902
c2df2efe 903 switch (le16_to_cpu(cmdptr->command)) {
0aef64d7 904 case CMD_MAC_REG_ACCESS:
876c9d3a
MT
905 {
906 struct cmd_ds_mac_reg_access *macreg;
907
908 cmdptr->size =
981f187b
DW
909 cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
910 + S_DS_GEN);
876c9d3a
MT
911 macreg =
912 (struct cmd_ds_mac_reg_access *)&cmdptr->params.
913 macreg;
914
915 macreg->action = cpu_to_le16(cmd_action);
916 macreg->offset = cpu_to_le16((u16) offval->offset);
917 macreg->value = cpu_to_le32(offval->value);
918
919 break;
920 }
921
0aef64d7 922 case CMD_BBP_REG_ACCESS:
876c9d3a
MT
923 {
924 struct cmd_ds_bbp_reg_access *bbpreg;
925
926 cmdptr->size =
927 cpu_to_le16(sizeof
928 (struct cmd_ds_bbp_reg_access)
929 + S_DS_GEN);
930 bbpreg =
931 (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
932 bbpreg;
933
934 bbpreg->action = cpu_to_le16(cmd_action);
935 bbpreg->offset = cpu_to_le16((u16) offval->offset);
936 bbpreg->value = (u8) offval->value;
937
938 break;
939 }
940
0aef64d7 941 case CMD_RF_REG_ACCESS:
876c9d3a
MT
942 {
943 struct cmd_ds_rf_reg_access *rfreg;
944
945 cmdptr->size =
946 cpu_to_le16(sizeof
947 (struct cmd_ds_rf_reg_access) +
948 S_DS_GEN);
949 rfreg =
950 (struct cmd_ds_rf_reg_access *)&cmdptr->params.
951 rfreg;
952
953 rfreg->action = cpu_to_le16(cmd_action);
954 rfreg->offset = cpu_to_le16((u16) offval->offset);
955 rfreg->value = (u8) offval->value;
956
957 break;
958 }
959
960 default:
961 break;
962 }
963
9012b28a 964 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
965 return 0;
966}
967
69f9032d 968static int lbs_cmd_802_11_mac_address(struct lbs_private *priv,
876c9d3a
MT
969 struct cmd_ds_command *cmd,
970 u16 cmd_action)
971{
876c9d3a 972
8ff12da1 973 lbs_deb_enter(LBS_DEB_CMD);
0aef64d7 974 cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
981f187b 975 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
876c9d3a
MT
976 S_DS_GEN);
977 cmd->result = 0;
978
979 cmd->params.macadd.action = cpu_to_le16(cmd_action);
980
0aef64d7 981 if (cmd_action == CMD_ACT_SET) {
876c9d3a 982 memcpy(cmd->params.macadd.macadd,
aa21c004
DW
983 priv->current_addr, ETH_ALEN);
984 lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6);
876c9d3a
MT
985 }
986
8ff12da1 987 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
988 return 0;
989}
990
69f9032d 991static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv,
876c9d3a
MT
992 struct cmd_ds_command *cmd,
993 int cmd_action, void *pdata_buf)
994{
10078321 995 struct lbs_ioctl_regrdwr *ea = pdata_buf;
876c9d3a 996
9012b28a 997 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 998
0aef64d7 999 cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
981f187b
DW
1000 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
1001 S_DS_GEN);
876c9d3a
MT
1002 cmd->result = 0;
1003
1004 cmd->params.rdeeprom.action = cpu_to_le16(ea->action);
1005 cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset);
1006 cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
1007 cmd->params.rdeeprom.value = 0;
1008
8ff12da1 1009 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
1010 return 0;
1011}
1012
69f9032d 1013static int lbs_cmd_bt_access(struct lbs_private *priv,
876c9d3a
MT
1014 struct cmd_ds_command *cmd,
1015 u16 cmd_action, void *pdata_buf)
1016{
1017 struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
8ff12da1 1018 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
876c9d3a 1019
0aef64d7 1020 cmd->command = cpu_to_le16(CMD_BT_ACCESS);
981f187b 1021 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
876c9d3a
MT
1022 cmd->result = 0;
1023 bt_access->action = cpu_to_le16(cmd_action);
1024
1025 switch (cmd_action) {
0aef64d7 1026 case CMD_ACT_BT_ACCESS_ADD:
876c9d3a 1027 memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
ece56191 1028 lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
876c9d3a 1029 break;
0aef64d7 1030 case CMD_ACT_BT_ACCESS_DEL:
876c9d3a 1031 memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
ece56191 1032 lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
876c9d3a 1033 break;
0aef64d7 1034 case CMD_ACT_BT_ACCESS_LIST:
876c9d3a
MT
1035 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
1036 break;
0aef64d7 1037 case CMD_ACT_BT_ACCESS_RESET:
876c9d3a 1038 break;
0aef64d7 1039 case CMD_ACT_BT_ACCESS_SET_INVERT:
90e8eafc
LCC
1040 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
1041 break;
0aef64d7 1042 case CMD_ACT_BT_ACCESS_GET_INVERT:
90e8eafc 1043 break;
876c9d3a
MT
1044 default:
1045 break;
1046 }
8ff12da1 1047 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
1048 return 0;
1049}
1050
69f9032d 1051static int lbs_cmd_fwt_access(struct lbs_private *priv,
876c9d3a
MT
1052 struct cmd_ds_command *cmd,
1053 u16 cmd_action, void *pdata_buf)
1054{
1055 struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
8ff12da1 1056 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
876c9d3a 1057
0aef64d7 1058 cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
981f187b 1059 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
876c9d3a
MT
1060 cmd->result = 0;
1061
1062 if (pdata_buf)
1063 memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
1064 else
1065 memset(fwt_access, 0, sizeof(*fwt_access));
1066
1067 fwt_access->action = cpu_to_le16(cmd_action);
1068
8ff12da1 1069 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
1070 return 0;
1071}
1072
301eacbf
DW
1073int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
1074 struct cmd_ds_mesh_access *cmd)
876c9d3a 1075{
301eacbf
DW
1076 int ret;
1077
8ff12da1 1078 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
876c9d3a 1079
301eacbf 1080 cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
9fae899c 1081 cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
301eacbf 1082 cmd->hdr.result = 0;
876c9d3a 1083
301eacbf 1084 cmd->action = cpu_to_le16(cmd_action);
876c9d3a 1085
689442dc 1086 ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
876c9d3a 1087
8ff12da1 1088 lbs_deb_leave(LBS_DEB_CMD);
301eacbf 1089 return ret;
876c9d3a 1090}
301eacbf 1091EXPORT_SYMBOL_GPL(lbs_mesh_access);
876c9d3a 1092
86062134 1093int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan)
23a397ac
DW
1094{
1095 struct cmd_ds_mesh_config cmd;
1096
1097 memset(&cmd, 0, sizeof(cmd));
1098 cmd.action = cpu_to_le16(enable);
86062134 1099 cmd.channel = cpu_to_le16(chan);
020f3d00 1100 cmd.type = cpu_to_le16(priv->mesh_tlv);
9fae899c 1101 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
7e226272 1102
23a397ac
DW
1103 if (enable) {
1104 cmd.length = cpu_to_le16(priv->mesh_ssid_len);
1105 memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len);
1106 }
020f3d00 1107 lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n",
86062134 1108 enable, priv->mesh_tlv, chan,
06113c1c 1109 escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
689442dc 1110 return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd);
23a397ac
DW
1111}
1112
96287ac4
BD
1113static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
1114 struct cmd_ds_command *cmd,
1115 u16 cmd_action)
1116{
1117 struct cmd_ds_802_11_beacon_control
1118 *bcn_ctrl = &cmd->params.bcn_ctrl;
96287ac4
BD
1119
1120 lbs_deb_enter(LBS_DEB_CMD);
1121 cmd->size =
1122 cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
1123 + S_DS_GEN);
1124 cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
1125
1126 bcn_ctrl->action = cpu_to_le16(cmd_action);
aa21c004
DW
1127 bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
1128 bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
96287ac4
BD
1129
1130 lbs_deb_leave(LBS_DEB_CMD);
1131 return 0;
1132}
1133
681ffbb7
DW
1134static void lbs_queue_cmd(struct lbs_private *priv,
1135 struct cmd_ctrl_node *cmdnode)
876c9d3a
MT
1136{
1137 unsigned long flags;
681ffbb7 1138 int addtail = 1;
876c9d3a 1139
8ff12da1 1140 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 1141
c4ab4127
DW
1142 if (!cmdnode) {
1143 lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
876c9d3a
MT
1144 goto done;
1145 }
d9896ee1
DW
1146 if (!cmdnode->cmdbuf->size) {
1147 lbs_deb_host("DNLD_CMD: cmd size is zero\n");
1148 goto done;
1149 }
ae125bf8 1150 cmdnode->result = 0;
876c9d3a
MT
1151
1152 /* Exit_PS command needs to be queued in the header always. */
ddac4526 1153 if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
38bfab1a 1154 struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf[1];
ddac4526 1155
0aef64d7 1156 if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
aa21c004 1157 if (priv->psstate != PS_STATE_FULL_POWER)
876c9d3a
MT
1158 addtail = 0;
1159 }
1160 }
1161
aa21c004 1162 spin_lock_irqsave(&priv->driver_lock, flags);
876c9d3a 1163
ac47246e 1164 if (addtail)
aa21c004 1165 list_add_tail(&cmdnode->list, &priv->cmdpendingq);
ac47246e 1166 else
aa21c004 1167 list_add(&cmdnode->list, &priv->cmdpendingq);
876c9d3a 1168
aa21c004 1169 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 1170
8ff12da1 1171 lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
c4ab4127 1172 le16_to_cpu(cmdnode->cmdbuf->command));
876c9d3a
MT
1173
1174done:
8ff12da1 1175 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1176}
1177
18c52e7c
DW
1178static void lbs_submit_command(struct lbs_private *priv,
1179 struct cmd_ctrl_node *cmdnode)
876c9d3a
MT
1180{
1181 unsigned long flags;
ddac4526 1182 struct cmd_header *cmd;
18c52e7c
DW
1183 uint16_t cmdsize;
1184 uint16_t command;
1185 int timeo = 5 * HZ;
1186 int ret;
876c9d3a 1187
8ff12da1 1188 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 1189
ddac4526 1190 cmd = cmdnode->cmdbuf;
876c9d3a 1191
aa21c004 1192 spin_lock_irqsave(&priv->driver_lock, flags);
aa21c004
DW
1193 priv->cur_cmd = cmdnode;
1194 priv->cur_cmd_retcode = 0;
1195 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 1196
ddac4526
DW
1197 cmdsize = le16_to_cpu(cmd->size);
1198 command = le16_to_cpu(cmd->command);
876c9d3a 1199
18c52e7c
DW
1200 /* These commands take longer */
1201 if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
1202 command == CMD_802_11_AUTHENTICATE)
1203 timeo = 10 * HZ;
1204
e1258177
DW
1205 lbs_deb_host("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n",
1206 command, le16_to_cpu(cmd->seqnum), cmdsize, jiffies);
ddac4526 1207 lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
8ff12da1 1208
ddac4526 1209 ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
18c52e7c 1210
d9896ee1
DW
1211 if (ret) {
1212 lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
18c52e7c
DW
1213 /* Let the timer kick in and retry, and potentially reset
1214 the whole thing if the condition persists */
1215 timeo = HZ;
1216 } else
1217 lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n",
1218 command, jiffies);
876c9d3a
MT
1219
1220 /* Setup the timer after transmit command */
18c52e7c 1221 mod_timer(&priv->command_timer, jiffies + timeo);
876c9d3a 1222
18c52e7c 1223 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1224}
1225
69f9032d 1226static int lbs_cmd_mac_control(struct lbs_private *priv,
876c9d3a
MT
1227 struct cmd_ds_command *cmd)
1228{
1229 struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
1230
9012b28a 1231 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 1232
0aef64d7 1233 cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
981f187b 1234 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
aa21c004 1235 mac->action = cpu_to_le16(priv->currentpacketfilter);
876c9d3a 1236
8ff12da1 1237 lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
981f187b 1238 le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
876c9d3a 1239
9012b28a 1240 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
1241 return 0;
1242}
1243
1244/**
1245 * This function inserts command node to cmdfreeq
aa21c004 1246 * after cleans it. Requires priv->driver_lock held.
876c9d3a 1247 */
183aeac1 1248static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
5ba2f8a0 1249 struct cmd_ctrl_node *cmdnode)
876c9d3a 1250{
5ba2f8a0
DW
1251 lbs_deb_enter(LBS_DEB_HOST);
1252
1253 if (!cmdnode)
1254 goto out;
1255
5ba2f8a0
DW
1256 cmdnode->callback = NULL;
1257 cmdnode->callback_arg = 0;
876c9d3a 1258
5ba2f8a0 1259 memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
876c9d3a 1260
5ba2f8a0
DW
1261 list_add_tail(&cmdnode->list, &priv->cmdfreeq);
1262 out:
1263 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1264}
1265
69f9032d
HS
1266static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1267 struct cmd_ctrl_node *ptempcmd)
876c9d3a
MT
1268{
1269 unsigned long flags;
1270
aa21c004 1271 spin_lock_irqsave(&priv->driver_lock, flags);
10078321 1272 __lbs_cleanup_and_insert_cmd(priv, ptempcmd);
aa21c004 1273 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1274}
1275
183aeac1
DW
1276void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
1277 int result)
1278{
1279 if (cmd == priv->cur_cmd)
1280 priv->cur_cmd_retcode = result;
5ba2f8a0 1281
ae125bf8 1282 cmd->result = result;
5ba2f8a0
DW
1283 cmd->cmdwaitqwoken = 1;
1284 wake_up_interruptible(&cmd->cmdwait_q);
1285
ad12d0f4
DW
1286 if (!cmd->callback)
1287 __lbs_cleanup_and_insert_cmd(priv, cmd);
183aeac1
DW
1288 priv->cur_cmd = NULL;
1289}
1290
69f9032d 1291int lbs_set_radio_control(struct lbs_private *priv)
876c9d3a
MT
1292{
1293 int ret = 0;
a7c45890 1294 struct cmd_ds_802_11_radio_control cmd;
876c9d3a 1295
9012b28a 1296 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 1297
a7c45890
DW
1298 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1299 cmd.action = cpu_to_le16(CMD_ACT_SET);
1300
1301 switch (priv->preamble) {
1302 case CMD_TYPE_SHORT_PREAMBLE:
1303 cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE);
1304 break;
1305
1306 case CMD_TYPE_LONG_PREAMBLE:
1307 cmd.control = cpu_to_le16(SET_LONG_PREAMBLE);
1308 break;
1309
1310 case CMD_TYPE_AUTO_PREAMBLE:
1311 default:
1312 cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE);
1313 break;
1314 }
876c9d3a 1315
a7c45890
DW
1316 if (priv->radioon)
1317 cmd.control |= cpu_to_le16(TURN_ON_RF);
1318 else
1319 cmd.control &= cpu_to_le16(~TURN_ON_RF);
1320
1321 lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon,
1322 priv->preamble);
1323
1324 ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
876c9d3a 1325
9012b28a 1326 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
1327 return ret;
1328}
1329
69f9032d 1330int lbs_set_mac_packet_filter(struct lbs_private *priv)
876c9d3a
MT
1331{
1332 int ret = 0;
1333
9012b28a 1334 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 1335
876c9d3a 1336 /* Send MAC control command to station */
10078321 1337 ret = lbs_prepare_and_send_command(priv,
0aef64d7 1338 CMD_MAC_CONTROL, 0, 0, 0, NULL);
876c9d3a 1339
9012b28a 1340 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
1341 return ret;
1342}
1343
1344/**
1345 * @brief This function prepare the command before send to firmware.
1346 *
69f9032d 1347 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1348 * @param cmd_no command number
1349 * @param cmd_action command action: GET or SET
1350 * @param wait_option wait option: wait response or not
1351 * @param cmd_oid cmd oid: treated as sub command
1352 * @param pdata_buf A pointer to informaion buffer
1353 * @return 0 or -1
1354 */
69f9032d 1355int lbs_prepare_and_send_command(struct lbs_private *priv,
876c9d3a
MT
1356 u16 cmd_no,
1357 u16 cmd_action,
1358 u16 wait_option, u32 cmd_oid, void *pdata_buf)
1359{
1360 int ret = 0;
876c9d3a
MT
1361 struct cmd_ctrl_node *cmdnode;
1362 struct cmd_ds_command *cmdptr;
1363 unsigned long flags;
1364
8ff12da1 1365 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 1366
aa21c004
DW
1367 if (!priv) {
1368 lbs_deb_host("PREP_CMD: priv is NULL\n");
876c9d3a
MT
1369 ret = -1;
1370 goto done;
1371 }
1372
aa21c004 1373 if (priv->surpriseremoved) {
8ff12da1 1374 lbs_deb_host("PREP_CMD: card removed\n");
876c9d3a
MT
1375 ret = -1;
1376 goto done;
1377 }
1378
0d61d042 1379 cmdnode = lbs_get_cmd_ctrl_node(priv);
876c9d3a
MT
1380
1381 if (cmdnode == NULL) {
8ff12da1 1382 lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
876c9d3a
MT
1383
1384 /* Wake up main thread to execute next command */
fe336150 1385 wake_up_interruptible(&priv->waitq);
876c9d3a
MT
1386 ret = -1;
1387 goto done;
1388 }
1389
8e5b6b2d 1390 lbs_set_cmd_ctrl_node(priv, cmdnode, pdata_buf);
876c9d3a 1391
ddac4526 1392 cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
876c9d3a 1393
8ff12da1 1394 lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
876c9d3a 1395
876c9d3a 1396 /* Set sequence number, command and INT option */
aa21c004
DW
1397 priv->seqnum++;
1398 cmdptr->seqnum = cpu_to_le16(priv->seqnum);
876c9d3a 1399
981f187b 1400 cmdptr->command = cpu_to_le16(cmd_no);
876c9d3a
MT
1401 cmdptr->result = 0;
1402
1403 switch (cmd_no) {
0aef64d7 1404 case CMD_802_11_PS_MODE:
10078321 1405 ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
876c9d3a
MT
1406 break;
1407
0aef64d7 1408 case CMD_802_11_SCAN:
10078321 1409 ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
876c9d3a
MT
1410 break;
1411
0aef64d7 1412 case CMD_MAC_CONTROL:
10078321 1413 ret = lbs_cmd_mac_control(priv, cmdptr);
876c9d3a
MT
1414 break;
1415
0aef64d7
DW
1416 case CMD_802_11_ASSOCIATE:
1417 case CMD_802_11_REASSOCIATE:
10078321 1418 ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
876c9d3a
MT
1419 break;
1420
0aef64d7 1421 case CMD_802_11_DEAUTHENTICATE:
10078321 1422 ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
876c9d3a
MT
1423 break;
1424
0aef64d7 1425 case CMD_802_11_SET_WEP:
10078321 1426 ret = lbs_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
876c9d3a
MT
1427 break;
1428
0aef64d7 1429 case CMD_802_11_AD_HOC_START:
10078321 1430 ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
876c9d3a 1431 break;
0aef64d7 1432 case CMD_CODE_DNLD:
876c9d3a
MT
1433 break;
1434
0aef64d7 1435 case CMD_802_11_RESET:
10078321 1436 ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
876c9d3a
MT
1437 break;
1438
0aef64d7 1439 case CMD_802_11_GET_LOG:
10078321 1440 ret = lbs_cmd_802_11_get_log(priv, cmdptr);
876c9d3a
MT
1441 break;
1442
0aef64d7 1443 case CMD_802_11_AUTHENTICATE:
10078321 1444 ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
876c9d3a
MT
1445 break;
1446
0aef64d7 1447 case CMD_802_11_GET_STAT:
10078321 1448 ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
876c9d3a
MT
1449 break;
1450
0aef64d7 1451 case CMD_802_11_SNMP_MIB:
10078321 1452 ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
876c9d3a
MT
1453 cmd_action, cmd_oid, pdata_buf);
1454 break;
1455
0aef64d7
DW
1456 case CMD_MAC_REG_ACCESS:
1457 case CMD_BBP_REG_ACCESS:
1458 case CMD_RF_REG_ACCESS:
10078321 1459 ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
876c9d3a
MT
1460 break;
1461
0aef64d7 1462 case CMD_802_11_RF_TX_POWER:
10078321 1463 ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
876c9d3a
MT
1464 cmd_action, pdata_buf);
1465 break;
1466
0aef64d7 1467 case CMD_802_11_RATE_ADAPT_RATESET:
10078321 1468 ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
876c9d3a
MT
1469 cmdptr, cmd_action);
1470 break;
1471
0aef64d7 1472 case CMD_MAC_MULTICAST_ADR:
10078321 1473 ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
876c9d3a
MT
1474 break;
1475
965f8bbc 1476 case CMD_802_11_MONITOR_MODE:
10078321 1477 ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
965f8bbc
LCC
1478 cmd_action, pdata_buf);
1479 break;
1480
0aef64d7 1481 case CMD_802_11_AD_HOC_JOIN:
10078321 1482 ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
876c9d3a
MT
1483 break;
1484
0aef64d7 1485 case CMD_802_11_RSSI:
10078321 1486 ret = lbs_cmd_802_11_rssi(priv, cmdptr);
876c9d3a
MT
1487 break;
1488
0aef64d7 1489 case CMD_802_11_AD_HOC_STOP:
10078321 1490 ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
876c9d3a
MT
1491 break;
1492
0aef64d7 1493 case CMD_802_11_ENABLE_RSN:
10078321 1494 ret = lbs_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
90a42210 1495 pdata_buf);
876c9d3a
MT
1496 break;
1497
0aef64d7 1498 case CMD_802_11_KEY_MATERIAL:
10078321 1499 ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
90a42210 1500 cmd_oid, pdata_buf);
876c9d3a
MT
1501 break;
1502
0aef64d7 1503 case CMD_802_11_PAIRWISE_TSC:
876c9d3a 1504 break;
0aef64d7 1505 case CMD_802_11_GROUP_TSC:
876c9d3a
MT
1506 break;
1507
0aef64d7 1508 case CMD_802_11_MAC_ADDRESS:
10078321 1509 ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
876c9d3a
MT
1510 break;
1511
0aef64d7 1512 case CMD_802_11_EEPROM_ACCESS:
10078321 1513 ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
876c9d3a
MT
1514 cmd_action, pdata_buf);
1515 break;
1516
0aef64d7
DW
1517 case CMD_802_11_SET_AFC:
1518 case CMD_802_11_GET_AFC:
876c9d3a
MT
1519
1520 cmdptr->command = cpu_to_le16(cmd_no);
981f187b
DW
1521 cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
1522 S_DS_GEN);
876c9d3a
MT
1523
1524 memmove(&cmdptr->params.afc,
1525 pdata_buf, sizeof(struct cmd_ds_802_11_afc));
1526
1527 ret = 0;
1528 goto done;
1529
0aef64d7 1530 case CMD_802_11D_DOMAIN_INFO:
10078321 1531 ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
876c9d3a
MT
1532 cmd_no, cmd_action);
1533 break;
1534
0aef64d7
DW
1535 case CMD_802_11_TPC_CFG:
1536 cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
876c9d3a
MT
1537 cmdptr->size =
1538 cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
1539 S_DS_GEN);
1540
1541 memmove(&cmdptr->params.tpccfg,
1542 pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
1543
1544 ret = 0;
1545 break;
0aef64d7 1546 case CMD_802_11_LED_GPIO_CTRL:
876c9d3a
MT
1547 {
1548 struct mrvlietypes_ledgpio *gpio =
1549 (struct mrvlietypes_ledgpio*)
1550 cmdptr->params.ledgpio.data;
1551
1552 memmove(&cmdptr->params.ledgpio,
1553 pdata_buf,
1554 sizeof(struct cmd_ds_802_11_led_ctrl));
1555
1556 cmdptr->command =
0aef64d7 1557 cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
876c9d3a
MT
1558
1559#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
1560 cmdptr->size =
c2df2efe
HS
1561 cpu_to_le16(le16_to_cpu(gpio->header.len)
1562 + S_DS_GEN
1563 + ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
1564 gpio->header.len = gpio->header.len;
876c9d3a
MT
1565
1566 ret = 0;
1567 break;
1568 }
3a188649
HS
1569 case CMD_802_11_SUBSCRIBE_EVENT:
1570 lbs_cmd_802_11_subscribe_event(priv, cmdptr,
1571 cmd_action, pdata_buf);
1572 break;
0aef64d7
DW
1573 case CMD_802_11_PWR_CFG:
1574 cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
876c9d3a
MT
1575 cmdptr->size =
1576 cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
1577 S_DS_GEN);
1578 memmove(&cmdptr->params.pwrcfg, pdata_buf,
1579 sizeof(struct cmd_ds_802_11_pwr_cfg));
1580
1581 ret = 0;
1582 break;
0aef64d7 1583 case CMD_BT_ACCESS:
10078321 1584 ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
876c9d3a
MT
1585 break;
1586
0aef64d7 1587 case CMD_FWT_ACCESS:
10078321 1588 ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
876c9d3a
MT
1589 break;
1590
0aef64d7
DW
1591 case CMD_GET_TSF:
1592 cmdptr->command = cpu_to_le16(CMD_GET_TSF);
981f187b
DW
1593 cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
1594 S_DS_GEN);
876c9d3a
MT
1595 ret = 0;
1596 break;
96287ac4
BD
1597 case CMD_802_11_BEACON_CTRL:
1598 ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
1599 break;
876c9d3a 1600 default:
8ff12da1 1601 lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
876c9d3a
MT
1602 ret = -1;
1603 break;
1604 }
1605
1606 /* return error, since the command preparation failed */
1607 if (ret != 0) {
8ff12da1 1608 lbs_deb_host("PREP_CMD: command preparation failed\n");
10078321 1609 lbs_cleanup_and_insert_cmd(priv, cmdnode);
876c9d3a
MT
1610 ret = -1;
1611 goto done;
1612 }
1613
1614 cmdnode->cmdwaitqwoken = 0;
1615
681ffbb7 1616 lbs_queue_cmd(priv, cmdnode);
fe336150 1617 wake_up_interruptible(&priv->waitq);
876c9d3a 1618
0aef64d7 1619 if (wait_option & CMD_OPTION_WAITFORRSP) {
8ff12da1 1620 lbs_deb_host("PREP_CMD: wait for response\n");
876c9d3a
MT
1621 might_sleep();
1622 wait_event_interruptible(cmdnode->cmdwait_q,
1623 cmdnode->cmdwaitqwoken);
1624 }
1625
aa21c004
DW
1626 spin_lock_irqsave(&priv->driver_lock, flags);
1627 if (priv->cur_cmd_retcode) {
8ff12da1 1628 lbs_deb_host("PREP_CMD: command failed with return code %d\n",
aa21c004
DW
1629 priv->cur_cmd_retcode);
1630 priv->cur_cmd_retcode = 0;
876c9d3a
MT
1631 ret = -1;
1632 }
aa21c004 1633 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1634
1635done:
8ff12da1 1636 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
876c9d3a
MT
1637 return ret;
1638}
10078321 1639EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
876c9d3a
MT
1640
1641/**
1642 * @brief This function allocates the command buffer and link
1643 * it to command free queue.
1644 *
69f9032d 1645 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1646 * @return 0 or -1
1647 */
69f9032d 1648int lbs_allocate_cmd_buffer(struct lbs_private *priv)
876c9d3a
MT
1649{
1650 int ret = 0;
ddac4526 1651 u32 bufsize;
876c9d3a 1652 u32 i;
ddac4526 1653 struct cmd_ctrl_node *cmdarray;
876c9d3a 1654
8ff12da1 1655 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 1656
ddac4526
DW
1657 /* Allocate and initialize the command array */
1658 bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
1659 if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
8ff12da1 1660 lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
876c9d3a
MT
1661 ret = -1;
1662 goto done;
1663 }
ddac4526 1664 priv->cmd_array = cmdarray;
876c9d3a 1665
ddac4526
DW
1666 /* Allocate and initialize each command buffer in the command array */
1667 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
1668 cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
1669 if (!cmdarray[i].cmdbuf) {
8ff12da1 1670 lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
876c9d3a
MT
1671 ret = -1;
1672 goto done;
1673 }
876c9d3a
MT
1674 }
1675
ddac4526
DW
1676 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
1677 init_waitqueue_head(&cmdarray[i].cmdwait_q);
1678 lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
876c9d3a 1679 }
876c9d3a 1680 ret = 0;
9012b28a
HS
1681
1682done:
8ff12da1 1683 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
876c9d3a
MT
1684 return ret;
1685}
1686
1687/**
1688 * @brief This function frees the command buffer.
1689 *
69f9032d 1690 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1691 * @return 0 or -1
1692 */
69f9032d 1693int lbs_free_cmd_buffer(struct lbs_private *priv)
876c9d3a 1694{
ddac4526 1695 struct cmd_ctrl_node *cmdarray;
876c9d3a 1696 unsigned int i;
876c9d3a 1697
8ff12da1 1698 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a
MT
1699
1700 /* need to check if cmd array is allocated or not */
aa21c004 1701 if (priv->cmd_array == NULL) {
8ff12da1 1702 lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
876c9d3a
MT
1703 goto done;
1704 }
1705
ddac4526 1706 cmdarray = priv->cmd_array;
876c9d3a
MT
1707
1708 /* Release shared memory buffers */
ddac4526
DW
1709 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
1710 if (cmdarray[i].cmdbuf) {
1711 kfree(cmdarray[i].cmdbuf);
1712 cmdarray[i].cmdbuf = NULL;
876c9d3a
MT
1713 }
1714 }
1715
1716 /* Release cmd_ctrl_node */
aa21c004
DW
1717 if (priv->cmd_array) {
1718 kfree(priv->cmd_array);
1719 priv->cmd_array = NULL;
876c9d3a
MT
1720 }
1721
1722done:
8ff12da1 1723 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1724 return 0;
1725}
1726
1727/**
1728 * @brief This function gets a free command node if available in
1729 * command free queue.
1730 *
69f9032d 1731 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1732 * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
1733 */
2fd6cfe3 1734static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
876c9d3a
MT
1735{
1736 struct cmd_ctrl_node *tempnode;
876c9d3a
MT
1737 unsigned long flags;
1738
8ff12da1
HS
1739 lbs_deb_enter(LBS_DEB_HOST);
1740
aa21c004 1741 if (!priv)
876c9d3a
MT
1742 return NULL;
1743
aa21c004 1744 spin_lock_irqsave(&priv->driver_lock, flags);
876c9d3a 1745
aa21c004
DW
1746 if (!list_empty(&priv->cmdfreeq)) {
1747 tempnode = list_first_entry(&priv->cmdfreeq,
abe3ed14
LZ
1748 struct cmd_ctrl_node, list);
1749 list_del(&tempnode->list);
876c9d3a 1750 } else {
8ff12da1 1751 lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
876c9d3a
MT
1752 tempnode = NULL;
1753 }
1754
aa21c004 1755 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 1756
8ff12da1 1757 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1758 return tempnode;
1759}
1760
1761/**
1762 * @brief This function cleans command node.
1763 *
1764 * @param ptempnode A pointer to cmdCtrlNode structure
1765 * @return n/a
1766 */
876c9d3a
MT
1767
1768/**
1769 * @brief This function initializes the command node.
1770 *
69f9032d 1771 * @param priv A pointer to struct lbs_private structure
876c9d3a 1772 * @param ptempnode A pointer to cmd_ctrl_node structure
876c9d3a
MT
1773 * @param pdata_buf A pointer to informaion buffer
1774 * @return 0 or -1
1775 */
2fd6cfe3
DW
1776static void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
1777 struct cmd_ctrl_node *ptempnode,
8e5b6b2d 1778 void *pdata_buf)
876c9d3a 1779{
8ff12da1 1780 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a
MT
1781
1782 if (!ptempnode)
1783 return;
1784
1723047d 1785 ptempnode->callback = NULL;
75567670 1786 ptempnode->callback_arg = (unsigned long)pdata_buf;
876c9d3a 1787
8ff12da1 1788 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1789}
1790
1791/**
1792 * @brief This function executes next command in command
1793 * pending queue. It will put fimware back to PS mode
1794 * if applicable.
1795 *
69f9032d 1796 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1797 * @return 0 or -1
1798 */
69f9032d 1799int lbs_execute_next_command(struct lbs_private *priv)
876c9d3a 1800{
876c9d3a 1801 struct cmd_ctrl_node *cmdnode = NULL;
ddac4526 1802 struct cmd_header *cmd;
876c9d3a
MT
1803 unsigned long flags;
1804 int ret = 0;
1805
8ff12da1 1806 // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
10078321 1807 // only caller to us is lbs_thread() and we get even when a
8ff12da1
HS
1808 // data packet is received
1809 lbs_deb_enter(LBS_DEB_THREAD);
876c9d3a 1810
aa21c004 1811 spin_lock_irqsave(&priv->driver_lock, flags);
876c9d3a 1812
aa21c004 1813 if (priv->cur_cmd) {
8ff12da1 1814 lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
aa21c004 1815 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1816 ret = -1;
1817 goto done;
1818 }
1819
aa21c004
DW
1820 if (!list_empty(&priv->cmdpendingq)) {
1821 cmdnode = list_first_entry(&priv->cmdpendingq,
abe3ed14 1822 struct cmd_ctrl_node, list);
876c9d3a
MT
1823 }
1824
aa21c004 1825 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1826
1827 if (cmdnode) {
ddac4526 1828 cmd = cmdnode->cmdbuf;
876c9d3a 1829
ddac4526 1830 if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
aa21c004
DW
1831 if ((priv->psstate == PS_STATE_SLEEP) ||
1832 (priv->psstate == PS_STATE_PRE_SLEEP)) {
8ff12da1
HS
1833 lbs_deb_host(
1834 "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
ddac4526 1835 le16_to_cpu(cmd->command),
aa21c004 1836 priv->psstate);
876c9d3a
MT
1837 ret = -1;
1838 goto done;
1839 }
8ff12da1 1840 lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
ddac4526
DW
1841 "0x%04x in psstate %d\n",
1842 le16_to_cpu(cmd->command), priv->psstate);
aa21c004 1843 } else if (priv->psstate != PS_STATE_FULL_POWER) {
876c9d3a
MT
1844 /*
1845 * 1. Non-PS command:
1846 * Queue it. set needtowakeup to TRUE if current state
10078321 1847 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
876c9d3a
MT
1848 * 2. PS command but not Exit_PS:
1849 * Ignore it.
1850 * 3. PS command Exit_PS:
1851 * Set needtowakeup to TRUE if current state is SLEEP,
1852 * otherwise send this command down to firmware
1853 * immediately.
1854 */
ddac4526 1855 if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
876c9d3a
MT
1856 /* Prepare to send Exit PS,
1857 * this non PS command will be sent later */
aa21c004
DW
1858 if ((priv->psstate == PS_STATE_SLEEP)
1859 || (priv->psstate == PS_STATE_PRE_SLEEP)
876c9d3a
MT
1860 ) {
1861 /* w/ new scheme, it will not reach here.
1862 since it is blocked in main_thread. */
aa21c004 1863 priv->needtowakeup = 1;
876c9d3a 1864 } else
10078321 1865 lbs_ps_wakeup(priv, 0);
876c9d3a
MT
1866
1867 ret = 0;
1868 goto done;
1869 } else {
1870 /*
1871 * PS command. Ignore it if it is not Exit_PS.
1872 * otherwise send it down immediately.
1873 */
38bfab1a 1874 struct cmd_ds_802_11_ps_mode *psm = (void *)&cmd[1];
876c9d3a 1875
8ff12da1
HS
1876 lbs_deb_host(
1877 "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
876c9d3a
MT
1878 psm->action);
1879 if (psm->action !=
0aef64d7 1880 cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
8ff12da1
HS
1881 lbs_deb_host(
1882 "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
abe3ed14 1883 list_del(&cmdnode->list);
183aeac1
DW
1884 spin_lock_irqsave(&priv->driver_lock, flags);
1885 lbs_complete_command(priv, cmdnode, 0);
1886 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1887
1888 ret = 0;
1889 goto done;
1890 }
1891
aa21c004
DW
1892 if ((priv->psstate == PS_STATE_SLEEP) ||
1893 (priv->psstate == PS_STATE_PRE_SLEEP)) {
8ff12da1
HS
1894 lbs_deb_host(
1895 "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
abe3ed14 1896 list_del(&cmdnode->list);
183aeac1
DW
1897 spin_lock_irqsave(&priv->driver_lock, flags);
1898 lbs_complete_command(priv, cmdnode, 0);
1899 spin_unlock_irqrestore(&priv->driver_lock, flags);
aa21c004 1900 priv->needtowakeup = 1;
876c9d3a
MT
1901
1902 ret = 0;
1903 goto done;
1904 }
1905
8ff12da1
HS
1906 lbs_deb_host(
1907 "EXEC_NEXT_CMD: sending EXIT_PS\n");
876c9d3a
MT
1908 }
1909 }
abe3ed14 1910 list_del(&cmdnode->list);
8ff12da1 1911 lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
ddac4526 1912 le16_to_cpu(cmd->command));
d9896ee1 1913 lbs_submit_command(priv, cmdnode);
876c9d3a
MT
1914 } else {
1915 /*
1916 * check if in power save mode, if yes, put the device back
1917 * to PS mode
1918 */
aa21c004
DW
1919 if ((priv->psmode != LBS802_11POWERMODECAM) &&
1920 (priv->psstate == PS_STATE_FULL_POWER) &&
1921 ((priv->connect_status == LBS_CONNECTED) ||
1922 (priv->mesh_connect_status == LBS_CONNECTED))) {
1923 if (priv->secinfo.WPAenabled ||
1924 priv->secinfo.WPA2enabled) {
876c9d3a 1925 /* check for valid WPA group keys */
aa21c004
DW
1926 if (priv->wpa_mcast_key.len ||
1927 priv->wpa_unicast_key.len) {
8ff12da1 1928 lbs_deb_host(
876c9d3a
MT
1929 "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
1930 " go back to PS_SLEEP");
10078321 1931 lbs_ps_sleep(priv, 0);
876c9d3a
MT
1932 }
1933 } else {
8ff12da1
HS
1934 lbs_deb_host(
1935 "EXEC_NEXT_CMD: cmdpendingq empty, "
1936 "go back to PS_SLEEP");
10078321 1937 lbs_ps_sleep(priv, 0);
876c9d3a
MT
1938 }
1939 }
1940 }
1941
1942 ret = 0;
1943done:
8ff12da1 1944 lbs_deb_leave(LBS_DEB_THREAD);
876c9d3a
MT
1945 return ret;
1946}
1947
69f9032d 1948void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
876c9d3a
MT
1949{
1950 union iwreq_data iwrq;
1951 u8 buf[50];
1952
8ff12da1 1953 lbs_deb_enter(LBS_DEB_WEXT);
876c9d3a
MT
1954
1955 memset(&iwrq, 0, sizeof(union iwreq_data));
1956 memset(buf, 0, sizeof(buf));
1957
1958 snprintf(buf, sizeof(buf) - 1, "%s", str);
1959
1960 iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
1961
1962 /* Send Event to upper layer */
8ff12da1
HS
1963 lbs_deb_wext("event indication string %s\n", (char *)buf);
1964 lbs_deb_wext("event indication length %d\n", iwrq.data.length);
1965 lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
876c9d3a 1966
634b8f49 1967 wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
876c9d3a 1968
8ff12da1 1969 lbs_deb_leave(LBS_DEB_WEXT);
876c9d3a
MT
1970}
1971
69f9032d 1972static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
876c9d3a
MT
1973{
1974 unsigned long flags;
876c9d3a
MT
1975 int ret = 0;
1976
8ff12da1 1977 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 1978
8ff12da1 1979 lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
876c9d3a
MT
1980 size);
1981
8ff12da1 1982 lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
876c9d3a 1983
208fdd2f 1984 ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
876c9d3a 1985
aa21c004
DW
1986 spin_lock_irqsave(&priv->driver_lock, flags);
1987 if (priv->intcounter || priv->currenttxskb)
8ff12da1 1988 lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
aa21c004
DW
1989 priv->intcounter, priv->currenttxskb);
1990 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1991
1992 if (ret) {
1993 lbs_pr_alert(
1994 "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
1995 } else {
aa21c004
DW
1996 spin_lock_irqsave(&priv->driver_lock, flags);
1997 if (!priv->intcounter) {
1998 priv->psstate = PS_STATE_SLEEP;
876c9d3a 1999 } else {
8ff12da1 2000 lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
aa21c004 2001 priv->intcounter);
876c9d3a 2002 }
aa21c004 2003 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 2004
8ff12da1 2005 lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
876c9d3a
MT
2006 }
2007
8ff12da1 2008 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
876c9d3a
MT
2009 return ret;
2010}
2011
69f9032d 2012void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
876c9d3a 2013{
8ff12da1 2014 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a
MT
2015
2016 /*
2017 * PS is currently supported only in Infrastructure mode
2018 * Remove this check if it is to be supported in IBSS mode also
2019 */
2020
10078321 2021 lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
0aef64d7 2022 CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
876c9d3a 2023
8ff12da1 2024 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
2025}
2026
2027/**
8ff12da1 2028 * @brief This function sends Exit_PS command to firmware.
876c9d3a 2029 *
69f9032d 2030 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
2031 * @param wait_option wait response or not
2032 * @return n/a
2033 */
69f9032d 2034void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
876c9d3a 2035{
981f187b 2036 __le32 Localpsmode;
876c9d3a 2037
8ff12da1 2038 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 2039
10078321 2040 Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
876c9d3a 2041
10078321 2042 lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
0aef64d7 2043 CMD_SUBCMD_EXIT_PS,
876c9d3a
MT
2044 wait_option, 0, &Localpsmode);
2045
8ff12da1 2046 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
2047}
2048
2049/**
2050 * @brief This function checks condition and prepares to
2051 * send sleep confirm command to firmware if ok.
2052 *
69f9032d 2053 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
2054 * @param psmode Power Saving mode
2055 * @return n/a
2056 */
69f9032d 2057void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode)
876c9d3a
MT
2058{
2059 unsigned long flags =0;
876c9d3a
MT
2060 u8 allowed = 1;
2061
8ff12da1 2062 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 2063
634b8f49 2064 if (priv->dnld_sent) {
876c9d3a 2065 allowed = 0;
23d36eec 2066 lbs_deb_host("dnld_sent was set\n");
876c9d3a
MT
2067 }
2068
aa21c004
DW
2069 spin_lock_irqsave(&priv->driver_lock, flags);
2070 if (priv->cur_cmd) {
876c9d3a 2071 allowed = 0;
23d36eec 2072 lbs_deb_host("cur_cmd was set\n");
876c9d3a 2073 }
aa21c004 2074 if (priv->intcounter > 0) {
876c9d3a 2075 allowed = 0;
23d36eec 2076 lbs_deb_host("intcounter %d\n", priv->intcounter);
876c9d3a 2077 }
aa21c004 2078 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
2079
2080 if (allowed) {
10078321 2081 lbs_deb_host("sending lbs_ps_confirm_sleep\n");
aa21c004 2082 sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep,
876c9d3a
MT
2083 sizeof(struct PS_CMD_ConfirmSleep));
2084 } else {
8ff12da1 2085 lbs_deb_host("sleep confirm has been delayed\n");
876c9d3a
MT
2086 }
2087
8ff12da1 2088 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a 2089}
675787e2
HS
2090
2091
a8bdcd71
DW
2092/**
2093 * @brief Simple callback that copies response back into command
2094 *
2095 * @param priv A pointer to struct lbs_private structure
2096 * @param extra A pointer to the original command structure for which
2097 * 'resp' is a response
2098 * @param resp A pointer to the command response
2099 *
2100 * @return 0 on success, error on failure
2101 */
2102int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
ad9d7a7f 2103 struct cmd_header *resp)
a8bdcd71
DW
2104{
2105 struct cmd_header *buf = (void *)extra;
2106 uint16_t copy_len;
2107
2108 lbs_deb_enter(LBS_DEB_CMD);
2109
2110 copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
2111 lbs_deb_cmd("Copying back %u bytes; command response was %u bytes, "
ad9d7a7f
DW
2112 "copy back buffer was %u bytes\n", copy_len,
2113 le16_to_cpu(resp->size), le16_to_cpu(buf->size));
a8bdcd71
DW
2114 memcpy(buf, resp, copy_len);
2115
2116 lbs_deb_leave(LBS_DEB_CMD);
2117 return 0;
2118}
689442dc 2119EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
a8bdcd71 2120
3399ea5f
DW
2121struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command,
2122 struct cmd_header *in_cmd, int in_cmd_size,
2123 int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
2124 unsigned long callback_arg)
675787e2 2125{
675787e2 2126 struct cmd_ctrl_node *cmdnode;
675787e2
HS
2127
2128 lbs_deb_enter(LBS_DEB_HOST);
675787e2 2129
aa21c004 2130 if (priv->surpriseremoved) {
675787e2 2131 lbs_deb_host("PREP_CMD: card removed\n");
3399ea5f 2132 cmdnode = ERR_PTR(-ENOENT);
675787e2
HS
2133 goto done;
2134 }
2135
2136 cmdnode = lbs_get_cmd_ctrl_node(priv);
675787e2
HS
2137 if (cmdnode == NULL) {
2138 lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
2139
2140 /* Wake up main thread to execute next command */
2141 wake_up_interruptible(&priv->waitq);
3399ea5f 2142 cmdnode = ERR_PTR(-ENOBUFS);
675787e2
HS
2143 goto done;
2144 }
2145
448a51ae 2146 cmdnode->callback = callback;
1309b55b 2147 cmdnode->callback_arg = callback_arg;
675787e2 2148
7ad994de 2149 /* Copy the incoming command to the buffer */
ddac4526 2150 memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
7ad994de 2151
675787e2 2152 /* Set sequence number, clean result, move to buffer */
aa21c004 2153 priv->seqnum++;
ddac4526
DW
2154 cmdnode->cmdbuf->command = cpu_to_le16(command);
2155 cmdnode->cmdbuf->size = cpu_to_le16(in_cmd_size);
2156 cmdnode->cmdbuf->seqnum = cpu_to_le16(priv->seqnum);
2157 cmdnode->cmdbuf->result = 0;
675787e2
HS
2158
2159 lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
2160
2161 /* here was the big old switch() statement, which is now obsolete,
2162 * because the caller of lbs_cmd() sets up all of *cmd for us. */
2163
2164 cmdnode->cmdwaitqwoken = 0;
681ffbb7 2165 lbs_queue_cmd(priv, cmdnode);
675787e2
HS
2166 wake_up_interruptible(&priv->waitq);
2167
3399ea5f
DW
2168 done:
2169 lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
2170 return cmdnode;
2171}
2172
2173int __lbs_cmd(struct lbs_private *priv, uint16_t command,
2174 struct cmd_header *in_cmd, int in_cmd_size,
2175 int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
2176 unsigned long callback_arg)
2177{
2178 struct cmd_ctrl_node *cmdnode;
2179 unsigned long flags;
2180 int ret = 0;
2181
2182 lbs_deb_enter(LBS_DEB_HOST);
2183
2184 cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
2185 callback, callback_arg);
2186 if (IS_ERR(cmdnode)) {
2187 ret = PTR_ERR(cmdnode);
2188 goto done;
2189 }
2190
675787e2
HS
2191 might_sleep();
2192 wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
2193
aa21c004 2194 spin_lock_irqsave(&priv->driver_lock, flags);
ae125bf8
DW
2195 ret = cmdnode->result;
2196 if (ret)
2197 lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
2198 command, ret);
3399ea5f 2199
ad12d0f4 2200 __lbs_cleanup_and_insert_cmd(priv, cmdnode);
aa21c004 2201 spin_unlock_irqrestore(&priv->driver_lock, flags);
675787e2
HS
2202
2203done:
2204 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
2205 return ret;
2206}
14e865ba 2207EXPORT_SYMBOL_GPL(__lbs_cmd);
675787e2
HS
2208
2209
This page took 0.337902 seconds and 5 git commands to generate.