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

#include <net/iw_handler.h>
7
#include <linux/kfifo.h>
8 9 10 11 12
#include "host.h"
#include "hostcmd.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
13
#include "assoc.h"
14
#include "wext.h"
15
#include "cmd.h"
16

17
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
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 59
/**
 *  @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;
}


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

77 78 79 80 81 82 83 84
/**
 *  @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)
85
{
86 87 88 89
	struct cmd_ds_get_hw_spec cmd;
	int ret = -1;
	u32 i;
	DECLARE_MAC_BUF(mac);
90

91
	lbs_deb_enter(LBS_DEB_CMD);
92

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

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

102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
	/* 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);
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
	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);
142

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
	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:
158
	lbs_deb_leave(LBS_DEB_CMD);
159
	return ret;
160 161
}

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

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

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

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

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

189
	lbs_deb_enter(LBS_DEB_CMD);
190

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

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

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

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

	default:
		break;
	}

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

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

228 229
	lbs_deb_enter(LBS_DEB_CMD);

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

233
	cmd.action = cpu_to_le16(cmd_action);
234

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

240 241 242 243 244 245
	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);
246 247 248
	return 0;
}

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

255
	lbs_deb_enter(LBS_DEB_CMD);
256

257
	if (cmd_action == CMD_ACT_GET) {
258 259 260 261 262 263 264 265
		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);
266
	}
267 268
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(cmd_action);
269

270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
	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);
288 289 290
	return 0;
}

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

297
	lbs_deb_enter(LBS_DEB_CMD);
298

299
	memset(&cmd, 0, sizeof(cmd));
300 301
	cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
302

303
	cmd.action = cpu_to_le16(cmd_action);
304

305 306
	if (cmd_action == CMD_ACT_ADD) {
		int i;
307 308

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

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

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

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

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

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

	lbs_deb_enter(LBS_DEB_CMD);
359

360 361
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(cmd_action);
362

363 364 365
	if (cmd_action == CMD_ACT_GET)
		cmd.enable = 0;
	else {
366
		if (*enable)
367
			cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
368
		else
369
			cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
370
		lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
371 372
	}

373 374 375 376 377 378
	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;
379 380
}

381 382
static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
                            struct enc_key *key)
383
{
384 385
	lbs_deb_enter(LBS_DEB_CMD);

386 387 388 389 390 391
	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);
392

393 394 395 396 397 398 399
	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);
400
	lbs_deb_leave(LBS_DEB_CMD);
401 402
}

403 404
int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
				struct assoc_request *assoc)
405
{
406
	struct cmd_ds_802_11_key_material cmd;
407 408 409
	int ret = 0;
	int index = 0;

410
	lbs_deb_enter(LBS_DEB_CMD);
411

412 413
	cmd.action = cpu_to_le16(cmd_action);
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
414

415
	if (cmd_action == CMD_ACT_GET) {
416 417 418
		cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2);
	} else {
		memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
419

420 421 422 423 424
		if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
			set_one_wpa_key(&cmd.keyParamSet[index],
					&assoc->wpa_unicast_key);
			index++;
		}
425

426 427 428 429 430
		if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
			set_one_wpa_key(&cmd.keyParamSet[index],
					&assoc->wpa_mcast_key);
			index++;
		}
431

432 433 434
		/* The common header and as many keys as we included */
		cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
						    keyParamSet[index]));
435
	}
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
	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;
457

458 459 460 461 462 463
			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;
464

