cmd.c 54.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/**
  * 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"

static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
16 17 18 19 20
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);

21 22

static u16 commands_allowed_in_ps[] = {
23
	CMD_802_11_RSSI,
24 25 26 27 28 29 30 31 32
};

/**
 *  @brief This function checks if the commans is allowed
 *  in PS mode not.
 *
 *  @param command the command ID
 *  @return 	   TRUE or FALSE
 */
33
static u8 is_command_allowed_in_ps(__le16 command)
34 35 36
{
	int i;

37
	for (i = 0; i < ARRAY_SIZE(commands_allowed_in_ps); i++) {
38 39 40 41 42 43 44
		if (command == cpu_to_le16(commands_allowed_in_ps[i]))
			return 1;
	}

	return 0;
}

45
static int lbs_cmd_hw_spec(struct lbs_private *priv, struct cmd_ds_command *cmd)
46 47 48
{
	struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec;

49
	lbs_deb_enter(LBS_DEB_CMD);
50

51
	cmd->command = cpu_to_le16(CMD_GET_HW_SPEC);
52
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
53 54
	memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN);

55
	lbs_deb_leave(LBS_DEB_CMD);
56 57 58
	return 0;
}

59
static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv,
60 61 62 63 64
				   struct cmd_ds_command *cmd,
				   u16 cmd_action)
{
	struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;

65
	lbs_deb_enter(LBS_DEB_CMD);
66

67
	cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
68 69
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
				S_DS_GEN);
70 71
	psm->action = cpu_to_le16(cmd_action);
	psm->multipledtim = 0;
72
	switch (cmd_action) {
73
	case CMD_SUBCMD_ENTER_PS:
74
		lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
75

76
		psm->locallisteninterval = 0;
77
		psm->nullpktinterval = 0;
78
		psm->multipledtim =
79
		    cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
80 81
		break;

82
	case CMD_SUBCMD_EXIT_PS:
83
		lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
84 85
		break;

86
	case CMD_SUBCMD_SLEEP_CONFIRMED:
87
		lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
88 89 90 91 92 93
		break;

	default:
		break;
	}

94
	lbs_deb_leave(LBS_DEB_CMD);
95 96 97
	return 0;
}

98
static int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
99 100 101 102 103
					      struct cmd_ds_command *cmd,
					      u16 cmd_action, void *pdata_buf)
{
	u16 *timeout = pdata_buf;

104 105
	lbs_deb_enter(LBS_DEB_CMD);

106
	cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
107 108 109 110 111 112 113
	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)
114
		cmd->params.inactivity_timeout.timeout = cpu_to_le16(*timeout);
115 116 117
	else
		cmd->params.inactivity_timeout.timeout = 0;

118
	lbs_deb_leave(LBS_DEB_CMD);
119 120 121
	return 0;
}

122
static int lbs_cmd_802_11_sleep_params(struct lbs_private *priv,
123 124 125
					struct cmd_ds_command *cmd,
					u16 cmd_action)
{
126
	struct lbs_adapter *adapter = priv->adapter;
127 128
	struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;

129
	lbs_deb_enter(LBS_DEB_CMD);
130

131 132
	cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
				S_DS_GEN);
133
	cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS);
134

135
	if (cmd_action == CMD_ACT_GET) {
136 137 138
		memset(&adapter->sp, 0, sizeof(struct sleep_params));
		memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
		sp->action = cpu_to_le16(cmd_action);
139
	} else if (cmd_action == CMD_ACT_SET) {
140 141 142 143 144 145 146 147 148
		sp->action = cpu_to_le16(cmd_action);
		sp->error = cpu_to_le16(adapter->sp.sp_error);
		sp->offset = cpu_to_le16(adapter->sp.sp_offset);
		sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime);
		sp->calcontrol = (u8) adapter->sp.sp_calcontrol;
		sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk;
		sp->reserved = cpu_to_le16(adapter->sp.sp_reserved);
	}

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

153
static int lbs_cmd_802_11_set_wep(struct lbs_private *priv,
154 155 156 157 158
                                   struct cmd_ds_command *cmd,
                                   u32 cmd_act,
                                   void * pdata_buf)
{
	struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
159
	struct lbs_adapter *adapter = priv->adapter;
160 161 162
	int ret = 0;
	struct assoc_request * assoc_req = pdata_buf;

163
	lbs_deb_enter(LBS_DEB_CMD);
164

165
	cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
166
	cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
167

168
	if (cmd_act == CMD_ACT_ADD) {
169 170 171
		int i;

		if (!assoc_req) {
172
			lbs_deb_cmd("Invalid association request!");
173 174 175 176
			ret = -1;
			goto done;
		}

177
		wep->action = cpu_to_le16(CMD_ACT_ADD);
178 179

		/* default tx key index */
180
		wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
181
						  (u32)CMD_WEP_KEY_INDEX_MASK));
182 183 184

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

			switch (pkey->len) {
			case KEY_LEN_WEP_40:
H
Holger Schurig 已提交
189
				wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
190 191
				memmove(&wep->keymaterial[i], pkey->key,
				        pkey->len);
192
				lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
193 194
				break;
			case KEY_LEN_WEP_104:
H
Holger Schurig 已提交
195
				wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
196 197
				memmove(&wep->keymaterial[i], pkey->key,
				        pkey->len);
198
				lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
199 200 201 202
				break;
			case 0:
				break;
			default:
203
				lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
204 205 206 207 208 209
				       i, pkey->len);
				ret = -1;
				goto done;
				break;
			}
		}
210
	} else if (cmd_act == CMD_ACT_REMOVE) {
211
		/* ACT_REMOVE clears _all_ WEP keys */
212
		wep->action = cpu_to_le16(CMD_ACT_REMOVE);
213 214

		/* default tx key index */
215
		wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx &
216
						  (u32)CMD_WEP_KEY_INDEX_MASK));
217
		lbs_deb_cmd("SET_WEP: remove key %d\n", adapter->wep_tx_keyidx);
218 219 220 221 222
	}

	ret = 0;

done:
223
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
224 225 226
	return ret;
}

227
static int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv,
228
				      struct cmd_ds_command *cmd,
229 230
				      u16 cmd_action,
				      void * pdata_buf)
231 232
{
	struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
233
	u32 * enable = pdata_buf;
234 235

	lbs_deb_enter(LBS_DEB_CMD);
236

237
	cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
238
	cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
239
	penableRSN->action = cpu_to_le16(cmd_action);
240

241
	if (cmd_action == CMD_ACT_SET) {
242
		if (*enable)
243
			penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
244
		else
245
			penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
246
		lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
247 248
	}

249
	lbs_deb_leave(LBS_DEB_CMD);
250 251 252 253
	return 0;
}


