cmd.c 54.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 19 20 21
struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
		    struct cmd_ctrl_node *ptempnode,
		    u16 wait_option, void *pdata_buf);

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 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 93
	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
	ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, cmd);
	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
static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv,
115 116 117 118 119
				   struct cmd_ds_command *cmd,
				   u16 cmd_action)
{
	struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;

120
	lbs_deb_enter(LBS_DEB_CMD);
121

122
	cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
123 124
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
				S_DS_GEN);
125 126
	psm->action = cpu_to_le16(cmd_action);
	psm->multipledtim = 0;
127
	switch (cmd_action) {
128
	case CMD_SUBCMD_ENTER_PS:
129
		lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
130

131
		psm->locallisteninterval = 0;
132
		psm->nullpktinterval = 0;
133
		psm->multipledtim =
134
		    cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
135 136
		break;

137
	case CMD_SUBCMD_EXIT_PS:
138
		lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
139 140
		break;

141
	case CMD_SUBCMD_SLEEP_CONFIRMED:
142
		lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
143 144 145 146 147 148
		break;

	default:
		break;
	}

149
	lbs_deb_leave(LBS_DEB_CMD);
150 151 152
	return 0;
}

153
static int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
154 155 156 157 158
					      struct cmd_ds_command *cmd,
					      u16 cmd_action, void *pdata_buf)
{
	u16 *timeout = pdata_buf;

159 160
	lbs_deb_enter(LBS_DEB_CMD);

161
	cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
162 163 164 165 166 167 168
	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)
169
		cmd->params.inactivity_timeout.timeout = cpu_to_le16(*timeout);
170 171 172
	else
		cmd->params.inactivity_timeout.timeout = 0;

173
	lbs_deb_leave(LBS_DEB_CMD);
174 175 176
	return 0;
}

177
static int lbs_cmd_802_11_sleep_params(struct lbs_private *priv,
178 179 180 181 182
					struct cmd_ds_command *cmd,
					u16 cmd_action)
{
	struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;

183
	lbs_deb_enter(LBS_DEB_CMD);
184

185 186
	cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
				S_DS_GEN);
187
	cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS);
188

189
	if (cmd_action == CMD_ACT_GET) {
190
		memset(&priv->sp, 0, sizeof(struct sleep_params));
191 192
		memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
		sp->action = cpu_to_le16(cmd_action);
193
	} else if (cmd_action == CMD_ACT_SET) {
194
		sp->action = cpu_to_le16(cmd_action);
195 196 197 198 199 200
		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);
201 202
	}

203
	lbs_deb_leave(LBS_DEB_CMD);
204 205 206
	return 0;
}

207
static int lbs_cmd_802_11_set_wep(struct lbs_private *priv,
208 209 210 211 212 213 214 215
                                   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;

216
	lbs_deb_enter(LBS_DEB_CMD);
217

218
	cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
219
	cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
220

221
	if (cmd_act == CMD_ACT_ADD) {
222 223 224
		int i;

		if (!assoc_req) {
225
			lbs_deb_cmd("Invalid association request!");
226 227 228 229
			ret = -1;
			goto done;
		}

230
		wep->action = cpu_to_le16(CMD_ACT_ADD);
231 232

		/* default tx key index */
233
		wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
234
						  (u32)CMD_WEP_KEY_INDEX_MASK));
235 236 237

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

			switch (pkey->len) {
			case KEY_LEN_WEP_40:
H
Holger Schurig 已提交
242
				wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
243 244
				memmove(&wep->keymaterial[i], pkey->key,
				        pkey->len);
245
				lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
246 247
				break;
			case KEY_LEN_WEP_104:
H
Holger Schurig 已提交
248
				wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
249 250
				memmove(&wep->keymaterial[i], pkey->key,
				        pkey->len);
251
				lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
252 253 254 255
				break;
			case 0:
				break;
			default:
256
				lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
257 258 259 260 261 262
				       i, pkey->len);
				ret = -1;
				goto done;
				break;
			}
		}
263
	} else if (cmd_act == CMD_ACT_REMOVE) {
264
		/* ACT_REMOVE clears _all_ WEP keys */
265
		wep->action = cpu_to_le16(CMD_ACT_REMOVE);
266 267

		/* default tx key index */
268
		wep->keyindex = cpu_to_le16((u16)(priv->wep_tx_keyidx &
269
						  (u32)CMD_WEP_KEY_INDEX_MASK));
270
		lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
271 272 273 274 275
	}

	ret = 0;

done:
276
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
277 278 279
	return ret;
}

280
static int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv,
281
				      struct cmd_ds_command *cmd,
282 283
				      u16 cmd_action,
				      void * pdata_buf)
284 285
{
	struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
286
	u32 * enable = pdata_buf;
287 288

	lbs_deb_enter(LBS_DEB_CMD);
289

290
	cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
291
	cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
292
	penableRSN->action = cpu_to_le16(cmd_action);
293

294
	if (cmd_action == CMD_ACT_SET) {
295
		if (*enable)
296
			penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
297
		else
298
			penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
299
		lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
300 301
	}

302
	lbs_deb_leave(LBS_DEB_CMD);
303 304 305 306
	return 0;
}


307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 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
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);
}

353
static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
354
                            struct enc_key * pkey)
355
{
356 357
	lbs_deb_enter(LBS_DEB_CMD);

358
	if (pkey->flags & KEY_INFO_WPA_ENABLED) {
359
		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
360 361 362
	}
	if (pkey->flags & KEY_INFO_WPA_UNICAST) {
		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
363 364
	}
	if (pkey->flags & KEY_INFO_WPA_MCAST) {
365 366 367 368
		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
	}

	pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
369
	pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
370 371 372 373 374 375
	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));
376
	lbs_deb_leave(LBS_DEB_CMD);
377 378
}

379
static int lbs_cmd_802_11_key_material(struct lbs_private *priv,
380 381 382 383 384 385
					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;
386
	struct assoc_request * assoc_req = pdata_buf;
387 388 389
	int ret = 0;
	int index = 0;

390
	lbs_deb_enter(LBS_DEB_CMD);
391

392
	cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
393 394
	pkeymaterial->action = cpu_to_le16(cmd_action);

395
	if (cmd_action == CMD_ACT_GET) {
396
		cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
397 398 399 400 401 402
		ret = 0;
		goto done;
	}

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

403
	if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
404
		set_one_wpa_key(&pkeymaterial->keyParamSet[index],
405
		                &assoc_req->wpa_unicast_key);
406 407 408
		index++;
	}