465 466 467 468 469 470 471 472 473 474 475 476
			/* 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;
		}
	}
477

478
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
479 480 481
	return ret;
}

482
static int lbs_cmd_802_11_reset(struct cmd_ds_command *cmd, int cmd_action)
483 484 485
{
	struct cmd_ds_802_11_reset *reset = &cmd->params.reset;

486 487
	lbs_deb_enter(LBS_DEB_CMD);

488
	cmd->command = cpu_to_le16(CMD_802_11_RESET);
489 490 491
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
	reset->action = cpu_to_le16(cmd_action);

492
	lbs_deb_leave(LBS_DEB_CMD);
493 494 495
	return 0;
}

496
static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
497 498 499 500 501 502 503
				    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;

504
	lbs_deb_enter(LBS_DEB_CMD);
505

506
	lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
507

508
	cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
509
	cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
510 511 512 513

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

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

		break;
	}

	case OID_802_11D_ENABLE:
		{
			u32 ulTemp;

534
			pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
535

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

	case OID_802_11_FRAGMENTATION_THRESHOLD:
		{
			u32 ulTemp;

550
			pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
551

552 553 554 555
			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);
556
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
557
				ulTemp = *((u32 *) pdata_buf);
558
				*((__le16 *)(pSNMPMIB->value)) =
559 560 561 562 563 564 565 566 567 568 569
				    cpu_to_le16((u16) ulTemp);

			}

			break;
		}

	case OID_802_11_RTS_THRESHOLD:
		{

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

572 573 574 575
			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);
576 577 578
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
				ulTemp = *((u32 *)pdata_buf);
				*(__le16 *)(pSNMPMIB->value) =
579 580 581 582 583 584
				    cpu_to_le16((u16) ulTemp);

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

587 588 589 590
		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);
591
			pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
592
			*((__le16 *)(pSNMPMIB->value)) =
593
			    cpu_to_le16((u16) priv->txretrycount);
594 595 596 597 598 599 600
		}

		break;
	default:
		break;
	}

601
	lbs_deb_cmd(
602
	       "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
603 604
	       le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
	       le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
605

606
	lbs_deb_cmd(
607
	       "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
608 609 610
	       le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
	       le16_to_cpu(pSNMPMIB->bufsize),
	       le16_to_cpu(*(__le16 *) pSNMPMIB->value));
611

612
	lbs_deb_leave(LBS_DEB_CMD);
613 614 615
	return 0;
}

616
static int lbs_cmd_802_11_rf_tx_power(struct cmd_ds_command *cmd,
617 618 619 620 621
				       u16 cmd_action, void *pdata_buf)
{

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

622
	lbs_deb_enter(LBS_DEB_CMD);
623 624

	cmd->size =
625
	    cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
626
	cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
627
	prtp->action = cpu_to_le16(cmd_action);
628

629 630 631
	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));
632 633

	switch (cmd_action) {
634 635
	case CMD_ACT_TX_POWER_OPT_GET:
		prtp->action = cpu_to_le16(CMD_ACT_GET);
636 637 638
		prtp->currentlevel = 0;
		break;

639 640 641
	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);
642 643
		break;

644 645 646
	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);
647 648
		break;

649 650
	case CMD_ACT_TX_POWER_OPT_SET_LOW:
		prtp->action = cpu_to_le16(CMD_ACT_SET);
651 652 653
		prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
		break;
	}
654 655

	lbs_deb_leave(LBS_DEB_CMD);
656 657 658
	return 0;
}

659
static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
				      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;
}

678
static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
679 680 681 682 683 684
					      struct cmd_ds_command *cmd,
					      u16 cmd_action)
{
	struct cmd_ds_802_11_rate_adapt_rateset
	*rateadapt = &cmd->params.rateset;

685
	lbs_deb_enter(LBS_DEB_CMD);
686 687 688
	cmd->size =
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
			     + S_DS_GEN);
689
	cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
690

691
	rateadapt->action = cpu_to_le16(cmd_action);
692 693
	rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
	rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
694

695
	lbs_deb_leave(LBS_DEB_CMD);
696 697 698
	return 0;
}

699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
/**
 *  @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);
729
		lbs_deb_cmd("DATA_RATE: setting auto\n");
730 731
	}

732
	ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
733 734 735 736 737 738 739 740 741 742 743 744 745 746
	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;
747 748
}

749
static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
750 751 752 753 754
				      struct cmd_ds_command *cmd,
				      u16 cmd_action)
{
	struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;

755
	lbs_deb_enter(LBS_DEB_CMD);
756
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
757
			     S_DS_GEN);
758
	cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
759

760
	lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
761 762
	pMCastAdr->action = cpu_to_le16(cmd_action);
	pMCastAdr->nr_of_adrs =
763 764 765
	    cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
	memcpy(pMCastAdr->maclist, priv->multicastlist,
	       priv->nr_of_multicastmacaddr * ETH_ALEN);
766

767
	lbs_deb_leave(LBS_DEB_CMD);
768 769 770
	return 0;
}

771 772 773 774 775 776 777 778
/**
 *  @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)
779
{
780 781
	struct cmd_ds_802_11_rf_channel cmd;
	int ret = 0;
782

783
	lbs_deb_enter(LBS_DEB_CMD);
784

785
	memset(&cmd, 0, sizeof(cmd));
786 787
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
788

789
	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
790 791
	if (ret)
		goto out;
792

793 794
	ret = le16_to_cpu(cmd.channel);
	lbs_deb_cmd("current radio channel is %d\n", ret);
795 796 797 798 799 800

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

801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816
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;
}

817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
/**
 *  @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);

833
	memset(&cmd, 0, sizeof(cmd));
834 835 836 837
	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);

838
	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
839 840 841
	if (ret)
		goto out;

842 843 844
	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);
845 846 847 848

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

851
static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
852 853 854
				struct cmd_ds_command *cmd)
{

855
	lbs_deb_enter(LBS_DEB_CMD);
856
	cmd->command = cpu_to_le16(CMD_802_11_RSSI);
857
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
858
	cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
859 860

	/* reset Beacon SNR/NF/RSSI values */
