cmd.c 56.6 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 17
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,
18
		    struct cmd_ctrl_node *ptempnode,
19
		    void *pdata_buf);
20

21 22

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

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

53
	lbs_deb_enter(LBS_DEB_CMD);
54

55 56 57
	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
58
	ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
59 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
	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);
93

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

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

118
	cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
119
	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
	cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
1105
	cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
1106
	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
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1126

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

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

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

1158 1159
static void lbs_queue_cmd(struct lbs_private *priv,
			  struct cmd_ctrl_node *cmdnode)
1160 1161
{
	unsigned long flags;
1162
	int addtail = 1;
1163

1164
	lbs_deb_enter(LBS_DEB_HOST);
1165

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

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

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

1186
	spin_lock_irqsave(&priv->driver_lock, flags);
1187

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

1193
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1194

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

done:
1199
	lbs_deb_leave(LBS_DEB_HOST);
1200 1201
}

1202 1203
static void lbs_submit_command(struct lbs_private *priv,
			       struct cmd_ctrl_node *cmdnode)
1204 1205
{
	unsigned long flags;
1206
	struct cmd_header *cmd;
1207 1208 1209 1210
	uint16_t cmdsize;
	uint16_t command;
	int timeo = 5 * HZ;
	int ret;
1211

1212
	lbs_deb_enter(LBS_DEB_HOST);
1213

1214
	cmd = cmdnode->cmdbuf;
1215

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

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

1224 1225 1226 1227 1228
	/* These commands take longer */
	if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
	    command == CMD_802_11_AUTHENTICATE)
		timeo = 10 * HZ;

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

1233
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
1234

1235 1236
	if (ret) {
		lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
1237 1238 1239 1240 1241 1242
		/* Let the timer kick in and retry, and potentially reset
		   the whole thing if the condition persists */
		timeo = HZ;
	} else
		lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n",
			    command, jiffies);
1243 1244

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

1247
	lbs_deb_leave(LBS_DEB_HOST);
1248 1249
}

1250
static int lbs_cmd_mac_control(struct lbs_private *priv,
1251 1252 1253 1254
				struct cmd_ds_command *cmd)
{
	struct cmd_ds_mac_control *mac = &cmd->params.macctrl;

1255
	lbs_deb_enter(LBS_DEB_CMD);
1256

1257
	cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
1258
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
1259
	mac->action = cpu_to_le16(priv->currentpacketfilter);
1260

1261
	lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
1262
		    le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
1263

1264
	lbs_deb_leave(LBS_DEB_CMD);
1265 1266 1267 1268 1269
	return 0;
}

/**
 *  This function inserts command node to cmdfreeq
1270
 *  after cleans it. Requires priv->driver_lock held.
1271
 */
1272
static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1273
					 struct cmd_ctrl_node *cmdnode)
1274
{
1275 1276 1277 1278 1279 1280 1281
	lbs_deb_enter(LBS_DEB_HOST);

	if (!cmdnode)
		goto out;

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

1283
	memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
1284

1285 1286 1287
	list_add_tail(&cmdnode->list, &priv->cmdfreeq);
 out:
	lbs_deb_leave(LBS_DEB_HOST);
1288 1289
}

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

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

1300 1301 1302 1303 1304
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;
1305

1306
	cmd->result = result;
1307 1308 1309
	cmd->cmdwaitqwoken = 1;
	wake_up_interruptible(&cmd->cmdwait_q);

1310 1311
	if (!cmd->callback)
		__lbs_cleanup_and_insert_cmd(priv, cmd);
1312 1313 1314
	priv->cur_cmd = NULL;
}

