cmd.c 50.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/**
  * This file contains the handling of command.
  * It prepares command and sends it to firmware when it is ready.
  */

#include <net/iw_handler.h>
#include "host.h"
#include "hostcmd.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
12
#include "assoc.h"
13
#include "wext.h"
14
#include "cmd.h"
15

16
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
17

18

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
/**
 *  @brief Simple callback that copies response back into command
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param extra  	A pointer to the original command structure for which
 *                      'resp' is a response
 *  @param resp         A pointer to the command response
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
		     struct cmd_header *resp)
{
	struct cmd_header *buf = (void *)extra;
	uint16_t copy_len;

	copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
	memcpy(buf, resp, copy_len);
	return 0;
}
EXPORT_SYMBOL_GPL(lbs_cmd_copyback);

/**
 *  @brief Simple callback that ignores the result. Use this if
 *  you just want to send a command to the hardware, but don't
 *  care for the result.
 *
 *  @param priv         ignored
 *  @param extra        ignored
 *  @param resp         ignored
 *
 *  @return 	   	0 for success
 */
static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
		     struct cmd_header *resp)
{
	return 0;
}


59
/**
60
 *  @brief Checks whether a command is allowed in Power Save mode
61 62
 *
 *  @param command the command ID
63
 *  @return 	   1 if allowed, 0 if not allowed
64
 */
65
static u8 is_command_allowed_in_ps(u16 cmd)
66
{
67 68 69 70 71
	switch (cmd) {
	case CMD_802_11_RSSI:
		return 1;
	default:
		break;
72 73 74 75
	}
	return 0;
}

76 77 78 79 80 81 82 83
/**
 *  @brief Updates the hardware details like MAC address and regulatory region
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_update_hw_spec(struct lbs_private *priv)
84
{
85 86 87 88
	struct cmd_ds_get_hw_spec cmd;
	int ret = -1;
	u32 i;
	DECLARE_MAC_BUF(mac);
89

90
	lbs_deb_enter(LBS_DEB_CMD);
91

92 93 94
	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
95
	ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
96 97 98 99 100
	if (ret)
		goto out;

	priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
	/* The firmware release is in an interesting format: the patch
	 * level is in the most significant nibble ... so fix that: */
	priv->fwrelease = le32_to_cpu(cmd.fwrelease);
	priv->fwrelease = (priv->fwrelease << 8) |
		(priv->fwrelease >> 24 & 0xff);

	/* Some firmware capabilities:
	 * CF card    firmware 5.0.16p0:   cap 0x00000303
	 * USB dongle firmware 5.110.17p2: cap 0x00000303
	 */
	printk("libertas: %s, fw %u.%u.%up%u, cap 0x%08x\n",
		print_mac(mac, cmd.permanentaddr),
		priv->fwrelease >> 24 & 0xff,
		priv->fwrelease >> 16 & 0xff,
		priv->fwrelease >>  8 & 0xff,
		priv->fwrelease       & 0xff,
		priv->fwcapinfo);
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
	lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
		    cmd.hwifversion, cmd.version);

	/* Clamp region code to 8-bit since FW spec indicates that it should
	 * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
	 * returns non-zero high 8 bits here.
	 */
	priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;

	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
		/* use the region code to search for the index */
		if (priv->regioncode == lbs_region_code_to_index[i])
			break;
	}

	/* if it's unidentified region code, use the default (USA) */
	if (i >= MRVDRV_MAX_REGION_CODE) {
		priv->regioncode = 0x10;
		lbs_pr_info("unidentified region code; using the default (USA)\n");
	}

	if (priv->current_addr[0] == 0xff)
		memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
141

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
	memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN);
	if (priv->mesh_dev)
		memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);

	if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
		ret = -1;
		goto out;
	}

	if (lbs_set_universaltable(priv, 0)) {
		ret = -1;
		goto out;
	}

out:
157
	lbs_deb_leave(LBS_DEB_CMD);
158
	return ret;
159 160
}

161
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria)
162 163 164 165
{
	struct cmd_ds_host_sleep cmd_config;
	int ret;

166
	cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
167
	cmd_config.criteria = cpu_to_le32(criteria);
168 169
	cmd_config.gpio = priv->wol_gpio;
	cmd_config.gap = priv->wol_gap;
170

171
	ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
172 173 174 175
	if (!ret) {
		lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
		priv->wol_criteria = criteria;
	} else {
176 177
		lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
	}
178

179 180 181 182
	return ret;
}
EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);

183
static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
184 185 186 187
				   u16 cmd_action)
{
	struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;

188
	lbs_deb_enter(LBS_DEB_CMD);
189

190
	cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
191 192
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
				S_DS_GEN);
193 194
	psm->action = cpu_to_le16(cmd_action);
	psm->multipledtim = 0;
195
	switch (cmd_action) {
196
	case CMD_SUBCMD_ENTER_PS:
197
		lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
198

199
		psm->locallisteninterval = 0;
200
		psm->nullpktinterval = 0;
201
		psm->multipledtim =
202
		    cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
203 204
		break;

205
	case CMD_SUBCMD_EXIT_PS:
206
		lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
207 208
		break;

209
	case CMD_SUBCMD_SLEEP_CONFIRMED:
210
		lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
211 212 213 214 215 216
		break;

	default:
		break;
	}

217
	lbs_deb_leave(LBS_DEB_CMD);
218 219 220
	return 0;
}

221 222
int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
				      uint16_t cmd_action, uint16_t *timeout)
223
{
224 225
	struct cmd_ds_802_11_inactivity_timeout cmd;
	int ret;
226

227 228
	lbs_deb_enter(LBS_DEB_CMD);

229 230
	cmd.hdr.command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
231

232
	cmd.action = cpu_to_le16(cmd_action);
233

234 235
	if (cmd_action == CMD_ACT_SET)
		cmd.timeout = cpu_to_le16(*timeout);
236
	else
237
		cmd.timeout = 0;
238

239 240 241 242 243 244
	ret = lbs_cmd_with_response(priv, CMD_802_11_INACTIVITY_TIMEOUT, &cmd);

	if (!ret)
		*timeout = le16_to_cpu(cmd.timeout);

	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
245 246 247
	return 0;
}

248 249
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
				struct sleep_params *sp)
250
{
251 252
	struct cmd_ds_802_11_sleep_params cmd;
	int ret;
253

254
	lbs_deb_enter(LBS_DEB_CMD);
255

256
	if (cmd_action == CMD_ACT_GET) {
257 258 259 260 261 262 263 264
		memset(&cmd, 0, sizeof(cmd));
	} else {
		cmd.error = cpu_to_le16(sp->sp_error);
		cmd.offset = cpu_to_le16(sp->sp_offset);
		cmd.stabletime = cpu_to_le16(sp->sp_stabletime);
		cmd.calcontrol = sp->sp_calcontrol;
		cmd.externalsleepclk = sp->sp_extsleepclk;
		cmd.reserved = cpu_to_le16(sp->sp_reserved);
265
	}
266 267
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(cmd_action);
268

269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
	ret = lbs_cmd_with_response(priv, CMD_802_11_SLEEP_PARAMS, &cmd);

	if (!ret) {
		lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, "
			    "calcontrol 0x%x extsleepclk 0x%x\n",
			    le16_to_cpu(cmd.error), le16_to_cpu(cmd.offset),
			    le16_to_cpu(cmd.stabletime), cmd.calcontrol,
			    cmd.externalsleepclk);

		sp->sp_error = le16_to_cpu(cmd.error);
		sp->sp_offset = le16_to_cpu(cmd.offset);
		sp->sp_stabletime = le16_to_cpu(cmd.stabletime);
		sp->sp_calcontrol = cmd.calcontrol;
		sp->sp_extsleepclk = cmd.externalsleepclk;
		sp->sp_reserved = le16_to_cpu(cmd.reserved);
	}

	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
