cmd.c 56.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/**
  * 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"
#include "join.h"
#include "wext.h"
14
#include "cmd.h"
15 16

static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
17 18
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
static void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
19
		    struct cmd_ctrl_node *ptempnode,
20
		    void *pdata_buf);
21

22 23

/**
24
 *  @brief Checks whether a command is allowed in Power Save mode
25 26
 *
 *  @param command the command ID
27
 *  @return 	   1 if allowed, 0 if not allowed
28
 */
29
static u8 is_command_allowed_in_ps(u16 cmd)
30
{
31 32 33 34 35
	switch (cmd) {
	case CMD_802_11_RSSI:
		return 1;
	default:
		break;
36 37 38 39
	}
	return 0;
}

40 41 42 43 44 45 46 47
/**
 *  @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)
48
{
49 50 51 52
	struct cmd_ds_get_hw_spec cmd;
	int ret = -1;
	u32 i;
	DECLARE_MAC_BUF(mac);
53

54
	lbs_deb_enter(LBS_DEB_CMD);
55

56 57 58
	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
59
	ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
	if (ret)
		goto out;

	priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
	memcpy(priv->fwreleasenumber, cmd.fwreleasenumber, 4);

	lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n",
		    priv->fwreleasenumber[2], priv->fwreleasenumber[1],
		    priv->fwreleasenumber[0], priv->fwreleasenumber[3]);
	lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n",
		    print_mac(mac, cmd.permanentaddr));
	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);
94

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
	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:
110
	lbs_deb_leave(LBS_DEB_CMD);
111
	return ret;
112 113
}

114
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria)
115 116 117 118 119
{
	struct cmd_ds_host_sleep cmd_config;
	int ret;

	cmd_config.criteria = cpu_to_le32(criteria);
120 121
	cmd_config.gpio = priv->wol_gpio;
	cmd_config.gap = priv->wol_gap;
122

123
	ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
124 125 126 127
	if (!ret) {
		lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
		priv->wol_criteria = criteria;
	} else {
128 129
		lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
	}
130

131 132 133 134
	return ret;
}
EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);

135
static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv,
136 137 138 139 140
				   struct cmd_ds_command *cmd,
				   u16 cmd_action)
{
	struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;

141
	lbs_deb_enter(LBS_DEB_CMD);
142

143
	cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
144 145
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
				S_DS_GEN);
146 147
	psm->action = cpu_to_le16(cmd_action);
	psm->multipledtim = 0;
148
	switch (cmd_action) {
149
	case CMD_SUBCMD_ENTER_PS:
150
		lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
151

152
		psm->locallisteninterval = 0;
153
		psm->nullpktinterval = 0;
154
		psm->multipledtim =
155
		    cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
156 157
		break;

158
	case CMD_SUBCMD_EXIT_PS:
159
		lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
160 161
		break;

162
	case CMD_SUBCMD_SLEEP_CONFIRMED:
163
		lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
164 165 166 167 168 169
		break;

	default:
		break;
	}

170
	lbs_deb_leave(LBS_DEB_CMD);
171 172 173
	return 0;
}

174
static int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
175 176 177 178 179
					      struct cmd_ds_command *cmd,
					      u16 cmd_action, void *pdata_buf)
{
	u16 *timeout = pdata_buf;

180 181
	lbs_deb_enter(LBS_DEB_CMD);

182
	cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
183 184 185 186 187 188 189
	cmd->size =
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
			     + S_DS_GEN);

	cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action);

	if (cmd_action)
190
		cmd->params.inactivity_timeout.timeout = cpu_to_le16(*timeout);
191 192 193
	else
		cmd->params.inactivity_timeout.timeout = 0;

194
	lbs_deb_leave(LBS_DEB_CMD);
195 196 197
	return 0;
}

198
static int lbs_cmd_802_11_sleep_params(struct lbs_private *priv,
199 200 201 202 203
					struct cmd_ds_command *cmd,
					u16 cmd_action)
{
	struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;

204
	lbs_deb_enter(LBS_DEB_CMD);
205

206 207
	cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
				S_DS_GEN);
208
	cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS);
209

210
	if (cmd_action == CMD_ACT_GET) {
211
		memset(&priv->sp, 0, sizeof(struct sleep_params));
212 213
		memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
		sp->action = cpu_to_le16(cmd_action);
214
	} else if (cmd_action == CMD_ACT_SET) {
215
		sp->action = cpu_to_le16(cmd_action);
216 217 218 219 220 221
		sp->error = cpu_to_le16(priv->sp.sp_error);
		sp->offset = cpu_to_le16(priv->sp.sp_offset);
		sp->stabletime = cpu_to_le16(priv->sp.sp_stabletime);
		sp->calcontrol = (u8) priv->sp.sp_calcontrol;
		sp->externalsleepclk = (u8) priv->sp.sp_extsleepclk;
		sp->reserved = cpu_to_le16(priv->sp.sp_reserved);
222 223
	}

224
	lbs_deb_leave(LBS_DEB_CMD);
225 226 227
	return 0;
}

228
static int lbs_cmd_802_11_set_wep(struct lbs_private *priv,
229 230 231 232 233 234 235 236
                                   struct cmd_ds_command *cmd,
                                   u32 cmd_act,
                                   void * pdata_buf)
{
	struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
	int ret = 0;
	struct assoc_request * assoc_req = pdata_buf;

237
	lbs_deb_enter(LBS_DEB_CMD);
238

239
	cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
240
	cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
241

242
	if (cmd_act == CMD_ACT_ADD) {
243 244 245
		int i;

		if (!assoc_req) {
246
			lbs_deb_cmd("Invalid association request!\n");
247 248 249 250
			ret = -1;
			goto done;
		}

251
		wep->action = cpu_to_le16(CMD_ACT_ADD);
252 253

		/* default tx key index */
254
		wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
255
						  (u32)CMD_WEP_KEY_INDEX_MASK));
256 257 258

		/* Copy key types and material to host command structure */
		for (i = 0; i < 4; i++) {
259
			struct enc_key * pkey = &assoc_req->wep_keys[i];
260 261 262

			switch (pkey->len) {
			case KEY_LEN_WEP_40:
H
Holger Schurig 已提交
263
				wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
264 265
				memmove(&wep->keymaterial[i], pkey->key,
				        pkey->len);
266
				lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
267 268
				break;
			case KEY_LEN_WEP_104:
H
Holger Schurig 已提交
269
				wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
270 271
				memmove(&wep->keymaterial[i], pkey->key,
				        pkey->len);
272
				lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
273 274 275 276
				break;
			case 0:
				break;
			default:
277
				lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
278 279 280 281 282 283
				       i, pkey->len);
				ret = -1;
				goto done;
				break;
			}
		}
284
	} else if (cmd_act == CMD_ACT_REMOVE) {
285
		/* ACT_REMOVE clears _all_ WEP keys */
286
		wep->action = cpu_to_le16(CMD_ACT_REMOVE);
287 288

		/* default tx key index */
289
		wep->keyindex = cpu_to_le16((u16)(priv->wep_tx_keyidx &
290
						  (u32)CMD_WEP_KEY_INDEX_MASK));
291
		lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
292 293 294 295 296
	}

	ret = 0;