1315
int lbs_set_radio_control(struct lbs_private *priv)
1316 1317 1318
{
	int ret = 0;

1319
	lbs_deb_enter(LBS_DEB_CMD);
1320

1321
	ret = lbs_prepare_and_send_command(priv,
1322 1323 1324
				    CMD_802_11_RADIO_CONTROL,
				    CMD_ACT_SET,
				    CMD_OPTION_WAITFORRSP, 0, NULL);
1325

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

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

1333
int lbs_set_mac_packet_filter(struct lbs_private *priv)
1334 1335 1336
{
	int ret = 0;

1337
	lbs_deb_enter(LBS_DEB_CMD);
1338 1339

	/* Send MAC control command to station */
1340
	ret = lbs_prepare_and_send_command(priv,
1341
				    CMD_MAC_CONTROL, 0, 0, 0, NULL);
1342

1343
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1344 1345 1346 1347 1348 1349
	return ret;
}

/**
 *  @brief This function prepare the command before send to firmware.
 *
1350
 *  @param priv		A pointer to struct lbs_private structure
1351 1352 1353 1354 1355 1356 1357
 *  @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
 */
1358
int lbs_prepare_and_send_command(struct lbs_private *priv,
1359 1360 1361 1362 1363 1364 1365 1366 1367
			  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;

1368
	lbs_deb_enter(LBS_DEB_HOST);
1369

1370 1371
	if (!priv) {
		lbs_deb_host("PREP_CMD: priv is NULL\n");
1372 1373 1374 1375
		ret = -1;
		goto done;
	}

1376
	if (priv->surpriseremoved) {
1377
		lbs_deb_host("PREP_CMD: card removed\n");
1378 1379 1380 1381
		ret = -1;
		goto done;
	}

1382
	cmdnode = lbs_get_cmd_ctrl_node(priv);
1383 1384

	if (cmdnode == NULL) {
1385
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1386 1387

		/* Wake up main thread to execute next command */
1388
		wake_up_interruptible(&priv->waitq);
1389 1390 1391 1392
		ret = -1;
		goto done;
	}

1393
	lbs_set_cmd_ctrl_node(priv, cmdnode, pdata_buf);
1394

1395
	cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
1396

1397
	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
1398 1399

	/* Set sequence number, command and INT option */
1400 1401
	priv->seqnum++;
	cmdptr->seqnum = cpu_to_le16(priv->seqnum);
1402

1403
	cmdptr->command = cpu_to_le16(cmd_no);
1404 1405 1406
	cmdptr->result = 0;

	switch (cmd_no) {
1407
	case CMD_802_11_PS_MODE:
1408
		ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
1409 1410
		break;

1411
	case CMD_802_11_SCAN:
1412
		ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
1413 1414
		break;

1415
	case CMD_MAC_CONTROL:
1416
		ret = lbs_cmd_mac_control(priv, cmdptr);
1417 1418
		break;

1419 1420
	case CMD_802_11_ASSOCIATE:
	case CMD_802_11_REASSOCIATE:
1421
		ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
1422 1423
		break;

1424
	case CMD_802_11_DEAUTHENTICATE:
1425
		ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
1426 1427
		break;

1428
	case CMD_802_11_SET_WEP:
1429
		ret = lbs_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
1430 1431
		break;

1432
	case CMD_802_11_AD_HOC_START:
1433
		ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
1434
		break;
1435
	case CMD_CODE_DNLD:
1436 1437
		break;

1438
	case CMD_802_11_RESET:
1439
		ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
1440 1441
		break;

1442
	case CMD_802_11_GET_LOG:
1443
		ret = lbs_cmd_802_11_get_log(priv, cmdptr);
1444 1445
		break;

1446
	case CMD_802_11_AUTHENTICATE:
1447
		ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
1448 1449
		break;

1450
	case CMD_802_11_GET_STAT:
1451
		ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
1452 1453
		break;

1454
	case CMD_802_11_SNMP_MIB:
1455
		ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
1456 1457 1458
					       cmd_action, cmd_oid, pdata_buf);
		break;

1459 1460 1461
	case CMD_MAC_REG_ACCESS:
	case CMD_BBP_REG_ACCESS:
	case CMD_RF_REG_ACCESS:
1462
		ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
1463 1464
		break;

1465
	case CMD_802_11_RF_TX_POWER:
1466
		ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
1467 1468 1469
						  cmd_action, pdata_buf);
		break;

1470
	case CMD_802_11_RADIO_CONTROL:
1471
		ret = lbs_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
1472 1473
		break;

1474
	case CMD_802_11_RATE_ADAPT_RATESET:
1475
		ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
1476 1477 1478
							 cmdptr, cmd_action);
		break;

1479
	case CMD_MAC_MULTICAST_ADR:
1480
		ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
1481 1482
		break;