287 288 289
	return 0;
}

290 291
int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
			   struct assoc_request *assoc)
292
{
293
	struct cmd_ds_802_11_set_wep cmd;
294 295
	int ret = 0;

296
	lbs_deb_enter(LBS_DEB_CMD);
297

298 299
	cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
300

301
	cmd.action = cpu_to_le16(cmd_action);
302

303 304
	if (cmd_action == CMD_ACT_ADD) {
		int i;
305 306

		/* default tx key index */
307 308
		cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
					   CMD_WEP_KEY_INDEX_MASK);
309 310 311

		/* Copy key types and material to host command structure */
		for (i = 0; i < 4; i++) {
312
			struct enc_key *pkey = &assoc->wep_keys[i];
313 314 315

			switch (pkey->len) {
			case KEY_LEN_WEP_40:
316 317
				cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
				memmove(cmd.keymaterial[i], pkey->key, pkey->len);
318
				lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
319 320
				break;
			case KEY_LEN_WEP_104:
321 322
				cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
				memmove(cmd.keymaterial[i], pkey->key, pkey->len);
323
				lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
324 325 326 327
				break;
			case 0:
				break;
			default:
328
				lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
329
					    i, pkey->len);
330 331 332 333 334
				ret = -1;
				goto done;
				break;
			}
		}
335
	} else if (cmd_action == CMD_ACT_REMOVE) {
336 337 338
		/* ACT_REMOVE clears _all_ WEP keys */

		/* default tx key index */
339 340
		cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
					   CMD_WEP_KEY_INDEX_MASK);
341
		lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
342 343
	}

344
	ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
345
done:
346
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
347 348 349
	return ret;
}

350 351
int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
			      uint16_t *enable)
352
{
353 354
	struct cmd_ds_802_11_enable_rsn cmd;
	int ret;
355 356

	lbs_deb_enter(LBS_DEB_CMD);
357

358 359
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(cmd_action);
360

361
	if (cmd_action == CMD_ACT_SET) {
362
		if (*enable)
363
			cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
364
		else
365
			cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
366
		lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
367 368
	}

369 370 371 372 373 374
	ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
	if (!ret && cmd_action == CMD_ACT_GET)
		*enable = le16_to_cpu(cmd.enable);

	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
375 376
}

377 378
static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
                            struct enc_key *key)
379
{
380 381
	lbs_deb_enter(LBS_DEB_CMD);

382 383 384 385 386 387
	if (key->flags & KEY_INFO_WPA_ENABLED)
		keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
	if (key->flags & KEY_INFO_WPA_UNICAST)
		keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
	if (key->flags & KEY_INFO_WPA_MCAST)
		keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
388

389 390 391 392 393 394 395
	keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
	keyparam->keytypeid = cpu_to_le16(key->type);
	keyparam->keylen = cpu_to_le16(key->len);
	memcpy(keyparam->key, key->key, key->len);

	/* Length field doesn't include the {type,length} header */
	keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
396
	lbs_deb_leave(LBS_DEB_CMD);
397 398
}

399 400
int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
				struct assoc_request *assoc)
401
{
402
	struct cmd_ds_802_11_key_material cmd;
403 404 405
	int ret = 0;
	int index = 0;

406
	lbs_deb_enter(LBS_DEB_CMD);
407

408 409
	cmd.action = cpu_to_le16(cmd_action);
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
410

411
	if (cmd_action == CMD_ACT_GET) {
412 413 414
		cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2);
	} else {
		memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
415

416 417 418 419 420
		if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
			set_one_wpa_key(&cmd.keyParamSet[index],
					&assoc->wpa_unicast_key);
			index++;
		}
421

422 423 424 425 426
		if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
			set_one_wpa_key(&cmd.keyParamSet[index],
					&assoc->wpa_mcast_key);
			index++;
		}
427

428 429 430
		/* The common header and as many keys as we included */
		cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
						    keyParamSet[index]));
431
	}
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
	ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
	/* Copy the returned key to driver private data */
	if (!ret && cmd_action == CMD_ACT_GET) {
		void *buf_ptr = cmd.keyParamSet;
		void *resp_end = &(&cmd)[1];

		while (buf_ptr < resp_end) {
			struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
			struct enc_key *key;
			uint16_t param_set_len = le16_to_cpu(keyparam->length);
			uint16_t key_len = le16_to_cpu(keyparam->keylen);
			uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
			uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
			void *end;

			end = (void *)keyparam + sizeof(keyparam->type)
				+ sizeof(keyparam->length) + param_set_len;

			/* Make sure we don't access past the end of the IEs */
			if (end > resp_end)
				break;
453

454 455 456 457 458 459
			if (key_flags & KEY_INFO_WPA_UNICAST)
				key = &priv->wpa_unicast_key;
			else if (key_flags & KEY_INFO_WPA_MCAST)
				key = &priv->wpa_mcast_key;
			else
				break;
460

461 462 463 464 465 466 467 468 469 470 471 472
			/* Copy returned key into driver */
			memset(key, 0, sizeof(struct enc_key));
			if (key_len > sizeof(key->key))
				break;
			key->type = key_type;
			key->flags = key_flags;
			key->len = key_len;
			memcpy(key->key, keyparam->key, key->len);

			buf_ptr = end + 1;
		}
	}
473

474
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
475 476 477
	return ret;
}

478
static int lbs_cmd_802_11_reset(struct cmd_ds_command *cmd, int cmd_action)
479 480 481
{
	struct cmd_ds_802_11_reset *reset = &cmd->params.reset;

482 483
	lbs_deb_enter(LBS_DEB_CMD);

484
	cmd->command = cpu_to_le16(CMD_802_11_RESET);
485 486 487
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
	reset->action = cpu_to_le16(cmd_action);

488
	lbs_deb_leave(LBS_DEB_CMD);
489 490 491
	return 0;
}