861 862 863 864 865 866
	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;
867

868
	lbs_deb_leave(LBS_DEB_CMD);
869 870 871
	return 0;
}

872
static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
873 874
			       u8 cmd_action, void *pdata_buf)
{
875
	struct lbs_offset_value *offval;
876

877
	lbs_deb_enter(LBS_DEB_CMD);
878

879
	offval = (struct lbs_offset_value *)pdata_buf;
880

H
Holger Schurig 已提交
881
	switch (le16_to_cpu(cmdptr->command)) {
882
	case CMD_MAC_REG_ACCESS:
883 884 885 886
		{
			struct cmd_ds_mac_reg_access *macreg;

			cmdptr->size =
887 888
			    cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
					+ S_DS_GEN);
889 890 891 892 893 894 895 896 897 898 899
			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;
		}

900
	case CMD_BBP_REG_ACCESS:
901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918
		{
			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;
		}

919
	case CMD_RF_REG_ACCESS:
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
		{
			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;
	}

942
	lbs_deb_leave(LBS_DEB_CMD);
943 944 945
	return 0;
}

946
static int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
947 948 949
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
950
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
951

952
	cmd->command = cpu_to_le16(CMD_BT_ACCESS);
953
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
954 955 956 957
	cmd->result = 0;
	bt_access->action = cpu_to_le16(cmd_action);

	switch (cmd_action) {
958
	case CMD_ACT_BT_ACCESS_ADD:
959
		memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
960
		lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
961
		break;
962
	case CMD_ACT_BT_ACCESS_DEL:
963
		memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
964
		lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
965
		break;
966
	case CMD_ACT_BT_ACCESS_LIST:
967 968
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
969
	case CMD_ACT_BT_ACCESS_RESET:
970
		break;
971
	case CMD_ACT_BT_ACCESS_SET_INVERT:
972 973
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
974
	case CMD_ACT_BT_ACCESS_GET_INVERT:
975
		break;
976 977 978
	default:
		break;
	}
979
	lbs_deb_leave(LBS_DEB_CMD);
980 981 982
	return 0;
}

983
static int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
984 985 986
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
987
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
988

989
	cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
990
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
991 992 993 994 995 996 997 998 999
	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);

1000
	lbs_deb_leave(LBS_DEB_CMD);
1001 1002 1003
	return 0;
}

1004 1005
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
		    struct cmd_ds_mesh_access *cmd)
1006
{
1007 1008
	int ret;

1009
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
1010

1011
	cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
1012
	cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
1013
	cmd->hdr.result = 0;
1014

1015
	cmd->action = cpu_to_le16(cmd_action);
1016

1017
	ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
1018

1019
	lbs_deb_leave(LBS_DEB_CMD);
1020
	return ret;
1021 1022
}

1023
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan)
1024 1025 1026 1027 1028
{
	struct cmd_ds_mesh_config cmd;

	memset(&cmd, 0, sizeof(cmd));
	cmd.action = cpu_to_le16(enable);
1029
	cmd.channel = cpu_to_le16(chan);
1030
	cmd.type = cpu_to_le16(priv->mesh_tlv);
1031
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1032

1033 1034 1035 1036
	if (enable) {
		cmd.length = cpu_to_le16(priv->mesh_ssid_len);
		memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len);
	}
1037
	lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n",
1038
		    enable, priv->mesh_tlv, chan,
1039
		    escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
1040
	return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd);
1041 1042
}

1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
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);
1057 1058
	bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
	bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
1059 1060 1061 1062 1063

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

1064 1065
static void lbs_queue_cmd(struct lbs_private *priv,
			  struct cmd_ctrl_node *cmdnode)
1066 1067
{
	unsigned long flags;
1068
	int addtail = 1;
1069

1070
	lbs_deb_enter(LBS_DEB_HOST);
1071

1072 1073
	if (!cmdnode) {
		lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
1074 1075
		goto done;
	}
1076 1077 1078 1079
	if (!cmdnode->cmdbuf->size) {
		lbs_deb_host("DNLD_CMD: cmd size is zero\n");
		goto done;
	}
1080
	cmdnode->result = 0;
1081 1082

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

1086
		if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1087
			if (priv->psstate != PS_STATE_FULL_POWER)
1088 1089 1090 1091
				addtail = 0;
		}
	}

1092
	spin_lock_irqsave(&priv->driver_lock, flags);
1093

1094
	if (addtail)
1095
		list_add_tail(&cmdnode->list, &priv->cmdpendingq);
1096
	else
1097
		list_add(&cmdnode->list, &priv->cmdpendingq);
1098

1099
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1100

1101
	lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
1102
		     le16_to_cpu(cmdnode->cmdbuf->command));
1103 1104

done:
1105
	lbs_deb_leave(LBS_DEB_HOST);
1106 1107
}