254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
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);
}

300
static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
301
                            struct enc_key * pkey)
302
{
303 304
	lbs_deb_enter(LBS_DEB_CMD);

305
	if (pkey->flags & KEY_INFO_WPA_ENABLED) {
306
		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
307 308 309
	}
	if (pkey->flags & KEY_INFO_WPA_UNICAST) {
		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
310 311
	}
	if (pkey->flags & KEY_INFO_WPA_MCAST) {
312 313 314 315
		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
	}

	pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
316
	pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
317 318 319 320 321 322
	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));
323
	lbs_deb_leave(LBS_DEB_CMD);
324 325
}

326
static int lbs_cmd_802_11_key_material(struct lbs_private *priv,
327 328 329 330 331 332
					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;
333
	struct assoc_request * assoc_req = pdata_buf;
334 335 336
	int ret = 0;
	int index = 0;

337
	lbs_deb_enter(LBS_DEB_CMD);
338

339
	cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
340 341
	pkeymaterial->action = cpu_to_le16(cmd_action);

342
	if (cmd_action == CMD_ACT_GET) {
343
		cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
344 345 346 347 348 349
		ret = 0;
		goto done;
	}

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

350
	if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
351
		set_one_wpa_key(&pkeymaterial->keyParamSet[index],
352
		                &assoc_req->wpa_unicast_key);
353 354 355
		index++;
	}

356
	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
357
		set_one_wpa_key(&pkeymaterial->keyParamSet[index],
358
		                &assoc_req->wpa_mcast_key);
359 360 361 362
		index++;
	}

	cmd->size = cpu_to_le16(  S_DS_GEN
363 364
	                        + sizeof (pkeymaterial->action)
	                        + (index * sizeof(struct MrvlIEtype_keyParamSet)));
365 366 367 368

	ret = 0;

done:
369
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
370 371 372
	return ret;
}

373
static int lbs_cmd_802_11_reset(struct lbs_private *priv,
374 375 376 377
				 struct cmd_ds_command *cmd, int cmd_action)
{
	struct cmd_ds_802_11_reset *reset = &cmd->params.reset;

378 379
	lbs_deb_enter(LBS_DEB_CMD);

380
	cmd->command = cpu_to_le16(CMD_802_11_RESET);
381 382 383
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
	reset->action = cpu_to_le16(cmd_action);

384
	lbs_deb_leave(LBS_DEB_CMD);
385 386 387
	return 0;
}

388
static int lbs_cmd_802_11_get_log(struct lbs_private *priv,
389 390
				   struct cmd_ds_command *cmd)
{
391
	lbs_deb_enter(LBS_DEB_CMD);
392
	cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
393 394 395
	cmd->size =
		cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);

396
	lbs_deb_leave(LBS_DEB_CMD);
397 398 399
	return 0;
}

400
static int lbs_cmd_802_11_get_stat(struct lbs_private *priv,
401 402
				    struct cmd_ds_command *cmd)
{
403
	lbs_deb_enter(LBS_DEB_CMD);
404
	cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
405
	cmd->size =
406
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
407

408
	lbs_deb_leave(LBS_DEB_CMD);
409 410 411
	return 0;
}

412
static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
413 414 415 416 417
				    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;
418
	struct lbs_adapter *adapter = priv->adapter;
419 420
	u8 ucTemp;

421
	lbs_deb_enter(LBS_DEB_CMD);
422

423
	lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
424

425
	cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
426
	cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
427 428 429 430

	switch (cmd_oid) {
	case OID_802_11_INFRASTRUCTURE_MODE:
	{
431
		u8 mode = (u8) (size_t) pdata_buf;
432 433
		pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
		pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
434
		pSNMPMIB->bufsize = sizeof(u8);
435
		if (mode == IW_MODE_ADHOC) {
436
			ucTemp = SNMP_MIB_VALUE_ADHOC;
437 438 439 440
		} else {
			/* Infra and Auto modes */
			ucTemp = SNMP_MIB_VALUE_INFRA;
		}
441 442 443 444 445 446 447 448 449 450

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

		break;
	}

	case OID_802_11D_ENABLE:
		{
			u32 ulTemp;

451
			pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
452

453 454
			if (cmd_action == CMD_ACT_SET) {
				pSNMPMIB->querytype = CMD_ACT_SET;
455 456
				pSNMPMIB->bufsize = sizeof(u16);
				ulTemp = *(u32 *)pdata_buf;
457
				*((__le16 *)(pSNMPMIB->value)) =
458 459 460 461 462 463 464 465 466
				    cpu_to_le16((u16) ulTemp);
			}
			break;
		}

	case OID_802_11_FRAGMENTATION_THRESHOLD:
		{
			u32 ulTemp;

467
			pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
468

469 470 471 472
			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);
473
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
474
				ulTemp = *((u32 *) pdata_buf);
475
				*((__le16 *)(pSNMPMIB->value)) =
476 477 478 479 480 481 482 483 484 485 486
				    cpu_to_le16((u16) ulTemp);

			}

			break;
		}

	case OID_802_11_RTS_THRESHOLD:
		{

			u32 ulTemp;
487
			pSNMPMIB->oid = le16_to_cpu((u16) RTSTHRESH_I);
488

489 490 491 492
			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);
493 494 495
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
				ulTemp = *((u32 *)pdata_buf);
				*(__le16 *)(pSNMPMIB->value) =
496 497 498 499 500 501
				    cpu_to_le16((u16) ulTemp);

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

504 505 506 507
		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);
508
			pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
509
			*((__le16 *)(pSNMPMIB->value)) =
510 511 512 513 514 515 516 517
			    cpu_to_le16((u16) adapter->txretrycount);
		}

		break;
	default:
		break;
	}

518
	lbs_deb_cmd(
519
	       "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
520 521
	       le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
	       le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
522

523
	lbs_deb_cmd(
524
	       "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
525 526 527
	       le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
	       le16_to_cpu(pSNMPMIB->bufsize),
	       le16_to_cpu(*(__le16 *) pSNMPMIB->value));
528

529
	lbs_deb_leave(LBS_DEB_CMD);
530 531 532
	return 0;
}