done:
297
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
298 299 300
	return ret;
}

301
static int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv,
302
				      struct cmd_ds_command *cmd,
303 304
				      u16 cmd_action,
				      void * pdata_buf)
305 306
{
	struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
307
	u32 * enable = pdata_buf;
308 309

	lbs_deb_enter(LBS_DEB_CMD);
310

311
	cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
312
	cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
313
	penableRSN->action = cpu_to_le16(cmd_action);
314

315
	if (cmd_action == CMD_ACT_SET) {
316
		if (*enable)
317
			penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
318
		else
319
			penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
320
		lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
321 322
	}

323
	lbs_deb_leave(LBS_DEB_CMD);
324 325 326 327
	return 0;
}


328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
static ssize_t lbs_tlv_size(const u8 *tlv, u16 size)
{
	ssize_t pos = 0;
	struct mrvlietypesheader *tlv_h;
	while (pos < size) {
		u16 length;
		tlv_h = (struct mrvlietypesheader *) tlv;
		if (tlv_h->len == 0)
			return pos;
		length = le16_to_cpu(tlv_h->len) +
			sizeof(struct mrvlietypesheader);
		pos += length;
		tlv += length;
	}
	return pos;
}


static void lbs_cmd_802_11_subscribe_event(struct lbs_private *priv,
	struct cmd_ds_command *cmd, u16 cmd_action,
	void *pdata_buf)
{
	struct cmd_ds_802_11_subscribe_event *events =
		(struct cmd_ds_802_11_subscribe_event *) pdata_buf;

	/* pdata_buf points to a struct cmd_ds_802_11_subscribe_event and room
	 * for various Marvell TLVs */

	lbs_deb_enter(LBS_DEB_CMD);

	cmd->size = cpu_to_le16(sizeof(*events)
			- sizeof(events->tlv)
			+ S_DS_GEN);
	cmd->params.subscribe_event.action = cpu_to_le16(cmd_action);
	if (cmd_action == CMD_ACT_GET) {
		cmd->params.subscribe_event.events = 0;
	} else {
		ssize_t sz = lbs_tlv_size(events->tlv, sizeof(events->tlv));
		cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + sz);
		cmd->params.subscribe_event.events = events->events;
		memcpy(cmd->params.subscribe_event.tlv, events->tlv, sz);
	}

	lbs_deb_leave(LBS_DEB_CMD);
}

374
static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
375
                            struct enc_key * pkey)
376
{
377 378
	lbs_deb_enter(LBS_DEB_CMD);

379
	if (pkey->flags & KEY_INFO_WPA_ENABLED) {
380
		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
381 382 383
	}
	if (pkey->flags & KEY_INFO_WPA_UNICAST) {
		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
384 385
	}
	if (pkey->flags & KEY_INFO_WPA_MCAST) {
386 387 388 389
		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
	}

	pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
390
	pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
391 392 393 394 395 396
	pkeyparamset->keylen = cpu_to_le16(pkey->len);
	memcpy(pkeyparamset->key, pkey->key, pkey->len);
	pkeyparamset->length = cpu_to_le16(  sizeof(pkeyparamset->keytypeid)
	                                        + sizeof(pkeyparamset->keyinfo)
	                                        + sizeof(pkeyparamset->keylen)
	                                        + sizeof(pkeyparamset->key));
397
	lbs_deb_leave(LBS_DEB_CMD);
398 399
}

400
static int lbs_cmd_802_11_key_material(struct lbs_private *priv,
401 402 403 404 405 406
					struct cmd_ds_command *cmd,
					u16 cmd_action,
					u32 cmd_oid, void *pdata_buf)
{
	struct cmd_ds_802_11_key_material *pkeymaterial =
	    &cmd->params.keymaterial;
407
	struct assoc_request * assoc_req = pdata_buf;
408 409 410
	int ret = 0;
	int index = 0;

411
	lbs_deb_enter(LBS_DEB_CMD);
412

413
	cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
414 415
	pkeymaterial->action = cpu_to_le16(cmd_action);

416
	if (cmd_action == CMD_ACT_GET) {
417
		cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
418 419 420 421 422 423
		ret = 0;
		goto done;
	}

	memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));

424
	if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
425
		set_one_wpa_key(&pkeymaterial->keyParamSet[index],
426
		                &assoc_req->wpa_unicast_key);
427 428 429
		index++;
	}

430
	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
431
		set_one_wpa_key(&pkeymaterial->keyParamSet[index],
432
		                &assoc_req->wpa_mcast_key);
433 434 435 436
		index++;
	}

	cmd->size = cpu_to_le16(  S_DS_GEN
437 438
	                        + sizeof (pkeymaterial->action)
	                        + (index * sizeof(struct MrvlIEtype_keyParamSet)));
439 440 441 442

	ret = 0;

done:
443
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
444 445 446
	return ret;
}

447
static int lbs_cmd_802_11_reset(struct lbs_private *priv,
448 449 450 451
				 struct cmd_ds_command *cmd, int cmd_action)
{
	struct cmd_ds_802_11_reset *reset = &cmd->params.reset;

452 453
	lbs_deb_enter(LBS_DEB_CMD);

454
	cmd->command = cpu_to_le16(CMD_802_11_RESET);
455 456 457
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
	reset->action = cpu_to_le16(cmd_action);

458
	lbs_deb_leave(LBS_DEB_CMD);
459 460 461
	return 0;
}

462
static int lbs_cmd_802_11_get_log(struct lbs_private *priv,
463 464
				   struct cmd_ds_command *cmd)
{
465
	lbs_deb_enter(LBS_DEB_CMD);
466
	cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
467 468 469
	cmd->size =
		cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);

470
	lbs_deb_leave(LBS_DEB_CMD);
471 472 473
	return 0;
}

474
static int lbs_cmd_802_11_get_stat(struct lbs_private *priv,
475 476
				    struct cmd_ds_command *cmd)
{
477
	lbs_deb_enter(LBS_DEB_CMD);
478
	cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
479
	cmd->size =
480
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
481

482
	lbs_deb_leave(LBS_DEB_CMD);
483 484 485
	return 0;
}

486
static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
487 488 489 490 491 492 493
				    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;

494
	lbs_deb_enter(LBS_DEB_CMD);
495

496
	lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
497

498
	cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
499
	cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
500 501 502 503

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

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

		break;
	}

	case OID_802_11D_ENABLE:
		{
			u32 ulTemp;

524
			pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
525

526
			if (cmd_action == CMD_ACT_SET) {
H
Holger Schurig 已提交
527 528
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
529
				ulTemp = *(u32 *)pdata_buf;
530
				*((__le16 *)(pSNMPMIB->value)) =
531 532 533 534 535 536 537 538 539
				    cpu_to_le16((u16) ulTemp);
			}
			break;
		}

	case OID_802_11_FRAGMENTATION_THRESHOLD:
		{
			u32 ulTemp;

540
			pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
541

542 543 544 545
			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);
546
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
547
				ulTemp = *((u32 *) pdata_buf);