492
static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
493 494 495 496 497 498 499
				    struct cmd_ds_command *cmd,
				    int cmd_action,
				    int cmd_oid, void *pdata_buf)
{
	struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
	u8 ucTemp;

500
	lbs_deb_enter(LBS_DEB_CMD);
501

502
	lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
503

504
	cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
505
	cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
506 507 508 509

	switch (cmd_oid) {
	case OID_802_11_INFRASTRUCTURE_MODE:
	{
510
		u8 mode = (u8) (size_t) pdata_buf;
511 512
		pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
		pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
H
Holger Schurig 已提交
513
		pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8));
514
		if (mode == IW_MODE_ADHOC) {
515
			ucTemp = SNMP_MIB_VALUE_ADHOC;
516 517 518 519
		} else {
			/* Infra and Auto modes */
			ucTemp = SNMP_MIB_VALUE_INFRA;
		}
520 521 522 523 524 525 526 527 528 529

		memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));

		break;
	}

	case OID_802_11D_ENABLE:
		{
			u32 ulTemp;

530
			pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
531

532
			if (cmd_action == CMD_ACT_SET) {
H
Holger Schurig 已提交
533 534
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
535
				ulTemp = *(u32 *)pdata_buf;
536
				*((__le16 *)(pSNMPMIB->value)) =
537 538 539 540 541 542 543 544 545
				    cpu_to_le16((u16) ulTemp);
			}
			break;
		}

	case OID_802_11_FRAGMENTATION_THRESHOLD:
		{
			u32 ulTemp;

546
			pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
547

548 549 550 551
			if (cmd_action == CMD_ACT_GET) {
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
			} else if (cmd_action == CMD_ACT_SET) {
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
552
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
553
				ulTemp = *((u32 *) pdata_buf);
554
				*((__le16 *)(pSNMPMIB->value)) =
555 556 557 558 559 560 561 562 563 564 565
				    cpu_to_le16((u16) ulTemp);

			}

			break;
		}

	case OID_802_11_RTS_THRESHOLD:
		{

			u32 ulTemp;
H
Holger Schurig 已提交
566
			pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I);
567

568 569 570 571
			if (cmd_action == CMD_ACT_GET) {
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
			} else if (cmd_action == CMD_ACT_SET) {
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
572 573 574
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
				ulTemp = *((u32 *)pdata_buf);
				*(__le16 *)(pSNMPMIB->value) =
575 576 577 578 579 580
				    cpu_to_le16((u16) ulTemp);

			}
			break;
		}
	case OID_802_11_TX_RETRYCOUNT:
581
		pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);
582

583 584 585 586
		if (cmd_action == CMD_ACT_GET) {
			pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
		} else if (cmd_action == CMD_ACT_SET) {
			pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
587
			pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
588
			*((__le16 *)(pSNMPMIB->value)) =
589
			    cpu_to_le16((u16) priv->txretrycount);
590 591 592 593 594 595 596
		}

		break;
	default:
		break;
	}

597
	lbs_deb_cmd(
598
	       "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
599 600
	       le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
	       le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
601

602
	lbs_deb_cmd(
603
	       "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
604 605 606
	       le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
	       le16_to_cpu(pSNMPMIB->bufsize),
	       le16_to_cpu(*(__le16 *) pSNMPMIB->value));
607

608
	lbs_deb_leave(LBS_DEB_CMD);
609 610 611
	return 0;
}

612
static int lbs_cmd_802_11_rf_tx_power(struct cmd_ds_command *cmd,
613 614 615 616 617
				       u16 cmd_action, void *pdata_buf)
{

	struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;

618
	lbs_deb_enter(LBS_DEB_CMD);
619 620

	cmd->size =
621
	    cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
622
	cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
623
	prtp->action = cpu_to_le16(cmd_action);
624

625 626 627
	lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n",
		    le16_to_cpu(cmd->size), le16_to_cpu(cmd->command),
		    le16_to_cpu(prtp->action));
628 629

	switch (cmd_action) {
630 631
	case CMD_ACT_TX_POWER_OPT_GET:
		prtp->action = cpu_to_le16(CMD_ACT_GET);
632 633 634
		prtp->currentlevel = 0;
		break;

635 636 637
	case CMD_ACT_TX_POWER_OPT_SET_HIGH:
		prtp->action = cpu_to_le16(CMD_ACT_SET);
		prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH);
638 639
		break;

640 641 642
	case CMD_ACT_TX_POWER_OPT_SET_MID:
		prtp->action = cpu_to_le16(CMD_ACT_SET);
		prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID);
643 644
		break;

645 646
	case CMD_ACT_TX_POWER_OPT_SET_LOW:
		prtp->action = cpu_to_le16(CMD_ACT_SET);
647 648 649
		prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
		break;
	}
650 651

	lbs_deb_leave(LBS_DEB_CMD);
652 653 654
	return 0;
}

655
static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
				      u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;

	cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
	cmd->size =
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
			     S_DS_GEN);

	monitor->action = cpu_to_le16(cmd_action);
	if (cmd_action == CMD_ACT_SET) {
		monitor->mode =
		    cpu_to_le16((u16) (*(u32 *) pdata_buf));
	}

	return 0;
}

674
static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
675 676 677 678 679 680
					      struct cmd_ds_command *cmd,
					      u16 cmd_action)
{
	struct cmd_ds_802_11_rate_adapt_rateset
	*rateadapt = &cmd->params.rateset;

681
	lbs_deb_enter(LBS_DEB_CMD);
682 683 684
	cmd->size =
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
			     + S_DS_GEN);
685
	cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
686

687
	rateadapt->action = cpu_to_le16(cmd_action);
688 689
	rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
	rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
690

691
	lbs_deb_leave(LBS_DEB_CMD);
692 693 694
	return 0;
}

695 696 697 698 699 700 701 702
/**
 *  @brief Get the current data rate
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *
 *  @return 	   	The data rate on success, error on failure
 */
int lbs_get_data_rate(struct lbs_private *priv)
703
{
704 705
	struct cmd_ds_802_11_data_rate cmd;
	int ret = -1;
706

707
	lbs_deb_enter(LBS_DEB_CMD);
708

709 710 711 712
	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_GET_TX_RATE);

713
	ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
	if (ret)
		goto out;

	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));

	ret = (int) lbs_fw_index_to_data_rate(cmd.rates[0]);
	lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", ret);

out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}

/**
 *  @brief Set the data rate
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param rate  	The desired data rate, or 0 to clear a locked rate
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
{
	struct cmd_ds_802_11_data_rate cmd;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_CMD);

	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));

	if (rate > 0) {
		cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
		cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
		if (cmd.rates[0] == 0) {
			lbs_deb_cmd("DATA_RATE: invalid requested rate of"
			            " 0x%02X\n", rate);
			ret = 0;
			goto out;
		}
		lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
	} else {
		cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
757
		lbs_deb_cmd("DATA_RATE: setting auto\n");
758 759
	}

760
	ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
761 762 763 764 765 766 767 768 769 770 771 772 773 774
	if (ret)
		goto out;

	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));

	/* FIXME: get actual rates FW can do if this command actually returns
	 * all data rates supported.
	 */
	priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
	lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);

out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
775 776
}

777
static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
778 779 780 781 782
				      struct cmd_ds_command *cmd,
				      u16 cmd_action)
{
	struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;

783
	lbs_deb_enter(LBS_DEB_CMD);
784
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
785
			     S_DS_GEN);
786
	cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
787

788
	lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
789 790
	pMCastAdr->action = cpu_to_le16(cmd_action);
	pMCastAdr->nr_of_adrs =
791 792 793
	    cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
	memcpy(pMCastAdr->maclist, priv->multicastlist,
	       priv->nr_of_multicastmacaddr * ETH_ALEN);
794

795
	lbs_deb_leave(LBS_DEB_CMD);
796 797 798
	return 0;
}

799 800 801 802 803 804 805 806
/**
 *  @brief Get the radio channel
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *
 *  @return 	   	The channel on success, error on failure
 */
int lbs_get_channel(struct lbs_private *priv)
807
{
808 809
	struct cmd_ds_802_11_rf_channel cmd;
	int ret = 0;
810

811
	lbs_deb_enter(LBS_DEB_CMD);
812

813 814
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
815

816
	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
817 818
	if (ret)
		goto out;
819

820 821
	ret = le16_to_cpu(cmd.channel);
	lbs_deb_cmd("current radio channel is %d\n", ret);
822 823 824 825 826 827

out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}