533
static int lbs_cmd_802_11_radio_control(struct lbs_private *priv,
534 535 536
					 struct cmd_ds_command *cmd,
					 int cmd_action)
{
537
	struct lbs_adapter *adapter = priv->adapter;
538
	struct cmd_ds_802_11_radio_control *pradiocontrol = &cmd->params.radio;
539

540
	lbs_deb_enter(LBS_DEB_CMD);
541 542 543 544

	cmd->size =
	    cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
			     S_DS_GEN);
545
	cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL);
546 547 548 549

	pradiocontrol->action = cpu_to_le16(cmd_action);

	switch (adapter->preamble) {
550
	case CMD_TYPE_SHORT_PREAMBLE:
551 552 553
		pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
		break;

554
	case CMD_TYPE_LONG_PREAMBLE:
555 556 557
		pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
		break;

558
	case CMD_TYPE_AUTO_PREAMBLE:
559 560 561 562 563 564 565 566 567 568
	default:
		pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
		break;
	}

	if (adapter->radioon)
		pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
	else
		pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);

569
	lbs_deb_leave(LBS_DEB_CMD);
570 571 572
	return 0;
}

573
static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv,
574 575 576 577 578 579
				       struct cmd_ds_command *cmd,
				       u16 cmd_action, void *pdata_buf)
{

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

580
	lbs_deb_enter(LBS_DEB_CMD);
581 582

	cmd->size =
583
	    cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
584
	cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
585
	prtp->action = cpu_to_le16(cmd_action);
586

587 588 589
	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));
590 591

	switch (cmd_action) {
592 593
	case CMD_ACT_TX_POWER_OPT_GET:
		prtp->action = cpu_to_le16(CMD_ACT_GET);
594 595 596
		prtp->currentlevel = 0;
		break;

597 598 599
	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);
600 601
		break;

602 603 604
	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);
605 606
		break;

607 608
	case CMD_ACT_TX_POWER_OPT_SET_LOW:
		prtp->action = cpu_to_le16(CMD_ACT_SET);
609 610 611
		prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
		break;
	}
612 613

	lbs_deb_leave(LBS_DEB_CMD);
614 615 616
	return 0;
}

617
static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv,
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
				      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;
}

637
static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
638 639 640 641 642
					      struct cmd_ds_command *cmd,
					      u16 cmd_action)
{
	struct cmd_ds_802_11_rate_adapt_rateset
	*rateadapt = &cmd->params.rateset;
643
	struct lbs_adapter *adapter = priv->adapter;
644

645
	lbs_deb_enter(LBS_DEB_CMD);
646 647 648
	cmd->size =
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
			     + S_DS_GEN);
649
	cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
650

651 652 653
	rateadapt->action = cpu_to_le16(cmd_action);
	rateadapt->enablehwauto = cpu_to_le16(adapter->enablehwauto);
	rateadapt->bitmap = cpu_to_le16(adapter->ratebitmap);
654

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

659
static int lbs_cmd_802_11_data_rate(struct lbs_private *priv,
660 661 662 663
				     struct cmd_ds_command *cmd,
				     u16 cmd_action)
{
	struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;
664
	struct lbs_adapter *adapter = priv->adapter;
665

666
	lbs_deb_enter(LBS_DEB_CMD);
667

668
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
669
			     S_DS_GEN);
670
	cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE);
671 672 673
	memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
	pdatarate->action = cpu_to_le16(cmd_action);

674
	if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) {
675
		pdatarate->rates[0] = lbs_data_rate_to_fw_index(adapter->cur_rate);
676
		lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n",
677
		       adapter->cur_rate);
678
	} else if (cmd_action == CMD_ACT_SET_TX_AUTO) {
679
		lbs_deb_cmd("DATA_RATE: setting auto\n");
680 681
	}

682
	lbs_deb_leave(LBS_DEB_CMD);
683 684 685
	return 0;
}

686
static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
687 688 689 690
				      struct cmd_ds_command *cmd,
				      u16 cmd_action)
{
	struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
691
	struct lbs_adapter *adapter = priv->adapter;
692

693
	lbs_deb_enter(LBS_DEB_CMD);
694
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
695
			     S_DS_GEN);
696
	cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
697

698
	lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
699 700 701 702 703 704
	pMCastAdr->action = cpu_to_le16(cmd_action);
	pMCastAdr->nr_of_adrs =
	    cpu_to_le16((u16) adapter->nr_of_multicastmacaddr);
	memcpy(pMCastAdr->maclist, adapter->multicastlist,
	       adapter->nr_of_multicastmacaddr * ETH_ALEN);

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

709
static int lbs_cmd_802_11_rf_channel(struct lbs_private *priv,
710 711 712 713 714
				      struct cmd_ds_command *cmd,
				      int option, void *pdata_buf)
{
	struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;

715
	lbs_deb_enter(LBS_DEB_CMD);
716
	cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL);
717 718
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) +
				S_DS_GEN);
719

720
	if (option == CMD_OPT_802_11_RF_CHANNEL_SET) {
721 722 723 724 725
		rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
	}

	rfchan->action = cpu_to_le16(option);

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

730
static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
731 732
				struct cmd_ds_command *cmd)
{
733
	struct lbs_adapter *adapter = priv->adapter;
734

735
	lbs_deb_enter(LBS_DEB_CMD);
736
	cmd->command = cpu_to_le16(CMD_802_11_RSSI);
737
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
738
	cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
739 740 741 742 743 744 745 746 747

	/* reset Beacon SNR/NF/RSSI values */
	adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
	adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0;
	adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
	adapter->NF[TYPE_BEACON][TYPE_AVG] = 0;
	adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
	adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0;

748
	lbs_deb_leave(LBS_DEB_CMD);
749 750 751
	return 0;
}

752
static int lbs_cmd_reg_access(struct lbs_private *priv,
753 754 755
			       struct cmd_ds_command *cmdptr,
			       u8 cmd_action, void *pdata_buf)
{
756
	struct lbs_offset_value *offval;
757

758
	lbs_deb_enter(LBS_DEB_CMD);
759

760
	offval = (struct lbs_offset_value *)pdata_buf;
761 762

	switch (cmdptr->command) {
763
	case CMD_MAC_REG_ACCESS:
764 765 766 767
		{
			struct cmd_ds_mac_reg_access *macreg;

			cmdptr->size =
768 769
			    cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
					+ S_DS_GEN);
770 771 772 773 774 775 776 777 778 779 780
			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;
		}

781
	case CMD_BBP_REG_ACCESS:
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
		{
			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;
		}

800
	case CMD_RF_REG_ACCESS:
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
		{
			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;
	}

823
	lbs_deb_leave(LBS_DEB_CMD);
824 825 826
	return 0;
}

