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