828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
int lbs_update_channel(struct lbs_private *priv)
{
	int ret;

	/* the channel in f/w could be out of sync; get the current channel */
	lbs_deb_enter(LBS_DEB_ASSOC);

	ret = lbs_get_channel(priv);
	if (ret > 0) {
		priv->curbssparams.channel = ret;
		ret = 0;
	}
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
	return ret;
}

844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
/**
 *  @brief Set the radio channel
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param channel  	The desired channel, or 0 to clear a locked channel
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_set_channel(struct lbs_private *priv, u8 channel)
{
	struct cmd_ds_802_11_rf_channel cmd;
	u8 old_channel = priv->curbssparams.channel;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_CMD);

	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
	cmd.channel = cpu_to_le16(channel);

864
	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
865 866 867
	if (ret)
		goto out;

868 869 870
	priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel);
	lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
		priv->curbssparams.channel);
871 872 873 874

out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
875 876
}

877
static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
878 879 880
				struct cmd_ds_command *cmd)
{

881
	lbs_deb_enter(LBS_DEB_CMD);
882
	cmd->command = cpu_to_le16(CMD_802_11_RSSI);
883
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
884
	cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
885 886

	/* reset Beacon SNR/NF/RSSI values */
887 888 889 890 891 892
	priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
	priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
	priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
	priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
	priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
	priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
893

894
	lbs_deb_leave(LBS_DEB_CMD);
895 896 897
	return 0;
}

898
static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
899 900
			       u8 cmd_action, void *pdata_buf)
{
901
	struct lbs_offset_value *offval;
902

903
	lbs_deb_enter(LBS_DEB_CMD);
904

905
	offval = (struct lbs_offset_value *)pdata_buf;
906

H
Holger Schurig 已提交
907
	switch (le16_to_cpu(cmdptr->command)) {
908
	case CMD_MAC_REG_ACCESS:
909 910 911 912
		{
			struct cmd_ds_mac_reg_access *macreg;

			cmdptr->size =
913 914
			    cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
					+ S_DS_GEN);
915 916 917 918 919 920 921 922 923 924 925
			macreg =
			    (struct cmd_ds_mac_reg_access *)&cmdptr->params.
			    macreg;

			macreg->action = cpu_to_le16(cmd_action);
			macreg->offset = cpu_to_le16((u16) offval->offset);
			macreg->value = cpu_to_le32(offval->value);

			break;
		}

926
	case CMD_BBP_REG_ACCESS:
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
		{
			struct cmd_ds_bbp_reg_access *bbpreg;

			cmdptr->size =
			    cpu_to_le16(sizeof
					     (struct cmd_ds_bbp_reg_access)
					     + S_DS_GEN);
			bbpreg =
			    (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
			    bbpreg;

			bbpreg->action = cpu_to_le16(cmd_action);
			bbpreg->offset = cpu_to_le16((u16) offval->offset);
			bbpreg->value = (u8) offval->value;

			break;
		}

945
	case CMD_RF_REG_ACCESS:
946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967
		{
			struct cmd_ds_rf_reg_access *rfreg;

			cmdptr->size =
			    cpu_to_le16(sizeof
					     (struct cmd_ds_rf_reg_access) +
					     S_DS_GEN);
			rfreg =
			    (struct cmd_ds_rf_reg_access *)&cmdptr->params.
			    rfreg;

			rfreg->action = cpu_to_le16(cmd_action);
			rfreg->offset = cpu_to_le16((u16) offval->offset);
			rfreg->value = (u8) offval->value;

			break;
		}

	default:
		break;
	}

968
	lbs_deb_leave(LBS_DEB_CMD);
969 970 971
	return 0;
}

972
static int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
973 974 975
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
976
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
977

978
	cmd->command = cpu_to_le16(CMD_BT_ACCESS);
979
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
980 981 982 983
	cmd->result = 0;
	bt_access->action = cpu_to_le16(cmd_action);

	switch (cmd_action) {
984
	case CMD_ACT_BT_ACCESS_ADD:
985
		memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
986
		lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
987
		break;
988
	case CMD_ACT_BT_ACCESS_DEL:
989
		memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
990
		lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
991
		break;
992
	case CMD_ACT_BT_ACCESS_LIST:
993 994
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
995
	case CMD_ACT_BT_ACCESS_RESET:
996
		break;
997
	case CMD_ACT_BT_ACCESS_SET_INVERT:
998 999
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
1000
	case CMD_ACT_BT_ACCESS_GET_INVERT:
1001
		break;
1002 1003 1004
	default:
		break;
	}
1005
	lbs_deb_leave(LBS_DEB_CMD);
1006 1007 1008
	return 0;
}

1009
static int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
1010 1011 1012
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
1013
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
1014

1015
	cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
1016
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
1017 1018 1019 1020 1021 1022 1023 1024 1025
	cmd->result = 0;

	if (pdata_buf)
		memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
	else
		memset(fwt_access, 0, sizeof(*fwt_access));

	fwt_access->action = cpu_to_le16(cmd_action);

1026
	lbs_deb_leave(LBS_DEB_CMD);
1027 1028 1029
	return 0;
}

1030 1031
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
		    struct cmd_ds_mesh_access *cmd)
1032
{
1033 1034
	int ret;

1035
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
1036

1037
	cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
1038
	cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
1039
	cmd->hdr.result = 0;
1040

1041
	cmd->action = cpu_to_le16(cmd_action);
1042

1043
	ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
1044

1045
	lbs_deb_leave(LBS_DEB_CMD);
1046
	return ret;
1047 1048
}

1049
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan)
1050 1051 1052 1053 1054
{
	struct cmd_ds_mesh_config cmd;

	memset(&cmd, 0, sizeof(cmd));
	cmd.action = cpu_to_le16(enable);
1055
	cmd.channel = cpu_to_le16(chan);
1056
	cmd.type = cpu_to_le16(priv->mesh_tlv);
1057
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1058

1059 1060 1061 1062
	if (enable) {
		cmd.length = cpu_to_le16(priv->mesh_ssid_len);
		memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len);
	}
1063
	lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n",
1064
		    enable, priv->mesh_tlv, chan,
1065
		    escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
1066
	return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd);
1067 1068
}

1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
				struct cmd_ds_command *cmd,
				u16 cmd_action)
{
	struct cmd_ds_802_11_beacon_control
		*bcn_ctrl = &cmd->params.bcn_ctrl;

	lbs_deb_enter(LBS_DEB_CMD);
	cmd->size =
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
			     + S_DS_GEN);
	cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);

	bcn_ctrl->action = cpu_to_le16(cmd_action);
1083 1084
	bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
	bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
1085 1086 1087 1088 1089

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

1090 1091
static void lbs_queue_cmd(struct lbs_private *priv,
			  struct cmd_ctrl_node *cmdnode)