827
static int lbs_cmd_802_11_mac_address(struct lbs_private *priv,
828 829 830
				       struct cmd_ds_command *cmd,
				       u16 cmd_action)
{
831
	struct lbs_adapter *adapter = priv->adapter;
832

833
	lbs_deb_enter(LBS_DEB_CMD);
834
	cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
835
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
836 837 838 839 840
			     S_DS_GEN);
	cmd->result = 0;

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

841
	if (cmd_action == CMD_ACT_SET) {
842 843
		memcpy(cmd->params.macadd.macadd,
		       adapter->current_addr, ETH_ALEN);
844
		lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", adapter->current_addr, 6);
845 846
	}

847
	lbs_deb_leave(LBS_DEB_CMD);
848 849 850
	return 0;
}

851
static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv,
852 853 854
					 struct cmd_ds_command *cmd,
					 int cmd_action, void *pdata_buf)
{
855
	struct lbs_ioctl_regrdwr *ea = pdata_buf;
856

857
	lbs_deb_enter(LBS_DEB_CMD);
858

859
	cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
860 861
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
				S_DS_GEN);
862 863 864 865 866 867 868
	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;

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

873
static int lbs_cmd_bt_access(struct lbs_private *priv,
874 875 876 877
			       struct cmd_ds_command *cmd,
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
878
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
879

880
	cmd->command = cpu_to_le16(CMD_BT_ACCESS);
881
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
882 883 884 885
	cmd->result = 0;
	bt_access->action = cpu_to_le16(cmd_action);

	switch (cmd_action) {
886
	case CMD_ACT_BT_ACCESS_ADD:
887
		memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
888
		lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
889
		break;
890
	case CMD_ACT_BT_ACCESS_DEL:
891
		memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
892
		lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
893
		break;
894
	case CMD_ACT_BT_ACCESS_LIST:
895 896
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
897
	case CMD_ACT_BT_ACCESS_RESET:
898
		break;
899
	case CMD_ACT_BT_ACCESS_SET_INVERT:
900 901
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
902
	case CMD_ACT_BT_ACCESS_GET_INVERT:
903
		break;
904 905 906
	default:
		break;
	}
907
	lbs_deb_leave(LBS_DEB_CMD);
908 909 910
	return 0;
}

911
static int lbs_cmd_fwt_access(struct lbs_private *priv,
912 913 914 915
			       struct cmd_ds_command *cmd,
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
916
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
917

918
	cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
919
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
920 921 922 923 924 925 926 927 928
	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);

929
	lbs_deb_leave(LBS_DEB_CMD);
930 931 932
	return 0;
}

933
static int lbs_cmd_mesh_access(struct lbs_private *priv,
934 935 936 937
				struct cmd_ds_command *cmd,
				u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
938
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
939

940
	cmd->command = cpu_to_le16(CMD_MESH_ACCESS);
941
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN);
942 943 944 945 946 947 948 949 950
	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);

951
	lbs_deb_leave(LBS_DEB_CMD);
952 953 954
	return 0;
}

955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
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;
	struct lbs_adapter *adapter = priv->adapter;

	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);
	bcn_ctrl->beacon_enable = cpu_to_le16(adapter->beacon_enable);
	bcn_ctrl->beacon_period = cpu_to_le16(adapter->beacon_period);

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

977
static int lbs_cmd_set_boot2_ver(struct lbs_private *priv,
978 979 980 981 982 983 984 985 986 987
				struct cmd_ds_command *cmd,
				u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_set_boot2_ver *boot2_ver = &cmd->params.boot2_ver;
	cmd->command = cpu_to_le16(CMD_SET_BOOT2_VER);
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_set_boot2_ver) + S_DS_GEN);
	boot2_ver->version = priv->boot2_version;
	return 0;
}

988
/*
989
 * Note: NEVER use lbs_queue_cmd() with addtail==0 other than for
990 991
 * the command timer, because it does not account for queued commands.
 */
992 993 994
void lbs_queue_cmd(struct lbs_adapter *adapter,
	struct cmd_ctrl_node *cmdnode,
	u8 addtail)
995 996 997 998
{
	unsigned long flags;
	struct cmd_ds_command *cmdptr;

999
	lbs_deb_enter(LBS_DEB_HOST);
1000 1001

	if (!cmdnode) {
1002
		lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
1003 1004 1005 1006 1007
		goto done;
	}

	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
	if (!cmdptr) {
1008
		lbs_deb_host("QUEUE_CMD: cmdptr is NULL\n");
1009 1010 1011 1012
		goto done;
	}

	/* Exit_PS command needs to be queued in the header always. */
1013
	if (cmdptr->command == CMD_802_11_PS_MODE) {
1014
		struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
1015
		if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1016 1017 1018 1019 1020 1021 1022
			if (adapter->psstate != PS_STATE_FULL_POWER)
				addtail = 0;
		}
	}

	spin_lock_irqsave(&adapter->driver_lock, flags);

1023
	if (addtail) {
1024 1025
		list_add_tail((struct list_head *)cmdnode,
			      &adapter->cmdpendingq);
1026 1027
		adapter->nr_cmd_pending++;
	} else
1028 1029 1030 1031
		list_add((struct list_head *)cmdnode, &adapter->cmdpendingq);

	spin_unlock_irqrestore(&adapter->driver_lock, flags);

1032
	lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
1033
	       le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command));
1034 1035

done:
1036
	lbs_deb_leave(LBS_DEB_HOST);
1037 1038 1039 1040
}

/*
 * TODO: Fix the issue when DownloadcommandToStation is being called the
1041
 * second time when the command times out. All the cmdptr->xxx are in little
1042 1043 1044 1045
 * 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
 */
1046
static int DownloadcommandToStation(struct lbs_private *priv,
1047 1048 1049 1050
				    struct cmd_ctrl_node *cmdnode)
{
	unsigned long flags;
	struct cmd_ds_command *cmdptr;
1051
	struct lbs_adapter *adapter = priv->adapter;
1052
	int ret = -1;
1053 1054 1055
	u16 cmdsize;
	u16 command;

1056
	lbs_deb_enter(LBS_DEB_HOST);
1057 1058

	if (!adapter || !cmdnode) {
1059
		lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n");
1060 1061 1062 1063 1064 1065 1066
		goto done;
	}

	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;