409
	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
410
		set_one_wpa_key(&pkeymaterial->keyParamSet[index],
411
		                &assoc_req->wpa_mcast_key);
412 413 414 415
		index++;
	}

	cmd->size = cpu_to_le16(  S_DS_GEN
416 417
	                        + sizeof (pkeymaterial->action)
	                        + (index * sizeof(struct MrvlIEtype_keyParamSet)));
418 419 420 421

	ret = 0;

done:
422
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
423 424 425
	return ret;
}

426
static int lbs_cmd_802_11_reset(struct lbs_private *priv,
427 428 429 430
				 struct cmd_ds_command *cmd, int cmd_action)
{
	struct cmd_ds_802_11_reset *reset = &cmd->params.reset;

431 432
	lbs_deb_enter(LBS_DEB_CMD);

433
	cmd->command = cpu_to_le16(CMD_802_11_RESET);
434 435 436
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
	reset->action = cpu_to_le16(cmd_action);

437
	lbs_deb_leave(LBS_DEB_CMD);
438 439 440
	return 0;
}

441
static int lbs_cmd_802_11_get_log(struct lbs_private *priv,
442 443
				   struct cmd_ds_command *cmd)
{
444
	lbs_deb_enter(LBS_DEB_CMD);
445
	cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
446 447 448
	cmd->size =
		cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);

449
	lbs_deb_leave(LBS_DEB_CMD);
450 451 452
	return 0;
}

453
static int lbs_cmd_802_11_get_stat(struct lbs_private *priv,
454 455
				    struct cmd_ds_command *cmd)
{
456
	lbs_deb_enter(LBS_DEB_CMD);
457
	cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
458
	cmd->size =
459
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
460

461
	lbs_deb_leave(LBS_DEB_CMD);
462 463 464
	return 0;
}

465
static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
466 467 468 469 470 471 472
				    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;

473
	lbs_deb_enter(LBS_DEB_CMD);
474

475
	lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
476

477
	cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
478
	cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
479 480 481 482

	switch (cmd_oid) {
	case OID_802_11_INFRASTRUCTURE_MODE:
	{
483
		u8 mode = (u8) (size_t) pdata_buf;
484 485
		pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
		pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
H
Holger Schurig 已提交
486
		pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8));
487
		if (mode == IW_MODE_ADHOC) {
488
			ucTemp = SNMP_MIB_VALUE_ADHOC;
489 490 491 492
		} else {
			/* Infra and Auto modes */
			ucTemp = SNMP_MIB_VALUE_INFRA;
		}
493 494 495 496 497 498 499 500 501 502

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

		break;
	}

	case OID_802_11D_ENABLE:
		{
			u32 ulTemp;

503
			pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
504

505
			if (cmd_action == CMD_ACT_SET) {
H
Holger Schurig 已提交
506 507
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
508
				ulTemp = *(u32 *)pdata_buf;
509
				*((__le16 *)(pSNMPMIB->value)) =
510 511 512 513 514 515 516 517 518
				    cpu_to_le16((u16) ulTemp);
			}
			break;
		}

	case OID_802_11_FRAGMENTATION_THRESHOLD:
		{
			u32 ulTemp;

519
			pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
520

521 522 523 524
			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);
525
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
526
				ulTemp = *((u32 *) pdata_buf);
527
				*((__le16 *)(pSNMPMIB->value)) =
528 529 530 531 532 533 534 535 536 537 538
				    cpu_to_le16((u16) ulTemp);

			}

			break;
		}

	case OID_802_11_RTS_THRESHOLD:
		{

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

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

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

556 557 558 559
		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);
560
			pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
561
			*((__le16 *)(pSNMPMIB->value)) =
562
			    cpu_to_le16((u16) priv->txretrycount);
563 564 565 566 567 568 569
		}

		break;
	default:
		break;
	}

570
	lbs_deb_cmd(
571
	       "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
572 573
	       le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
	       le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
574

575
	lbs_deb_cmd(
576
	       "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
577 578 579
	       le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
	       le16_to_cpu(pSNMPMIB->bufsize),
	       le16_to_cpu(*(__le16 *) pSNMPMIB->value));
580

581
	lbs_deb_leave(LBS_DEB_CMD);
582 583 584
	return 0;
}

585
static int lbs_cmd_802_11_radio_control(struct lbs_private *priv,
586 587 588
					 struct cmd_ds_command *cmd,
					 int cmd_action)
{
589
	struct cmd_ds_802_11_radio_control *pradiocontrol = &cmd->params.radio;
590

591
	lbs_deb_enter(LBS_DEB_CMD);
592 593 594 595

	cmd->size =
	    cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
			     S_DS_GEN);
596
	cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL);
597 598 599

	pradiocontrol->action = cpu_to_le16(cmd_action);

600
	switch (priv->preamble) {
601
	case CMD_TYPE_SHORT_PREAMBLE:
602 603 604
		pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
		break;

605
	case CMD_TYPE_LONG_PREAMBLE:
606 607 608
		pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
		break;

609
	case CMD_TYPE_AUTO_PREAMBLE:
610 611 612 613 614
	default:
		pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
		break;
	}

615
	if (priv->radioon)
616 617 618 619
		pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
	else
		pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);

620
	lbs_deb_leave(LBS_DEB_CMD);
621 622 623
	return 0;
}

624
static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv,
625 626 627 628 629 630
				       struct cmd_ds_command *cmd,
				       u16 cmd_action, void *pdata_buf)
{

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

631
	lbs_deb_enter(LBS_DEB_CMD);
632 633

	cmd->size =
634
	    cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
635
	cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
636
	prtp->action = cpu_to_le16(cmd_action);
637

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

	switch (cmd_action) {
643 644
	case CMD_ACT_TX_POWER_OPT_GET:
		prtp->action = cpu_to_le16(CMD_ACT_GET);
645 646 647
		prtp->currentlevel = 0;
		break;

648 649 650
	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);
651 652
		break;

653 654 655
	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);
656 657
		break;

658 659
	case CMD_ACT_TX_POWER_OPT_SET_LOW:
		prtp->action = cpu_to_le16(CMD_ACT_SET);