1108 1109
static void lbs_submit_command(struct lbs_private *priv,
			       struct cmd_ctrl_node *cmdnode)
1110 1111
{
	unsigned long flags;
1112
	struct cmd_header *cmd;
1113 1114 1115 1116
	uint16_t cmdsize;
	uint16_t command;
	int timeo = 5 * HZ;
	int ret;
1117

1118
	lbs_deb_enter(LBS_DEB_HOST);
1119

1120
	cmd = cmdnode->cmdbuf;
1121

1122 1123 1124 1125
	spin_lock_irqsave(&priv->driver_lock, flags);
	priv->cur_cmd = cmdnode;
	priv->cur_cmd_retcode = 0;
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1126

1127 1128
	cmdsize = le16_to_cpu(cmd->size);
	command = le16_to_cpu(cmd->command);
1129

1130 1131 1132 1133 1134
	/* 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 已提交
1135 1136
	lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
		     command, le16_to_cpu(cmd->seqnum), cmdsize);
1137
	lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
1138

1139
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
1140

1141 1142
	if (ret) {
		lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
1143 1144 1145
		/* Let the timer kick in and retry, and potentially reset
		   the whole thing if the condition persists */
		timeo = HZ;
1146
	}
1147 1148

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

1151
	lbs_deb_leave(LBS_DEB_HOST);
1152 1153 1154 1155
}

/**
 *  This function inserts command node to cmdfreeq
1156
 *  after cleans it. Requires priv->driver_lock held.
1157
 */
1158
static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1159
					 struct cmd_ctrl_node *cmdnode)
1160
{
1161 1162 1163 1164 1165 1166 1167
	lbs_deb_enter(LBS_DEB_HOST);

	if (!cmdnode)
		goto out;

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

1169
	memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
1170

1171 1172 1173
	list_add_tail(&cmdnode->list, &priv->cmdfreeq);
 out:
	lbs_deb_leave(LBS_DEB_HOST);
1174 1175
}

1176 1177
static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1178 1179 1180
{
	unsigned long flags;

1181
	spin_lock_irqsave(&priv->driver_lock, flags);
1182
	__lbs_cleanup_and_insert_cmd(priv, ptempcmd);
1183
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1184 1185
}

1186 1187 1188 1189 1190
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;
1191

1192
	cmd->result = result;
1193 1194 1195
	cmd->cmdwaitqwoken = 1;
	wake_up_interruptible(&cmd->cmdwait_q);

1196
	if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
1197
		__lbs_cleanup_and_insert_cmd(priv, cmd);
1198 1199 1200
	priv->cur_cmd = NULL;
}

1201
int lbs_set_radio_control(struct lbs_private *priv)
1202 1203
{
	int ret = 0;
1204
	struct cmd_ds_802_11_radio_control cmd;
1205

1206
	lbs_deb_enter(LBS_DEB_CMD);
1207

1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
	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;
	}
1225

1226 1227 1228 1229 1230 1231 1232 1233 1234
	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);
1235

1236
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1237 1238 1239
	return ret;
}

1240
void lbs_set_mac_control(struct lbs_private *priv)
1241
{
1242
	struct cmd_ds_mac_control cmd;
1243

1244
	lbs_deb_enter(LBS_DEB_CMD);
1245

1246
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1247
	cmd.action = cpu_to_le16(priv->mac_control);
1248 1249
	cmd.reserved = 0;

1250 1251
	lbs_cmd_async(priv, CMD_MAC_CONTROL,
		&cmd.hdr, sizeof(cmd));
1252

1253
	lbs_deb_leave(LBS_DEB_CMD);
1254 1255 1256 1257 1258
}

/**
 *  @brief This function prepare the command before send to firmware.
 *
1259
 *  @param priv		A pointer to struct lbs_private structure
1260 1261 1262 1263 1264 1265 1266
 *  @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
 */