1483
	case CMD_802_11_MONITOR_MODE:
1484
		ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
1485 1486 1487
				          cmd_action, pdata_buf);
		break;

1488
	case CMD_802_11_AD_HOC_JOIN:
1489
		ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
1490 1491
		break;

1492
	case CMD_802_11_RSSI:
1493
		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
1494 1495
		break;

1496
	case CMD_802_11_AD_HOC_STOP:
1497
		ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
1498 1499
		break;

1500
	case CMD_802_11_ENABLE_RSN:
1501
		ret = lbs_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
1502
				pdata_buf);
1503 1504
		break;

1505
	case CMD_802_11_KEY_MATERIAL:
1506
		ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
1507
				cmd_oid, pdata_buf);
1508 1509
		break;

1510
	case CMD_802_11_PAIRWISE_TSC:
1511
		break;
1512
	case CMD_802_11_GROUP_TSC:
1513 1514
		break;

1515
	case CMD_802_11_MAC_ADDRESS:
1516
		ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
1517 1518
		break;

1519
	case CMD_802_11_EEPROM_ACCESS:
1520
		ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
1521 1522 1523
						    cmd_action, pdata_buf);
		break;

1524 1525
	case CMD_802_11_SET_AFC:
	case CMD_802_11_GET_AFC:
1526 1527

		cmdptr->command = cpu_to_le16(cmd_no);
1528 1529
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
					   S_DS_GEN);
1530 1531 1532 1533 1534 1535 1536

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

		ret = 0;
		goto done;

1537
	case CMD_802_11D_DOMAIN_INFO:
1538
		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
1539 1540 1541
						   cmd_no, cmd_action);
		break;

1542
	case CMD_802_11_SLEEP_PARAMS:
1543
		ret = lbs_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
1544
		break;
1545
	case CMD_802_11_INACTIVITY_TIMEOUT:
1546
		ret = lbs_cmd_802_11_inactivity_timeout(priv, cmdptr,
1547
							 cmd_action, pdata_buf);
1548
		lbs_set_cmd_ctrl_node(priv, cmdnode, pdata_buf);
1549 1550
		break;

1551 1552
	case CMD_802_11_TPC_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1553 1554 1555 1556 1557 1558 1559 1560 1561
		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;
1562
	case CMD_802_11_LED_GPIO_CTRL:
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572
		{
			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 =
1573
			    cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
1574 1575 1576

#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
			cmdptr->size =
H
Holger Schurig 已提交
1577 1578 1579 1580
			    cpu_to_le16(le16_to_cpu(gpio->header.len)
				+ S_DS_GEN
				+ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
			gpio->header.len = gpio->header.len;
1581 1582 1583 1584

			ret = 0;
			break;
		}
1585 1586 1587 1588
	case CMD_802_11_SUBSCRIBE_EVENT:
		lbs_cmd_802_11_subscribe_event(priv, cmdptr,
			cmd_action, pdata_buf);
		break;
1589 1590
	case CMD_802_11_PWR_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
1591 1592 1593 1594 1595 1596 1597 1598
		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;
1599
	case CMD_BT_ACCESS:
1600
		ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
1601 1602
		break;

1603
	case CMD_FWT_ACCESS:
1604
		ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
1605 1606
		break;

1607 1608
	case CMD_GET_TSF:
		cmdptr->command = cpu_to_le16(CMD_GET_TSF);
1609 1610
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
					   S_DS_GEN);
1611 1612
		ret = 0;
		break;
1613 1614 1615
	case CMD_802_11_BEACON_CTRL:
		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
		break;
1616
	default:
1617
		lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
1618 1619 1620 1621 1622 1623
		ret = -1;
		break;
	}

	/* return error, since the command preparation failed */
	if (ret != 0) {
1624
		lbs_deb_host("PREP_CMD: command preparation failed\n");
1625
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1626 1627 1628 1629 1630 1631
		ret = -1;
		goto done;
	}

	cmdnode->cmdwaitqwoken = 0;

1632
	lbs_queue_cmd(priv, cmdnode);
1633
	wake_up_interruptible(&priv->waitq);
1634