660 661 662
		prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
		break;
	}
663 664

	lbs_deb_leave(LBS_DEB_CMD);
665 666 667
	return 0;
}

668
static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv,
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
				      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;
}

688
static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
689 690 691 692 693 694
					      struct cmd_ds_command *cmd,
					      u16 cmd_action)
{
	struct cmd_ds_802_11_rate_adapt_rateset
	*rateadapt = &cmd->params.rateset;

695
	lbs_deb_enter(LBS_DEB_CMD);
696 697 698
	cmd->size =
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
			     + S_DS_GEN);
699
	cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
700

701
	rateadapt->action = cpu_to_le16(cmd_action);
702 703
	rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
	rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
704

705
	lbs_deb_leave(LBS_DEB_CMD);
706 707 708
	return 0;
}

709
static int lbs_cmd_802_11_data_rate(struct lbs_private *priv,
710 711 712 713 714
				     struct cmd_ds_command *cmd,
				     u16 cmd_action)
{
	struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;

715
	lbs_deb_enter(LBS_DEB_CMD);
716

717
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
718
			     S_DS_GEN);
719
	cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE);
720 721 722
	memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
	pdatarate->action = cpu_to_le16(cmd_action);

723
	if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) {
724
		pdatarate->rates[0] = lbs_data_rate_to_fw_index(priv->cur_rate);
725
		lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n",
726
		       priv->cur_rate);
727
	} else if (cmd_action == CMD_ACT_SET_TX_AUTO) {
728
		lbs_deb_cmd("DATA_RATE: setting auto\n");
729 730
	}

731
	lbs_deb_leave(LBS_DEB_CMD);
732 733 734
	return 0;
}

735
static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
736 737 738 739 740
				      struct cmd_ds_command *cmd,
				      u16 cmd_action)
{
	struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;

741
	lbs_deb_enter(LBS_DEB_CMD);
742
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
743
			     S_DS_GEN);
744
	cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
745

746
	lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
747 748
	pMCastAdr->action = cpu_to_le16(cmd_action);
	pMCastAdr->nr_of_adrs =
749 750 751
	    cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
	memcpy(pMCastAdr->maclist, priv->multicastlist,
	       priv->nr_of_multicastmacaddr * ETH_ALEN);
752

753
	lbs_deb_leave(LBS_DEB_CMD);
754 755 756
	return 0;
}

757
static int lbs_cmd_802_11_rf_channel(struct lbs_private *priv,
758 759 760 761 762
				      struct cmd_ds_command *cmd,
				      int option, void *pdata_buf)
{
	struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;

763
	lbs_deb_enter(LBS_DEB_CMD);
764
	cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL);
765 766
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) +
				S_DS_GEN);
767

768
	if (option == CMD_OPT_802_11_RF_CHANNEL_SET) {
769 770 771 772 773
		rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
	}

	rfchan->action = cpu_to_le16(option);

774
	lbs_deb_leave(LBS_DEB_CMD);
775 776 777
	return 0;
}

778
static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
779 780 781
				struct cmd_ds_command *cmd)
{

782
	lbs_deb_enter(LBS_DEB_CMD);
783
	cmd->command = cpu_to_le16(CMD_802_11_RSSI);
784
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
785
	cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
786 787

	/* reset Beacon SNR/NF/RSSI values */
788 789 790 791 792 793
	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;
794

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

799
static int lbs_cmd_reg_access(struct lbs_private *priv,
800 801 802
			       struct cmd_ds_command *cmdptr,
			       u8 cmd_action, void *pdata_buf)
{
803
	struct lbs_offset_value *offval;
804

805
	lbs_deb_enter(LBS_DEB_CMD);
806

807
	offval = (struct lbs_offset_value *)pdata_buf;
808

H
Holger Schurig 已提交
809
	switch (le16_to_cpu(cmdptr->command)) {
810
	case CMD_MAC_REG_ACCESS:
811 812 813 814
		{
			struct cmd_ds_mac_reg_access *macreg;

			cmdptr->size =
815 816
			    cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
					+ S_DS_GEN);
817 818 819 820 821 822 823 824 825 826 827
			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;
		}

828
	case CMD_BBP_REG_ACCESS:
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
		{
			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;
		}

847
	case CMD_RF_REG_ACCESS:
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
		{
			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;
	}

870
	lbs_deb_leave(LBS_DEB_CMD);
871 872 873
	return 0;
}

874
static int lbs_cmd_802_11_mac_address(struct lbs_private *priv,
875 876 877 878
				       struct cmd_ds_command *cmd,
				       u16 cmd_action)
{

879
	lbs_deb_enter(LBS_DEB_CMD);
880
	cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
881
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
882 883 884 885 886
			     S_DS_GEN);
	cmd->result = 0;

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

887
	if (cmd_action == CMD_ACT_SET) {
888
		memcpy(cmd->params.macadd.macadd,
889 890
		       priv->current_addr, ETH_ALEN);
		lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6);
891 892
	}

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

897
static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv,
898 899 900
					 struct cmd_ds_command *cmd,
					 int cmd_action, void *pdata_buf)
{
901
	struct lbs_ioctl_regrdwr *ea = pdata_buf;
902

903
	lbs_deb_enter(LBS_DEB_CMD);
904

905
	cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
906 907
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
				S_DS_GEN);
908 909 910 911 912 913 914
	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;

915
	lbs_deb_leave(LBS_DEB_CMD);
916 917 918
	return 0;
}

919
static int lbs_cmd_bt_access(struct lbs_private *priv,
920 921 922 923
			       struct cmd_ds_command *cmd,
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
924
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
925

926
	cmd->command = cpu_to_le16(CMD_BT_ACCESS);
927
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
928 929 930 931
	cmd->result = 0;
	bt_access->action = cpu_to_le16(cmd_action);

	switch (cmd_action) {
932
	case CMD_ACT_BT_ACCESS_ADD:
933
		memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
934
		lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
935
		break;
936
	case CMD_ACT_BT_ACCESS_DEL:
937
		memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
938
		lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
939
		break;
940
	case CMD_ACT_BT_ACCESS_LIST:
941 942
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
943
	case CMD_ACT_BT_ACCESS_RESET:
944
		break;
945
	case CMD_ACT_BT_ACCESS_SET_INVERT:
946 947
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
948
	case CMD_ACT_BT_ACCESS_GET_INVERT:
949
		break;
950 951 952
	default:
		break;
	}
953
	lbs_deb_leave(LBS_DEB_CMD);
954 955 956
	return 0;
}