548
				*((__le16 *)(pSNMPMIB->value)) =
549 550 551 552 553 554 555 556 557 558 559
				    cpu_to_le16((u16) ulTemp);

			}

			break;
		}

	case OID_802_11_RTS_THRESHOLD:
		{

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

562 563 564 565
			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);
566 567 568
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
				ulTemp = *((u32 *)pdata_buf);
				*(__le16 *)(pSNMPMIB->value) =
569 570 571 572 573 574
				    cpu_to_le16((u16) ulTemp);

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

577 578 579 580
		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);
581
			pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
582
			*((__le16 *)(pSNMPMIB->value)) =
583
			    cpu_to_le16((u16) priv->txretrycount);
584 585 586 587 588 589 590
		}

		break;
	default:
		break;
	}

591
	lbs_deb_cmd(
592
	       "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
593 594
	       le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
	       le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
595

596
	lbs_deb_cmd(
597
	       "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
598 599 600
	       le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
	       le16_to_cpu(pSNMPMIB->bufsize),
	       le16_to_cpu(*(__le16 *) pSNMPMIB->value));
601

602
	lbs_deb_leave(LBS_DEB_CMD);
603 604 605
	return 0;
}

606
static int lbs_cmd_802_11_radio_control(struct lbs_private *priv,
607 608 609
					 struct cmd_ds_command *cmd,
					 int cmd_action)
{
610
	struct cmd_ds_802_11_radio_control *pradiocontrol = &cmd->params.radio;
611

612
	lbs_deb_enter(LBS_DEB_CMD);
613 614 615 616

	cmd->size =
	    cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
			     S_DS_GEN);
617
	cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL);
618 619 620

	pradiocontrol->action = cpu_to_le16(cmd_action);

621
	switch (priv->preamble) {
622
	case CMD_TYPE_SHORT_PREAMBLE:
623 624 625
		pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
		break;

626
	case CMD_TYPE_LONG_PREAMBLE:
627 628 629
		pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
		break;

630
	case CMD_TYPE_AUTO_PREAMBLE:
631 632 633 634 635
	default:
		pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
		break;
	}

636
	if (priv->radioon)
637 638 639 640
		pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
	else
		pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);

641
	lbs_deb_leave(LBS_DEB_CMD);
642 643 644
	return 0;
}

645
static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv,
646 647 648 649 650 651
				       struct cmd_ds_command *cmd,
				       u16 cmd_action, void *pdata_buf)
{

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

652
	lbs_deb_enter(LBS_DEB_CMD);
653 654

	cmd->size =
655
	    cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
656
	cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
657
	prtp->action = cpu_to_le16(cmd_action);
658

659 660 661
	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));
662 663

	switch (cmd_action) {
664 665
	case CMD_ACT_TX_POWER_OPT_GET:
		prtp->action = cpu_to_le16(CMD_ACT_GET);
666 667 668
		prtp->currentlevel = 0;
		break;

669 670 671
	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);
672 673
		break;

674 675 676
	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);
677 678
		break;

679 680
	case CMD_ACT_TX_POWER_OPT_SET_LOW:
		prtp->action = cpu_to_le16(CMD_ACT_SET);
681 682 683
		prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
		break;
	}
684 685

	lbs_deb_leave(LBS_DEB_CMD);
686 687 688
	return 0;
}

689
static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv,
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
				      struct cmd_ds_command *cmd,
				      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;
}

709
static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
710 711 712 713 714 715
					      struct cmd_ds_command *cmd,
					      u16 cmd_action)
{
	struct cmd_ds_802_11_rate_adapt_rateset
	*rateadapt = &cmd->params.rateset;

716
	lbs_deb_enter(LBS_DEB_CMD);
717 718 719
	cmd->size =
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
			     + S_DS_GEN);
720
	cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
721

722
	rateadapt->action = cpu_to_le16(cmd_action);
723 724
	rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
	rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
725

726
	lbs_deb_leave(LBS_DEB_CMD);
727 728 729
	return 0;
}

730 731 732 733 734 735 736 737
/**
 *  @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)
738
{
739 740
	struct cmd_ds_802_11_data_rate cmd;
	int ret = -1;
741

742
	lbs_deb_enter(LBS_DEB_CMD);
743

744 745 746 747
	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_GET_TX_RATE);

748
	ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
	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);
792
		lbs_deb_cmd("DATA_RATE: setting auto\n");
793 794
	}

795
	ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
796 797 798 799 800 801 802 803 804 805 806 807 808 809
	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;
810 811
}

812
static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
813 814 815 816 817
				      struct cmd_ds_command *cmd,
				      u16 cmd_action)
{
	struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;

818
	lbs_deb_enter(LBS_DEB_CMD);
819
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
820
			     S_DS_GEN);
821
	cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
822

823
	lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
824 825
	pMCastAdr->action = cpu_to_le16(cmd_action);
	pMCastAdr->nr_of_adrs =
826 827 828
	    cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
	memcpy(pMCastAdr->maclist, priv->multicastlist,
	       priv->nr_of_multicastmacaddr * ETH_ALEN);
829

830
	lbs_deb_leave(LBS_DEB_CMD);
831 832 833
	return 0;
}

834 835 836 837 838 839 840 841
/**
 *  @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)
842
{
843 844
	struct cmd_ds_802_11_rf_channel cmd;
	int ret = 0;
845

846
	lbs_deb_enter(LBS_DEB_CMD);
847

848 849
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
850

851
	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
852 853
	if (ret)
		goto out;
854

855 856
	ret = le16_to_cpu(cmd.channel);
	lbs_deb_cmd("current radio channel is %d\n", ret);
857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882

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

/**
 *  @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);

883
	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
884 885 886
	if (ret)
		goto out;

887 888 889
	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);
890 891 892 893

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

896
static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
897 898 899
				struct cmd_ds_command *cmd)
{

900
	lbs_deb_enter(LBS_DEB_CMD);
901
	cmd->command = cpu_to_le16(CMD_802_11_RSSI);
902
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
903
	cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
904 905

	/* reset Beacon SNR/NF/RSSI values */
906 907 908 909 910 911
	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;
912

913
	lbs_deb_leave(LBS_DEB_CMD);
914 915 916
	return 0;
}

917
static int lbs_cmd_reg_access(struct lbs_private *priv,
918 919 920
			       struct cmd_ds_command *cmdptr,
			       u8 cmd_action, void *pdata_buf)
{
921
	struct lbs_offset_value *offval;
922

923
	lbs_deb_enter(LBS_DEB_CMD);
924

925
	offval = (struct lbs_offset_value *)pdata_buf;
926

H
Holger Schurig 已提交
927
	switch (le16_to_cpu(cmdptr->command)) {
928
	case CMD_MAC_REG_ACCESS:
929 930 931 932
		{
			struct cmd_ds_mac_reg_access *macreg;

			cmdptr->size =
933 934
			    cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
					+ S_DS_GEN);
935 936 937 938 939 940 941 942 943 944 945
			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;
		}

946
	case CMD_BBP_REG_ACCESS:
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
		{
			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;
		}

965
	case CMD_RF_REG_ACCESS:
966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987
		{
			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;
	}

988
	lbs_deb_leave(LBS_DEB_CMD);
989 990 991
	return 0;
}