1092 1093
{
	unsigned long flags;
1094
	int addtail = 1;
1095

1096
	lbs_deb_enter(LBS_DEB_HOST);
1097

1098 1099
	if (!cmdnode) {
		lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
1100 1101
		goto done;
	}
1102 1103 1104 1105
	if (!cmdnode->cmdbuf->size) {
		lbs_deb_host("DNLD_CMD: cmd size is zero\n");
		goto done;
	}
1106
	cmdnode->result = 0;
1107 1108

	/* Exit_PS command needs to be queued in the header always. */
1109
	if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
1110
		struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf[1];
1111

1112
		if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1113
			if (priv->psstate != PS_STATE_FULL_POWER)
1114 1115 1116 1117
				addtail = 0;
		}
	}

1118
	spin_lock_irqsave(&priv->driver_lock, flags);
1119

1120
	if (addtail)
1121
		list_add_tail(&cmdnode->list, &priv->cmdpendingq);
1122
	else
1123
		list_add(&cmdnode->list, &priv->cmdpendingq);
1124

1125
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1126

1127
	lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
1128
		     le16_to_cpu(cmdnode->cmdbuf->command));
1129 1130

done:
1131
	lbs_deb_leave(LBS_DEB_HOST);
1132 1133
}

1134 1135
static void lbs_submit_command(struct lbs_private *priv,
			       struct cmd_ctrl_node *cmdnode)
1136 1137
{
	unsigned long flags;
1138
	struct cmd_header *cmd;
1139 1140 1141 1142
	uint16_t cmdsize;
	uint16_t command;
	int timeo = 5 * HZ;
	int ret;
1143

1144
	lbs_deb_enter(LBS_DEB_HOST);
1145

1146
	cmd = cmdnode->cmdbuf;
1147

1148 1149 1150 1151
	spin_lock_irqsave(&priv->driver_lock, flags);
	priv->cur_cmd = cmdnode;
	priv->cur_cmd_retcode = 0;
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1152

1153 1154
	cmdsize = le16_to_cpu(cmd->size);
	command = le16_to_cpu(cmd->command);
1155

1156 1157 1158 1159 1160
	/* These commands take longer */
	if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
	    command == CMD_802_11_AUTHENTICATE)
		timeo = 10 * HZ;

H
Holger Schurig 已提交
1161 1162
	lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
		     command, le16_to_cpu(cmd->seqnum), cmdsize);
1163
	lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
1164

1165
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
1166

1167 1168
	if (ret) {
		lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
1169 1170 1171
		/* Let the timer kick in and retry, and potentially reset
		   the whole thing if the condition persists */
		timeo = HZ;
1172
	}
1173 1174

	/* Setup the timer after transmit command */
1175
	mod_timer(&priv->command_timer, jiffies + timeo);
1176

1177
	lbs_deb_leave(LBS_DEB_HOST);
1178 1179 1180 1181
}

/**
 *  This function inserts command node to cmdfreeq
1182
 *  after cleans it. Requires priv->driver_lock held.
1183
 */
1184
static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1185
					 struct cmd_ctrl_node *cmdnode)
1186
{
1187 1188 1189 1190 1191 1192 1193
	lbs_deb_enter(LBS_DEB_HOST);

	if (!cmdnode)
		goto out;

	cmdnode->callback = NULL;
	cmdnode->callback_arg = 0;
1194

1195
	memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
1196

1197 1198 1199
	list_add_tail(&cmdnode->list, &priv->cmdfreeq);
 out:
	lbs_deb_leave(LBS_DEB_HOST);
1200 1201
}

1202 1203
static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1204 1205 1206
{
	unsigned long flags;

1207
	spin_lock_irqsave(&priv->driver_lock, flags);
1208
	__lbs_cleanup_and_insert_cmd(priv, ptempcmd);
1209
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1210 1211
}

1212 1213 1214 1215 1216
void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
			  int result)
{
	if (cmd == priv->cur_cmd)
		priv->cur_cmd_retcode = result;
1217

1218
	cmd->result = result;
1219 1220 1221
	cmd->cmdwaitqwoken = 1;
	wake_up_interruptible(&cmd->cmdwait_q);

1222
	if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
1223
		__lbs_cleanup_and_insert_cmd(priv, cmd);
1224 1225 1226
	priv->cur_cmd = NULL;
}

1227
int lbs_set_radio_control(struct lbs_private *priv)
1228 1229
{
	int ret = 0;
1230
	struct cmd_ds_802_11_radio_control cmd;
1231

1232
	lbs_deb_enter(LBS_DEB_CMD);
1233

1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_SET);

	switch (priv->preamble) {
	case CMD_TYPE_SHORT_PREAMBLE:
		cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE);
		break;

	case CMD_TYPE_LONG_PREAMBLE:
		cmd.control = cpu_to_le16(SET_LONG_PREAMBLE);
		break;

	case CMD_TYPE_AUTO_PREAMBLE:
	default:
		cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE);
		break;
	}
1251

1252 1253 1254 1255 1256 1257 1258 1259 1260
	if (priv->radioon)
		cmd.control |= cpu_to_le16(TURN_ON_RF);
	else
		cmd.control &= cpu_to_le16(~TURN_ON_RF);

	lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon,
		    priv->preamble);

	ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
1261

1262
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1263 1264 1265
	return ret;
}

1266
void lbs_set_mac_control(struct lbs_private *priv)
1267
{
1268
	struct cmd_ds_mac_control cmd;
1269

1270
	lbs_deb_enter(LBS_DEB_CMD);
1271

1272
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1273
	cmd.action = cpu_to_le16(priv->mac_control);
1274 1275
	cmd.reserved = 0;

1276 1277
	lbs_cmd_async(priv, CMD_MAC_CONTROL,
		&cmd.hdr, sizeof(cmd));
1278

1279
	lbs_deb_leave(LBS_DEB_CMD);
1280 1281 1282 1283 1284
}

/**
 *  @brief This function prepare the command before send to firmware.
 *
1285
 *  @param priv		A pointer to struct lbs_private structure
1286 1287 1288 1289 1290 1291 1292
 *  @param cmd_no	command number
 *  @param cmd_action	command action: GET or SET
 *  @param wait_option	wait option: wait response or not
 *  @param cmd_oid	cmd oid: treated as sub command
 *  @param pdata_buf	A pointer to informaion buffer
 *  @return 		0 or -1
 */