957
static int lbs_cmd_fwt_access(struct lbs_private *priv,
958 959 960 961
			       struct cmd_ds_command *cmd,
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
962
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
963

964
	cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
965
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
966 967 968 969 970 971 972 973 974
	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);

975
	lbs_deb_leave(LBS_DEB_CMD);
976 977 978
	return 0;
}

979
static int lbs_cmd_mesh_access(struct lbs_private *priv,
980 981 982 983
				struct cmd_ds_command *cmd,
				u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
984
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
985

986
	cmd->command = cpu_to_le16(CMD_MESH_ACCESS);
987
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN);
988 989 990 991 992 993 994 995 996
	cmd->result = 0;

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

	mesh_access->action = cpu_to_le16(cmd_action);

997
	lbs_deb_leave(LBS_DEB_CMD);
998 999 1000
	return 0;
}

1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
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);
1015 1016
	bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
	bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
1017 1018 1019 1020 1021

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

1022
/*
1023
 * Note: NEVER use lbs_queue_cmd() with addtail==0 other than for
1024 1025
 * the command timer, because it does not account for queued commands.
 */
1026
void lbs_queue_cmd(struct lbs_private *priv,
1027 1028
	struct cmd_ctrl_node *cmdnode,
	u8 addtail)
1029 1030 1031
{
	unsigned long flags;

1032
	lbs_deb_enter(LBS_DEB_HOST);
1033

1034 1035
	if (!cmdnode || !cmdnode->cmdbuf) {
		lbs_deb_host("QUEUE_CMD: cmdnode or cmdbuf is NULL\n");
1036 1037 1038 1039
		goto done;
	}

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

1043
		if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1044
			if (priv->psstate != PS_STATE_FULL_POWER)
1045 1046 1047 1048
				addtail = 0;
		}
	}

1049
	spin_lock_irqsave(&priv->driver_lock, flags);
1050

1051
	if (addtail)
1052
		list_add_tail(&cmdnode->list, &priv->cmdpendingq);
1053
	else
1054
		list_add(&cmdnode->list, &priv->cmdpendingq);
1055

1056
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1057

1058
	lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
1059
	       le16_to_cpu(cmdnode->cmdbuf->command));
1060 1061

done:
1062
	lbs_deb_leave(LBS_DEB_HOST);
1063 1064 1065 1066
}

/*
 * TODO: Fix the issue when DownloadcommandToStation is being called the
1067
 * second time when the command times out. All the cmdptr->xxx are in little
1068 1069 1070 1071
 * endian and therefore all the comparissions will fail.
 * For now - we are not performing the endian conversion the second time - but
 * for PS and DEEP_SLEEP we need to worry
 */
1072
static int DownloadcommandToStation(struct lbs_private *priv,
1073 1074 1075
				    struct cmd_ctrl_node *cmdnode)
{
	unsigned long flags;
1076
	struct cmd_header *cmd;
1077
	int ret = -1;
1078 1079 1080
	u16 cmdsize;
	u16 command;

1081
	lbs_deb_enter(LBS_DEB_HOST);
1082

1083 1084
	if (!priv || !cmdnode) {
		lbs_deb_host("DNLD_CMD: priv or cmdmode is NULL\n");
1085 1086 1087
		goto done;
	}

1088
	cmd = cmdnode->cmdbuf;
1089

1090
	spin_lock_irqsave(&priv->driver_lock, flags);
1091
	if (!cmd || !cmd->size) {
1092
		lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n");
1093
		__lbs_cleanup_and_insert_cmd(priv, cmdnode);
1094
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1095 1096 1097
		goto done;
	}

1098 1099 1100
	priv->cur_cmd = cmdnode;
	priv->cur_cmd_retcode = 0;
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1101

1102 1103
	cmdsize = le16_to_cpu(cmd->size);
	command = le16_to_cpu(cmd->command);
1104

1105
	lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n",
H
Holger Schurig 已提交
1106
		    command, cmdsize, jiffies);
1107
	lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
1108

1109 1110
	cmdnode->cmdwaitqwoken = 0;

1111
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
1112 1113

	if (ret != 0) {
1114
		lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n");
1115 1116 1117 1118 1119
		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);
1120 1121 1122
		goto done;
	}

1123
	lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
1124 1125

	/* Setup the timer after transmit command */
1126 1127
	if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
	    || command == CMD_802_11_ASSOCIATE)
1128
		mod_timer(&priv->command_timer, jiffies + (10*HZ));
1129
	else
1130
		mod_timer(&priv->command_timer, jiffies + (5*HZ));
1131 1132 1133

	ret = 0;

1134
done:
1135
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1136 1137 1138
	return ret;
}

1139
static int lbs_cmd_mac_control(struct lbs_private *priv,
1140 1141 1142 1143
				struct cmd_ds_command *cmd)
{
	struct cmd_ds_mac_control *mac = &cmd->params.macctrl;

1144
	lbs_deb_enter(LBS_DEB_CMD);
1145

1146
	cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
1147
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
1148
	mac->action = cpu_to_le16(priv->currentpacketfilter);
1149

1150
	lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
1151
		    le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
1152

1153
	lbs_deb_leave(LBS_DEB_CMD);
1154 1155 1156 1157 1158
	return 0;
}

/**
 *  This function inserts command node to cmdfreeq
1159
 *  after cleans it. Requires priv->driver_lock held.
1160
 */
1161 1162
void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1163 1164 1165
{

	if (!ptempcmd)
1166
		return;
1167 1168

	cleanup_cmdnode(ptempcmd);
1169
	list_add_tail(&ptempcmd->list, &priv->cmdfreeq);
1170 1171
}

1172 1173
static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1174 1175 1176
{
	unsigned long flags;

1177
	spin_lock_irqsave(&priv->driver_lock, flags);
1178
	__lbs_cleanup_and_insert_cmd(priv, ptempcmd);
1179
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1180 1181
}