1267
int lbs_prepare_and_send_command(struct lbs_private *priv,
1268 1269 1270 1271 1272 1273 1274 1275 1276
			  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;

1277
	lbs_deb_enter(LBS_DEB_HOST);
1278

1279 1280
	if (!priv) {
		lbs_deb_host("PREP_CMD: priv is NULL\n");
1281 1282 1283 1284
		ret = -1;
		goto done;
	}

1285
	if (priv->surpriseremoved) {
1286
		lbs_deb_host("PREP_CMD: card removed\n");
1287 1288 1289 1290
		ret = -1;
		goto done;
	}

1291
	cmdnode = lbs_get_cmd_ctrl_node(priv);
1292 1293

	if (cmdnode == NULL) {
1294
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1295 1296

		/* Wake up main thread to execute next command */
1297
		wake_up_interruptible(&priv->waitq);
1298 1299 1300 1301
		ret = -1;
		goto done;
	}

1302 1303
	cmdnode->callback = NULL;
	cmdnode->callback_arg = (unsigned long)pdata_buf;
1304

1305
	cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
1306

1307
	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
1308 1309

	/* Set sequence number, command and INT option */
1310 1311
	priv->seqnum++;
	cmdptr->seqnum = cpu_to_le16(priv->seqnum);
1312

1313
	cmdptr->command = cpu_to_le16(cmd_no);
1314 1315 1316
	cmdptr->result = 0;

	switch (cmd_no) {
1317
	case CMD_802_11_PS_MODE:
1318
		ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action);
1319 1320
		break;

1321 1322
	case CMD_802_11_ASSOCIATE:
	case CMD_802_11_REASSOCIATE:
1323
		ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
1324 1325
		break;

1326
	case CMD_802_11_DEAUTHENTICATE:
1327
		ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
1328 1329
		break;

1330
	case CMD_802_11_AD_HOC_START:
1331
		ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
1332 1333
		break;

1334
	case CMD_802_11_RESET:
1335
		ret = lbs_cmd_802_11_reset(cmdptr, cmd_action);
1336 1337
		break;

1338
	case CMD_802_11_AUTHENTICATE:
1339
		ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
1340 1341
		break;

1342
	case CMD_802_11_SNMP_MIB:
1343
		ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
1344 1345 1346
					       cmd_action, cmd_oid, pdata_buf);
		break;

1347 1348 1349
	case CMD_MAC_REG_ACCESS:
	case CMD_BBP_REG_ACCESS:
	case CMD_RF_REG_ACCESS:
1350
		ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf);
1351 1352
		break;

1353
	case CMD_802_11_RF_TX_POWER:
1354 1355
		ret = lbs_cmd_802_11_rf_tx_power(cmdptr,
						 cmd_action, pdata_buf);
1356 1357
		break;

1358
	case CMD_802_11_RATE_ADAPT_RATESET:
1359
		ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
1360 1361 1362
							 cmdptr, cmd_action);
		break;

1363
	case CMD_MAC_MULTICAST_ADR:
1364
		ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
1365 1366
		break;

1367
	case CMD_802_11_MONITOR_MODE:
1368
		ret = lbs_cmd_802_11_monitor_mode(cmdptr,
1369 1370 1371
				          cmd_action, pdata_buf);
		break;

1372
	case CMD_802_11_AD_HOC_JOIN:
1373
		ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
1374 1375
		break;

1376
	case CMD_802_11_RSSI:
1377
		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
1378 1379
		break;

1380
	case CMD_802_11_AD_HOC_STOP:
1381
		ret = lbs_cmd_80211_ad_hoc_stop(cmdptr);
1382 1383
		break;

1384 1385
	case CMD_802_11_SET_AFC:
	case CMD_802_11_GET_AFC:
1386 1387

		cmdptr->command = cpu_to_le16(cmd_no);
1388 1389
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
					   S_DS_GEN);
1390 1391 1392 1393 1394 1395 1396

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

		ret = 0;
		goto done;

1397
	case CMD_802_11D_DOMAIN_INFO:
1398
		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
1399 1400 1401
						   cmd_no, cmd_action);
		break;

1402 1403
	case CMD_802_11_TPC_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1404 1405 1406 1407 1408 1409 1410 1411 1412
		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;
1413
	case CMD_802_11_LED_GPIO_CTRL:
1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
		{
			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 =
1424
			    cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
1425 1426 1427

#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
			cmdptr->size =
H
Holger Schurig 已提交
1428 1429 1430 1431
			    cpu_to_le16(le16_to_cpu(gpio->header.len)
				+ S_DS_GEN
				+ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
			gpio->header.len = gpio->header.len;
1432 1433 1434 1435

			ret = 0;
			break;
		}
1436

1437
	case CMD_BT_ACCESS:
1438
		ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
1439 1440
		break;

1441
	case CMD_FWT_ACCESS:
1442
		ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
1443 1444
		break;

1445 1446
	case CMD_GET_TSF:
		cmdptr->command = cpu_to_le16(CMD_GET_TSF);
1447 1448
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
					   S_DS_GEN);
1449 1450
		ret = 0;
		break;
1451 1452 1453
	case CMD_802_11_BEACON_CTRL:
		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
		break;
1454
	default:
1455
		lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
1456 1457 1458 1459 1460 1461
		ret = -1;
		break;
	}

	/* return error, since the command preparation failed */
	if (ret != 0) {
1462
		lbs_deb_host("PREP_CMD: command preparation failed\n");
1463
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1464 1465 1466 1467 1468 1469
		ret = -1;
		goto done;
	}

	cmdnode->cmdwaitqwoken = 0;

1470
	lbs_queue_cmd(priv, cmdnode);
1471
	wake_up_interruptible(&priv->waitq);
1472