1293
int lbs_prepare_and_send_command(struct lbs_private *priv,
1294 1295 1296 1297 1298 1299 1300 1301 1302
			  u16 cmd_no,
			  u16 cmd_action,
			  u16 wait_option, u32 cmd_oid, void *pdata_buf)
{
	int ret = 0;
	struct cmd_ctrl_node *cmdnode;
	struct cmd_ds_command *cmdptr;
	unsigned long flags;

1303
	lbs_deb_enter(LBS_DEB_HOST);
1304

1305 1306
	if (!priv) {
		lbs_deb_host("PREP_CMD: priv is NULL\n");
1307 1308 1309 1310
		ret = -1;
		goto done;
	}

1311
	if (priv->surpriseremoved) {
1312
		lbs_deb_host("PREP_CMD: card removed\n");
1313 1314 1315 1316
		ret = -1;
		goto done;
	}

1317
	cmdnode = lbs_get_cmd_ctrl_node(priv);
1318 1319

	if (cmdnode == NULL) {
1320
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1321 1322

		/* Wake up main thread to execute next command */
1323
		wake_up_interruptible(&priv->waitq);
1324 1325 1326 1327
		ret = -1;
		goto done;
	}

1328 1329
	cmdnode->callback = NULL;
	cmdnode->callback_arg = (unsigned long)pdata_buf;
1330

1331
	cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
1332

1333
	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
1334 1335

	/* Set sequence number, command and INT option */
1336 1337
	priv->seqnum++;
	cmdptr->seqnum = cpu_to_le16(priv->seqnum);
1338

1339
	cmdptr->command = cpu_to_le16(cmd_no);
1340 1341 1342
	cmdptr->result = 0;

	switch (cmd_no) {
1343
	case CMD_802_11_PS_MODE:
1344
		ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action);
1345 1346
		break;

1347 1348
	case CMD_802_11_ASSOCIATE:
	case CMD_802_11_REASSOCIATE:
1349
		ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
1350 1351
		break;

1352
	case CMD_802_11_DEAUTHENTICATE:
1353
		ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
1354 1355
		break;

1356
	case CMD_802_11_AD_HOC_START:
1357
		ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
1358 1359
		break;

1360
	case CMD_802_11_RESET:
1361
		ret = lbs_cmd_802_11_reset(cmdptr, cmd_action);
1362 1363
		break;

1364
	case CMD_802_11_AUTHENTICATE:
1365
		ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
1366 1367
		break;

1368
	case CMD_802_11_SNMP_MIB:
1369
		ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
1370 1371 1372
					       cmd_action, cmd_oid, pdata_buf);
		break;

1373 1374 1375
	case CMD_MAC_REG_ACCESS:
	case CMD_BBP_REG_ACCESS:
	case CMD_RF_REG_ACCESS:
1376
		ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf);
1377 1378
		break;

1379
	case CMD_802_11_RF_TX_POWER:
1380 1381
		ret = lbs_cmd_802_11_rf_tx_power(cmdptr,
						 cmd_action, pdata_buf);
1382 1383
		break;

1384
	case CMD_802_11_RATE_ADAPT_RATESET:
1385
		ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
1386 1387 1388
							 cmdptr, cmd_action);
		break;

1389
	case CMD_MAC_MULTICAST_ADR:
1390
		ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
1391 1392
		break;

1393
	case CMD_802_11_MONITOR_MODE:
1394
		ret = lbs_cmd_802_11_monitor_mode(cmdptr,
1395 1396 1397
				          cmd_action, pdata_buf);
		break;

1398
	case CMD_802_11_AD_HOC_JOIN:
1399
		ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
1400 1401
		break;

1402
	case CMD_802_11_RSSI:
1403
		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
1404 1405
		break;

1406
	case CMD_802_11_AD_HOC_STOP:
1407
		ret = lbs_cmd_80211_ad_hoc_stop(cmdptr);
1408 1409
		break;

1410 1411
	case CMD_802_11_SET_AFC:
	case CMD_802_11_GET_AFC:
1412 1413

		cmdptr->command = cpu_to_le16(cmd_no);
1414 1415
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
					   S_DS_GEN);
1416 1417 1418 1419 1420 1421 1422

		memmove(&cmdptr->params.afc,
			pdata_buf, sizeof(struct cmd_ds_802_11_afc));

		ret = 0;
		goto done;

1423
	case CMD_802_11D_DOMAIN_INFO:
1424
		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
1425 1426 1427
						   cmd_no, cmd_action);
		break;

1428 1429
	case CMD_802_11_TPC_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1430 1431 1432 1433 1434 1435 1436 1437 1438
		cmdptr->size =
		    cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
				     S_DS_GEN);

		memmove(&cmdptr->params.tpccfg,
			pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));

		ret = 0;
		break;
1439
	case CMD_802_11_LED_GPIO_CTRL:
1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
		{
			struct mrvlietypes_ledgpio *gpio =
			    (struct mrvlietypes_ledgpio*)
			    cmdptr->params.ledgpio.data;

			memmove(&cmdptr->params.ledgpio,
				pdata_buf,
				sizeof(struct cmd_ds_802_11_led_ctrl));

			cmdptr->command =
1450
			    cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
1451 1452 1453

#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
			cmdptr->size =
H
Holger Schurig 已提交
1454 1455 1456 1457
			    cpu_to_le16(le16_to_cpu(gpio->header.len)
				+ S_DS_GEN
				+ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
			gpio->header.len = gpio->header.len;
1458 1459 1460 1461

			ret = 0;
			break;
		}
1462

1463
	case CMD_BT_ACCESS:
1464
		ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
1465 1466
		break;

1467
	case CMD_FWT_ACCESS:
1468
		ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
1469 1470
		break;

1471 1472
	case CMD_GET_TSF:
		cmdptr->command = cpu_to_le16(CMD_GET_TSF);
1473 1474
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
					   S_DS_GEN);
1475 1476
		ret = 0;
		break;
1477 1478 1479
	case CMD_802_11_BEACON_CTRL:
		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
		break;
1480
	default:
1481
		lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
1482 1483 1484 1485 1486 1487
		ret = -1;
		break;
	}

	/* return error, since the command preparation failed */
	if (ret != 0) {
1488
		lbs_deb_host("PREP_CMD: command preparation failed\n");
1489
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1490 1491 1492 1493 1494 1495
		ret = -1;
		goto done;
	}

	cmdnode->cmdwaitqwoken = 0;

1496
	lbs_queue_cmd(priv, cmdnode);
1497
	wake_up_interruptible(&priv->waitq);
1498

1499
	if (wait_option & CMD_OPTION_WAITFORRSP) {
1500
		lbs_deb_host("PREP_CMD: wait for response\n");
1501 1502 1503 1504 1505
		might_sleep();
		wait_event_interruptible(cmdnode->cmdwait_q,
					 cmdnode->cmdwaitqwoken);
	}

1506 1507
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd_retcode) {
1508
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
1509 1510
		       priv->cur_cmd_retcode);
		priv->cur_cmd_retcode = 0;
1511 1512
		ret = -1;
	}
1513
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1514 1515

done:
1516
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1517 1518 1519 1520 1521 1522 1523
	return ret;
}

/**
 *  @brief This function allocates the command buffer and link
 *  it to command free queue.
 *
1524
 *  @param priv		A pointer to struct lbs_private structure
1525 1526
 *  @return 		0 or -1
 */
1527
int lbs_allocate_cmd_buffer(struct lbs_private *priv)
1528 1529
{
	int ret = 0;
1530
	u32 bufsize;
1531
	u32 i;
1532
	struct cmd_ctrl_node *cmdarray;
1533

1534
	lbs_deb_enter(LBS_DEB_HOST);
1535

1536 1537 1538
	/* Allocate and initialize the command array */
	bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
	if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
1539
		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
1540 1541 1542
		ret = -1;
		goto done;
	}
1543
	priv->cmd_array = cmdarray;
1544

1545 1546 1547 1548
	/* Allocate and initialize each command buffer in the command array */
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
		if (!cmdarray[i].cmdbuf) {
1549
			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
1550 1551 1552 1553 1554
			ret = -1;
			goto done;
		}
	}

1555 1556 1557
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		init_waitqueue_head(&cmdarray[i].cmdwait_q);
		lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
1558 1559
	}
	ret = 0;
1560 1561

done:
1562
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1563 1564 1565 1566 1567 1568
	return ret;
}

/**
 *  @brief This function frees the command buffer.
 *
1569
 *  @param priv		A pointer to struct lbs_private structure
1570 1571
 *  @return 		0 or -1
 */