	spin_lock_irqsave(&adapter->driver_lock, flags);
	if (!cmdptr || !cmdptr->size) {
1067
		lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n");
1068
		__lbs_cleanup_and_insert_cmd(priv, cmdnode);
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		goto done;
	}

	adapter->cur_cmd = cmdnode;
	adapter->cur_cmd_retcode = 0;
	spin_unlock_irqrestore(&adapter->driver_lock, flags);

	cmdsize = cmdptr->size;
	command = cpu_to_le16(cmdptr->command);

1080 1081 1082 1083
	lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n",
		    command, le16_to_cpu(cmdptr->size), jiffies);
	lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize);

1084 1085 1086
	cmdnode->cmdwaitqwoken = 0;
	cmdsize = cpu_to_le16(cmdsize);

1087
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
1088 1089

	if (ret != 0) {
1090
		lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n");
1091
		spin_lock_irqsave(&adapter->driver_lock, flags);
1092
		adapter->cur_cmd_retcode = ret;
1093
		__lbs_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
1094
		adapter->nr_cmd_pending--;
1095 1096 1097 1098 1099
		adapter->cur_cmd = NULL;
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		goto done;
	}

1100
	lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
1101 1102

	/* Setup the timer after transmit command */
1103 1104
	if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
	    || command == CMD_802_11_ASSOCIATE)
1105 1106 1107 1108 1109 1110
		mod_timer(&adapter->command_timer, jiffies + (10*HZ));
	else
		mod_timer(&adapter->command_timer, jiffies + (5*HZ));

	ret = 0;

1111
done:
1112
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1113 1114 1115
	return ret;
}

1116
static int lbs_cmd_mac_control(struct lbs_private *priv,
1117 1118 1119 1120
				struct cmd_ds_command *cmd)
{
	struct cmd_ds_mac_control *mac = &cmd->params.macctrl;

1121
	lbs_deb_enter(LBS_DEB_CMD);
1122

1123
	cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
1124
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
1125 1126
	mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);

1127
	lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
1128
		    le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
1129

1130
	lbs_deb_leave(LBS_DEB_CMD);
1131 1132 1133 1134 1135 1136 1137
	return 0;
}

/**
 *  This function inserts command node to cmdfreeq
 *  after cleans it. Requires adapter->driver_lock held.
 */
1138 1139
void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1140
{
1141
	struct lbs_adapter *adapter = priv->adapter;
1142 1143

	if (!ptempcmd)
1144
		return;
1145 1146 1147 1148 1149

	cleanup_cmdnode(ptempcmd);
	list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq);
}

1150 1151
static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1152 1153 1154 1155
{
	unsigned long flags;

	spin_lock_irqsave(&priv->adapter->driver_lock, flags);
1156
	__lbs_cleanup_and_insert_cmd(priv, ptempcmd);
1157 1158 1159
	spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
}

1160
int lbs_set_radio_control(struct lbs_private *priv)
1161 1162 1163
{
	int ret = 0;

1164
	lbs_deb_enter(LBS_DEB_CMD);
1165

1166
	ret = lbs_prepare_and_send_command(priv,
1167 1168 1169
				    CMD_802_11_RADIO_CONTROL,
				    CMD_ACT_SET,
				    CMD_OPTION_WAITFORRSP, 0, NULL);
1170

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

1174
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1175 1176 1177
	return ret;
}

1178
int lbs_set_mac_packet_filter(struct lbs_private *priv)
1179 1180 1181
{
	int ret = 0;

1182
	lbs_deb_enter(LBS_DEB_CMD);
1183 1184

	/* Send MAC control command to station */
1185
	ret = lbs_prepare_and_send_command(priv,
1186
				    CMD_MAC_CONTROL, 0, 0, 0, NULL);
1187

1188
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1189 1190 1191 1192 1193 1194
	return ret;
}

/**
 *  @brief This function prepare the command before send to firmware.
 *
1195
 *  @param priv		A pointer to struct lbs_private structure
1196 1197 1198 1199 1200 1201 1202
 *  @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
 */
1203
int lbs_prepare_and_send_command(struct lbs_private *priv,
1204 1205 1206 1207 1208
			  u16 cmd_no,
			  u16 cmd_action,
			  u16 wait_option, u32 cmd_oid, void *pdata_buf)
{
	int ret = 0;
1209
	struct lbs_adapter *adapter = priv->adapter;
1210 1211 1212 1213
	struct cmd_ctrl_node *cmdnode;
	struct cmd_ds_command *cmdptr;
	unsigned long flags;

1214
	lbs_deb_enter(LBS_DEB_HOST);
1215 1216

	if (!adapter) {
1217
		lbs_deb_host("PREP_CMD: adapter is NULL\n");
1218 1219 1220 1221 1222
		ret = -1;
		goto done;
	}

	if (adapter->surpriseremoved) {
1223
		lbs_deb_host("PREP_CMD: card removed\n");
1224 1225 1226 1227
		ret = -1;
		goto done;
	}

1228
	cmdnode = lbs_get_cmd_ctrl_node(priv);
1229 1230

	if (cmdnode == NULL) {
1231
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1232 1233

		/* Wake up main thread to execute next command */
1234
		wake_up_interruptible(&priv->waitq);
1235 1236 1237 1238
		ret = -1;
		goto done;
	}

1239
	lbs_set_cmd_ctrl_node(priv, cmdnode, wait_option, pdata_buf);
1240 1241 1242

	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;

1243
	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
1244 1245

	if (!cmdptr) {
1246
		lbs_deb_host("PREP_CMD: cmdptr is NULL\n");
1247
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1248 1249 1250 1251 1252 1253 1254 1255
		ret = -1;
		goto done;
	}

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

1256
	cmdptr->command = cpu_to_le16(cmd_no);
1257 1258 1259
	cmdptr->result = 0;

	switch (cmd_no) {
1260
	case CMD_GET_HW_SPEC:
1261
		ret = lbs_cmd_hw_spec(priv, cmdptr);
1262
		break;
1263
	case CMD_802_11_PS_MODE:
1264
		ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
1265 1266
		break;

1267
	case CMD_802_11_SCAN:
1268
		ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
1269 1270
		break;

1271
	case CMD_MAC_CONTROL:
1272
		ret = lbs_cmd_mac_control(priv, cmdptr);
1273 1274
		break;

1275 1276
	case CMD_802_11_ASSOCIATE:
	case CMD_802_11_REASSOCIATE:
1277
		ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
1278 1279
		break;

1280
	case CMD_802_11_DEAUTHENTICATE:
1281
		ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
1282 1283
		break;

1284
	case CMD_802_11_SET_WEP:
1285
		ret = lbs_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
1286 1287
		break;

1288
	case CMD_802_11_AD_HOC_START:
1289
		ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
1290
		break;
1291
	case CMD_CODE_DNLD:
1292 1293
		break;

1294
	case CMD_802_11_RESET:
1295
		ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
1296 1297
		break;

1298
	case CMD_802_11_GET_LOG:
1299
		ret = lbs_cmd_802_11_get_log(priv, cmdptr);
1300 1301
		break;

1302
	case CMD_802_11_AUTHENTICATE:
1303
		ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
1304 1305
		break;

1306
	case CMD_802_11_GET_STAT:
1307
		ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
1308 1309
		break;

1310
	case CMD_802_11_SNMP_MIB:
1311
		ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
1312 1313 1314
					       cmd_action, cmd_oid, pdata_buf);
		break;

1315 1316 1317
	case CMD_MAC_REG_ACCESS:
	case CMD_BBP_REG_ACCESS:
	case CMD_RF_REG_ACCESS:
1318
		ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
1319 1320
		break;

1321
	case CMD_802_11_RF_CHANNEL:
1322
		ret = lbs_cmd_802_11_rf_channel(priv, cmdptr,
1323 1324 1325
						 cmd_action, pdata_buf);
		break;

1326
	case CMD_802_11_RF_TX_POWER:
1327
		ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
1328 1329 1330
						  cmd_action, pdata_buf);
		break;