1182
int lbs_set_radio_control(struct lbs_private *priv)
1183 1184 1185
{
	int ret = 0;

1186
	lbs_deb_enter(LBS_DEB_CMD);
1187

1188
	ret = lbs_prepare_and_send_command(priv,
1189 1190 1191
				    CMD_802_11_RADIO_CONTROL,
				    CMD_ACT_SET,
				    CMD_OPTION_WAITFORRSP, 0, NULL);
1192

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

1196
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1197 1198 1199
	return ret;
}

1200
int lbs_set_mac_packet_filter(struct lbs_private *priv)
1201 1202 1203
{
	int ret = 0;

1204
	lbs_deb_enter(LBS_DEB_CMD);
1205 1206

	/* Send MAC control command to station */
1207
	ret = lbs_prepare_and_send_command(priv,
1208
				    CMD_MAC_CONTROL, 0, 0, 0, NULL);
1209

1210
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1211 1212 1213 1214 1215 1216
	return ret;
}

/**
 *  @brief This function prepare the command before send to firmware.
 *
1217
 *  @param priv		A pointer to struct lbs_private structure
1218 1219 1220 1221 1222 1223 1224
 *  @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
 */
1225
int lbs_prepare_and_send_command(struct lbs_private *priv,
1226 1227 1228 1229 1230 1231 1232 1233 1234
			  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;

1235
	lbs_deb_enter(LBS_DEB_HOST);
1236

1237 1238
	if (!priv) {
		lbs_deb_host("PREP_CMD: priv is NULL\n");
1239 1240 1241 1242
		ret = -1;
		goto done;
	}

1243
	if (priv->surpriseremoved) {
1244
		lbs_deb_host("PREP_CMD: card removed\n");
1245 1246 1247 1248
		ret = -1;
		goto done;
	}

1249
	cmdnode = lbs_get_cmd_ctrl_node(priv);
1250 1251

	if (cmdnode == NULL) {
1252
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1253 1254

		/* Wake up main thread to execute next command */
1255
		wake_up_interruptible(&priv->waitq);
1256 1257 1258 1259
		ret = -1;
		goto done;
	}

1260
	lbs_set_cmd_ctrl_node(priv, cmdnode, wait_option, pdata_buf);
1261

1262
	cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
1263

1264
	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
1265 1266

	if (!cmdptr) {
1267
		lbs_deb_host("PREP_CMD: cmdptr is NULL\n");
1268
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1269 1270 1271 1272 1273
		ret = -1;
		goto done;
	}

	/* Set sequence number, command and INT option */
1274 1275
	priv->seqnum++;
	cmdptr->seqnum = cpu_to_le16(priv->seqnum);
1276

1277
	cmdptr->command = cpu_to_le16(cmd_no);
1278 1279 1280
	cmdptr->result = 0;

	switch (cmd_no) {
1281
	case CMD_802_11_PS_MODE:
1282
		ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
1283 1284
		break;

1285
	case CMD_802_11_SCAN:
1286
		ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
1287 1288
		break;

1289
	case CMD_MAC_CONTROL:
1290
		ret = lbs_cmd_mac_control(priv, cmdptr);
1291 1292
		break;

1293 1294
	case CMD_802_11_ASSOCIATE:
	case CMD_802_11_REASSOCIATE:
1295
		ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
1296 1297
		break;

1298
	case CMD_802_11_DEAUTHENTICATE:
1299
		ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
1300 1301
		break;

1302
	case CMD_802_11_SET_WEP:
1303
		ret = lbs_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
1304 1305
		break;

1306
	case CMD_802_11_AD_HOC_START:
1307
		ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
1308
		break;
1309
	case CMD_CODE_DNLD:
1310 1311
		break;

1312
	case CMD_802_11_RESET:
1313
		ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
1314 1315
		break;

1316
	case CMD_802_11_GET_LOG:
1317
		ret = lbs_cmd_802_11_get_log(priv, cmdptr);
1318 1319
		break;

1320
	case CMD_802_11_AUTHENTICATE:
1321
		ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
1322 1323
		break;

1324
	case CMD_802_11_GET_STAT:
1325
		ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
1326 1327
		break;

1328
	case CMD_802_11_SNMP_MIB:
1329
		ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
1330 1331 1332
					       cmd_action, cmd_oid, pdata_buf);
		break;

1333 1334 1335
	case CMD_MAC_REG_ACCESS:
	case CMD_BBP_REG_ACCESS:
	case CMD_RF_REG_ACCESS:
1336
		ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
1337 1338
		break;

1339
	case CMD_802_11_RF_CHANNEL:
1340
		ret = lbs_cmd_802_11_rf_channel(priv, cmdptr,
1341 1342 1343
						 cmd_action, pdata_buf);
		break;

1344
	case CMD_802_11_RF_TX_POWER:
1345
		ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
1346 1347 1348
						  cmd_action, pdata_buf);
		break;

1349
	case CMD_802_11_RADIO_CONTROL:
1350
		ret = lbs_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
1351 1352
		break;

1353
	case CMD_802_11_DATA_RATE:
1354
		ret = lbs_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
1355
		break;
1356
	case CMD_802_11_RATE_ADAPT_RATESET:
1357
		ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
1358 1359 1360
							 cmdptr, cmd_action);
		break;

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

1365
	case CMD_802_11_MONITOR_MODE:
1366
		ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
1367 1368 1369
				          cmd_action, pdata_buf);
		break;

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

1374
	case CMD_802_11_RSSI:
1375
		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
1376 1377
		break;

1378
	case CMD_802_11_AD_HOC_STOP:
1379
		ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
1380 1381
		break;

1382
	case CMD_802_11_ENABLE_RSN:
1383
		ret = lbs_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
1384
				pdata_buf);
1385 1386
		break;

1387
	case CMD_802_11_KEY_MATERIAL:
1388
		ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
1389
				cmd_oid, pdata_buf);
1390 1391
		break;

1392
	case CMD_802_11_PAIRWISE_TSC:
1393
		break;
1394
	case CMD_802_11_GROUP_TSC:
1395 1396
		break;

1397
	case CMD_802_11_MAC_ADDRESS:
1398
		ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
1399 1400
		break;

1401
	case CMD_802_11_EEPROM_ACCESS:
1402
		ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
1403 1404 1405
						    cmd_action, pdata_buf);
		break;

1406 1407
	case CMD_802_11_SET_AFC:
	case CMD_802_11_GET_AFC:
1408 1409

		cmdptr->command = cpu_to_le16(cmd_no);
1410 1411
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
					   S_DS_GEN);
1412 1413 1414 1415 1416 1417 1418

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

		ret = 0;
		goto done;

1419
	case CMD_802_11D_DOMAIN_INFO:
1420
		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
1421 1422 1423
						   cmd_no, cmd_action);
		break;

1424
	case CMD_802_11_SLEEP_PARAMS:
1425
		ret = lbs_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
1426
		break;
1427
	case CMD_802_11_INACTIVITY_TIMEOUT:
1428
		ret = lbs_cmd_802_11_inactivity_timeout(priv, cmdptr,
1429
							 cmd_action, pdata_buf);
1430
		lbs_set_cmd_ctrl_node(priv, cmdnode, 0, pdata_buf);
1431 1432
		break;

1433 1434
	case CMD_802_11_TPC_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1435 1436 1437 1438 1439 1440 1441 1442 1443
		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;
1444
	case CMD_802_11_LED_GPIO_CTRL:
1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
		{
			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 =
1455
			    cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
1456 1457 1458

#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
			cmdptr->size =
H
Holger Schurig 已提交
1459 1460 1461 1462
			    cpu_to_le16(le16_to_cpu(gpio->header.len)
				+ S_DS_GEN
				+ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
			gpio->header.len = gpio->header.len;
1463 1464 1465 1466

			ret = 0;
			break;
		}
1467 1468 1469 1470
	case CMD_802_11_SUBSCRIBE_EVENT:
		lbs_cmd_802_11_subscribe_event(priv, cmdptr,
			cmd_action, pdata_buf);
		break;
1471 1472
	case CMD_802_11_PWR_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
1473 1474 1475 1476 1477 1478 1479 1480
		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;
1481
	case CMD_BT_ACCESS:
1482
		ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
1483 1484
		break;

1485
	case CMD_FWT_ACCESS:
1486
		ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
1487 1488
		break;

1489
	case CMD_MESH_ACCESS:
1490
		ret = lbs_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
1491 1492
		break;

1493 1494
	case CMD_GET_TSF:
		cmdptr->command = cpu_to_le16(CMD_GET_TSF);
1495 1496
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
					   S_DS_GEN);
1497 1498
		ret = 0;
		break;
1499 1500 1501
	case CMD_802_11_BEACON_CTRL:
		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
		break;
1502
	default:
1503
		lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
1504 1505 1506 1507 1508 1509
		ret = -1;
		break;
	}

	/* return error, since the command preparation failed */
	if (ret != 0) {
1510
		lbs_deb_host("PREP_CMD: command preparation failed\n");
1511
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1512 1513 1514 1515 1516 1517
		ret = -1;
		goto done;
	}

	cmdnode->cmdwaitqwoken = 0;

1518
	lbs_queue_cmd(priv, cmdnode, 1);
1519
	wake_up_interruptible(&priv->waitq);
1520

1521
	if (wait_option & CMD_OPTION_WAITFORRSP) {
1522
		lbs_deb_host("PREP_CMD: wait for response\n");
1523 1524 1525 1526 1527
		might_sleep();
		wait_event_interruptible(cmdnode->cmdwait_q,
					 cmdnode->cmdwaitqwoken);
	}

1528 1529
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd_retcode) {
1530
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
1531 1532
		       priv->cur_cmd_retcode);
		priv->cur_cmd_retcode = 0;
1533 1534
		ret = -1;
	}
1535
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1536 1537

done:
1538
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1539 1540
	return ret;
}
1541
EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
1542 1543 1544 1545 1546

/**
 *  @brief This function allocates the command buffer and link
 *  it to command free queue.
 *
1547
 *  @param priv		A pointer to struct lbs_private structure
1548 1549
 *  @return 		0 or -1
 */
1550
int lbs_allocate_cmd_buffer(struct lbs_private *priv)
1551 1552
{
	int ret = 0;
1553
	u32 bufsize;
1554
	u32 i;
1555
	struct cmd_ctrl_node *cmdarray;
1556

1557
	lbs_deb_enter(LBS_DEB_HOST);
1558

1559 1560 1561
	/* Allocate and initialize the command array */
	bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
	if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
1562
		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
1563 1564 1565
		ret = -1;
		goto done;
	}
1566
	priv->cmd_array = cmdarray;
1567

1568 1569 1570 1571
	/* 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) {
1572
			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
1573 1574 1575 1576 1577
			ret = -1;
			goto done;
		}
	}

1578 1579 1580
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		init_waitqueue_head(&cmdarray[i].cmdwait_q);
		lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
1581 1582
	}
	ret = 0;
1583 1584

done:
1585
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1586 1587 1588 1589 1590 1591
	return ret;
}

/**
 *  @brief This function frees the command buffer.
 *
1592
 *  @param priv		A pointer to struct lbs_private structure
1593 1594
 *  @return 		0 or -1
 */
1595
int lbs_free_cmd_buffer(struct lbs_private *priv)
1596
{
1597
	struct cmd_ctrl_node *cmdarray;
1598 1599
	unsigned int i;

1600
	lbs_deb_enter(LBS_DEB_HOST);
1601 1602

	/* need to check if cmd array is allocated or not */
1603
	if (priv->cmd_array == NULL) {
1604
		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
1605 1606 1607
		goto done;
	}

1608
	cmdarray = priv->cmd_array;
1609 1610

	/* Release shared memory buffers */
1611 1612 1613 1614
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		if (cmdarray[i].cmdbuf) {
			kfree(cmdarray[i].cmdbuf);
			cmdarray[i].cmdbuf = NULL;
1615 1616 1617 1618
		}
	}

	/* Release cmd_ctrl_node */
1619 1620 1621
	if (priv->cmd_array) {
		kfree(priv->cmd_array);
		priv->cmd_array = NULL;
1622 1623 1624
	}

done:
1625
	lbs_deb_leave(LBS_DEB_HOST);
1626 1627 1628 1629 1630 1631 1632
	return 0;
}

/**
 *  @brief This function gets a free command node if available in
 *  command free queue.
 *
1633
 *  @param priv		A pointer to struct lbs_private structure
1634 1635
 *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
 */
