libertas: don't block usb8388 suspend if no wakeup conditions are set
[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
7919b89c 6#include <linux/kfifo.h>
e93156e7 7#include <linux/sched.h>
5a0e3ad6 8#include <linux/slab.h>
a45b6f4f 9#include <linux/if_arp.h>
e93156e7 10
876c9d3a 11#include "decl.h"
e86dc1ca 12#include "cfg.h"
6e66f03f 13#include "cmd.h"
876c9d3a 14
9fb7663d
DW
15#define CAL_NF(nf) ((s32)(-(s32)(nf)))
16#define CAL_RSSI(snr, nf) ((s32)((s32)(snr) + CAL_NF(nf)))
e93156e7 17
8db4a2b9
HS
18/**
19 * @brief Simple callback that copies response back into command
20 *
21 * @param priv A pointer to struct lbs_private structure
22 * @param extra A pointer to the original command structure for which
23 * 'resp' is a response
24 * @param resp A pointer to the command response
25 *
26 * @return 0 on success, error on failure
27 */
28int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
29 struct cmd_header *resp)
30{
31 struct cmd_header *buf = (void *)extra;
32 uint16_t copy_len;
33
34 copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
35 memcpy(buf, resp, copy_len);
36 return 0;
37}
38EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
39
40/**
41 * @brief Simple callback that ignores the result. Use this if
42 * you just want to send a command to the hardware, but don't
43 * care for the result.
44 *
45 * @param priv ignored
46 * @param extra ignored
47 * @param resp ignored
48 *
49 * @return 0 for success
50 */
51static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
52 struct cmd_header *resp)
53{
54 return 0;
55}
56
57
876c9d3a 58/**
852e1f2a 59 * @brief Checks whether a command is allowed in Power Save mode
876c9d3a
MT
60 *
61 * @param command the command ID
852e1f2a 62 * @return 1 if allowed, 0 if not allowed
876c9d3a 63 */
852e1f2a 64static u8 is_command_allowed_in_ps(u16 cmd)
876c9d3a 65{
852e1f2a
DW
66 switch (cmd) {
67 case CMD_802_11_RSSI:
68 return 1;
66fceb69
AK
69 case CMD_802_11_HOST_SLEEP_CFG:
70 return 1;
852e1f2a
DW
71 default:
72 break;
876c9d3a 73 }
876c9d3a
MT
74 return 0;
75}
76
6e66f03f
DW
77/**
78 * @brief Updates the hardware details like MAC address and regulatory region
79 *
80 * @param priv A pointer to struct lbs_private structure
81 *
82 * @return 0 on success, error on failure
83 */
84int lbs_update_hw_spec(struct lbs_private *priv)
876c9d3a 85{
6e66f03f
DW
86 struct cmd_ds_get_hw_spec cmd;
87 int ret = -1;
88 u32 i;
876c9d3a 89
9012b28a 90 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 91
6e66f03f
DW
92 memset(&cmd, 0, sizeof(cmd));
93 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
94 memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
689442dc 95 ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
6e66f03f
DW
96 if (ret)
97 goto out;
98
99 priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
6e66f03f 100
dac10a9f
HS
101 /* The firmware release is in an interesting format: the patch
102 * level is in the most significant nibble ... so fix that: */
103 priv->fwrelease = le32_to_cpu(cmd.fwrelease);
104 priv->fwrelease = (priv->fwrelease << 8) |
105 (priv->fwrelease >> 24 & 0xff);
106
107 /* Some firmware capabilities:
108 * CF card firmware 5.0.16p0: cap 0x00000303
109 * USB dongle firmware 5.110.17p2: cap 0x00000303
110 */
e174961c
JB
111 lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n",
112 cmd.permanentaddr,
dac10a9f
HS
113 priv->fwrelease >> 24 & 0xff,
114 priv->fwrelease >> 16 & 0xff,
115 priv->fwrelease >> 8 & 0xff,
116 priv->fwrelease & 0xff,
117 priv->fwcapinfo);
6e66f03f
DW
118 lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
119 cmd.hwifversion, cmd.version);
120
121 /* Clamp region code to 8-bit since FW spec indicates that it should
122 * only ever be 8-bit, even though the field size is 16-bit. Some firmware
123 * returns non-zero high 8 bits here.
15483996
MV
124 *
125 * Firmware version 4.0.102 used in CF8381 has region code shifted. We
126 * need to check for this problem and handle it properly.
6e66f03f 127 */
15483996
MV
128 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V4)
129 priv->regioncode = (le16_to_cpu(cmd.regioncode) >> 8) & 0xFF;
130 else
131 priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
6e66f03f
DW
132
133 for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
134 /* use the region code to search for the index */
135 if (priv->regioncode == lbs_region_code_to_index[i])
136 break;
137 }
138
139 /* if it's unidentified region code, use the default (USA) */
140 if (i >= MRVDRV_MAX_REGION_CODE) {
141 priv->regioncode = 0x10;
142 lbs_pr_info("unidentified region code; using the default (USA)\n");
143 }
144
145 if (priv->current_addr[0] == 0xff)
146 memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
876c9d3a 147
6e66f03f
DW
148 memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN);
149 if (priv->mesh_dev)
150 memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
151
6e66f03f 152out:
9012b28a 153 lbs_deb_leave(LBS_DEB_CMD);
6e66f03f 154 return ret;
876c9d3a
MT
155}
156
66fceb69
AK
157static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
158 struct cmd_header *resp)
159{
160 lbs_deb_enter(LBS_DEB_CMD);
1311843c 161 if (priv->is_host_sleep_activated) {
66fceb69
AK
162 priv->is_host_sleep_configured = 0;
163 if (priv->psstate == PS_STATE_FULL_POWER) {
164 priv->is_host_sleep_activated = 0;
165 wake_up_interruptible(&priv->host_sleep_q);
166 }
167 } else {
168 priv->is_host_sleep_configured = 1;
169 }
170 lbs_deb_leave(LBS_DEB_CMD);
171 return 0;
172}
173
582c1b53
AN
174int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
175 struct wol_config *p_wol_config)
6ce4fd2a
DW
176{
177 struct cmd_ds_host_sleep cmd_config;
178 int ret;
179
9fae899c 180 cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
6ce4fd2a 181 cmd_config.criteria = cpu_to_le32(criteria);
506e9025
DW
182 cmd_config.gpio = priv->wol_gpio;
183 cmd_config.gap = priv->wol_gap;
6ce4fd2a 184
582c1b53
AN
185 if (p_wol_config != NULL)
186 memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config,
187 sizeof(struct wol_config));
188 else
189 cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;
190
66fceb69
AK
191 ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config.hdr,
192 le16_to_cpu(cmd_config.hdr.size),
193 lbs_ret_host_sleep_cfg, 0);
506e9025 194 if (!ret) {
66fceb69 195 if (p_wol_config)
582c1b53
AN
196 memcpy((uint8_t *) p_wol_config,
197 (uint8_t *)&cmd_config.wol_conf,
198 sizeof(struct wol_config));
506e9025 199 } else {
6ce4fd2a 200 lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
6ce4fd2a 201 }
506e9025 202
6ce4fd2a
DW
203 return ret;
204}
205EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
206
0bb64087
DW
207/**
208 * @brief Sets the Power Save mode
209 *
210 * @param priv A pointer to struct lbs_private structure
211 * @param cmd_action The Power Save operation (PS_MODE_ACTION_ENTER_PS or
212 * PS_MODE_ACTION_EXIT_PS)
213 * @param block Whether to block on a response or not
214 *
215 * @return 0 on success, error on failure
216 */
217int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
876c9d3a 218{
0bb64087
DW
219 struct cmd_ds_802_11_ps_mode cmd;
220 int ret = 0;
876c9d3a 221
9012b28a 222 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 223
0bb64087
DW
224 memset(&cmd, 0, sizeof(cmd));
225 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
226 cmd.action = cpu_to_le16(cmd_action);
876c9d3a 227
0bb64087
DW
228 if (cmd_action == PS_MODE_ACTION_ENTER_PS) {
229 lbs_deb_cmd("PS_MODE: action ENTER_PS\n");
230 cmd.multipledtim = cpu_to_le16(1); /* Default DTIM multiple */
231 } else if (cmd_action == PS_MODE_ACTION_EXIT_PS) {
232 lbs_deb_cmd("PS_MODE: action EXIT_PS\n");
233 } else {
234 /* We don't handle CONFIRM_SLEEP here because it needs to
235 * be fastpathed to the firmware.
236 */
237 lbs_deb_cmd("PS_MODE: unknown action 0x%X\n", cmd_action);
238 ret = -EOPNOTSUPP;
239 goto out;
876c9d3a
MT
240 }
241
0bb64087
DW
242 if (block)
243 ret = lbs_cmd_with_response(priv, CMD_802_11_PS_MODE, &cmd);
244 else
245 lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd));
246
247out:
248 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
249 return ret;
876c9d3a
MT
250}
251
3fbe104c
DW
252int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
253 struct sleep_params *sp)
876c9d3a 254{
3fbe104c
DW
255 struct cmd_ds_802_11_sleep_params cmd;
256 int ret;
876c9d3a 257
9012b28a 258 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 259
0aef64d7 260 if (cmd_action == CMD_ACT_GET) {
3fbe104c
DW
261 memset(&cmd, 0, sizeof(cmd));
262 } else {
263 cmd.error = cpu_to_le16(sp->sp_error);
264 cmd.offset = cpu_to_le16(sp->sp_offset);
265 cmd.stabletime = cpu_to_le16(sp->sp_stabletime);
266 cmd.calcontrol = sp->sp_calcontrol;
267 cmd.externalsleepclk = sp->sp_extsleepclk;
268 cmd.reserved = cpu_to_le16(sp->sp_reserved);
876c9d3a 269 }
3fbe104c
DW
270 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
271 cmd.action = cpu_to_le16(cmd_action);
876c9d3a 272
3fbe104c
DW
273 ret = lbs_cmd_with_response(priv, CMD_802_11_SLEEP_PARAMS, &cmd);
274
275 if (!ret) {
276 lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, "
277 "calcontrol 0x%x extsleepclk 0x%x\n",
278 le16_to_cpu(cmd.error), le16_to_cpu(cmd.offset),
279 le16_to_cpu(cmd.stabletime), cmd.calcontrol,
280 cmd.externalsleepclk);
281
282 sp->sp_error = le16_to_cpu(cmd.error);
283 sp->sp_offset = le16_to_cpu(cmd.offset);
284 sp->sp_stabletime = le16_to_cpu(cmd.stabletime);
285 sp->sp_calcontrol = cmd.calcontrol;
286 sp->sp_extsleepclk = cmd.externalsleepclk;
287 sp->sp_reserved = le16_to_cpu(cmd.reserved);
288 }
289
290 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
291 return 0;
292}
293
49125454
AK
294static int lbs_wait_for_ds_awake(struct lbs_private *priv)
295{
296 int ret = 0;
297
298 lbs_deb_enter(LBS_DEB_CMD);
299
300 if (priv->is_deep_sleep) {
301 if (!wait_event_interruptible_timeout(priv->ds_awake_q,
302 !priv->is_deep_sleep, (10 * HZ))) {
303 lbs_pr_err("ds_awake_q: timer expired\n");
304 ret = -1;
305 }
306 }
307
308 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
309 return ret;
310}
311
312int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
313{
314 int ret = 0;
315
316 lbs_deb_enter(LBS_DEB_CMD);
317
318 if (deep_sleep) {
319 if (priv->is_deep_sleep != 1) {
320 lbs_deb_cmd("deep sleep: sleep\n");
321 BUG_ON(!priv->enter_deep_sleep);
322 ret = priv->enter_deep_sleep(priv);
323 if (!ret) {
324 netif_stop_queue(priv->dev);
325 netif_carrier_off(priv->dev);
326 }
327 } else {
328 lbs_pr_err("deep sleep: already enabled\n");
329 }
330 } else {
331 if (priv->is_deep_sleep) {
332 lbs_deb_cmd("deep sleep: wakeup\n");
333 BUG_ON(!priv->exit_deep_sleep);
334 ret = priv->exit_deep_sleep(priv);
335 if (!ret) {
336 ret = lbs_wait_for_ds_awake(priv);
337 if (ret)
338 lbs_pr_err("deep sleep: wakeup"
339 "failed\n");
340 }
341 }
342 }
343
344 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
345 return ret;
346}
347
1311843c
AK
348static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
349 unsigned long dummy,
350 struct cmd_header *cmd)
351{
352 lbs_deb_enter(LBS_DEB_FW);
353 priv->is_host_sleep_activated = 1;
354 wake_up_interruptible(&priv->host_sleep_q);
355 lbs_deb_leave(LBS_DEB_FW);
356 return 0;
357}
358
359int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
360{
361 struct cmd_header cmd;
362 int ret = 0;
363 uint32_t criteria = EHS_REMOVE_WAKEUP;
364
365 lbs_deb_enter(LBS_DEB_CMD);
366
367 if (host_sleep) {
368 if (priv->is_host_sleep_activated != 1) {
369 memset(&cmd, 0, sizeof(cmd));
370 ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
371 (struct wol_config *)NULL);
372 if (ret) {
373 lbs_pr_info("Host sleep configuration failed: "
374 "%d\n", ret);
375 return ret;
376 }
377 if (priv->psstate == PS_STATE_FULL_POWER) {
378 ret = __lbs_cmd(priv,
379 CMD_802_11_HOST_SLEEP_ACTIVATE,
380 &cmd,
381 sizeof(cmd),
382 lbs_ret_host_sleep_activate, 0);
383 if (ret)
384 lbs_pr_info("HOST_SLEEP_ACTIVATE "
385 "failed: %d\n", ret);
386 }
387
388 if (!wait_event_interruptible_timeout(
389 priv->host_sleep_q,
390 priv->is_host_sleep_activated,
391 (10 * HZ))) {
392 lbs_pr_err("host_sleep_q: timer expired\n");
393 ret = -1;
394 }
395 } else {
396 lbs_pr_err("host sleep: already enabled\n");
397 }
398 } else {
399 if (priv->is_host_sleep_activated)
400 ret = lbs_host_sleep_cfg(priv, criteria,
401 (struct wol_config *)NULL);
402 }
403
404 return ret;
405}
406
39fcf7a3
DW
407/**
408 * @brief Set an SNMP MIB value
409 *
410 * @param priv A pointer to struct lbs_private structure
411 * @param oid The OID to set in the firmware
412 * @param val Value to set the OID to
413 *
414 * @return 0 on success, error on failure
415 */
416int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
876c9d3a 417{
39fcf7a3
DW
418 struct cmd_ds_802_11_snmp_mib cmd;
419 int ret;
876c9d3a 420
9012b28a 421 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 422
39fcf7a3
DW
423 memset(&cmd, 0, sizeof (cmd));
424 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
425 cmd.action = cpu_to_le16(CMD_ACT_SET);
426 cmd.oid = cpu_to_le16((u16) oid);
876c9d3a 427
39fcf7a3
DW
428 switch (oid) {
429 case SNMP_MIB_OID_BSS_TYPE:
430 cmd.bufsize = cpu_to_le16(sizeof(u8));
fef0640e 431 cmd.value[0] = val;
39fcf7a3
DW
432 break;
433 case SNMP_MIB_OID_11D_ENABLE:
434 case SNMP_MIB_OID_FRAG_THRESHOLD:
435 case SNMP_MIB_OID_RTS_THRESHOLD:
436 case SNMP_MIB_OID_SHORT_RETRY_LIMIT:
437 case SNMP_MIB_OID_LONG_RETRY_LIMIT:
438 cmd.bufsize = cpu_to_le16(sizeof(u16));
439 *((__le16 *)(&cmd.value)) = cpu_to_le16(val);
876c9d3a 440 break;
39fcf7a3
DW
441 default:
442 lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid);
443 ret = -EINVAL;
444 goto out;
876c9d3a
MT
445 }
446
39fcf7a3
DW
447 lbs_deb_cmd("SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x\n",
448 le16_to_cpu(cmd.oid), le16_to_cpu(cmd.bufsize), val);
876c9d3a 449
39fcf7a3 450 ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
876c9d3a 451
39fcf7a3
DW
452out:
453 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
454 return ret;
455}
876c9d3a 456
39fcf7a3
DW
457/**
458 * @brief Get an SNMP MIB value
459 *
460 * @param priv A pointer to struct lbs_private structure
461 * @param oid The OID to retrieve from the firmware
462 * @param out_val Location for the returned value
463 *
464 * @return 0 on success, error on failure
465 */
466int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
467{
468 struct cmd_ds_802_11_snmp_mib cmd;
469 int ret;
876c9d3a 470
39fcf7a3 471 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 472
39fcf7a3
DW
473 memset(&cmd, 0, sizeof (cmd));
474 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
475 cmd.action = cpu_to_le16(CMD_ACT_GET);
476 cmd.oid = cpu_to_le16(oid);
876c9d3a 477
39fcf7a3
DW
478 ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
479 if (ret)
480 goto out;
876c9d3a 481
39fcf7a3
DW
482 switch (le16_to_cpu(cmd.bufsize)) {
483 case sizeof(u8):
fef0640e 484 *out_val = cmd.value[0];
39fcf7a3
DW
485 break;
486 case sizeof(u16):
487 *out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
876c9d3a
MT
488 break;
489 default:
39fcf7a3
DW
490 lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n",
491 oid, le16_to_cpu(cmd.bufsize));
876c9d3a
MT
492 break;
493 }
494
39fcf7a3
DW
495out:
496 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
497 return ret;
876c9d3a
MT
498}
499
87c8c72d
DW
500/**
501 * @brief Get the min, max, and current TX power
502 *
503 * @param priv A pointer to struct lbs_private structure
504 * @param curlevel Current power level in dBm
505 * @param minlevel Minimum supported power level in dBm (optional)
506 * @param maxlevel Maximum supported power level in dBm (optional)
507 *
508 * @return 0 on success, error on failure
509 */
510int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
511 s16 *maxlevel)
876c9d3a 512{
87c8c72d
DW
513 struct cmd_ds_802_11_rf_tx_power cmd;
514 int ret;
876c9d3a 515
9012b28a 516 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 517
87c8c72d
DW
518 memset(&cmd, 0, sizeof(cmd));
519 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
520 cmd.action = cpu_to_le16(CMD_ACT_GET);
521
522 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
523 if (ret == 0) {
524 *curlevel = le16_to_cpu(cmd.curlevel);
525 if (minlevel)
87bf24f3 526 *minlevel = cmd.minlevel;
87c8c72d 527 if (maxlevel)
87bf24f3 528 *maxlevel = cmd.maxlevel;
87c8c72d 529 }
876c9d3a 530
87c8c72d
DW
531 lbs_deb_leave(LBS_DEB_CMD);
532 return ret;
533}
876c9d3a 534
87c8c72d
DW
535/**
536 * @brief Set the TX power
537 *
538 * @param priv A pointer to struct lbs_private structure
539 * @param dbm The desired power level in dBm
540 *
541 * @return 0 on success, error on failure
542 */
543int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
544{
545 struct cmd_ds_802_11_rf_tx_power cmd;
546 int ret;
876c9d3a 547
87c8c72d 548 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 549
87c8c72d
DW
550 memset(&cmd, 0, sizeof(cmd));
551 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
552 cmd.action = cpu_to_le16(CMD_ACT_SET);
553 cmd.curlevel = cpu_to_le16(dbm);
876c9d3a 554
87c8c72d
DW
555 lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm);
556
557 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
9012b28a
HS
558
559 lbs_deb_leave(LBS_DEB_CMD);
87c8c72d 560 return ret;
876c9d3a
MT
561}
562
a45b6f4f
DW
563/**
564 * @brief Enable or disable monitor mode (only implemented on OLPC usb8388 FW)
565 *
566 * @param priv A pointer to struct lbs_private structure
567 * @param enable 1 to enable monitor mode, 0 to disable
568 *
569 * @return 0 on success, error on failure
570 */
571int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
965f8bbc 572{
a45b6f4f
DW
573 struct cmd_ds_802_11_monitor_mode cmd;
574 int ret;
965f8bbc 575
a45b6f4f
DW
576 memset(&cmd, 0, sizeof(cmd));
577 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
578 cmd.action = cpu_to_le16(CMD_ACT_SET);
579 if (enable)
580 cmd.mode = cpu_to_le16(0x1);
965f8bbc 581
a45b6f4f
DW
582 lbs_deb_cmd("SET_MONITOR_MODE: %d\n", enable);
583
584 ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd);
585 if (ret == 0) {
586 priv->dev->type = enable ? ARPHRD_IEEE80211_RADIOTAP :
587 ARPHRD_ETHER;
965f8bbc
LCC
588 }
589
a45b6f4f
DW
590 lbs_deb_leave(LBS_DEB_CMD);
591 return ret;
965f8bbc
LCC
592}
593
2dd4b262
DW
594/**
595 * @brief Get the radio channel
596 *
597 * @param priv A pointer to struct lbs_private structure
598 *
599 * @return The channel on success, error on failure
600 */
a3cbfb08 601static int lbs_get_channel(struct lbs_private *priv)
876c9d3a 602{
2dd4b262
DW
603 struct cmd_ds_802_11_rf_channel cmd;
604 int ret = 0;
876c9d3a 605
8ff12da1 606 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 607
8d0c7fad 608 memset(&cmd, 0, sizeof(cmd));
2dd4b262
DW
609 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
610 cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
876c9d3a 611
689442dc 612 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
2dd4b262
DW
613 if (ret)
614 goto out;
876c9d3a 615
cb182a60
DW
616 ret = le16_to_cpu(cmd.channel);
617 lbs_deb_cmd("current radio channel is %d\n", ret);
2dd4b262
DW
618
619out:
620 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
621 return ret;
622}
623
73ab1f25
HS
624int lbs_update_channel(struct lbs_private *priv)
625{
626 int ret;
627
628 /* the channel in f/w could be out of sync; get the current channel */
629 lbs_deb_enter(LBS_DEB_ASSOC);
630
631 ret = lbs_get_channel(priv);
632 if (ret > 0) {
c14951fe 633 priv->channel = ret;
73ab1f25
HS
634 ret = 0;
635 }
636 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
637 return ret;
638}
639
2dd4b262
DW
640/**
641 * @brief Set the radio channel
642 *
643 * @param priv A pointer to struct lbs_private structure
644 * @param channel The desired channel, or 0 to clear a locked channel
645 *
646 * @return 0 on success, error on failure
647 */
648int lbs_set_channel(struct lbs_private *priv, u8 channel)
649{
650 struct cmd_ds_802_11_rf_channel cmd;
96d46d5d 651#ifdef DEBUG
c14951fe 652 u8 old_channel = priv->channel;
96d46d5d 653#endif
2dd4b262
DW
654 int ret = 0;
655
656 lbs_deb_enter(LBS_DEB_CMD);
657
8d0c7fad 658 memset(&cmd, 0, sizeof(cmd));
2dd4b262
DW
659 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
660 cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
661 cmd.channel = cpu_to_le16(channel);
662
689442dc 663 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
2dd4b262
DW
664 if (ret)
665 goto out;
666
c14951fe 667 priv->channel = (uint8_t) le16_to_cpu(cmd.channel);
cb182a60 668 lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
c14951fe 669 priv->channel);
2dd4b262
DW
670
671out:
672 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
673 return ret;
876c9d3a
MT
674}
675
9fb7663d
DW
676/**
677 * @brief Get current RSSI and noise floor
678 *
679 * @param priv A pointer to struct lbs_private structure
680 * @param rssi On successful return, signal level in mBm
681 *
682 * @return The channel on success, error on failure
683 */
684int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
685{
686 struct cmd_ds_802_11_rssi cmd;
687 int ret = 0;
688
689 lbs_deb_enter(LBS_DEB_CMD);
690
691 BUG_ON(rssi == NULL);
692 BUG_ON(nf == NULL);
693
694 memset(&cmd, 0, sizeof(cmd));
695 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
696 /* Average SNR over last 8 beacons */
697 cmd.n_or_snr = cpu_to_le16(8);
698
699 ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd);
700 if (ret == 0) {
701 *nf = CAL_NF(le16_to_cpu(cmd.nf));
702 *rssi = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), le16_to_cpu(cmd.nf));
703 }
704
705 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
706 return ret;
707}
708
cc4b9d39
DW
709/**
710 * @brief Send regulatory and 802.11d domain information to the firmware
711 *
712 * @param priv pointer to struct lbs_private
713 * @param request cfg80211 regulatory request structure
714 * @param bands the device's supported bands and channels
715 *
716 * @return 0 on success, error code on failure
717*/
718int lbs_set_11d_domain_info(struct lbs_private *priv,
719 struct regulatory_request *request,
720 struct ieee80211_supported_band **bands)
721{
722 struct cmd_ds_802_11d_domain_info cmd;
723 struct mrvl_ie_domain_param_set *domain = &cmd.domain;
724 struct ieee80211_country_ie_triplet *t;
725 enum ieee80211_band band;
726 struct ieee80211_channel *ch;
727 u8 num_triplet = 0;
728 u8 num_parsed_chan = 0;
729 u8 first_channel = 0, next_chan = 0, max_pwr = 0;
730 u8 i, flag = 0;
731 size_t triplet_size;
732 int ret;
733
734 lbs_deb_enter(LBS_DEB_11D);
735
736 memset(&cmd, 0, sizeof(cmd));
737 cmd.action = cpu_to_le16(CMD_ACT_SET);
738
739 lbs_deb_11d("Setting country code '%c%c'\n",
740 request->alpha2[0], request->alpha2[1]);
741
742 domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
743
744 /* Set country code */
745 domain->country_code[0] = request->alpha2[0];
746 domain->country_code[1] = request->alpha2[1];
747 domain->country_code[2] = ' ';
748
749 /* Now set up the channel triplets; firmware is somewhat picky here
750 * and doesn't validate channel numbers and spans; hence it would
751 * interpret a triplet of (36, 4, 20) as channels 36, 37, 38, 39. Since
752 * the last 3 aren't valid channels, the driver is responsible for
753 * splitting that up into 4 triplet pairs of (36, 1, 20) + (40, 1, 20)
754 * etc.
755 */
756 for (band = 0;
757 (band < IEEE80211_NUM_BANDS) && (num_triplet < MAX_11D_TRIPLETS);
758 band++) {
759
760 if (!bands[band])
761 continue;
762
763 for (i = 0;
764 (i < bands[band]->n_channels) && (num_triplet < MAX_11D_TRIPLETS);
765 i++) {
766 ch = &bands[band]->channels[i];
767 if (ch->flags & IEEE80211_CHAN_DISABLED)
768 continue;
769
770 if (!flag) {
771 flag = 1;
772 next_chan = first_channel = (u32) ch->hw_value;
773 max_pwr = ch->max_power;
774 num_parsed_chan = 1;
775 continue;
776 }
777
778 if ((ch->hw_value == next_chan + 1) &&
779 (ch->max_power == max_pwr)) {
780 /* Consolidate adjacent channels */
781 next_chan++;
782 num_parsed_chan++;
783 } else {
784 /* Add this triplet */
785 lbs_deb_11d("11D triplet (%d, %d, %d)\n",
786 first_channel, num_parsed_chan,
787 max_pwr);
788 t = &domain->triplet[num_triplet];
789 t->chans.first_channel = first_channel;
790 t->chans.num_channels = num_parsed_chan;
791 t->chans.max_power = max_pwr;
792 num_triplet++;
793 flag = 0;
794 }
795 }
796
797 if (flag) {
798 /* Add last triplet */
799 lbs_deb_11d("11D triplet (%d, %d, %d)\n", first_channel,
800 num_parsed_chan, max_pwr);
801 t = &domain->triplet[num_triplet];
802 t->chans.first_channel = first_channel;
803 t->chans.num_channels = num_parsed_chan;
804 t->chans.max_power = max_pwr;
805 num_triplet++;
806 }
807 }
808
809 lbs_deb_11d("# triplets %d\n", num_triplet);
810
811 /* Set command header sizes */
812 triplet_size = num_triplet * sizeof(struct ieee80211_country_ie_triplet);
813 domain->header.len = cpu_to_le16(sizeof(domain->country_code) +
814 triplet_size);
815
816 lbs_deb_hex(LBS_DEB_11D, "802.11D domain param set",
817 (u8 *) &cmd.domain.country_code,
818 le16_to_cpu(domain->header.len));
819
820 cmd.hdr.size = cpu_to_le16(sizeof(cmd.hdr) +
821 sizeof(cmd.action) +
822 sizeof(cmd.domain.header) +
823 sizeof(cmd.domain.country_code) +
824 triplet_size);
825
826 ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);
827
828 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
829 return ret;
830}
831
4c7c6e00
DW
832/**
833 * @brief Read a MAC, Baseband, or RF register
834 *
835 * @param priv pointer to struct lbs_private
836 * @param cmd register command, one of CMD_MAC_REG_ACCESS,
837 * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
838 * @param offset byte offset of the register to get
839 * @param value on success, the value of the register at 'offset'
840 *
841 * @return 0 on success, error code on failure
842*/
843int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
876c9d3a 844{
4c7c6e00
DW
845 struct cmd_ds_reg_access cmd;
846 int ret = 0;
876c9d3a 847
9012b28a 848 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 849
4c7c6e00 850 BUG_ON(value == NULL);
876c9d3a 851
4c7c6e00
DW
852 memset(&cmd, 0, sizeof(cmd));
853 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
854 cmd.action = cpu_to_le16(CMD_ACT_GET);
876c9d3a 855
4c7c6e00
DW
856 if (reg != CMD_MAC_REG_ACCESS &&
857 reg != CMD_BBP_REG_ACCESS &&
858 reg != CMD_RF_REG_ACCESS) {
859 ret = -EINVAL;
860 goto out;
861 }
876c9d3a 862
4c7c6e00
DW
863 ret = lbs_cmd_with_response(priv, reg, &cmd);
864 if (ret) {
865 if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
866 *value = cmd.value.bbp_rf;
867 else if (reg == CMD_MAC_REG_ACCESS)
868 *value = le32_to_cpu(cmd.value.mac);
869 }
876c9d3a 870
4c7c6e00
DW
871out:
872 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
873 return ret;
874}
876c9d3a 875
4c7c6e00
DW
876/**
877 * @brief Write a MAC, Baseband, or RF register
878 *
879 * @param priv pointer to struct lbs_private
880 * @param cmd register command, one of CMD_MAC_REG_ACCESS,
881 * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
882 * @param offset byte offset of the register to set
883 * @param value the value to write to the register at 'offset'
884 *
885 * @return 0 on success, error code on failure
886*/
887int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
888{
889 struct cmd_ds_reg_access cmd;
890 int ret = 0;
876c9d3a 891
4c7c6e00 892 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 893
4c7c6e00
DW
894 memset(&cmd, 0, sizeof(cmd));
895 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
896 cmd.action = cpu_to_le16(CMD_ACT_SET);
876c9d3a 897
4c7c6e00
DW
898 if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
899 cmd.value.bbp_rf = (u8) (value & 0xFF);
900 else if (reg == CMD_MAC_REG_ACCESS)
901 cmd.value.mac = cpu_to_le32(value);
902 else {
903 ret = -EINVAL;
904 goto out;
876c9d3a
MT
905 }
906
4c7c6e00
DW
907 ret = lbs_cmd_with_response(priv, reg, &cmd);
908
909out:
910 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
911 return ret;
876c9d3a
MT
912}
913
681ffbb7
DW
914static void lbs_queue_cmd(struct lbs_private *priv,
915 struct cmd_ctrl_node *cmdnode)
876c9d3a
MT
916{
917 unsigned long flags;
681ffbb7 918 int addtail = 1;
876c9d3a 919
8ff12da1 920 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 921
c4ab4127
DW
922 if (!cmdnode) {
923 lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
876c9d3a
MT
924 goto done;
925 }
d9896ee1
DW
926 if (!cmdnode->cmdbuf->size) {
927 lbs_deb_host("DNLD_CMD: cmd size is zero\n");
928 goto done;
929 }
ae125bf8 930 cmdnode->result = 0;
876c9d3a
MT
931
932 /* Exit_PS command needs to be queued in the header always. */
ddac4526 933 if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
0bb64087 934 struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf;
ddac4526 935
0bb64087 936 if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
aa21c004 937 if (priv->psstate != PS_STATE_FULL_POWER)
876c9d3a
MT
938 addtail = 0;
939 }
940 }
941
0bb64087 942 if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_WAKEUP_CONFIRM)
66fceb69
AK
943 addtail = 0;
944
aa21c004 945 spin_lock_irqsave(&priv->driver_lock, flags);
876c9d3a 946
ac47246e 947 if (addtail)
aa21c004 948 list_add_tail(&cmdnode->list, &priv->cmdpendingq);
ac47246e 949 else
aa21c004 950 list_add(&cmdnode->list, &priv->cmdpendingq);
876c9d3a 951
aa21c004 952 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 953
8ff12da1 954 lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
c4ab4127 955 le16_to_cpu(cmdnode->cmdbuf->command));
876c9d3a
MT
956
957done:
8ff12da1 958 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
959}
960
18c52e7c
DW
961static void lbs_submit_command(struct lbs_private *priv,
962 struct cmd_ctrl_node *cmdnode)
876c9d3a
MT
963{
964 unsigned long flags;
ddac4526 965 struct cmd_header *cmd;
18c52e7c
DW
966 uint16_t cmdsize;
967 uint16_t command;
57962f0b 968 int timeo = 3 * HZ;
18c52e7c 969 int ret;
876c9d3a 970
8ff12da1 971 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 972
ddac4526 973 cmd = cmdnode->cmdbuf;
876c9d3a 974
aa21c004 975 spin_lock_irqsave(&priv->driver_lock, flags);
aa21c004 976 priv->cur_cmd = cmdnode;
aa21c004 977 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 978
ddac4526
DW
979 cmdsize = le16_to_cpu(cmd->size);
980 command = le16_to_cpu(cmd->command);
876c9d3a 981
18c52e7c 982 /* These commands take longer */
be0d76e4 983 if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE)
57962f0b 984 timeo = 5 * HZ;
18c52e7c 985
e5225b39
HS
986 lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
987 command, le16_to_cpu(cmd->seqnum), cmdsize);
1afc09ab 988 lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
8ff12da1 989
ddac4526 990 ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
18c52e7c 991
d9896ee1
DW
992 if (ret) {
993 lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
18c52e7c
DW
994 /* Let the timer kick in and retry, and potentially reset
995 the whole thing if the condition persists */
57962f0b 996 timeo = HZ/4;
1afc09ab 997 }
876c9d3a 998
49125454
AK
999 if (command == CMD_802_11_DEEP_SLEEP) {
1000 if (priv->is_auto_deep_sleep_enabled) {
1001 priv->wakeup_dev_required = 1;
1002 priv->dnld_sent = 0;
1003 }
1004 priv->is_deep_sleep = 1;
1005 lbs_complete_command(priv, cmdnode, 0);
1006 } else {
1007 /* Setup the timer after transmit command */
1008 mod_timer(&priv->command_timer, jiffies + timeo);
1009 }
876c9d3a 1010
18c52e7c 1011 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1012}
1013
876c9d3a
MT
1014/**
1015 * This function inserts command node to cmdfreeq
aa21c004 1016 * after cleans it. Requires priv->driver_lock held.
876c9d3a 1017 */
183aeac1 1018static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
5ba2f8a0 1019 struct cmd_ctrl_node *cmdnode)
876c9d3a 1020{
5ba2f8a0
DW
1021 lbs_deb_enter(LBS_DEB_HOST);
1022
1023 if (!cmdnode)
1024 goto out;
1025
5ba2f8a0
DW
1026 cmdnode->callback = NULL;
1027 cmdnode->callback_arg = 0;
876c9d3a 1028
5ba2f8a0 1029 memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
876c9d3a 1030
5ba2f8a0
DW
1031 list_add_tail(&cmdnode->list, &priv->cmdfreeq);
1032 out:
1033 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1034}
1035
69f9032d
HS
1036static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1037 struct cmd_ctrl_node *ptempcmd)
876c9d3a
MT
1038{
1039 unsigned long flags;
1040
aa21c004 1041 spin_lock_irqsave(&priv->driver_lock, flags);
10078321 1042 __lbs_cleanup_and_insert_cmd(priv, ptempcmd);
aa21c004 1043 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1044}
1045
183aeac1
DW
1046void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
1047 int result)
1048{
ae125bf8 1049 cmd->result = result;
5ba2f8a0
DW
1050 cmd->cmdwaitqwoken = 1;
1051 wake_up_interruptible(&cmd->cmdwait_q);
1052
8db4a2b9 1053 if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
ad12d0f4 1054 __lbs_cleanup_and_insert_cmd(priv, cmd);
183aeac1
DW
1055 priv->cur_cmd = NULL;
1056}
1057
d5db2dfa 1058int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
876c9d3a 1059{
a7c45890 1060 struct cmd_ds_802_11_radio_control cmd;
d5db2dfa 1061 int ret = -EINVAL;
876c9d3a 1062
9012b28a 1063 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 1064
a7c45890
DW
1065 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1066 cmd.action = cpu_to_le16(CMD_ACT_SET);
1067
d5db2dfa
DW
1068 /* Only v8 and below support setting the preamble */
1069 if (priv->fwrelease < 0x09000000) {
1070 switch (preamble) {
1071 case RADIO_PREAMBLE_SHORT:
d5db2dfa
DW
1072 case RADIO_PREAMBLE_AUTO:
1073 case RADIO_PREAMBLE_LONG:
1074 cmd.control = cpu_to_le16(preamble);
1075 break;
1076 default:
1077 goto out;
1078 }
1079 }
a7c45890 1080
d5db2dfa
DW
1081 if (radio_on)
1082 cmd.control |= cpu_to_le16(0x1);
1083 else {
1084 cmd.control &= cpu_to_le16(~0x1);
1085 priv->txpower_cur = 0;
a7c45890 1086 }
876c9d3a 1087
d5db2dfa
DW
1088 lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n",
1089 radio_on ? "ON" : "OFF", preamble);
a7c45890 1090
d5db2dfa 1091 priv->radio_on = radio_on;
a7c45890
DW
1092
1093 ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
876c9d3a 1094
d5db2dfa 1095out:
9012b28a 1096 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
1097 return ret;
1098}
1099
c97329e2 1100void lbs_set_mac_control(struct lbs_private *priv)
876c9d3a 1101{
835d3ac5 1102 struct cmd_ds_mac_control cmd;
876c9d3a 1103
9012b28a 1104 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 1105
835d3ac5 1106 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
d9e9778c 1107 cmd.action = cpu_to_le16(priv->mac_control);
835d3ac5
HS
1108 cmd.reserved = 0;
1109
75bf45a7 1110 lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
876c9d3a 1111
c97329e2 1112 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
1113}
1114
876c9d3a
MT
1115/**
1116 * @brief This function allocates the command buffer and link
1117 * it to command free queue.
1118 *
69f9032d 1119 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1120 * @return 0 or -1
1121 */
69f9032d 1122int lbs_allocate_cmd_buffer(struct lbs_private *priv)
876c9d3a
MT
1123{
1124 int ret = 0;
ddac4526 1125 u32 bufsize;
876c9d3a 1126 u32 i;
ddac4526 1127 struct cmd_ctrl_node *cmdarray;
876c9d3a 1128
8ff12da1 1129 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 1130
ddac4526
DW
1131 /* Allocate and initialize the command array */
1132 bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
1133 if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
8ff12da1 1134 lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
876c9d3a
MT
1135 ret = -1;
1136 goto done;
1137 }
ddac4526 1138 priv->cmd_array = cmdarray;
876c9d3a 1139
ddac4526
DW
1140 /* Allocate and initialize each command buffer in the command array */
1141 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
1142 cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
1143 if (!cmdarray[i].cmdbuf) {
8ff12da1 1144 lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
876c9d3a
MT
1145 ret = -1;
1146 goto done;
1147 }
876c9d3a
MT
1148 }
1149
ddac4526
DW
1150 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
1151 init_waitqueue_head(&cmdarray[i].cmdwait_q);
1152 lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
876c9d3a 1153 }
876c9d3a 1154 ret = 0;
9012b28a
HS
1155
1156done:
8ff12da1 1157 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
876c9d3a
MT
1158 return ret;
1159}
1160
1161/**
1162 * @brief This function frees the command buffer.
1163 *
69f9032d 1164 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1165 * @return 0 or -1
1166 */
69f9032d 1167int lbs_free_cmd_buffer(struct lbs_private *priv)
876c9d3a 1168{
ddac4526 1169 struct cmd_ctrl_node *cmdarray;
876c9d3a 1170 unsigned int i;
876c9d3a 1171
8ff12da1 1172 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a
MT
1173
1174 /* need to check if cmd array is allocated or not */
aa21c004 1175 if (priv->cmd_array == NULL) {
8ff12da1 1176 lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
876c9d3a
MT
1177 goto done;
1178 }
1179
ddac4526 1180 cmdarray = priv->cmd_array;
876c9d3a
MT
1181
1182 /* Release shared memory buffers */
ddac4526
DW
1183 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
1184 if (cmdarray[i].cmdbuf) {
1185 kfree(cmdarray[i].cmdbuf);
1186 cmdarray[i].cmdbuf = NULL;
876c9d3a
MT
1187 }
1188 }
1189
1190 /* Release cmd_ctrl_node */
aa21c004
DW
1191 if (priv->cmd_array) {
1192 kfree(priv->cmd_array);
1193 priv->cmd_array = NULL;
876c9d3a
MT
1194 }
1195
1196done:
8ff12da1 1197 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1198 return 0;
1199}
1200
1201/**
1202 * @brief This function gets a free command node if available in
1203 * command free queue.
1204 *
69f9032d 1205 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1206 * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
1207 */
d06956b5 1208static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
876c9d3a
MT
1209{
1210 struct cmd_ctrl_node *tempnode;
876c9d3a
MT
1211 unsigned long flags;
1212
8ff12da1
HS
1213 lbs_deb_enter(LBS_DEB_HOST);
1214
aa21c004 1215 if (!priv)
876c9d3a
MT
1216 return NULL;
1217
aa21c004 1218 spin_lock_irqsave(&priv->driver_lock, flags);
876c9d3a 1219
aa21c004
DW
1220 if (!list_empty(&priv->cmdfreeq)) {
1221 tempnode = list_first_entry(&priv->cmdfreeq,
abe3ed14
LZ
1222 struct cmd_ctrl_node, list);
1223 list_del(&tempnode->list);
876c9d3a 1224 } else {
8ff12da1 1225 lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
876c9d3a
MT
1226 tempnode = NULL;
1227 }
1228
aa21c004 1229 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 1230
8ff12da1 1231 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1232 return tempnode;
1233}
1234
876c9d3a
MT
1235/**
1236 * @brief This function executes next command in command
877d0310 1237 * pending queue. It will put firmware back to PS mode
876c9d3a
MT
1238 * if applicable.
1239 *
69f9032d 1240 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1241 * @return 0 or -1
1242 */
69f9032d 1243int lbs_execute_next_command(struct lbs_private *priv)
876c9d3a 1244{
876c9d3a 1245 struct cmd_ctrl_node *cmdnode = NULL;
ddac4526 1246 struct cmd_header *cmd;
876c9d3a
MT
1247 unsigned long flags;
1248 int ret = 0;
1249
1afc09ab
HS
1250 /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
1251 * only caller to us is lbs_thread() and we get even when a
1252 * data packet is received */
8ff12da1 1253 lbs_deb_enter(LBS_DEB_THREAD);
876c9d3a 1254
aa21c004 1255 spin_lock_irqsave(&priv->driver_lock, flags);
876c9d3a 1256
aa21c004 1257 if (priv->cur_cmd) {
8ff12da1 1258 lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
aa21c004 1259 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1260 ret = -1;
1261 goto done;
1262 }
1263
aa21c004
DW
1264 if (!list_empty(&priv->cmdpendingq)) {
1265 cmdnode = list_first_entry(&priv->cmdpendingq,
abe3ed14 1266 struct cmd_ctrl_node, list);
876c9d3a
MT
1267 }
1268
aa21c004 1269 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1270
1271 if (cmdnode) {
ddac4526 1272 cmd = cmdnode->cmdbuf;
876c9d3a 1273
ddac4526 1274 if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
aa21c004
DW
1275 if ((priv->psstate == PS_STATE_SLEEP) ||
1276 (priv->psstate == PS_STATE_PRE_SLEEP)) {
8ff12da1
HS
1277 lbs_deb_host(
1278 "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
ddac4526 1279 le16_to_cpu(cmd->command),
aa21c004 1280 priv->psstate);
876c9d3a
MT
1281 ret = -1;
1282 goto done;
1283 }
8ff12da1 1284 lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
ddac4526
DW
1285 "0x%04x in psstate %d\n",
1286 le16_to_cpu(cmd->command), priv->psstate);
aa21c004 1287 } else if (priv->psstate != PS_STATE_FULL_POWER) {
876c9d3a
MT
1288 /*
1289 * 1. Non-PS command:
1290 * Queue it. set needtowakeup to TRUE if current state
0bb64087
DW
1291 * is SLEEP, otherwise call send EXIT_PS.
1292 * 2. PS command but not EXIT_PS:
876c9d3a 1293 * Ignore it.
0bb64087 1294 * 3. PS command EXIT_PS:
876c9d3a
MT
1295 * Set needtowakeup to TRUE if current state is SLEEP,
1296 * otherwise send this command down to firmware
1297 * immediately.
1298 */
ddac4526 1299 if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
876c9d3a
MT
1300 /* Prepare to send Exit PS,
1301 * this non PS command will be sent later */
aa21c004
DW
1302 if ((priv->psstate == PS_STATE_SLEEP)
1303 || (priv->psstate == PS_STATE_PRE_SLEEP)
876c9d3a
MT
1304 ) {
1305 /* w/ new scheme, it will not reach here.
1306 since it is blocked in main_thread. */
aa21c004 1307 priv->needtowakeup = 1;
0bb64087
DW
1308 } else {
1309 lbs_set_ps_mode(priv,
1310 PS_MODE_ACTION_EXIT_PS,
1311 false);
1312 }
876c9d3a
MT
1313
1314 ret = 0;
1315 goto done;
1316 } else {
1317 /*
1318 * PS command. Ignore it if it is not Exit_PS.
1319 * otherwise send it down immediately.
1320 */
38bfab1a 1321 struct cmd_ds_802_11_ps_mode *psm = (void *)&cmd[1];
876c9d3a 1322
8ff12da1
HS
1323 lbs_deb_host(
1324 "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
876c9d3a
MT
1325 psm->action);
1326 if (psm->action !=
0bb64087 1327 cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
8ff12da1
HS
1328 lbs_deb_host(
1329 "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
abe3ed14 1330 list_del(&cmdnode->list);
183aeac1
DW
1331 spin_lock_irqsave(&priv->driver_lock, flags);
1332 lbs_complete_command(priv, cmdnode, 0);
1333 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1334
1335 ret = 0;
1336 goto done;
1337 }
1338
aa21c004
DW
1339 if ((priv->psstate == PS_STATE_SLEEP) ||
1340 (priv->psstate == PS_STATE_PRE_SLEEP)) {
8ff12da1
HS
1341 lbs_deb_host(
1342 "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
abe3ed14 1343 list_del(&cmdnode->list);
183aeac1
DW
1344 spin_lock_irqsave(&priv->driver_lock, flags);
1345 lbs_complete_command(priv, cmdnode, 0);
1346 spin_unlock_irqrestore(&priv->driver_lock, flags);
aa21c004 1347 priv->needtowakeup = 1;
876c9d3a
MT
1348
1349 ret = 0;
1350 goto done;
1351 }
1352
8ff12da1
HS
1353 lbs_deb_host(
1354 "EXEC_NEXT_CMD: sending EXIT_PS\n");
876c9d3a
MT
1355 }
1356 }
abe3ed14 1357 list_del(&cmdnode->list);
8ff12da1 1358 lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
ddac4526 1359 le16_to_cpu(cmd->command));
d9896ee1 1360 lbs_submit_command(priv, cmdnode);
876c9d3a
MT
1361 } else {
1362 /*
1363 * check if in power save mode, if yes, put the device back
1364 * to PS mode
1365 */
e86dc1ca
KD
1366#ifdef TODO
1367 /*
1368 * This was the old code for libertas+wext. Someone that
1369 * understands this beast should re-code it in a sane way.
1370 *
1371 * I actually don't understand why this is related to WPA
1372 * and to connection status, shouldn't powering should be
1373 * independ of such things?
1374 */
aa21c004
DW
1375 if ((priv->psmode != LBS802_11POWERMODECAM) &&
1376 (priv->psstate == PS_STATE_FULL_POWER) &&
1377 ((priv->connect_status == LBS_CONNECTED) ||
602114ae 1378 lbs_mesh_connected(priv))) {
aa21c004
DW
1379 if (priv->secinfo.WPAenabled ||
1380 priv->secinfo.WPA2enabled) {
876c9d3a 1381 /* check for valid WPA group keys */
aa21c004
DW
1382 if (priv->wpa_mcast_key.len ||
1383 priv->wpa_unicast_key.len) {
8ff12da1 1384 lbs_deb_host(
876c9d3a
MT
1385 "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
1386 " go back to PS_SLEEP");
0bb64087
DW
1387 lbs_set_ps_mode(priv,
1388 PS_MODE_ACTION_ENTER_PS,
1389 false);
876c9d3a
MT
1390 }
1391 } else {
8ff12da1
HS
1392 lbs_deb_host(
1393 "EXEC_NEXT_CMD: cmdpendingq empty, "
1394 "go back to PS_SLEEP");
0bb64087
DW
1395 lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
1396 false);
876c9d3a
MT
1397 }
1398 }
e86dc1ca 1399#endif
876c9d3a
MT
1400 }
1401
1402 ret = 0;
1403done:
8ff12da1 1404 lbs_deb_leave(LBS_DEB_THREAD);
876c9d3a
MT
1405 return ret;
1406}
1407
f539f2ef 1408static void lbs_send_confirmsleep(struct lbs_private *priv)
876c9d3a
MT
1409{
1410 unsigned long flags;
f539f2ef 1411 int ret;
876c9d3a 1412
8ff12da1 1413 lbs_deb_enter(LBS_DEB_HOST);
f539f2ef
HS
1414 lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,
1415 sizeof(confirm_sleep));
876c9d3a 1416
f539f2ef
HS
1417 ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
1418 sizeof(confirm_sleep));
876c9d3a 1419 if (ret) {
f539f2ef 1420 lbs_pr_alert("confirm_sleep failed\n");
7919b89c 1421 goto out;
876c9d3a 1422 }
7919b89c
HS
1423
1424 spin_lock_irqsave(&priv->driver_lock, flags);
1425
a01f5450
HS
1426 /* We don't get a response on the sleep-confirmation */
1427 priv->dnld_sent = DNLD_RES_RECEIVED;
1428
66fceb69
AK
1429 if (priv->is_host_sleep_configured) {
1430 priv->is_host_sleep_activated = 1;
1431 wake_up_interruptible(&priv->host_sleep_q);
1432 }
1433
7919b89c 1434 /* If nothing to do, go back to sleep (?) */
e64c026d 1435 if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx])
7919b89c
HS
1436 priv->psstate = PS_STATE_SLEEP;
1437
1438 spin_unlock_irqrestore(&priv->driver_lock, flags);
1439
1440out:
f539f2ef 1441 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
1442}
1443
876c9d3a
MT
1444/**
1445 * @brief This function checks condition and prepares to
1446 * send sleep confirm command to firmware if ok.
1447 *
69f9032d 1448 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
1449 * @param psmode Power Saving mode
1450 * @return n/a
1451 */
d4ff0ef6 1452void lbs_ps_confirm_sleep(struct lbs_private *priv)
876c9d3a
MT
1453{
1454 unsigned long flags =0;
d4ff0ef6 1455 int allowed = 1;
876c9d3a 1456
8ff12da1 1457 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a 1458
a01f5450 1459 spin_lock_irqsave(&priv->driver_lock, flags);
634b8f49 1460 if (priv->dnld_sent) {
876c9d3a 1461 allowed = 0;
23d36eec 1462 lbs_deb_host("dnld_sent was set\n");
876c9d3a
MT
1463 }
1464
7919b89c 1465 /* In-progress command? */
aa21c004 1466 if (priv->cur_cmd) {
876c9d3a 1467 allowed = 0;
23d36eec 1468 lbs_deb_host("cur_cmd was set\n");
876c9d3a 1469 }
7919b89c
HS
1470
1471 /* Pending events or command responses? */
e64c026d 1472 if (kfifo_len(&priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
876c9d3a 1473 allowed = 0;
7919b89c 1474 lbs_deb_host("pending events or command responses\n");
876c9d3a 1475 }
aa21c004 1476 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
1477
1478 if (allowed) {
10078321 1479 lbs_deb_host("sending lbs_ps_confirm_sleep\n");
f539f2ef 1480 lbs_send_confirmsleep(priv);
876c9d3a 1481 } else {
8ff12da1 1482 lbs_deb_host("sleep confirm has been delayed\n");
876c9d3a
MT
1483 }
1484
8ff12da1 1485 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a 1486}
675787e2
HS
1487
1488
0112c9e9
AN
1489/**
1490 * @brief Configures the transmission power control functionality.
1491 *
1492 * @param priv A pointer to struct lbs_private structure
1493 * @param enable Transmission power control enable
1494 * @param p0 Power level when link quality is good (dBm).
1495 * @param p1 Power level when link quality is fair (dBm).
1496 * @param p2 Power level when link quality is poor (dBm).
1497 * @param usesnr Use Signal to Noise Ratio in TPC
1498 *
1499 * @return 0 on success
1500 */
1501int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
1502 int8_t p2, int usesnr)
1503{
1504 struct cmd_ds_802_11_tpc_cfg cmd;
1505 int ret;
1506
1507 memset(&cmd, 0, sizeof(cmd));
1508 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1509 cmd.action = cpu_to_le16(CMD_ACT_SET);
1510 cmd.enable = !!enable;
3ed6e080 1511 cmd.usesnr = !!usesnr;
0112c9e9
AN
1512 cmd.P0 = p0;
1513 cmd.P1 = p1;
1514 cmd.P2 = p2;
1515
1516 ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd);
1517
1518 return ret;
1519}
1520
1521/**
1522 * @brief Configures the power adaptation settings.
1523 *
1524 * @param priv A pointer to struct lbs_private structure
1525 * @param enable Power adaptation enable
1526 * @param p0 Power level for 1, 2, 5.5 and 11 Mbps (dBm).
1527 * @param p1 Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
1528 * @param p2 Power level for 48 and 54 Mbps (dBm).
1529 *
1530 * @return 0 on Success
1531 */
1532
1533int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
1534 int8_t p1, int8_t p2)
1535{
1536 struct cmd_ds_802_11_pa_cfg cmd;
1537 int ret;
1538
1539 memset(&cmd, 0, sizeof(cmd));
1540 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1541 cmd.action = cpu_to_le16(CMD_ACT_SET);
1542 cmd.enable = !!enable;
1543 cmd.P0 = p0;
1544 cmd.P1 = p1;
1545 cmd.P2 = p2;
1546
1547 ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd);
1548
1549 return ret;
1550}
1551
1552
6d898b19 1553struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
8db4a2b9
HS
1554 uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
1555 int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
1556 unsigned long callback_arg)
675787e2 1557{
675787e2 1558 struct cmd_ctrl_node *cmdnode;
675787e2
HS
1559
1560 lbs_deb_enter(LBS_DEB_HOST);
675787e2 1561
aa21c004 1562 if (priv->surpriseremoved) {
675787e2 1563 lbs_deb_host("PREP_CMD: card removed\n");
3399ea5f 1564 cmdnode = ERR_PTR(-ENOENT);
675787e2
HS
1565 goto done;
1566 }
1567
77ccdcf2
DW
1568 /* No commands are allowed in Deep Sleep until we toggle the GPIO
1569 * to wake up the card and it has signaled that it's ready.
1570 */
1571 if (!priv->is_auto_deep_sleep_enabled) {
1572 if (priv->is_deep_sleep) {
1573 lbs_deb_cmd("command not allowed in deep sleep\n");
1574 cmdnode = ERR_PTR(-EBUSY);
1575 goto done;
1576 }
63f275df
AK
1577 }
1578
d06956b5 1579 cmdnode = lbs_get_free_cmd_node(priv);
675787e2
HS
1580 if (cmdnode == NULL) {
1581 lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1582
1583 /* Wake up main thread to execute next command */
1584 wake_up_interruptible(&priv->waitq);
3399ea5f 1585 cmdnode = ERR_PTR(-ENOBUFS);
675787e2
HS
1586 goto done;
1587 }
1588
448a51ae 1589 cmdnode->callback = callback;
1309b55b 1590 cmdnode->callback_arg = callback_arg;
675787e2 1591
7ad994de 1592 /* Copy the incoming command to the buffer */
ddac4526 1593 memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
7ad994de 1594
675787e2 1595 /* Set sequence number, clean result, move to buffer */
aa21c004 1596 priv->seqnum++;
ddac4526
DW
1597 cmdnode->cmdbuf->command = cpu_to_le16(command);
1598 cmdnode->cmdbuf->size = cpu_to_le16(in_cmd_size);
1599 cmdnode->cmdbuf->seqnum = cpu_to_le16(priv->seqnum);
1600 cmdnode->cmdbuf->result = 0;
675787e2
HS
1601
1602 lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
1603
675787e2 1604 cmdnode->cmdwaitqwoken = 0;
681ffbb7 1605 lbs_queue_cmd(priv, cmdnode);
675787e2
HS
1606 wake_up_interruptible(&priv->waitq);
1607
3399ea5f
DW
1608 done:
1609 lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
1610 return cmdnode;
1611}
1612
8db4a2b9
HS
1613void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
1614 struct cmd_header *in_cmd, int in_cmd_size)
1615{
1616 lbs_deb_enter(LBS_DEB_CMD);
1617 __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
1618 lbs_cmd_async_callback, 0);
1619 lbs_deb_leave(LBS_DEB_CMD);
1620}
1621
3399ea5f
DW
1622int __lbs_cmd(struct lbs_private *priv, uint16_t command,
1623 struct cmd_header *in_cmd, int in_cmd_size,
1624 int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
1625 unsigned long callback_arg)
1626{
1627 struct cmd_ctrl_node *cmdnode;
1628 unsigned long flags;
1629 int ret = 0;
1630
1631 lbs_deb_enter(LBS_DEB_HOST);
1632
1633 cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
1634 callback, callback_arg);
1635 if (IS_ERR(cmdnode)) {
1636 ret = PTR_ERR(cmdnode);
1637 goto done;
1638 }
1639
675787e2
HS
1640 might_sleep();
1641 wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
1642
aa21c004 1643 spin_lock_irqsave(&priv->driver_lock, flags);
ae125bf8
DW
1644 ret = cmdnode->result;
1645 if (ret)
1646 lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
1647 command, ret);
3399ea5f 1648
ad12d0f4 1649 __lbs_cleanup_and_insert_cmd(priv, cmdnode);
aa21c004 1650 spin_unlock_irqrestore(&priv->driver_lock, flags);
675787e2
HS
1651
1652done:
1653 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1654 return ret;
1655}
14e865ba 1656EXPORT_SYMBOL_GPL(__lbs_cmd);
This page took 0.683865 seconds and 5 git commands to generate.