1331
	case CMD_802_11_RADIO_CONTROL:
1332
		ret = lbs_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
1333 1334
		break;

1335
	case CMD_802_11_DATA_RATE:
1336
		ret = lbs_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
1337
		break;
1338
	case CMD_802_11_RATE_ADAPT_RATESET:
1339
		ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
1340 1341 1342
							 cmdptr, cmd_action);
		break;

1343
	case CMD_MAC_MULTICAST_ADR:
1344
		ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
1345 1346
		break;

1347
	case CMD_802_11_MONITOR_MODE:
1348
		ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
1349 1350 1351
				          cmd_action, pdata_buf);
		break;

1352
	case CMD_802_11_AD_HOC_JOIN:
1353
		ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
1354 1355
		break;

1356
	case CMD_802_11_RSSI:
1357
		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
1358 1359
		break;

1360
	case CMD_802_11_AD_HOC_STOP:
1361
		ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
1362 1363
		break;

1364
	case CMD_802_11_ENABLE_RSN:
1365
		ret = lbs_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
1366
				pdata_buf);
1367 1368
		break;

1369
	case CMD_802_11_KEY_MATERIAL:
1370
		ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
1371
				cmd_oid, pdata_buf);
1372 1373
		break;

1374
	case CMD_802_11_PAIRWISE_TSC:
1375
		break;
1376
	case CMD_802_11_GROUP_TSC:
1377 1378
		break;

1379
	case CMD_802_11_MAC_ADDRESS:
1380
		ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
1381 1382
		break;

1383
	case CMD_802_11_EEPROM_ACCESS:
1384
		ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
1385 1386 1387
						    cmd_action, pdata_buf);
		break;

1388 1389
	case CMD_802_11_SET_AFC:
	case CMD_802_11_GET_AFC:
1390 1391

		cmdptr->command = cpu_to_le16(cmd_no);
1392 1393
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
					   S_DS_GEN);
1394 1395 1396 1397 1398 1399 1400

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

		ret = 0;
		goto done;

1401
	case CMD_802_11D_DOMAIN_INFO:
1402
		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
1403 1404 1405
						   cmd_no, cmd_action);
		break;

1406
	case CMD_802_11_SLEEP_PARAMS:
1407
		ret = lbs_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
1408
		break;
1409
	case CMD_802_11_INACTIVITY_TIMEOUT:
1410
		ret = lbs_cmd_802_11_inactivity_timeout(priv, cmdptr,
1411
							 cmd_action, pdata_buf);
1412
		lbs_set_cmd_ctrl_node(priv, cmdnode, 0, pdata_buf);
1413 1414
		break;

1415 1416
	case CMD_802_11_TPC_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1417 1418 1419 1420 1421 1422 1423 1424 1425
		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;
1426
	case CMD_802_11_LED_GPIO_CTRL:
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436
		{
			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 =
1437
			    cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
1438 1439 1440 1441 1442 1443 1444 1445 1446 1447

#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
			cmdptr->size =
			    cpu_to_le16(gpio->header.len + S_DS_GEN +
					     ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
			gpio->header.len = cpu_to_le16(gpio->header.len);

			ret = 0;
			break;
		}
1448 1449 1450 1451
	case CMD_802_11_SUBSCRIBE_EVENT:
		lbs_cmd_802_11_subscribe_event(priv, cmdptr,
			cmd_action, pdata_buf);
		break;
1452 1453
	case CMD_802_11_PWR_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
1454 1455 1456 1457 1458 1459 1460 1461
		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;
1462
	case CMD_BT_ACCESS:
1463
		ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
1464 1465
		break;

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

1470
	case CMD_MESH_ACCESS:
1471
		ret = lbs_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
1472 1473
		break;

1474
	case CMD_SET_BOOT2_VER:
1475
		ret = lbs_cmd_set_boot2_ver(priv, cmdptr, cmd_action, pdata_buf);
1476 1477
		break;

1478 1479
	case CMD_GET_TSF:
		cmdptr->command = cpu_to_le16(CMD_GET_TSF);
1480 1481
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
					   S_DS_GEN);
1482 1483
		ret = 0;
		break;
1484 1485 1486
	case CMD_802_11_BEACON_CTRL:
		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
		break;
1487
	default:
1488
		lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
1489 1490 1491 1492 1493 1494
		ret = -1;
		break;
	}

	/* return error, since the command preparation failed */
	if (ret != 0) {
1495
		lbs_deb_host("PREP_CMD: command preparation failed\n");
1496
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1497 1498 1499 1500 1501 1502
		ret = -1;
		goto done;
	}

	cmdnode->cmdwaitqwoken = 0;

1503
	lbs_queue_cmd(adapter, cmdnode, 1);
1504
	wake_up_interruptible(&priv->waitq);
1505