992
static int lbs_cmd_802_11_mac_address(struct lbs_private *priv,
993 994 995 996
				       struct cmd_ds_command *cmd,
				       u16 cmd_action)
{

997
	lbs_deb_enter(LBS_DEB_CMD);
998
	cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
999
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
1000 1001 1002 1003 1004
			     S_DS_GEN);
	cmd->result = 0;

	cmd->params.macadd.action = cpu_to_le16(cmd_action);

1005
	if (cmd_action == CMD_ACT_SET) {
1006
		memcpy(cmd->params.macadd.macadd,
1007 1008
		       priv->current_addr, ETH_ALEN);
		lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6);
1009 1010
	}

1011
	lbs_deb_leave(LBS_DEB_CMD);
1012 1013 1014
	return 0;
}

1015
static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv,
1016 1017 1018
					 struct cmd_ds_command *cmd,
					 int cmd_action, void *pdata_buf)
{
1019
	struct lbs_ioctl_regrdwr *ea = pdata_buf;
1020

1021
	lbs_deb_enter(LBS_DEB_CMD);
1022

1023
	cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
1024 1025
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
				S_DS_GEN);
1026 1027 1028 1029 1030 1031 1032
	cmd->result = 0;

	cmd->params.rdeeprom.action = cpu_to_le16(ea->action);
	cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset);
	cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
	cmd->params.rdeeprom.value = 0;

1033
	lbs_deb_leave(LBS_DEB_CMD);
1034 1035 1036
	return 0;
}

1037
static int lbs_cmd_bt_access(struct lbs_private *priv,
1038 1039 1040 1041
			       struct cmd_ds_command *cmd,
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
1042
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
1043

1044
	cmd->command = cpu_to_le16(CMD_BT_ACCESS);
1045
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
1046 1047 1048 1049
	cmd->result = 0;
	bt_access->action = cpu_to_le16(cmd_action);

	switch (cmd_action) {
1050
	case CMD_ACT_BT_ACCESS_ADD:
1051
		memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
1052
		lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
1053
		break;
1054
	case CMD_ACT_BT_ACCESS_DEL:
1055
		memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
1056
		lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
1057
		break;
1058
	case CMD_ACT_BT_ACCESS_LIST:
1059 1060
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
1061
	case CMD_ACT_BT_ACCESS_RESET:
1062
		break;
1063
	case CMD_ACT_BT_ACCESS_SET_INVERT:
1064 1065
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
1066
	case CMD_ACT_BT_ACCESS_GET_INVERT:
1067
		break;
1068 1069 1070
	default:
		break;
	}
1071
	lbs_deb_leave(LBS_DEB_CMD);
1072 1073 1074
	return 0;
}

1075
static int lbs_cmd_fwt_access(struct lbs_private *priv,
1076 1077 1078 1079
			       struct cmd_ds_command *cmd,
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
1080
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
1081

1082
	cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
1083
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
1084 1085 1086 1087 1088 1089 1090 1091 1092
	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);

1093
	lbs_deb_leave(LBS_DEB_CMD);
1094 1095 1096
	return 0;
}

1097 1098
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
		    struct cmd_ds_mesh_access *cmd)
1099
{
1100 1101
	int ret;

1102
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
1103

1104 1105 1106
	cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
	cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN);
	cmd->hdr.result = 0;
1107

1108
	cmd->action = cpu_to_le16(cmd_action);
1109

1110
	ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
1111

1112
	lbs_deb_leave(LBS_DEB_CMD);
1113
	return ret;
1114
}
1115
EXPORT_SYMBOL_GPL(lbs_mesh_access);
1116

1117
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan)
1118 1119 1120 1121 1122
{
	struct cmd_ds_mesh_config cmd;

	memset(&cmd, 0, sizeof(cmd));
	cmd.action = cpu_to_le16(enable);
1123
	cmd.channel = cpu_to_le16(chan);
1124
	cmd.type = cpu_to_le16(priv->mesh_tlv);
1125

1126 1127 1128 1129
	if (enable) {
		cmd.length = cpu_to_le16(priv->mesh_ssid_len);
		memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len);
	}
1130
	lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n",
1131
		    enable, priv->mesh_tlv, chan,
1132
		    escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
1133
	return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd);
1134 1135
}

1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
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);
1150 1151
	bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
	bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
1152 1153 1154 1155 1156

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

1157
/*
1158
 * Note: NEVER use lbs_queue_cmd() with addtail==0 other than for
1159 1160
 * the command timer, because it does not account for queued commands.
 */
1161
void lbs_queue_cmd(struct lbs_private *priv,
1162 1163
	struct cmd_ctrl_node *cmdnode,
	u8 addtail)
1164 1165 1166
{
	unsigned long flags;

1167
	lbs_deb_enter(LBS_DEB_HOST);
1168

1169 1170
	if (!cmdnode) {
		lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
1171 1172
		goto done;
	}
1173 1174 1175 1176
	if (!cmdnode->cmdbuf->size) {
		lbs_deb_host("DNLD_CMD: cmd size is zero\n");
		goto done;
	}
1177 1178

	/* Exit_PS command needs to be queued in the header always. */
1179 1180 1181
	if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
		struct cmd_ds_802_11_ps_mode *psm = (void *) cmdnode->cmdbuf;

1182
		if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1183
			if (priv->psstate != PS_STATE_FULL_POWER)
1184 1185 1186 1187
				addtail = 0;
		}
	}

1188
	spin_lock_irqsave(&priv->driver_lock, flags);
1189

1190
	if (addtail)
1191
		list_add_tail(&cmdnode->list, &priv->cmdpendingq);
1192
	else
1193
		list_add(&cmdnode->list, &priv->cmdpendingq);
1194

1195
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1196

1197
	lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
1198
		     le16_to_cpu(cmdnode->cmdbuf->command));
1199 1200

done:
1201
	lbs_deb_leave(LBS_DEB_HOST);
1202 1203
}

1204 1205
static int lbs_submit_command(struct lbs_private *priv,
			      struct cmd_ctrl_node *cmdnode)
1206 1207
{
	unsigned long flags;
1208
	struct cmd_header *cmd;
1209
	int ret = -1;
1210 1211 1212
	u16 cmdsize;
	u16 command;

1213
	lbs_deb_enter(LBS_DEB_HOST);
1214

1215
	cmd = cmdnode->cmdbuf;
1216

1217 1218 1219 1220
	spin_lock_irqsave(&priv->driver_lock, flags);
	priv->cur_cmd = cmdnode;
	priv->cur_cmd_retcode = 0;
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1221

1222 1223
	cmdsize = le16_to_cpu(cmd->size);
	command = le16_to_cpu(cmd->command);
1224

1225 1226
	lbs_deb_host("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n",
		     command, le16_to_cpu(cmd->seqnum), cmdsize, jiffies);
1227
	lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
1228

1229
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
1230 1231
	if (ret) {
		lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
1232 1233 1234 1235 1236
		spin_lock_irqsave(&priv->driver_lock, flags);
		priv->cur_cmd_retcode = ret;
		__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
		priv->cur_cmd = NULL;
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1237 1238 1239
		goto done;
	}

1240
	lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
1241 1242

	/* Setup the timer after transmit command */
1243 1244
	if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
	    || command == CMD_802_11_ASSOCIATE)