1473
	if (wait_option & CMD_OPTION_WAITFORRSP) {
1474
		lbs_deb_host("PREP_CMD: wait for response\n");
1475 1476 1477 1478 1479
		might_sleep();
		wait_event_interruptible(cmdnode->cmdwait_q,
					 cmdnode->cmdwaitqwoken);
	}

1480 1481
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd_retcode) {
1482
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
1483 1484
		       priv->cur_cmd_retcode);
		priv->cur_cmd_retcode = 0;
1485 1486
		ret = -1;
	}
1487
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1488 1489

done:
1490
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1491 1492 1493 1494 1495 1496 1497
	return ret;
}

/**
 *  @brief This function allocates the command buffer and link
 *  it to command free queue.
 *
1498
 *  @param priv		A pointer to struct lbs_private structure
1499 1500
 *  @return 		0 or -1
 */
1501
int lbs_allocate_cmd_buffer(struct lbs_private *priv)
1502 1503
{
	int ret = 0;
1504
	u32 bufsize;
1505
	u32 i;
1506
	struct cmd_ctrl_node *cmdarray;
1507

1508
	lbs_deb_enter(LBS_DEB_HOST);
1509

1510 1511 1512
	/* Allocate and initialize the command array */
	bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
	if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
1513
		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
1514 1515 1516
		ret = -1;
		goto done;
	}
1517
	priv->cmd_array = cmdarray;
1518

1519 1520 1521 1522
	/* 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) {
1523
			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
1524 1525 1526 1527 1528
			ret = -1;
			goto done;
		}
	}

1529 1530 1531
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		init_waitqueue_head(&cmdarray[i].cmdwait_q);
		lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
1532 1533
	}
	ret = 0;
1534 1535

done:
1536
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1537 1538 1539 1540 1541 1542
	return ret;
}

/**
 *  @brief This function frees the command buffer.
 *
1543
 *  @param priv		A pointer to struct lbs_private structure
1544 1545
 *  @return 		0 or -1
 */
1546
int lbs_free_cmd_buffer(struct lbs_private *priv)
1547
{
1548
	struct cmd_ctrl_node *cmdarray;
1549 1550
	unsigned int i;

1551
	lbs_deb_enter(LBS_DEB_HOST);
1552 1553

	/* need to check if cmd array is allocated or not */
1554
	if (priv->cmd_array == NULL) {
1555
		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
1556 1557 1558
		goto done;
	}

1559
	cmdarray = priv->cmd_array;
1560 1561

	/* Release shared memory buffers */
1562 1563 1564 1565
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		if (cmdarray[i].cmdbuf) {
			kfree(cmdarray[i].cmdbuf);
			cmdarray[i].cmdbuf = NULL;
1566 1567 1568 1569
		}
	}

	/* Release cmd_ctrl_node */
1570 1571 1572
	if (priv->cmd_array) {
		kfree(priv->cmd_array);
		priv->cmd_array = NULL;
1573 1574 1575
	}

done:
1576
	lbs_deb_leave(LBS_DEB_HOST);
1577 1578 1579 1580 1581 1582 1583
	return 0;
}

/**
 *  @brief This function gets a free command node if available in
 *  command free queue.
 *
1584
 *  @param priv		A pointer to struct lbs_private structure
1585 1586
 *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
 */
1587
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
1588 1589 1590 1591
{
	struct cmd_ctrl_node *tempnode;
	unsigned long flags;

1592 1593
	lbs_deb_enter(LBS_DEB_HOST);

1594
	if (!priv)
1595 1596
		return NULL;

1597
	spin_lock_irqsave(&priv->driver_lock, flags);
1598

1599 1600
	if (!list_empty(&priv->cmdfreeq)) {
		tempnode = list_first_entry(&priv->cmdfreeq,
1601 1602
					    struct cmd_ctrl_node, list);
		list_del(&tempnode->list);
1603
	} else {
1604
		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
1605 1606 1607
		tempnode = NULL;
	}

1608
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1609

1610
	lbs_deb_leave(LBS_DEB_HOST);
1611 1612 1613 1614 1615 1616 1617 1618
	return tempnode;
}

/**
 *  @brief This function executes next command in command
 *  pending queue. It will put fimware back to PS mode
 *  if applicable.
 *
1619
 *  @param priv     A pointer to struct lbs_private structure
1620 1621
 *  @return 	   0 or -1
 */