1635
	if (wait_option & CMD_OPTION_WAITFORRSP) {
1636
		lbs_deb_host("PREP_CMD: wait for response\n");
1637 1638 1639 1640 1641
		might_sleep();
		wait_event_interruptible(cmdnode->cmdwait_q,
					 cmdnode->cmdwaitqwoken);
	}

1642 1643
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd_retcode) {
1644
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
1645 1646
		       priv->cur_cmd_retcode);
		priv->cur_cmd_retcode = 0;
1647 1648
		ret = -1;
	}
1649
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1650 1651

done:
1652
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1653 1654
	return ret;
}
1655
EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
1656 1657 1658 1659 1660

/**
 *  @brief This function allocates the command buffer and link
 *  it to command free queue.
 *
1661
 *  @param priv		A pointer to struct lbs_private structure
1662 1663
 *  @return 		0 or -1
 */
1664
int lbs_allocate_cmd_buffer(struct lbs_private *priv)
1665 1666
{
	int ret = 0;
1667
	u32 bufsize;
1668
	u32 i;
1669
	struct cmd_ctrl_node *cmdarray;
1670

1671
	lbs_deb_enter(LBS_DEB_HOST);
1672

1673 1674 1675
	/* Allocate and initialize the command array */
	bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
	if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
1676
		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
1677 1678 1679
		ret = -1;
		goto done;
	}
1680
	priv->cmd_array = cmdarray;
1681

1682 1683 1684 1685
	/* 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) {
1686
			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
1687 1688 1689 1690 1691
			ret = -1;
			goto done;
		}
	}

1692 1693 1694
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		init_waitqueue_head(&cmdarray[i].cmdwait_q);
		lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
1695 1696
	}
	ret = 0;
1697 1698

done:
1699
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1700 1701 1702 1703 1704 1705
	return ret;
}

/**
 *  @brief This function frees the command buffer.
 *
1706
 *  @param priv		A pointer to struct lbs_private structure
1707 1708
 *  @return 		0 or -1
 */
1709
int lbs_free_cmd_buffer(struct lbs_private *priv)
1710
{
1711
	struct cmd_ctrl_node *cmdarray;
1712 1713
	unsigned int i;

1714
	lbs_deb_enter(LBS_DEB_HOST);
1715 1716

	/* need to check if cmd array is allocated or not */
1717
	if (priv->cmd_array == NULL) {
1718
		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
1719 1720 1721
		goto done;
	}

1722
	cmdarray = priv->cmd_array;
1723 1724

	/* Release shared memory buffers */
1725 1726 1727 1728
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		if (cmdarray[i].cmdbuf) {
			kfree(cmdarray[i].cmdbuf);
			cmdarray[i].cmdbuf = NULL;
1729 1730 1731 1732
		}
	}

	/* Release cmd_ctrl_node */
1733 1734 1735
	if (priv->cmd_array) {
		kfree(priv->cmd_array);
		priv->cmd_array = NULL;
1736 1737 1738
	}

done:
1739
	lbs_deb_leave(LBS_DEB_HOST);
1740 1741 1742 1743 1744 1745 1746
	return 0;
}

/**
 *  @brief This function gets a free command node if available in
 *  command free queue.
 *
1747
 *  @param priv		A pointer to struct lbs_private structure
1748 1749
 *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
 */
1750
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
1751 1752 1753 1754
{
	struct cmd_ctrl_node *tempnode;
	unsigned long flags;

1755 1756
	lbs_deb_enter(LBS_DEB_HOST);

1757
	if (!priv)
1758 1759
		return NULL;

1760
	spin_lock_irqsave(&priv->driver_lock, flags);
1761

1762 1763
	if (!list_empty(&priv->cmdfreeq)) {
		tempnode = list_first_entry(&priv->cmdfreeq,
1764 1765
					    struct cmd_ctrl_node, list);
		list_del(&tempnode->list);
1766
	} else {
1767
		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
1768 1769 1770
		tempnode = NULL;
	}

1771
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1772

1773
	lbs_deb_leave(LBS_DEB_HOST);
1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786
	return tempnode;
}

/**
 *  @brief This function cleans command node.
 *
 *  @param ptempnode	A pointer to cmdCtrlNode structure
 *  @return 		n/a
 */

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

	if (!ptempnode)
		return;