1245
		mod_timer(&priv->command_timer, jiffies + (10*HZ));
1246
	else
1247
		mod_timer(&priv->command_timer, jiffies + (5*HZ));
1248 1249 1250

	ret = 0;

1251
done:
1252
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1253 1254 1255
	return ret;
}

1256
static int lbs_cmd_mac_control(struct lbs_private *priv,
1257 1258 1259 1260
				struct cmd_ds_command *cmd)
{
	struct cmd_ds_mac_control *mac = &cmd->params.macctrl;

1261
	lbs_deb_enter(LBS_DEB_CMD);
1262

1263
	cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
1264
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
1265
	mac->action = cpu_to_le16(priv->currentpacketfilter);
1266

1267
	lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
1268
		    le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
1269

1270
	lbs_deb_leave(LBS_DEB_CMD);
1271 1272 1273 1274 1275
	return 0;
}

/**
 *  This function inserts command node to cmdfreeq
1276
 *  after cleans it. Requires priv->driver_lock held.
1277
 */
1278 1279
void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1280 1281 1282
{

	if (!ptempcmd)
1283
		return;
1284 1285

	cleanup_cmdnode(ptempcmd);
1286
	list_add_tail(&ptempcmd->list, &priv->cmdfreeq);
1287 1288
}

1289 1290
static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1291 1292 1293
{
	unsigned long flags;

1294
	spin_lock_irqsave(&priv->driver_lock, flags);
1295
	__lbs_cleanup_and_insert_cmd(priv, ptempcmd);
1296
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1297 1298
}

1299
int lbs_set_radio_control(struct lbs_private *priv)
1300 1301 1302
{
	int ret = 0;

1303
	lbs_deb_enter(LBS_DEB_CMD);
1304

1305
	ret = lbs_prepare_and_send_command(priv,
1306 1307 1308
				    CMD_802_11_RADIO_CONTROL,
				    CMD_ACT_SET,
				    CMD_OPTION_WAITFORRSP, 0, NULL);
1309

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

1313
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1314 1315 1316
	return ret;
}

1317
int lbs_set_mac_packet_filter(struct lbs_private *priv)
1318 1319 1320
{
	int ret = 0;

1321
	lbs_deb_enter(LBS_DEB_CMD);
1322 1323

	/* Send MAC control command to station */
1324
	ret = lbs_prepare_and_send_command(priv,
1325
				    CMD_MAC_CONTROL, 0, 0, 0, NULL);
1326

1327
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1328 1329 1330 1331 1332 1333
	return ret;
}

/**
 *  @brief This function prepare the command before send to firmware.
 *
1334
 *  @param priv		A pointer to struct lbs_private structure
1335 1336 1337 1338 1339 1340 1341
 *  @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
 */
1342
int lbs_prepare_and_send_command(struct lbs_private *priv,
1343 1344 1345 1346 1347 1348 1349 1350 1351
			  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;

1352
	lbs_deb_enter(LBS_DEB_HOST);
1353

1354 1355
	if (!priv) {
		lbs_deb_host("PREP_CMD: priv is NULL\n");
1356 1357 1358 1359
		ret = -1;
		goto done;
	}

1360
	if (priv->surpriseremoved) {
1361
		lbs_deb_host("PREP_CMD: card removed\n");
1362 1363 1364 1365
		ret = -1;
		goto done;
	}

1366
	cmdnode = lbs_get_cmd_ctrl_node(priv);
1367 1368

	if (cmdnode == NULL) {
1369
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1370 1371

		/* Wake up main thread to execute next command */
1372
		wake_up_interruptible(&priv->waitq);
1373 1374 1375 1376
		ret = -1;
		goto done;
	}

1377
	lbs_set_cmd_ctrl_node(priv, cmdnode, pdata_buf);
1378

1379
	cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
1380

1381
	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
1382 1383

	/* Set sequence number, command and INT option */
1384 1385
	priv->seqnum++;
	cmdptr->seqnum = cpu_to_le16(priv->seqnum);
1386

1387
	cmdptr->command = cpu_to_le16(cmd_no);
1388 1389 1390
	cmdptr->result = 0;

	switch (cmd_no) {
1391
	case CMD_802_11_PS_MODE:
1392
		ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
1393 1394
		break;

1395
	case CMD_802_11_SCAN:
1396
		ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
1397 1398
		break;

1399
	case CMD_MAC_CONTROL:
1400
		ret = lbs_cmd_mac_control(priv, cmdptr);
1401 1402
		break;

1403 1404
	case CMD_802_11_ASSOCIATE:
	case CMD_802_11_REASSOCIATE:
1405
		ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
1406 1407
		break;

1408
	case CMD_802_11_DEAUTHENTICATE:
1409
		ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
1410 1411
		break;

1412
	case CMD_802_11_SET_WEP:
1413
		ret = lbs_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
1414 1415
		break;

1416
	case CMD_802_11_AD_HOC_START:
1417
		ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
1418
		break;
1419
	case CMD_CODE_DNLD:
1420 1421
		break;

1422
	case CMD_802_11_RESET:
1423
		ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
1424 1425
		break;

1426
	case CMD_802_11_GET_LOG:
1427
		ret = lbs_cmd_802_11_get_log(priv, cmdptr);
1428 1429
		break;

1430
	case CMD_802_11_AUTHENTICATE:
1431
		ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
1432 1433
		break;

1434
	case CMD_802_11_GET_STAT:
1435
		ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
1436 1437
		break;

1438
	case CMD_802_11_SNMP_MIB:
1439
		ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
1440 1441 1442
					       cmd_action, cmd_oid, pdata_buf);
		break;

1443 1444 1445
	case CMD_MAC_REG_ACCESS:
	case CMD_BBP_REG_ACCESS:
	case CMD_RF_REG_ACCESS:
1446
		ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
1447 1448
		break;

1449
	case CMD_802_11_RF_TX_POWER:
1450
		ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
1451 1452 1453
						  cmd_action, pdata_buf);
		break;

1454
	case CMD_802_11_RADIO_CONTROL:
1455
		ret = lbs_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
1456 1457
		break;

1458
	case CMD_802_11_RATE_ADAPT_RATESET:
1459
		ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
1460 1461 1462
							 cmdptr, cmd_action);
		break;

1463
	case CMD_MAC_MULTICAST_ADR:
1464
		ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
1465 1466
		break;

1467
	case CMD_802_11_MONITOR_MODE:
1468
		ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
1469 1470 1471
				          cmd_action, pdata_buf);
		break;

1472
	case CMD_802_11_AD_HOC_JOIN:
1473
		ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
1474 1475
		break;

1476
	case CMD_802_11_RSSI:
1477
		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
1478 1479
		break;

1480
	case CMD_802_11_AD_HOC_STOP:
1481
		ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
1482 1483
		break;

1484
	case CMD_802_11_ENABLE_RSN:
1485
		ret = lbs_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
1486
				pdata_buf);
1487 1488
		break;

1489
	case CMD_802_11_KEY_MATERIAL:
1490
		ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
1491
				cmd_oid, pdata_buf);
1492 1493
		break;

1494
	case CMD_802_11_PAIRWISE_TSC:
1495
		break;
1496
	case CMD_802_11_GROUP_TSC:
1497 1498
		break;

1499
	case CMD_802_11_MAC_ADDRESS:
1500
		ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
1501 1502
		break;

1503
	case CMD_802_11_EEPROM_ACCESS:
1504
		ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
1505 1506 1507
						    cmd_action, pdata_buf);
		break;

1508 1509
	case CMD_802_11_SET_AFC:
	case CMD_802_11_GET_AFC:
1510 1511

		cmdptr->command = cpu_to_le16(cmd_no);
1512 1513
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
					   S_DS_GEN);
1514 1515 1516 1517 1518 1519 1520

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

		ret = 0;
		goto done;

1521
	case CMD_802_11D_DOMAIN_INFO:
1522
		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
1523 1524 1525
						   cmd_no, cmd_action);
		break;

1526
	case CMD_802_11_SLEEP_PARAMS:
1527
		ret = lbs_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
1528
		break;
1529
	case CMD_802_11_INACTIVITY_TIMEOUT:
1530
		ret = lbs_cmd_802_11_inactivity_timeout(priv, cmdptr,
1531
							 cmd_action, pdata_buf);
1532
		lbs_set_cmd_ctrl_node(priv, cmdnode, pdata_buf);
1533 1534
		break;

1535 1536
	case CMD_802_11_TPC_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1537 1538 1539 1540 1541 1542 1543 1544 1545
		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;
1546
	case CMD_802_11_LED_GPIO_CTRL:
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556
		{
			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 =
1557
			    cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
1558 1559 1560

#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
			cmdptr->size =
H
Holger Schurig 已提交
1561 1562 1563 1564
			    cpu_to_le16(le16_to_cpu(gpio->header.len)
				+ S_DS_GEN
				+ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
			gpio->header.len = gpio->header.len;
1565 1566 1567 1568

			ret = 0;
			break;
		}
1569 1570 1571 1572
	case CMD_802_11_SUBSCRIBE_EVENT:
		lbs_cmd_802_11_subscribe_event(priv, cmdptr,
			cmd_action, pdata_buf);
		break;
1573 1574
	case CMD_802_11_PWR_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
1575 1576 1577 1578 1579 1580 1581 1582
		cmdptr->size =
		    cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
				     S_DS_GEN);
		memmove(&cmdptr->params.pwrcfg, pdata_buf,
			sizeof(struct cmd_ds_802_11_pwr_cfg));

		ret = 0;
		break;
1583
	case CMD_BT_ACCESS:
1584
		ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
1585 1586
		break;

1587
	case CMD_FWT_ACCESS:
1588
		ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
1589 1590
		break;

1591 1592
	case CMD_GET_TSF:
		cmdptr->command = cpu_to_le16(CMD_GET_TSF);
1593 1594
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
					   S_DS_GEN);
1595 1596
		ret = 0;
		break;
1597 1598 1599
	case CMD_802_11_BEACON_CTRL:
		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
		break;
1600
	default:
1601
		lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
1602 1603 1604 1605 1606 1607
		ret = -1;
		break;
	}

	/* return error, since the command preparation failed */
	if (ret != 0) {
1608
		lbs_deb_host("PREP_CMD: command preparation failed\n");
1609
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1610 1611 1612 1613 1614 1615
		ret = -1;
		goto done;
	}

	cmdnode->cmdwaitqwoken = 0;

1616
	lbs_queue_cmd(priv, cmdnode, 1);
1617
	wake_up_interruptible(&priv->waitq);
1618

1619
	if (wait_option & CMD_OPTION_WAITFORRSP) {
1620
		lbs_deb_host("PREP_CMD: wait for response\n");
1621 1622 1623 1624 1625
		might_sleep();
		wait_event_interruptible(cmdnode->cmdwait_q,
					 cmdnode->cmdwaitqwoken);
	}

1626 1627
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd_retcode) {
1628
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
1629 1630
		       priv->cur_cmd_retcode);
		priv->cur_cmd_retcode = 0;
1631 1632
		ret = -1;
	}
1633
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1634 1635

done:
1636
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1637 1638
	return ret;
}
1639
EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
1640 1641 1642 1643 1644

/**
 *  @brief This function allocates the command buffer and link
 *  it to command free queue.
 *
1645
 *  @param priv		A pointer to struct lbs_private structure
1646 1647
 *  @return 		0 or -1
 */
1648
int lbs_allocate_cmd_buffer(struct lbs_private *priv)
1649 1650
{
	int ret = 0;
1651
	u32 bufsize;
1652
	u32 i;
1653
	struct cmd_ctrl_node *cmdarray;
1654

1655
	lbs_deb_enter(LBS_DEB_HOST);
1656

1657 1658 1659
	/* Allocate and initialize the command array */
	bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
	if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
1660
		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
1661 1662 1663
		ret = -1;
		goto done;
	}
1664
	priv->cmd_array = cmdarray;
1665

1666 1667 1668 1669
	/* 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) {
1670
			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
1671 1672 1673 1674 1675
			ret = -1;
			goto done;
		}
	}

1676 1677 1678
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		init_waitqueue_head(&cmdarray[i].cmdwait_q);
		lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
1679 1680
	}
	ret = 0;
1681 1682

done:
1683
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1684 1685 1686 1687 1688 1689
	return ret;
}

/**
 *  @brief This function frees the command buffer.
 *
1690
 *  @param priv		A pointer to struct lbs_private structure
1691 1692
 *  @return 		0 or -1
 */
1693
int lbs_free_cmd_buffer(struct lbs_private *priv)
1694
{
1695
	struct cmd_ctrl_node *cmdarray;
1696 1697
	unsigned int i;

1698
	lbs_deb_enter(LBS_DEB_HOST);
1699 1700

	/* need to check if cmd array is allocated or not */
1701
	if (priv->cmd_array == NULL) {
1702
		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
1703 1704 1705
		goto done;
	}

1706
	cmdarray = priv->cmd_array;
1707 1708

	/* Release shared memory buffers */
1709 1710 1711 1712
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		if (cmdarray[i].cmdbuf) {
			kfree(cmdarray[i].cmdbuf);
			cmdarray[i].cmdbuf = NULL;
1713 1714 1715 1716
		}
	}

	/* Release cmd_ctrl_node */
1717 1718 1719
	if (priv->cmd_array) {
		kfree(priv->cmd_array);
		priv->cmd_array = NULL;
1720 1721 1722
	}

done:
1723
	lbs_deb_leave(LBS_DEB_HOST);
1724 1725 1726 1727 1728 1729 1730
	return 0;
}

/**
 *  @brief This function gets a free command node if available in
 *  command free queue.
 *
1731
 *  @param priv		A pointer to struct lbs_private structure
1732 1733
 *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
 */