1572
int lbs_free_cmd_buffer(struct lbs_private *priv)
1573
{
1574
	struct cmd_ctrl_node *cmdarray;
1575 1576
	unsigned int i;

1577
	lbs_deb_enter(LBS_DEB_HOST);
1578 1579

	/* need to check if cmd array is allocated or not */
1580
	if (priv->cmd_array == NULL) {
1581
		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
1582 1583 1584
		goto done;
	}

1585
	cmdarray = priv->cmd_array;
1586 1587

	/* Release shared memory buffers */
1588 1589 1590 1591
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		if (cmdarray[i].cmdbuf) {
			kfree(cmdarray[i].cmdbuf);
			cmdarray[i].cmdbuf = NULL;
1592 1593 1594 1595
		}
	}

	/* Release cmd_ctrl_node */
1596 1597 1598
	if (priv->cmd_array) {
		kfree(priv->cmd_array);
		priv->cmd_array = NULL;
1599 1600 1601
	}

done:
1602
	lbs_deb_leave(LBS_DEB_HOST);
1603 1604 1605 1606 1607 1608 1609
	return 0;
}

/**
 *  @brief This function gets a free command node if available in
 *  command free queue.
 *
1610
 *  @param priv		A pointer to struct lbs_private structure
1611 1612
 *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
 */
1613
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
1614 1615 1616 1617
{
	struct cmd_ctrl_node *tempnode;
	unsigned long flags;

1618 1619
	lbs_deb_enter(LBS_DEB_HOST);

1620
	if (!priv)
1621 1622
		return NULL;

1623
	spin_lock_irqsave(&priv->driver_lock, flags);
1624

1625 1626
	if (!list_empty(&priv->cmdfreeq)) {
		tempnode = list_first_entry(&priv->cmdfreeq,
1627 1628
					    struct cmd_ctrl_node, list);
		list_del(&tempnode->list);
1629
	} else {
1630
		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
1631 1632 1633
		tempnode = NULL;
	}

1634
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1635

1636
	lbs_deb_leave(LBS_DEB_HOST);
1637 1638 1639 1640 1641 1642 1643 1644
	return tempnode;
}

/**
 *  @brief This function executes next command in command
 *  pending queue. It will put fimware back to PS mode
 *  if applicable.
 *
1645
 *  @param priv     A pointer to struct lbs_private structure
1646 1647
 *  @return 	   0 or -1
 */
1648
int lbs_execute_next_command(struct lbs_private *priv)
1649 1650
{
	struct cmd_ctrl_node *cmdnode = NULL;
1651
	struct cmd_header *cmd;
1652 1653 1654
	unsigned long flags;
	int ret = 0;

1655 1656 1657
	/* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
	 * only caller to us is lbs_thread() and we get even when a
	 * data packet is received */
1658
	lbs_deb_enter(LBS_DEB_THREAD);
1659

1660
	spin_lock_irqsave(&priv->driver_lock, flags);
1661

1662
	if (priv->cur_cmd) {
1663
		lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
1664
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1665 1666 1667 1668
		ret = -1;
		goto done;
	}

1669 1670
	if (!list_empty(&priv->cmdpendingq)) {
		cmdnode = list_first_entry(&priv->cmdpendingq,
1671
					   struct cmd_ctrl_node, list);
1672 1673
	}

1674
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1675 1676

	if (cmdnode) {
1677
		cmd = cmdnode->cmdbuf;
1678

1679
		if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
1680 1681
			if ((priv->psstate == PS_STATE_SLEEP) ||
			    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1682 1683
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
1684
				       le16_to_cpu(cmd->command),
1685
				       priv->psstate);
1686 1687 1688
				ret = -1;
				goto done;
			}
1689
			lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
1690 1691
				     "0x%04x in psstate %d\n",
				     le16_to_cpu(cmd->command), priv->psstate);
1692
		} else if (priv->psstate != PS_STATE_FULL_POWER) {
1693 1694 1695
			/*
			 * 1. Non-PS command:
			 * Queue it. set needtowakeup to TRUE if current state
1696
			 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
1697 1698 1699 1700 1701 1702 1703
			 * 2. PS command but not Exit_PS:
			 * Ignore it.
			 * 3. PS command Exit_PS:
			 * Set needtowakeup to TRUE if current state is SLEEP,
			 * otherwise send this command down to firmware
			 * immediately.
			 */
1704
			if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
1705 1706
				/*  Prepare to send Exit PS,
				 *  this non PS command will be sent later */
1707 1708
				if ((priv->psstate == PS_STATE_SLEEP)
				    || (priv->psstate == PS_STATE_PRE_SLEEP)
1709 1710 1711
				    ) {
					/* w/ new scheme, it will not reach here.
					   since it is blocked in main_thread. */
1712
					priv->needtowakeup = 1;
1713
				} else
1714
					lbs_ps_wakeup(priv, 0);
1715 1716 1717 1718 1719 1720 1721 1722

				ret = 0;
				goto done;
			} else {
				/*
				 * PS command. Ignore it if it is not Exit_PS.
				 * otherwise send it down immediately.
				 */
1723
				struct cmd_ds_802_11_ps_mode *psm = (void *)&cmd[1];
1724

1725 1726
				lbs_deb_host(
				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
1727 1728
				       psm->action);
				if (psm->action !=
1729
				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1730 1731
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
1732
					list_del(&cmdnode->list);
1733 1734 1735
					spin_lock_irqsave(&priv->driver_lock, flags);
					lbs_complete_command(priv, cmdnode, 0);
					spin_unlock_irqrestore(&priv->driver_lock, flags);
1736 1737 1738 1739 1740

					ret = 0;
					goto done;
				}

1741 1742
				if ((priv->psstate == PS_STATE_SLEEP) ||
				    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1743 1744
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
1745
					list_del(&cmdnode->list);
1746 1747 1748
					spin_lock_irqsave(&priv->driver_lock, flags);
					lbs_complete_command(priv, cmdnode, 0);
					spin_unlock_irqrestore(&priv->driver_lock, flags);
1749
					priv->needtowakeup = 1;
1750 1751 1752 1753 1754

					ret = 0;
					goto done;
				}

1755 1756
				lbs_deb_host(
				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
1757 1758
			}
		}
1759
		list_del(&cmdnode->list);
1760
		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
1761
			    le16_to_cpu(cmd->command));
1762
		lbs_submit_command(priv, cmdnode);
1763 1764 1765 1766 1767
	} else {
		/*
		 * check if in power save mode, if yes, put the device back
		 * to PS mode
		 */
1768 1769 1770 1771 1772 1773
		if ((priv->psmode != LBS802_11POWERMODECAM) &&
		    (priv->psstate == PS_STATE_FULL_POWER) &&
		    ((priv->connect_status == LBS_CONNECTED) ||
		    (priv->mesh_connect_status == LBS_CONNECTED))) {
			if (priv->secinfo.WPAenabled ||
			    priv->secinfo.WPA2enabled) {
1774
				/* check for valid WPA group keys */
1775 1776
				if (priv->wpa_mcast_key.len ||
				    priv->wpa_unicast_key.len) {
1777
					lbs_deb_host(
1778 1779
					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
					       " go back to PS_SLEEP");
1780
					lbs_ps_sleep(priv, 0);
1781 1782
				}
			} else {
1783 1784 1785
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cmdpendingq empty, "
				       "go back to PS_SLEEP");
1786
				lbs_ps_sleep(priv, 0);
1787 1788 1789 1790 1791 1792
			}
		}
	}

	ret = 0;