1636
struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
1637 1638 1639 1640
{
	struct cmd_ctrl_node *tempnode;
	unsigned long flags;

1641 1642
	lbs_deb_enter(LBS_DEB_HOST);

1643
	if (!priv)
1644 1645
		return NULL;

1646
	spin_lock_irqsave(&priv->driver_lock, flags);
1647

1648 1649
	if (!list_empty(&priv->cmdfreeq)) {
		tempnode = list_first_entry(&priv->cmdfreeq,
1650 1651
					    struct cmd_ctrl_node, list);
		list_del(&tempnode->list);
1652
	} else {
1653
		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
1654 1655 1656
		tempnode = NULL;
	}

1657
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1658

1659
	if (tempnode)
1660 1661
		cleanup_cmdnode(tempnode);

1662
	lbs_deb_leave(LBS_DEB_HOST);
1663 1664 1665 1666 1667 1668 1669 1670 1671
	return tempnode;
}

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

1676
	if (!cmdnode)
1677
		return;
1678 1679 1680 1681 1682 1683
	cmdnode->cmdwaitqwoken = 1;
	wake_up_interruptible(&cmdnode->cmdwait_q);
	cmdnode->wait_option = 0;
	cmdnode->pdata_buf = NULL;
	cmdnode->callback = NULL;
	cmdnode->callback_arg = 0;
1684

1685 1686
	if (cmdnode->cmdbuf != NULL)
		memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
1687 1688

	lbs_deb_leave(LBS_DEB_HOST);
1689 1690 1691 1692 1693
}

/**
 *  @brief This function initializes the command node.
 *
1694
 *  @param priv		A pointer to struct lbs_private structure
1695 1696 1697 1698 1699
 *  @param ptempnode	A pointer to cmd_ctrl_node structure
 *  @param wait_option	wait option: wait response or not
 *  @param pdata_buf	A pointer to informaion buffer
 *  @return 		0 or -1
 */
1700
void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
1701
		    struct cmd_ctrl_node *ptempnode,
1702
		    u16 wait_option, void *pdata_buf)
1703
{
1704
	lbs_deb_enter(LBS_DEB_HOST);
1705 1706 1707 1708 1709 1710

	if (!ptempnode)
		return;

	ptempnode->wait_option = wait_option;
	ptempnode->pdata_buf = pdata_buf;
1711
	ptempnode->callback = NULL;
1712
	ptempnode->callback_arg = 0;
1713

1714
	lbs_deb_leave(LBS_DEB_HOST);
1715 1716 1717 1718 1719 1720 1721
}

/**
 *  @brief This function executes next command in command
 *  pending queue. It will put fimware back to PS mode
 *  if applicable.
 *
1722
 *  @param priv     A pointer to struct lbs_private structure
1723 1724
 *  @return 	   0 or -1
 */
1725
int lbs_execute_next_command(struct lbs_private *priv)
1726 1727
{
	struct cmd_ctrl_node *cmdnode = NULL;
1728
	struct cmd_header *cmd;
1729 1730 1731
	unsigned long flags;
	int ret = 0;

1732
	// Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
1733
	// only caller to us is lbs_thread() and we get even when a
1734 1735
	// data packet is received
	lbs_deb_enter(LBS_DEB_THREAD);
1736

1737
	spin_lock_irqsave(&priv->driver_lock, flags);
1738

1739
	if (priv->cur_cmd) {
1740
		lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
1741
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1742 1743 1744 1745
		ret = -1;
		goto done;
	}

1746 1747
	if (!list_empty(&priv->cmdpendingq)) {
		cmdnode = list_first_entry(&priv->cmdpendingq,
1748
					   struct cmd_ctrl_node, list);
1749 1750
	}

1751
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1752 1753

	if (cmdnode) {
1754
		cmd = cmdnode->cmdbuf;
1755

1756
		if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
1757 1758
			if ((priv->psstate == PS_STATE_SLEEP) ||
			    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1759 1760
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
1761
				       le16_to_cpu(cmd->command),
1762
				       priv->psstate);
1763 1764 1765
				ret = -1;
				goto done;
			}
1766
			lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
1767 1768
				     "0x%04x in psstate %d\n",
				     le16_to_cpu(cmd->command), priv->psstate);
1769
		} else if (priv->psstate != PS_STATE_FULL_POWER) {
1770 1771 1772
			/*
			 * 1. Non-PS command:
			 * Queue it. set needtowakeup to TRUE if current state
1773
			 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
1774 1775 1776 1777 1778 1779 1780
			 * 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.
			 */
1781
			if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
1782 1783
				/*  Prepare to send Exit PS,
				 *  this non PS command will be sent later */
1784 1785
				if ((priv->psstate == PS_STATE_SLEEP)
				    || (priv->psstate == PS_STATE_PRE_SLEEP)
1786 1787 1788
				    ) {
					/* w/ new scheme, it will not reach here.
					   since it is blocked in main_thread. */
1789
					priv->needtowakeup = 1;
1790
				} else
1791
					lbs_ps_wakeup(priv, 0);
1792 1793 1794 1795 1796 1797 1798 1799

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

1802 1803
				lbs_deb_host(
				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
1804 1805
				       psm->action);
				if (psm->action !=
1806
				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1807 1808
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
1809
					list_del(&cmdnode->list);
1810
					lbs_cleanup_and_insert_cmd(priv, cmdnode);
1811 1812 1813 1814 1815

					ret = 0;
					goto done;
				}

1816 1817
				if ((priv->psstate == PS_STATE_SLEEP) ||
				    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1818 1819
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
1820
					list_del(&cmdnode->list);
1821
					lbs_cleanup_and_insert_cmd(priv, cmdnode);
1822
					priv->needtowakeup = 1;
1823 1824 1825 1826 1827

					ret = 0;
					goto done;
				}

1828 1829
				lbs_deb_host(
				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
1830 1831
			}
		}
1832
		list_del(&cmdnode->list);
1833
		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
1834
			    le16_to_cpu(cmd->command));
1835 1836 1837 1838 1839 1840
		DownloadcommandToStation(priv, cmdnode);
	} else {
		/*
		 * check if in power save mode, if yes, put the device back
		 * to PS mode
		 */
1841 1842 1843 1844 1845 1846
		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) {
1847
				/* check for valid WPA group keys */
1848 1849
				if (priv->wpa_mcast_key.len ||
				    priv->wpa_unicast_key.len) {
1850
					lbs_deb_host(
1851 1852
					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
					       " go back to PS_SLEEP");
1853
					lbs_ps_sleep(priv, 0);
1854 1855
				}
			} else {
1856 1857 1858
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cmdpendingq empty, "
				       "go back to PS_SLEEP");