1734
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
1735 1736 1737 1738
{
	struct cmd_ctrl_node *tempnode;
	unsigned long flags;

1739 1740
	lbs_deb_enter(LBS_DEB_HOST);

1741
	if (!priv)
1742 1743
		return NULL;

1744
	spin_lock_irqsave(&priv->driver_lock, flags);
1745

1746 1747
	if (!list_empty(&priv->cmdfreeq)) {
		tempnode = list_first_entry(&priv->cmdfreeq,
1748 1749
					    struct cmd_ctrl_node, list);
		list_del(&tempnode->list);
1750
	} else {
1751
		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
1752 1753 1754
		tempnode = NULL;
	}

1755
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1756

1757
	if (tempnode)
1758 1759
		cleanup_cmdnode(tempnode);

1760
	lbs_deb_leave(LBS_DEB_HOST);
1761 1762 1763 1764 1765 1766 1767 1768 1769
	return tempnode;
}

/**
 *  @brief This function cleans command node.
 *
 *  @param ptempnode	A pointer to cmdCtrlNode structure
 *  @return 		n/a
 */
1770
static void cleanup_cmdnode(struct cmd_ctrl_node *cmdnode)
1771
{
1772 1773
	lbs_deb_enter(LBS_DEB_HOST);

1774
	if (!cmdnode)
1775
		return;
1776 1777 1778 1779 1780
	cmdnode->cmdwaitqwoken = 1;
	wake_up_interruptible(&cmdnode->cmdwait_q);
	cmdnode->pdata_buf = NULL;
	cmdnode->callback = NULL;
	cmdnode->callback_arg = 0;
1781

1782
	memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
1783 1784

	lbs_deb_leave(LBS_DEB_HOST);
1785 1786 1787 1788 1789
}

/**
 *  @brief This function initializes the command node.
 *
1790
 *  @param priv		A pointer to struct lbs_private structure
1791 1792 1793 1794
 *  @param ptempnode	A pointer to cmd_ctrl_node structure
 *  @param pdata_buf	A pointer to informaion buffer
 *  @return 		0 or -1
 */
1795 1796
static void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
				  struct cmd_ctrl_node *ptempnode,
1797
				  void *pdata_buf)
1798
{
1799
	lbs_deb_enter(LBS_DEB_HOST);
1800 1801 1802 1803 1804

	if (!ptempnode)
		return;

	ptempnode->pdata_buf = pdata_buf;
1805
	ptempnode->callback = NULL;
1806
	ptempnode->callback_arg = 0;
1807

1808
	lbs_deb_leave(LBS_DEB_HOST);
1809 1810 1811 1812 1813 1814 1815
}

/**
 *  @brief This function executes next command in command
 *  pending queue. It will put fimware back to PS mode
 *  if applicable.
 *
1816
 *  @param priv     A pointer to struct lbs_private structure
1817 1818
 *  @return 	   0 or -1
 */
1819
int lbs_execute_next_command(struct lbs_private *priv)
1820 1821
{
	struct cmd_ctrl_node *cmdnode = NULL;
1822
	struct cmd_header *cmd;
1823 1824 1825
	unsigned long flags;
	int ret = 0;

1826
	// Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
1827
	// only caller to us is lbs_thread() and we get even when a
1828 1829
	// data packet is received
	lbs_deb_enter(LBS_DEB_THREAD);
1830

1831
	spin_lock_irqsave(&priv->driver_lock, flags);
1832

1833
	if (priv->cur_cmd) {
1834
		lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
1835
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1836 1837 1838 1839
		ret = -1;
		goto done;
	}

1840 1841
	if (!list_empty(&priv->cmdpendingq)) {
		cmdnode = list_first_entry(&priv->cmdpendingq,
1842
					   struct cmd_ctrl_node, list);
1843 1844
	}

1845
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1846 1847

	if (cmdnode) {
1848
		cmd = cmdnode->cmdbuf;
1849

1850
		if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
1851 1852
			if ((priv->psstate == PS_STATE_SLEEP) ||
			    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1853 1854
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
1855
				       le16_to_cpu(cmd->command),
1856
				       priv->psstate);
1857 1858 1859
				ret = -1;
				goto done;
			}
1860
			lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
1861 1862
				     "0x%04x in psstate %d\n",
				     le16_to_cpu(cmd->command), priv->psstate);
1863
		} else if (priv->psstate != PS_STATE_FULL_POWER) {
1864 1865 1866
			/*
			 * 1. Non-PS command:
			 * Queue it. set needtowakeup to TRUE if current state
1867
			 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
1868 1869 1870 1871 1872 1873 1874
			 * 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.
			 */
1875
			if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
1876 1877
				/*  Prepare to send Exit PS,
				 *  this non PS command will be sent later */
1878 1879
				if ((priv->psstate == PS_STATE_SLEEP)
				    || (priv->psstate == PS_STATE_PRE_SLEEP)
1880 1881 1882
				    ) {
					/* w/ new scheme, it will not reach here.
					   since it is blocked in main_thread. */
1883
					priv->needtowakeup = 1;
1884
				} else
1885
					lbs_ps_wakeup(priv, 0);
1886 1887 1888 1889 1890 1891 1892 1893

				ret = 0;
				goto done;
			} else {
				/*
				 * PS command. Ignore it if it is not Exit_PS.
				 * otherwise send it down immediately.
				 */
1894
				struct cmd_ds_802_11_ps_mode *psm = (void *)cmd;
1895

1896 1897
				lbs_deb_host(
				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
1898 1899
				       psm->action);
				if (psm->action !=
1900
				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1901 1902
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
1903
					list_del(&cmdnode->list);
1904
					lbs_cleanup_and_insert_cmd(priv, cmdnode);
1905 1906 1907 1908 1909

					ret = 0;
					goto done;
				}

1910 1911
				if ((priv->psstate == PS_STATE_SLEEP) ||
				    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1912 1913
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
1914
					list_del(&cmdnode->list);
1915
					lbs_cleanup_and_insert_cmd(priv, cmdnode);
1916
					priv->needtowakeup = 1;
1917 1918 1919 1920 1921

					ret = 0;
					goto done;
				}

1922 1923
				lbs_deb_host(
				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
1924 1925
			}
		}
1926
		list_del(&cmdnode->list);
1927
		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
1928
			    le16_to_cpu(cmd->command));
1929
		lbs_submit_command(priv, cmdnode);
1930 1931 1932 1933 1934
	} else {
		/*
		 * check if in power save mode, if yes, put the device back
		 * to PS mode
		 */
1935 1936 1937 1938 1939 1940
		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) {
1941
				/* check for valid WPA group keys */
1942 1943
				if (priv->wpa_mcast_key.len ||
				    priv->wpa_unicast_key.len) {
1944
					lbs_deb_host(
1945 1946
					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
					       " go back to PS_SLEEP");
1947
					lbs_ps_sleep(priv, 0);
1948 1949
				}
			} else {
1950 1951 1952
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cmdpendingq empty, "
				       "go back to PS_SLEEP");
1953
				lbs_ps_sleep(priv, 0);
1954 1955 1956 1957 1958 1959
			}
		}
	}

	ret = 0;