1622
int lbs_execute_next_command(struct lbs_private *priv)
1623 1624
{
	struct cmd_ctrl_node *cmdnode = NULL;
1625
	struct cmd_header *cmd;
1626 1627 1628
	unsigned long flags;
	int ret = 0;

1629 1630 1631
	/* 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 */
1632
	lbs_deb_enter(LBS_DEB_THREAD);
1633

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

1636
	if (priv->cur_cmd) {
1637
		lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
1638
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1639 1640 1641 1642
		ret = -1;
		goto done;
	}

1643 1644
	if (!list_empty(&priv->cmdpendingq)) {
		cmdnode = list_first_entry(&priv->cmdpendingq,
1645
					   struct cmd_ctrl_node, list);
1646 1647
	}

1648
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1649 1650

	if (cmdnode) {
1651
		cmd = cmdnode->cmdbuf;
1652

1653
		if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
1654 1655
			if ((priv->psstate == PS_STATE_SLEEP) ||
			    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1656 1657
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
1658
				       le16_to_cpu(cmd->command),
1659
				       priv->psstate);
1660 1661 1662
				ret = -1;
				goto done;
			}
1663
			lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
1664 1665
				     "0x%04x in psstate %d\n",
				     le16_to_cpu(cmd->command), priv->psstate);
1666
		} else if (priv->psstate != PS_STATE_FULL_POWER) {
1667 1668 1669
			/*
			 * 1. Non-PS command:
			 * Queue it. set needtowakeup to TRUE if current state
1670
			 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
1671 1672 1673 1674 1675 1676 1677
			 * 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.
			 */
1678
			if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
1679 1680
				/*  Prepare to send Exit PS,
				 *  this non PS command will be sent later */
1681 1682
				if ((priv->psstate == PS_STATE_SLEEP)
				    || (priv->psstate == PS_STATE_PRE_SLEEP)
1683 1684 1685
				    ) {
					/* w/ new scheme, it will not reach here.
					   since it is blocked in main_thread. */
1686
					priv->needtowakeup = 1;
1687
				} else
1688
					lbs_ps_wakeup(priv, 0);
1689 1690 1691 1692 1693 1694 1695 1696

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

1699 1700
				lbs_deb_host(
				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
1701 1702
				       psm->action);
				if (psm->action !=
1703
				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1704 1705
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
1706
					list_del(&cmdnode->list);
1707 1708 1709
					spin_lock_irqsave(&priv->driver_lock, flags);
					lbs_complete_command(priv, cmdnode, 0);
					spin_unlock_irqrestore(&priv->driver_lock, flags);
1710 1711 1712 1713 1714

					ret = 0;
					goto done;
				}

1715 1716
				if ((priv->psstate == PS_STATE_SLEEP) ||
				    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1717 1718
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
1719
					list_del(&cmdnode->list);
1720 1721 1722
					spin_lock_irqsave(&priv->driver_lock, flags);
					lbs_complete_command(priv, cmdnode, 0);
					spin_unlock_irqrestore(&priv->driver_lock, flags);
1723
					priv->needtowakeup = 1;
1724 1725 1726 1727 1728

					ret = 0;
					goto done;
				}

1729 1730
				lbs_deb_host(
				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
1731 1732
			}
		}
1733
		list_del(&cmdnode->list);
1734
		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
1735
			    le16_to_cpu(cmd->command));
1736
		lbs_submit_command(priv, cmdnode);
1737 1738 1739 1740 1741
	} else {
		/*
		 * check if in power save mode, if yes, put the device back
		 * to PS mode
		 */
1742 1743 1744 1745 1746 1747
		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) {
1748
				/* check for valid WPA group keys */
1749 1750
				if (priv->wpa_mcast_key.len ||
				    priv->wpa_unicast_key.len) {
1751
					lbs_deb_host(
1752 1753
					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
					       " go back to PS_SLEEP");
1754
					lbs_ps_sleep(priv, 0);
1755 1756
				}
			} else {
1757 1758 1759
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cmdpendingq empty, "
				       "go back to PS_SLEEP");
1760
				lbs_ps_sleep(priv, 0);
1761 1762 1763 1764 1765 1766
			}
		}
	}

	ret = 0;
done:
1767
	lbs_deb_leave(LBS_DEB_THREAD);
1768 1769 1770
	return ret;
}

1771
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
1772 1773 1774 1775
{
	union iwreq_data iwrq;
	u8 buf[50];

1776
	lbs_deb_enter(LBS_DEB_WEXT);
1777 1778 1779 1780 1781 1782 1783 1784 1785

	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 */
1786 1787 1788
	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);
1789

1790
	wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
1791

1792
	lbs_deb_leave(LBS_DEB_WEXT);
1793 1794
}

1795
static void lbs_send_confirmsleep(struct lbs_private *priv)
1796 1797
{
	unsigned long flags;
1798
	int ret;
1799

1800
	lbs_deb_enter(LBS_DEB_HOST);
1801 1802
	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,
		sizeof(confirm_sleep));
1803

1804 1805
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
		sizeof(confirm_sleep));
1806
	if (ret) {
1807
		lbs_pr_alert("confirm_sleep failed\n");
1808
		goto out;
1809
	}