done:
1793
	lbs_deb_leave(LBS_DEB_THREAD);
1794 1795 1796
	return ret;
}

1797
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
1798 1799 1800 1801
{
	union iwreq_data iwrq;
	u8 buf[50];

1802
	lbs_deb_enter(LBS_DEB_WEXT);
1803 1804 1805 1806 1807 1808 1809 1810 1811

	memset(&iwrq, 0, sizeof(union iwreq_data));
	memset(buf, 0, sizeof(buf));

	snprintf(buf, sizeof(buf) - 1, "%s", str);

	iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;

	/* Send Event to upper layer */
1812 1813 1814
	lbs_deb_wext("event indication string %s\n", (char *)buf);
	lbs_deb_wext("event indication length %d\n", iwrq.data.length);
	lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
1815

1816
	wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
1817

1818
	lbs_deb_leave(LBS_DEB_WEXT);
1819 1820
}

1821
static void lbs_send_confirmsleep(struct lbs_private *priv)
1822 1823
{
	unsigned long flags;
1824
	int ret;
1825

1826
	lbs_deb_enter(LBS_DEB_HOST);
1827 1828
	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,
		sizeof(confirm_sleep));
1829

1830 1831
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
		sizeof(confirm_sleep));
1832 1833

	if (ret) {
1834
		lbs_pr_alert("confirm_sleep failed\n");
1835
	} else {
1836
		spin_lock_irqsave(&priv->driver_lock, flags);
1837
		if (!priv->intcounter)
1838 1839
			priv->psstate = PS_STATE_SLEEP;
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1840
	}
1841
	lbs_deb_leave(LBS_DEB_HOST);
1842 1843
}

1844
void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
1845
{
1846
	lbs_deb_enter(LBS_DEB_HOST);
1847 1848 1849 1850 1851 1852

	/*
	 * PS is currently supported only in Infrastructure mode
	 * Remove this check if it is to be supported in IBSS mode also
	 */

1853
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1854
			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
1855

1856
	lbs_deb_leave(LBS_DEB_HOST);
1857 1858 1859
}

/**
1860
 *  @brief This function sends Exit_PS command to firmware.
1861
 *
1862
 *  @param priv    	A pointer to struct lbs_private structure
1863 1864 1865
 *  @param wait_option	wait response or not
 *  @return 	   	n/a
 */
1866
void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
1867
{
1868
	__le32 Localpsmode;
1869

1870
	lbs_deb_enter(LBS_DEB_HOST);
1871

1872
	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
1873

1874
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1875
			      CMD_SUBCMD_EXIT_PS,
1876 1877
			      wait_option, 0, &Localpsmode);

1878
	lbs_deb_leave(LBS_DEB_HOST);
1879 1880 1881 1882 1883 1884
}

/**
 *  @brief This function checks condition and prepares to
 *  send sleep confirm command to firmware if ok.
 *
1885
 *  @param priv    	A pointer to struct lbs_private structure
1886 1887 1888
 *  @param psmode  	Power Saving mode
 *  @return 	   	n/a
 */
1889
void lbs_ps_confirm_sleep(struct lbs_private *priv)
1890 1891
{
	unsigned long flags =0;
1892
	int allowed = 1;
1893

1894
	lbs_deb_enter(LBS_DEB_HOST);
1895

1896
	if (priv->dnld_sent) {
1897
		allowed = 0;
1898
		lbs_deb_host("dnld_sent was set\n");
1899 1900
	}

1901 1902
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd) {
1903
		allowed = 0;
1904
		lbs_deb_host("cur_cmd was set\n");
1905
	}
1906
	if (priv->intcounter > 0) {
1907
		allowed = 0;
1908
		lbs_deb_host("intcounter %d\n", priv->intcounter);
1909
	}
1910
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1911 1912

	if (allowed) {
1913
		lbs_deb_host("sending lbs_ps_confirm_sleep\n");
1914
		lbs_send_confirmsleep(priv);
1915
	} else {
1916
		lbs_deb_host("sleep confirm has been delayed\n");
1917 1918
	}

1919
	lbs_deb_leave(LBS_DEB_HOST);
1920
}
1921 1922


1923 1924 1925 1926
static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
	uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
	int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
	unsigned long callback_arg)
1927 1928 1929 1930 1931
{
	struct cmd_ctrl_node *cmdnode;

	lbs_deb_enter(LBS_DEB_HOST);

1932
	if (priv->surpriseremoved) {
1933
		lbs_deb_host("PREP_CMD: card removed\n");
1934
		cmdnode = ERR_PTR(-ENOENT);
1935 1936 1937 1938 1939 1940 1941 1942 1943
		goto done;
	}

	cmdnode = lbs_get_cmd_ctrl_node(priv);
	if (cmdnode == NULL) {
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");

		/* Wake up main thread to execute next command */
		wake_up_interruptible(&priv->waitq);
1944
		cmdnode = ERR_PTR(-ENOBUFS);
1945 1946 1947
		goto done;
	}

1948
	cmdnode->callback = callback;
1949
	cmdnode->callback_arg = callback_arg;
1950

1951
	/* Copy the incoming command to the buffer */
1952
	memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
1953

1954
	/* Set sequence number, clean result, move to buffer */
1955
	priv->seqnum++;
1956 1957 1958 1959
	cmdnode->cmdbuf->command = cpu_to_le16(command);
	cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
	cmdnode->cmdbuf->seqnum  = cpu_to_le16(priv->seqnum);
	cmdnode->cmdbuf->result  = 0;
1960 1961 1962 1963

	lbs_deb_host("PREP_CMD: command 0x%04x\n", command);

	cmdnode->cmdwaitqwoken = 0;
1964
	lbs_queue_cmd(priv, cmdnode);
1965 1966
	wake_up_interruptible(&priv->waitq);

1967 1968 1969 1970 1971
 done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
	return cmdnode;
}

1972 1973 1974 1975 1976 1977 1978 1979 1980
void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
	struct cmd_header *in_cmd, int in_cmd_size)
{
	lbs_deb_enter(LBS_DEB_CMD);
	__lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
		lbs_cmd_async_callback, 0);
	lbs_deb_leave(LBS_DEB_CMD);
}

1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998
int __lbs_cmd(struct lbs_private *priv, uint16_t command,
	      struct cmd_header *in_cmd, int in_cmd_size,
	      int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
	      unsigned long callback_arg)
{
	struct cmd_ctrl_node *cmdnode;
	unsigned long flags;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_HOST);

	cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
				  callback, callback_arg);
	if (IS_ERR(cmdnode)) {
		ret = PTR_ERR(cmdnode);
		goto done;
	}

1999 2000 2001
	might_sleep();
	wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);

2002
	spin_lock_irqsave(&priv->driver_lock, flags);
2003 2004 2005 2006
	ret = cmdnode->result;
	if (ret)
		lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
			    command, ret);
2007

2008
	__lbs_cleanup_and_insert_cmd(priv, cmdnode);
2009
	spin_unlock_irqrestore(&priv->driver_lock, flags);
2010 2011 2012 2013 2014

done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
	return ret;
}
2015
EXPORT_SYMBOL_GPL(__lbs_cmd);
2016 2017