done:
1960
	lbs_deb_leave(LBS_DEB_THREAD);
1961 1962 1963
	return ret;
}

1964
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
1965 1966 1967 1968
{
	union iwreq_data iwrq;
	u8 buf[50];

1969
	lbs_deb_enter(LBS_DEB_WEXT);
1970 1971 1972 1973 1974 1975 1976 1977 1978

	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 */
1979 1980 1981
	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);
1982

1983
	wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
1984

1985
	lbs_deb_leave(LBS_DEB_WEXT);
1986 1987
}

1988
static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
1989 1990 1991 1992
{
	unsigned long flags;
	int ret = 0;

1993
	lbs_deb_enter(LBS_DEB_HOST);
1994

1995
	lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
1996 1997
	       size);

1998
	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
1999

2000
	ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
2001
	priv->dnld_sent = DNLD_RES_RECEIVED;
2002

2003 2004
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->intcounter || priv->currenttxskb)
2005
		lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
2006 2007
		       priv->intcounter, priv->currenttxskb);
	spin_unlock_irqrestore(&priv->driver_lock, flags);
2008 2009 2010 2011 2012

	if (ret) {
		lbs_pr_alert(
		       "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
	} else {
2013 2014 2015
		spin_lock_irqsave(&priv->driver_lock, flags);
		if (!priv->intcounter) {
			priv->psstate = PS_STATE_SLEEP;
2016
		} else {
2017
			lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
2018
			       priv->intcounter);
2019
		}
2020
		spin_unlock_irqrestore(&priv->driver_lock, flags);
2021

2022
		lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
2023 2024
	}

2025
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
2026 2027 2028
	return ret;
}

2029
void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
2030
{
2031
	lbs_deb_enter(LBS_DEB_HOST);
2032 2033 2034 2035 2036 2037

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

2038
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
2039
			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
2040

2041
	lbs_deb_leave(LBS_DEB_HOST);
2042 2043 2044
}

/**
2045
 *  @brief This function sends Exit_PS command to firmware.
2046
 *
2047
 *  @param priv    	A pointer to struct lbs_private structure
2048 2049 2050
 *  @param wait_option	wait response or not
 *  @return 	   	n/a
 */
2051
void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
2052
{
2053
	__le32 Localpsmode;
2054

2055
	lbs_deb_enter(LBS_DEB_HOST);
2056

2057
	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
2058

2059
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
2060
			      CMD_SUBCMD_EXIT_PS,
2061 2062
			      wait_option, 0, &Localpsmode);

2063
	lbs_deb_leave(LBS_DEB_HOST);
2064 2065 2066 2067 2068 2069
}

/**
 *  @brief This function checks condition and prepares to
 *  send sleep confirm command to firmware if ok.
 *
2070
 *  @param priv    	A pointer to struct lbs_private structure
2071 2072 2073
 *  @param psmode  	Power Saving mode
 *  @return 	   	n/a
 */
2074
void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode)
2075 2076 2077 2078
{
	unsigned long flags =0;
	u8 allowed = 1;

2079
	lbs_deb_enter(LBS_DEB_HOST);
2080

2081
	if (priv->dnld_sent) {
2082
		allowed = 0;
2083
		lbs_deb_host("dnld_sent was set\n");
2084 2085
	}

2086 2087
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd) {
2088
		allowed = 0;
2089
		lbs_deb_host("cur_cmd was set\n");
2090
	}
2091
	if (priv->intcounter > 0) {
2092
		allowed = 0;
2093
		lbs_deb_host("intcounter %d\n", priv->intcounter);
2094
	}
2095
	spin_unlock_irqrestore(&priv->driver_lock, flags);
2096 2097

	if (allowed) {
2098
		lbs_deb_host("sending lbs_ps_confirm_sleep\n");
2099
		sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep,
2100 2101
				 sizeof(struct PS_CMD_ConfirmSleep));
	} else {
2102
		lbs_deb_host("sleep confirm has been delayed\n");
2103 2104
	}

2105
	lbs_deb_leave(LBS_DEB_HOST);
2106
}
2107 2108


2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119
/**
 *  @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,
2120
		     struct cmd_header *resp)
2121 2122 2123 2124 2125 2126 2127 2128
{
	struct cmd_header *buf = (void *)extra;
	uint16_t copy_len;

	lbs_deb_enter(LBS_DEB_CMD);

	copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
	lbs_deb_cmd("Copying back %u bytes; command response was %u bytes, "
2129 2130
		    "copy back buffer was %u bytes\n", copy_len,
		    le16_to_cpu(resp->size), le16_to_cpu(buf->size));
2131 2132 2133 2134 2135
	memcpy(buf, resp, copy_len);

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}
2136
EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
2137

2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153
/**
 *  @brief Simple way to call firmware functions
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param psmode  	one of the many CMD_802_11_xxxx
 *  @param cmd          pointer to the parameters structure for above command
 *                      (this should not include the command, size, sequence
 *                      and result fields from struct cmd_ds_gen)
 *  @param cmd_size     size structure pointed to by cmd
 *  @param rsp          pointer to an area where the result should be placed
 *  @param rsp_size     pointer to the size of the rsp area. If the firmware
 *                      returns fewer bytes, then this *rsp_size will be
 *                      changed to the actual size.
 *  @return 	   	-1 in case of a higher level error, otherwise
 *                      the result code from the firmware
 */
2154 2155 2156
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 *),
2157
	      unsigned long callback_arg)
2158 2159 2160 2161 2162 2163 2164
{
	struct cmd_ctrl_node *cmdnode;
	unsigned long flags;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_HOST);

2165 2166
	if (!priv) {
		lbs_deb_host("PREP_CMD: priv is NULL\n");
2167 2168 2169 2170
		ret = -1;
		goto done;
	}

2171
	if (priv->surpriseremoved) {
2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186
		lbs_deb_host("PREP_CMD: card removed\n");
		ret = -1;
		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);
		ret = -1;
		goto done;
	}

2187
	cmdnode->callback = callback;
2188
	cmdnode->callback_arg = callback_arg;
2189

2190
	/* Copy the incoming command to the buffer */
2191
	memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
2192

2193
	/* Set sequence number, clean result, move to buffer */
2194
	priv->seqnum++;
2195 2196 2197 2198
	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;
2199 2200 2201 2202 2203 2204 2205

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

	/* here was the big old switch() statement, which is now obsolete,
	 * because the caller of lbs_cmd() sets up all of *cmd for us. */

	cmdnode->cmdwaitqwoken = 0;
2206
	lbs_queue_cmd(priv, cmdnode, 1);
2207 2208 2209 2210 2211
	wake_up_interruptible(&priv->waitq);

	might_sleep();
	wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);

2212 2213
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd_retcode) {
2214
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
2215 2216
		       priv->cur_cmd_retcode);
		priv->cur_cmd_retcode = 0;
2217 2218
		ret = -1;
	}
2219
	spin_unlock_irqrestore(&priv->driver_lock, flags);
2220 2221 2222 2223 2224

done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
	return ret;
}
2225
EXPORT_SYMBOL_GPL(__lbs_cmd);
2226 2227