1810 1811 1812 1813 1814 1815 1816 1817 1818 1819

	spin_lock_irqsave(&priv->driver_lock, flags);

	/* If nothing to do, go back to sleep (?) */
	if (!__kfifo_len(priv->event_fifo) && !priv->resp_len[priv->resp_idx])
		priv->psstate = PS_STATE_SLEEP;

	spin_unlock_irqrestore(&priv->driver_lock, flags);

out:
1820
	lbs_deb_leave(LBS_DEB_HOST);
1821 1822
}

1823
void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
1824
{
1825
	lbs_deb_enter(LBS_DEB_HOST);
1826 1827 1828 1829 1830 1831

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

1832
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1833
			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
1834

1835
	lbs_deb_leave(LBS_DEB_HOST);
1836 1837 1838
}

/**
1839
 *  @brief This function sends Exit_PS command to firmware.
1840
 *
1841
 *  @param priv    	A pointer to struct lbs_private structure
1842 1843 1844
 *  @param wait_option	wait response or not
 *  @return 	   	n/a
 */
1845
void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
1846
{
1847
	__le32 Localpsmode;
1848

1849
	lbs_deb_enter(LBS_DEB_HOST);
1850

1851
	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
1852

1853
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1854
			      CMD_SUBCMD_EXIT_PS,
1855 1856
			      wait_option, 0, &Localpsmode);

1857
	lbs_deb_leave(LBS_DEB_HOST);
1858 1859 1860 1861 1862 1863
}

/**
 *  @brief This function checks condition and prepares to
 *  send sleep confirm command to firmware if ok.
 *
1864
 *  @param priv    	A pointer to struct lbs_private structure
1865 1866 1867
 *  @param psmode  	Power Saving mode
 *  @return 	   	n/a
 */
1868
void lbs_ps_confirm_sleep(struct lbs_private *priv)
1869 1870
{
	unsigned long flags =0;
1871
	int allowed = 1;
1872

1873
	lbs_deb_enter(LBS_DEB_HOST);
1874

1875
	if (priv->dnld_sent) {
1876
		allowed = 0;
1877
		lbs_deb_host("dnld_sent was set\n");
1878 1879
	}

1880
	spin_lock_irqsave(&priv->driver_lock, flags);
1881
	/* In-progress command? */
1882
	if (priv->cur_cmd) {
1883
		allowed = 0;
1884
		lbs_deb_host("cur_cmd was set\n");
1885
	}
1886 1887 1888

	/* Pending events or command responses? */
	if (__kfifo_len(priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
1889
		allowed = 0;
1890
		lbs_deb_host("pending events or command responses\n");
1891
	}
1892
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1893 1894

	if (allowed) {
1895
		lbs_deb_host("sending lbs_ps_confirm_sleep\n");
1896
		lbs_send_confirmsleep(priv);
1897
	} else {
1898
		lbs_deb_host("sleep confirm has been delayed\n");
1899 1900
	}

1901
	lbs_deb_leave(LBS_DEB_HOST);
1902
}
1903 1904


1905 1906 1907 1908
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)
1909 1910 1911 1912 1913
{
	struct cmd_ctrl_node *cmdnode;

	lbs_deb_enter(LBS_DEB_HOST);

1914
	if (priv->surpriseremoved) {
1915
		lbs_deb_host("PREP_CMD: card removed\n");
1916
		cmdnode = ERR_PTR(-ENOENT);
1917 1918 1919 1920 1921 1922 1923 1924 1925
		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);
1926
		cmdnode = ERR_PTR(-ENOBUFS);
1927 1928 1929
		goto done;
	}

1930
	cmdnode->callback = callback;
1931
	cmdnode->callback_arg = callback_arg;
1932

1933
	/* Copy the incoming command to the buffer */
1934
	memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
1935

1936
	/* Set sequence number, clean result, move to buffer */
1937
	priv->seqnum++;
1938 1939 1940 1941
	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;
1942 1943 1944 1945

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

	cmdnode->cmdwaitqwoken = 0;
1946
	lbs_queue_cmd(priv, cmdnode);
1947 1948
	wake_up_interruptible(&priv->waitq);

1949 1950 1951 1952 1953
 done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
	return cmdnode;
}

1954 1955 1956 1957 1958 1959 1960 1961 1962
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);
}

1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980
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;
	}

1981 1982 1983
	might_sleep();
	wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);

1984
	spin_lock_irqsave(&priv->driver_lock, flags);
1985 1986 1987 1988
	ret = cmdnode->result;
	if (ret)
		lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
			    command, ret);
1989

1990
	__lbs_cleanup_and_insert_cmd(priv, cmdnode);
1991
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1992 1993 1994 1995 1996

done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
	return ret;
}
1997
EXPORT_SYMBOL_GPL(__lbs_cmd);
1998 1999