1506
	if (wait_option & CMD_OPTION_WAITFORRSP) {
1507
		lbs_deb_host("PREP_CMD: wait for response\n");
1508 1509 1510 1511 1512 1513 1514
		might_sleep();
		wait_event_interruptible(cmdnode->cmdwait_q,
					 cmdnode->cmdwaitqwoken);
	}

	spin_lock_irqsave(&adapter->driver_lock, flags);
	if (adapter->cur_cmd_retcode) {
1515
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
1516 1517 1518 1519 1520 1521 1522
		       adapter->cur_cmd_retcode);
		adapter->cur_cmd_retcode = 0;
		ret = -1;
	}
	spin_unlock_irqrestore(&adapter->driver_lock, flags);

done:
1523
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1524 1525
	return ret;
}
1526
EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
1527 1528 1529 1530 1531

/**
 *  @brief This function allocates the command buffer and link
 *  it to command free queue.
 *
1532
 *  @param priv		A pointer to struct lbs_private structure
1533 1534
 *  @return 		0 or -1
 */
1535
int lbs_allocate_cmd_buffer(struct lbs_private *priv)
1536 1537 1538 1539 1540 1541
{
	int ret = 0;
	u32 ulbufsize;
	u32 i;
	struct cmd_ctrl_node *tempcmd_array;
	u8 *ptempvirtualaddr;
1542
	struct lbs_adapter *adapter = priv->adapter;
1543

1544
	lbs_deb_enter(LBS_DEB_HOST);
1545 1546 1547 1548

	/* Allocate and initialize cmdCtrlNode */
	ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;

1549
	if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) {
1550
		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
1551 1552 1553 1554 1555 1556 1557 1558
		ret = -1;
		goto done;
	}
	adapter->cmd_array = tempcmd_array;

	/* Allocate and initialize command buffers */
	ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
1559
		if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) {
1560
			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
1561 1562 1563 1564 1565 1566 1567 1568 1569 1570
			ret = -1;
			goto done;
		}

		/* Update command buffer virtual */
		tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr;
	}

	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
		init_waitqueue_head(&tempcmd_array[i].cmdwait_q);
1571
		lbs_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
1572 1573 1574
	}

	ret = 0;
1575 1576

done:
1577
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1578 1579 1580 1581 1582 1583
	return ret;
}

/**
 *  @brief This function frees the command buffer.
 *
1584
 *  @param priv		A pointer to struct lbs_private structure
1585 1586
 *  @return 		0 or -1
 */
1587
int lbs_free_cmd_buffer(struct lbs_private *priv)
1588
{
1589
	u32 ulbufsize; /* Someone needs to die for this. Slowly and painfully */
1590 1591
	unsigned int i;
	struct cmd_ctrl_node *tempcmd_array;
1592
	struct lbs_adapter *adapter = priv->adapter;
1593

1594
	lbs_deb_enter(LBS_DEB_HOST);
1595 1596 1597

	/* need to check if cmd array is allocated or not */
	if (adapter->cmd_array == NULL) {
1598
		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619
		goto done;
	}

	tempcmd_array = adapter->cmd_array;

	/* Release shared memory buffers */
	ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
		if (tempcmd_array[i].bufvirtualaddr) {
			kfree(tempcmd_array[i].bufvirtualaddr);
			tempcmd_array[i].bufvirtualaddr = NULL;
		}
	}

	/* Release cmd_ctrl_node */
	if (adapter->cmd_array) {
		kfree(adapter->cmd_array);
		adapter->cmd_array = NULL;
	}

done:
1620
	lbs_deb_leave(LBS_DEB_HOST);
1621 1622 1623 1624 1625 1626 1627
	return 0;
}

/**
 *  @brief This function gets a free command node if available in
 *  command free queue.
 *
1628
 *  @param priv		A pointer to struct lbs_private structure
1629 1630
 *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
 */
1631
struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
1632 1633
{
	struct cmd_ctrl_node *tempnode;
1634
	struct lbs_adapter *adapter = priv->adapter;
1635 1636
	unsigned long flags;

1637 1638
	lbs_deb_enter(LBS_DEB_HOST);

1639 1640 1641 1642 1643 1644 1645 1646 1647
	if (!adapter)
		return NULL;

	spin_lock_irqsave(&adapter->driver_lock, flags);

	if (!list_empty(&adapter->cmdfreeq)) {
		tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next;
		list_del((struct list_head *)tempnode);
	} else {
1648
		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
1649 1650 1651 1652 1653
		tempnode = NULL;
	}

	spin_unlock_irqrestore(&adapter->driver_lock, flags);

1654
	if (tempnode)
1655 1656
		cleanup_cmdnode(tempnode);

1657
	lbs_deb_leave(LBS_DEB_HOST);
1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668
	return tempnode;
}

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

1671 1672 1673 1674 1675 1676
	if (!ptempnode)
		return;
	ptempnode->cmdwaitqwoken = 1;
	wake_up_interruptible(&ptempnode->cmdwait_q);
	ptempnode->wait_option = 0;
	ptempnode->pdata_buf = NULL;
1677
	ptempnode->pdata_size = 0;
1678 1679 1680

	if (ptempnode->bufvirtualaddr != NULL)
		memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
1681 1682

	lbs_deb_leave(LBS_DEB_HOST);
1683 1684 1685 1686 1687
}

/**
 *  @brief This function initializes the command node.
 *
1688
 *  @param priv		A pointer to struct lbs_private structure
1689 1690 1691 1692 1693
 *  @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
 */
1694
void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
1695
		    struct cmd_ctrl_node *ptempnode,
1696
		    u16 wait_option, void *pdata_buf)
1697
{
1698
	lbs_deb_enter(LBS_DEB_HOST);
1699 1700 1701 1702 1703 1704

	if (!ptempnode)
		return;

	ptempnode->wait_option = wait_option;
	ptempnode->pdata_buf = pdata_buf;
1705
	ptempnode->pdata_size = 0;
1706

1707
	lbs_deb_leave(LBS_DEB_HOST);
1708 1709 1710 1711 1712 1713 1714
}

/**
 *  @brief This function executes next command in command
 *  pending queue. It will put fimware back to PS mode
 *  if applicable.
 *
1715
 *  @param priv     A pointer to struct lbs_private structure
1716 1717
 *  @return 	   0 or -1
 */