1801
	ptempnode->callback = NULL;
1802
	ptempnode->callback_arg = (unsigned long)pdata_buf;
1803

1804
	lbs_deb_leave(LBS_DEB_HOST);
1805 1806 1807 1808 1809 1810 1811
}

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

1822
	// Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
1823
	// only caller to us is lbs_thread() and we get even when a
1824 1825
	// data packet is received
	lbs_deb_enter(LBS_DEB_THREAD);
1826

1827
	spin_lock_irqsave(&priv->driver_lock, flags);
1828

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

1836 1837
	if (!list_empty(&priv->cmdpendingq)) {
		cmdnode = list_first_entry(&priv->cmdpendingq,
1838
					   struct cmd_ctrl_node, list);
1839 1840
	}

1841
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1842 1843

	if (cmdnode) {
1844
		cmd = cmdnode->cmdbuf;
1845

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

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

1892 1893
				lbs_deb_host(
				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
1894 1895
				       psm->action);
				if (psm->action !=
1896
				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1897 1898
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
1899
					list_del(&cmdnode->list);
1900 1901 1902
					spin_lock_irqsave(&priv->driver_lock, flags);
					lbs_complete_command(priv, cmdnode, 0);
					spin_unlock_irqrestore(&priv->driver_lock, flags);
1903 1904 1905 1906 1907

					ret = 0;
					goto done;
				}

1908 1909
				if ((priv->psstate == PS_STATE_SLEEP) ||
				    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1910 1911
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
1912
					list_del(&cmdnode->list);
1913 1914 1915
					spin_lock_irqsave(&priv->driver_lock, flags);
					lbs_complete_command(priv, cmdnode, 0);
					spin_unlock_irqrestore(&priv->driver_lock, flags);
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

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

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

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

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

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

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

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

2040
	lbs_deb_leave(LBS_DEB_HOST);
2041 2042 2043
}

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

2054
	lbs_deb_enter(LBS_DEB_HOST);
2055

2056
	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
2057

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

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

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

2078
	lbs_deb_enter(LBS_DEB_HOST);
2079

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

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

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

2104
	lbs_deb_leave(LBS_DEB_HOST);
2105
}
2106 2107


2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118
/**
 *  @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,
2119
		     struct cmd_header *resp)
2120 2121 2122 2123 2124 2125 2126 2127
{
	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, "
2128 2129
		    "copy back buffer was %u bytes\n", copy_len,
		    le16_to_cpu(resp->size), le16_to_cpu(buf->size));
2130 2131 2132 2133 2134
	memcpy(buf, resp, copy_len);

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

2137 2138 2139 2140
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)
2141 2142 2143 2144 2145
{
	struct cmd_ctrl_node *cmdnode;

	lbs_deb_enter(LBS_DEB_HOST);

2146
	if (priv->surpriseremoved) {
2147
		lbs_deb_host("PREP_CMD: card removed\n");
2148
		cmdnode = ERR_PTR(-ENOENT);
2149 2150 2151 2152 2153 2154 2155 2156 2157
		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);
2158
		cmdnode = ERR_PTR(-ENOBUFS);
2159 2160 2161
		goto done;
	}

2162
	cmdnode->callback = callback;
2163
	cmdnode->callback_arg = callback_arg;
2164

2165
	/* Copy the incoming command to the buffer */
2166
	memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
2167

2168
	/* Set sequence number, clean result, move to buffer */
2169
	priv->seqnum++;
2170 2171 2172 2173
	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;
2174 2175 2176 2177 2178 2179 2180

	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;
2181
	lbs_queue_cmd(priv, cmdnode);
2182 2183
	wake_up_interruptible(&priv->waitq);

2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206
 done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
	return cmdnode;
}

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;
	}

2207 2208 2209
	might_sleep();
	wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);

2210
	spin_lock_irqsave(&priv->driver_lock, flags);
2211 2212 2213 2214
	ret = cmdnode->result;
	if (ret)
		lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
			    command, ret);
2215

2216
	__lbs_cleanup_and_insert_cmd(priv, cmdnode);
2217
	spin_unlock_irqrestore(&priv->driver_lock, flags);
2218 2219 2220 2221 2222

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