1859
				lbs_ps_sleep(priv, 0);
1860 1861 1862 1863 1864 1865
			}
		}
	}

	ret = 0;
done:
1866
	lbs_deb_leave(LBS_DEB_THREAD);
1867 1868 1869
	return ret;
}

1870
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
1871 1872 1873 1874
{
	union iwreq_data iwrq;
	u8 buf[50];

1875
	lbs_deb_enter(LBS_DEB_WEXT);
1876 1877 1878 1879 1880 1881 1882 1883 1884

	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 */
1885 1886 1887
	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);
1888

1889
	wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
1890

1891
	lbs_deb_leave(LBS_DEB_WEXT);
1892 1893
}

1894
static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
1895 1896 1897 1898
{
	unsigned long flags;
	int ret = 0;

1899
	lbs_deb_enter(LBS_DEB_HOST);
1900

1901
	lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
1902 1903
	       size);

1904
	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
1905

1906
	ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
1907
	priv->dnld_sent = DNLD_RES_RECEIVED;
1908

1909 1910
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->intcounter || priv->currenttxskb)
1911
		lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
1912 1913
		       priv->intcounter, priv->currenttxskb);
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1914 1915 1916 1917 1918

	if (ret) {
		lbs_pr_alert(
		       "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
	} else {
1919 1920 1921
		spin_lock_irqsave(&priv->driver_lock, flags);
		if (!priv->intcounter) {
			priv->psstate = PS_STATE_SLEEP;
1922
		} else {
1923
			lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
1924
			       priv->intcounter);
1925
		}
1926
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1927

1928
		lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
1929 1930
	}

1931
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1932 1933 1934
	return ret;
}

1935
void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
1936
{
1937
	lbs_deb_enter(LBS_DEB_HOST);
1938 1939 1940 1941 1942 1943

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

1944
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1945
			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
1946

1947
	lbs_deb_leave(LBS_DEB_HOST);
1948 1949 1950
}

/**
1951
 *  @brief This function sends Exit_PS command to firmware.
1952
 *
1953
 *  @param priv    	A pointer to struct lbs_private structure
1954 1955 1956
 *  @param wait_option	wait response or not
 *  @return 	   	n/a
 */
1957
void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
1958
{
1959
	__le32 Localpsmode;
1960

1961
	lbs_deb_enter(LBS_DEB_HOST);
1962

1963
	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
1964

1965
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1966
			      CMD_SUBCMD_EXIT_PS,
1967 1968
			      wait_option, 0, &Localpsmode);

1969
	lbs_deb_leave(LBS_DEB_HOST);
1970 1971 1972 1973 1974 1975
}

/**
 *  @brief This function checks condition and prepares to
 *  send sleep confirm command to firmware if ok.
 *
1976
 *  @param priv    	A pointer to struct lbs_private structure
1977 1978 1979
 *  @param psmode  	Power Saving mode
 *  @return 	   	n/a
 */
1980
void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode)
1981 1982 1983 1984
{
	unsigned long flags =0;
	u8 allowed = 1;

1985
	lbs_deb_enter(LBS_DEB_HOST);
1986

1987
	if (priv->dnld_sent) {
1988
		allowed = 0;
1989
		lbs_deb_host("dnld_sent was set");
1990 1991
	}

1992 1993
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd) {
1994
		allowed = 0;
1995
		lbs_deb_host("cur_cmd was set");
1996
	}
1997
	if (priv->intcounter > 0) {
1998
		allowed = 0;
1999
		lbs_deb_host("intcounter %d", priv->intcounter);
2000
	}
2001
	spin_unlock_irqrestore(&priv->driver_lock, flags);
2002 2003

	if (allowed) {
2004
		lbs_deb_host("sending lbs_ps_confirm_sleep\n");
2005
		sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep,
2006 2007
				 sizeof(struct PS_CMD_ConfirmSleep));
	} else {
2008
		lbs_deb_host("sleep confirm has been delayed\n");
2009 2010
	}

2011
	lbs_deb_leave(LBS_DEB_HOST);
2012
}
2013 2014


2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042
/**
 *  @brief Simple callback that copies response back into command
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param extra  	A pointer to the original command structure for which
 *                      'resp' is a response
 *  @param resp         A pointer to the command response
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
			struct cmd_header *resp)
{
	struct cmd_header *buf = (void *)extra;
	uint16_t copy_len;

	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, "
		    "copy back buffer was %u bytes", copy_len, resp->size,
		    buf->size);
	memcpy(buf, resp, copy_len);

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058
/**
 *  @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
 */
2059 2060 2061
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 *),
2062
	      unsigned long callback_arg)
2063 2064 2065 2066 2067 2068 2069
{
	struct cmd_ctrl_node *cmdnode;
	unsigned long flags;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_HOST);

2070 2071
	if (!priv) {
		lbs_deb_host("PREP_CMD: priv is NULL\n");
2072 2073 2074 2075
		ret = -1;
		goto done;
	}

2076
	if (priv->surpriseremoved) {
2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092
		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;
	}

	cmdnode->wait_option = CMD_OPTION_WAITFORRSP;
2093
	cmdnode->callback = callback;
2094
	cmdnode->callback_arg = callback_arg;
2095

2096
	/* Copy the incoming command to the buffer */
2097
	memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
2098

2099
	/* Set sequence number, clean result, move to buffer */
2100
	priv->seqnum++;
2101 2102 2103 2104
	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;
2105 2106 2107 2108 2109 2110 2111

	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;
2112
	lbs_queue_cmd(priv, cmdnode, 1);
2113 2114 2115 2116 2117
	wake_up_interruptible(&priv->waitq);

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

2118 2119
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd_retcode) {
2120
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
2121 2122
		       priv->cur_cmd_retcode);
		priv->cur_cmd_retcode = 0;
2123 2124
		ret = -1;
	}
2125
	spin_unlock_irqrestore(&priv->driver_lock, flags);
2126 2127 2128 2129 2130

done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
	return ret;
}
2131
EXPORT_SYMBOL_GPL(__lbs_cmd);
2132 2133