1718
int lbs_execute_next_command(struct lbs_private *priv)
1719
{
1720
	struct lbs_adapter *adapter = priv->adapter;
1721 1722 1723 1724 1725
	struct cmd_ctrl_node *cmdnode = NULL;
	struct cmd_ds_command *cmdptr;
	unsigned long flags;
	int ret = 0;

1726
	// Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
1727
	// only caller to us is lbs_thread() and we get even when a
1728 1729
	// data packet is received
	lbs_deb_enter(LBS_DEB_THREAD);
1730 1731 1732 1733

	spin_lock_irqsave(&adapter->driver_lock, flags);

	if (adapter->cur_cmd) {
1734
		lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		ret = -1;
		goto done;
	}

	if (!list_empty(&adapter->cmdpendingq)) {
		cmdnode = (struct cmd_ctrl_node *)
		    adapter->cmdpendingq.next;
	}

	spin_unlock_irqrestore(&adapter->driver_lock, flags);

	if (cmdnode) {
		cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;

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

				ret = 0;
				goto done;
			} else {
				/*
				 * PS command. Ignore it if it is not Exit_PS.
				 * otherwise send it down immediately.
				 */
				struct cmd_ds_802_11_ps_mode *psm =
				    &cmdptr->params.psmode;

1799 1800
				lbs_deb_host(
				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
1801 1802
				       psm->action);
				if (psm->action !=
1803
				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1804 1805
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
1806
					list_del((struct list_head *)cmdnode);
1807
					lbs_cleanup_and_insert_cmd(priv, cmdnode);
1808 1809 1810 1811 1812

					ret = 0;
					goto done;
				}

1813 1814
				if ((adapter->psstate == PS_STATE_SLEEP) ||
				    (adapter->psstate == PS_STATE_PRE_SLEEP)) {
1815 1816
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
1817
					list_del((struct list_head *)cmdnode);
1818
					lbs_cleanup_and_insert_cmd(priv, cmdnode);
1819 1820 1821 1822 1823 1824
					adapter->needtowakeup = 1;

					ret = 0;
					goto done;
				}

1825 1826
				lbs_deb_host(
				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
1827 1828 1829
			}
		}
		list_del((struct list_head *)cmdnode);
1830
		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
1831
			    le16_to_cpu(cmdptr->command));
1832 1833 1834 1835 1836 1837
		DownloadcommandToStation(priv, cmdnode);
	} else {
		/*
		 * check if in power save mode, if yes, put the device back
		 * to PS mode
		 */
1838
		if ((adapter->psmode != LBS802_11POWERMODECAM) &&
1839
		    (adapter->psstate == PS_STATE_FULL_POWER) &&
1840 1841
		    ((adapter->connect_status == LBS_CONNECTED) ||
		    (adapter->mesh_connect_status == LBS_CONNECTED))) {
1842 1843
			if (adapter->secinfo.WPAenabled ||
			    adapter->secinfo.WPA2enabled) {
1844
				/* check for valid WPA group keys */
1845 1846
				if (adapter->wpa_mcast_key.len ||
				    adapter->wpa_unicast_key.len) {
1847
					lbs_deb_host(
1848 1849
					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
					       " go back to PS_SLEEP");
1850
					lbs_ps_sleep(priv, 0);
1851 1852
				}
			} else {
1853 1854 1855
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cmdpendingq empty, "
				       "go back to PS_SLEEP");
1856
				lbs_ps_sleep(priv, 0);
1857 1858 1859 1860 1861 1862
			}
		}
	}

	ret = 0;
done:
1863
	lbs_deb_leave(LBS_DEB_THREAD);
1864 1865 1866
	return ret;
}

1867
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
1868 1869 1870 1871
{
	union iwreq_data iwrq;
	u8 buf[50];

1872
	lbs_deb_enter(LBS_DEB_WEXT);
1873 1874 1875 1876 1877 1878 1879 1880 1881

	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 */
1882 1883 1884
	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);
1885

1886
	wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
1887

1888
	lbs_deb_leave(LBS_DEB_WEXT);
1889 1890
}

1891
static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
1892 1893
{
	unsigned long flags;
1894
	struct lbs_adapter *adapter = priv->adapter;
1895 1896
	int ret = 0;

1897
	lbs_deb_enter(LBS_DEB_HOST);
1898

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

1902
	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
1903

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

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

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

1926
		lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
1927 1928
	}

1929
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1930 1931 1932
	return ret;
}

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

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

1942
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1943
			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
1944

1945
	lbs_deb_leave(LBS_DEB_HOST);
1946 1947 1948
}

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

1959
	lbs_deb_enter(LBS_DEB_HOST);
1960

1961
	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
1962

1963
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1964
			      CMD_SUBCMD_EXIT_PS,
1965 1966
			      wait_option, 0, &Localpsmode);

1967
	lbs_deb_leave(LBS_DEB_HOST);
1968 1969 1970 1971 1972 1973
}

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

1984
	lbs_deb_enter(LBS_DEB_HOST);
1985

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

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

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

2010
	lbs_deb_leave(LBS_DEB_HOST);
2011
}
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 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107


/**
 *  @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
 */
int lbs_cmd(struct lbs_private *priv,
	u16 command,
	void *cmd, int cmd_size,
	void *rsp, int *rsp_size)
{
	struct lbs_adapter *adapter = priv->adapter;
	struct cmd_ctrl_node *cmdnode;
	struct cmd_ds_gen *cmdptr;
	unsigned long flags;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_HOST);
	lbs_deb_host("rsp at %p, rsp_size at %p\n", rsp, rsp_size);

	if (!adapter || !rsp_size) {
		lbs_deb_host("PREP_CMD: adapter is NULL\n");
		ret = -1;
		goto done;
	}

	if (adapter->surpriseremoved) {
		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;
	}

	cmdptr = (struct cmd_ds_gen *)cmdnode->bufvirtualaddr;
	cmdnode->wait_option = CMD_OPTION_WAITFORRSP;
	cmdnode->pdata_buf = rsp;
	cmdnode->pdata_size = rsp_size;

	/* Set sequence number, clean result, move to buffer */
	adapter->seqnum++;
	cmdptr->command = cpu_to_le16(command);
	cmdptr->size    = cmd_size + S_DS_GEN;
	cmdptr->seqnum = cpu_to_le16(adapter->seqnum);
	cmdptr->result = 0;
	memcpy(cmdptr->cmdresp, cmd, cmd_size);

	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;
	lbs_queue_cmd(adapter, cmdnode, 1);
	wake_up_interruptible(&priv->waitq);

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

	spin_lock_irqsave(&adapter->driver_lock, flags);
	if (adapter->cur_cmd_retcode) {
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
		       adapter->cur_cmd_retcode);
		adapter->cur_cmd_retcode = 0;
		ret = -1;
	}
	spin_unlock_irqrestore(&adapter->driver_lock, flags);

done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
	return ret;
}
EXPORT_SYMBOL_GPL(lbs_cmd);