cmd.c 55.1 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
/*
978
 * Note: NEVER use lbs_queue_cmd() with addtail==0 other than for
979 980
 * the command timer, because it does not account for queued commands.
 */
981 982 983
void lbs_queue_cmd(struct lbs_adapter *adapter,
	struct cmd_ctrl_node *cmdnode,
	u8 addtail)
984 985 986 987
{
	unsigned long flags;
	struct cmd_ds_command *cmdptr;

988
	lbs_deb_enter(LBS_DEB_HOST);
989 990

	if (!cmdnode) {
991
		lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
992 993 994 995 996
		goto done;
	}

	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
	if (!cmdptr) {
997
		lbs_deb_host("QUEUE_CMD: cmdptr is NULL\n");
998 999 1000 1001
		goto done;
	}

	/* Exit_PS command needs to be queued in the header always. */
1002
	if (cmdptr->command == CMD_802_11_PS_MODE) {
1003
		struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
1004
		if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1005 1006 1007 1008 1009 1010 1011
			if (adapter->psstate != PS_STATE_FULL_POWER)
				addtail = 0;
		}
	}

	spin_lock_irqsave(&adapter->driver_lock, flags);

1012
	if (addtail) {
1013
		list_add_tail(&cmdnode->list, &adapter->cmdpendingq);
1014 1015
		adapter->nr_cmd_pending++;
	} else
1016
		list_add(&cmdnode->list, &adapter->cmdpendingq);
1017 1018 1019

	spin_unlock_irqrestore(&adapter->driver_lock, flags);

1020
	lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
1021
	       le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command));
1022 1023

done:
1024
	lbs_deb_leave(LBS_DEB_HOST);
1025 1026 1027 1028
}

/*
 * TODO: Fix the issue when DownloadcommandToStation is being called the
1029
 * second time when the command times out. All the cmdptr->xxx are in little
1030 1031 1032 1033
 * 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
 */
1034
static int DownloadcommandToStation(struct lbs_private *priv,
1035 1036 1037 1038
				    struct cmd_ctrl_node *cmdnode)
{
	unsigned long flags;
	struct cmd_ds_command *cmdptr;
1039
	struct lbs_adapter *adapter = priv->adapter;
1040
	int ret = -1;
1041 1042 1043
	u16 cmdsize;
	u16 command;

1044
	lbs_deb_enter(LBS_DEB_HOST);
1045 1046

	if (!adapter || !cmdnode) {
1047
		lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n");
1048 1049 1050 1051 1052 1053 1054
		goto done;
	}

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

	spin_lock_irqsave(&adapter->driver_lock, flags);
	if (!cmdptr || !cmdptr->size) {
1055
		lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n");
1056
		__lbs_cleanup_and_insert_cmd(priv, cmdnode);
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
		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);

1068 1069 1070 1071
	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);

1072 1073 1074
	cmdnode->cmdwaitqwoken = 0;
	cmdsize = cpu_to_le16(cmdsize);

1075
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
1076 1077

	if (ret != 0) {
1078
		lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n");
1079
		spin_lock_irqsave(&adapter->driver_lock, flags);
1080
		adapter->cur_cmd_retcode = ret;
1081
		__lbs_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
1082
		adapter->nr_cmd_pending--;
1083 1084 1085 1086 1087
		adapter->cur_cmd = NULL;
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		goto done;
	}

1088
	lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
1089 1090

	/* Setup the timer after transmit command */
1091 1092
	if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
	    || command == CMD_802_11_ASSOCIATE)
1093 1094 1095 1096 1097 1098
		mod_timer(&adapter->command_timer, jiffies + (10*HZ));
	else
		mod_timer(&adapter->command_timer, jiffies + (5*HZ));

	ret = 0;

1099
done:
1100
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1101 1102 1103
	return ret;
}

1104
static int lbs_cmd_mac_control(struct lbs_private *priv,
1105 1106 1107 1108
				struct cmd_ds_command *cmd)
{
	struct cmd_ds_mac_control *mac = &cmd->params.macctrl;

1109
	lbs_deb_enter(LBS_DEB_CMD);
1110

1111
	cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
1112
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
1113 1114
	mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);

1115
	lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
1116
		    le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
1117

1118
	lbs_deb_leave(LBS_DEB_CMD);
1119 1120 1121 1122 1123 1124 1125
	return 0;
}

/**
 *  This function inserts command node to cmdfreeq
 *  after cleans it. Requires adapter->driver_lock held.
 */
1126 1127
void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1128
{
1129
	struct lbs_adapter *adapter = priv->adapter;
1130 1131

	if (!ptempcmd)
1132
		return;
1133 1134

	cleanup_cmdnode(ptempcmd);
1135
	list_add_tail(&ptempcmd->list, &adapter->cmdfreeq);
1136 1137
}

1138 1139
static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1140 1141 1142 1143
{
	unsigned long flags;

	spin_lock_irqsave(&priv->adapter->driver_lock, flags);
1144
	__lbs_cleanup_and_insert_cmd(priv, ptempcmd);
1145 1146 1147
	spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
}

1148
int lbs_set_radio_control(struct lbs_private *priv)
1149 1150 1151
{
	int ret = 0;

1152
	lbs_deb_enter(LBS_DEB_CMD);
1153

1154
	ret = lbs_prepare_and_send_command(priv,
1155 1156 1157
				    CMD_802_11_RADIO_CONTROL,
				    CMD_ACT_SET,
				    CMD_OPTION_WAITFORRSP, 0, NULL);
1158

1159
	lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n",
1160 1161
	       priv->adapter->radioon, priv->adapter->preamble);

1162
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1163 1164 1165
	return ret;
}

1166
int lbs_set_mac_packet_filter(struct lbs_private *priv)
1167 1168 1169
{
	int ret = 0;

1170
	lbs_deb_enter(LBS_DEB_CMD);
1171 1172

	/* Send MAC control command to station */
1173
	ret = lbs_prepare_and_send_command(priv,
1174
				    CMD_MAC_CONTROL, 0, 0, 0, NULL);
1175

1176
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1177 1178 1179 1180 1181 1182
	return ret;
}

/**
 *  @brief This function prepare the command before send to firmware.
 *
1183
 *  @param priv		A pointer to struct lbs_private structure
1184 1185 1186 1187 1188 1189 1190
 *  @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
 */
1191
int lbs_prepare_and_send_command(struct lbs_private *priv,
1192 1193 1194 1195 1196
			  u16 cmd_no,
			  u16 cmd_action,
			  u16 wait_option, u32 cmd_oid, void *pdata_buf)
{
	int ret = 0;
1197
	struct lbs_adapter *adapter = priv->adapter;
1198 1199 1200 1201
	struct cmd_ctrl_node *cmdnode;
	struct cmd_ds_command *cmdptr;
	unsigned long flags;

1202
	lbs_deb_enter(LBS_DEB_HOST);
1203 1204

	if (!adapter) {
1205
		lbs_deb_host("PREP_CMD: adapter is NULL\n");
1206 1207 1208 1209 1210
		ret = -1;
		goto done;
	}

	if (adapter->surpriseremoved) {
1211
		lbs_deb_host("PREP_CMD: card removed\n");
1212 1213 1214 1215
		ret = -1;
		goto done;
	}

1216
	cmdnode = lbs_get_cmd_ctrl_node(priv);
1217 1218

	if (cmdnode == NULL) {
1219
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1220 1221

		/* Wake up main thread to execute next command */
1222
		wake_up_interruptible(&priv->waitq);
1223 1224 1225 1226
		ret = -1;
		goto done;
	}

1227
	lbs_set_cmd_ctrl_node(priv, cmdnode, wait_option, pdata_buf);
1228 1229 1230

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

1231
	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
1232 1233

	if (!cmdptr) {
1234
		lbs_deb_host("PREP_CMD: cmdptr is NULL\n");
1235
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1236 1237 1238 1239 1240 1241 1242 1243
		ret = -1;
		goto done;
	}

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

1244
	cmdptr->command = cpu_to_le16(cmd_no);
1245 1246 1247
	cmdptr->result = 0;

	switch (cmd_no) {
1248
	case CMD_GET_HW_SPEC:
1249
		ret = lbs_cmd_hw_spec(priv, cmdptr);
1250
		break;
1251
	case CMD_802_11_PS_MODE:
1252
		ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
1253 1254
		break;

1255
	case CMD_802_11_SCAN:
1256
		ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
1257 1258
		break;

1259
	case CMD_MAC_CONTROL:
1260
		ret = lbs_cmd_mac_control(priv, cmdptr);
1261 1262
		break;

1263 1264
	case CMD_802_11_ASSOCIATE:
	case CMD_802_11_REASSOCIATE:
1265
		ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
1266 1267
		break;

1268
	case CMD_802_11_DEAUTHENTICATE:
1269
		ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
1270 1271
		break;

1272
	case CMD_802_11_SET_WEP:
1273
		ret = lbs_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
1274 1275
		break;

1276
	case CMD_802_11_AD_HOC_START:
1277
		ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
1278
		break;
1279
	case CMD_CODE_DNLD:
1280 1281
		break;

1282
	case CMD_802_11_RESET:
1283
		ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
1284 1285
		break;

1286
	case CMD_802_11_GET_LOG:
1287
		ret = lbs_cmd_802_11_get_log(priv, cmdptr);
1288 1289
		break;

1290
	case CMD_802_11_AUTHENTICATE:
1291
		ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
1292 1293
		break;

1294
	case CMD_802_11_GET_STAT:
1295
		ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
1296 1297
		break;

1298
	case CMD_802_11_SNMP_MIB:
1299
		ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
1300 1301 1302
					       cmd_action, cmd_oid, pdata_buf);
		break;

1303 1304 1305
	case CMD_MAC_REG_ACCESS:
	case CMD_BBP_REG_ACCESS:
	case CMD_RF_REG_ACCESS:
1306
		ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
1307 1308
		break;

1309
	case CMD_802_11_RF_CHANNEL:
1310
		ret = lbs_cmd_802_11_rf_channel(priv, cmdptr,
1311 1312 1313
						 cmd_action, pdata_buf);
		break;

1314
	case CMD_802_11_RF_TX_POWER:
1315
		ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
1316 1317 1318
						  cmd_action, pdata_buf);
		break;

1319
	case CMD_802_11_RADIO_CONTROL:
1320
		ret = lbs_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
1321 1322
		break;

1323
	case CMD_802_11_DATA_RATE:
1324
		ret = lbs_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
1325
		break;
1326
	case CMD_802_11_RATE_ADAPT_RATESET:
1327
		ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
1328 1329 1330
							 cmdptr, cmd_action);
		break;

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

1335
	case CMD_802_11_MONITOR_MODE:
1336
		ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
1337 1338 1339
				          cmd_action, pdata_buf);
		break;

1340
	case CMD_802_11_AD_HOC_JOIN:
1341
		ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
1342 1343
		break;

1344
	case CMD_802_11_RSSI:
1345
		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
1346 1347
		break;

1348
	case CMD_802_11_AD_HOC_STOP:
1349
		ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
1350 1351
		break;

1352
	case CMD_802_11_ENABLE_RSN:
1353
		ret = lbs_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
1354
				pdata_buf);
1355 1356
		break;

1357
	case CMD_802_11_KEY_MATERIAL:
1358
		ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
1359
				cmd_oid, pdata_buf);
1360 1361
		break;

1362
	case CMD_802_11_PAIRWISE_TSC:
1363
		break;
1364
	case CMD_802_11_GROUP_TSC:
1365 1366
		break;

1367
	case CMD_802_11_MAC_ADDRESS:
1368
		ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
1369 1370
		break;

1371
	case CMD_802_11_EEPROM_ACCESS:
1372
		ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
1373 1374 1375
						    cmd_action, pdata_buf);
		break;

1376 1377
	case CMD_802_11_SET_AFC:
	case CMD_802_11_GET_AFC:
1378 1379

		cmdptr->command = cpu_to_le16(cmd_no);
1380 1381
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
					   S_DS_GEN);
1382 1383 1384 1385 1386 1387 1388

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

		ret = 0;
		goto done;

1389
	case CMD_802_11D_DOMAIN_INFO:
1390
		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
1391 1392 1393
						   cmd_no, cmd_action);
		break;

1394
	case CMD_802_11_SLEEP_PARAMS:
1395
		ret = lbs_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
1396
		break;
1397
	case CMD_802_11_INACTIVITY_TIMEOUT:
1398
		ret = lbs_cmd_802_11_inactivity_timeout(priv, cmdptr,
1399
							 cmd_action, pdata_buf);
1400
		lbs_set_cmd_ctrl_node(priv, cmdnode, 0, pdata_buf);
1401 1402
		break;

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

#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;
		}
1436 1437 1438 1439
	case CMD_802_11_SUBSCRIBE_EVENT:
		lbs_cmd_802_11_subscribe_event(priv, cmdptr,
			cmd_action, pdata_buf);
		break;
1440 1441
	case CMD_802_11_PWR_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
1442 1443 1444 1445 1446 1447 1448 1449
		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;
1450
	case CMD_BT_ACCESS:
1451
		ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
1452 1453
		break;

1454
	case CMD_FWT_ACCESS:
1455
		ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
1456 1457
		break;

1458
	case CMD_MESH_ACCESS:
1459
		ret = lbs_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
1460 1461
		break;

1462 1463
	case CMD_GET_TSF:
		cmdptr->command = cpu_to_le16(CMD_GET_TSF);
1464 1465
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
					   S_DS_GEN);
1466 1467
		ret = 0;
		break;
1468 1469 1470
	case CMD_802_11_BEACON_CTRL:
		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
		break;
1471
	default:
1472
		lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
1473 1474 1475 1476 1477 1478
		ret = -1;
		break;
	}

	/* return error, since the command preparation failed */
	if (ret != 0) {
1479
		lbs_deb_host("PREP_CMD: command preparation failed\n");
1480
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1481 1482 1483 1484 1485 1486
		ret = -1;
		goto done;
	}

	cmdnode->cmdwaitqwoken = 0;

1487
	lbs_queue_cmd(adapter, cmdnode, 1);
1488
	wake_up_interruptible(&priv->waitq);
1489

1490
	if (wait_option & CMD_OPTION_WAITFORRSP) {
1491
		lbs_deb_host("PREP_CMD: wait for response\n");
1492 1493 1494 1495 1496 1497 1498
		might_sleep();
		wait_event_interruptible(cmdnode->cmdwait_q,
					 cmdnode->cmdwaitqwoken);
	}

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

done:
1507
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1508 1509
	return ret;
}
1510
EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
1511 1512 1513 1514 1515

/**
 *  @brief This function allocates the command buffer and link
 *  it to command free queue.
 *
1516
 *  @param priv		A pointer to struct lbs_private structure
1517 1518
 *  @return 		0 or -1
 */
1519
int lbs_allocate_cmd_buffer(struct lbs_private *priv)
1520 1521 1522 1523 1524 1525
{
	int ret = 0;
	u32 ulbufsize;
	u32 i;
	struct cmd_ctrl_node *tempcmd_array;
	u8 *ptempvirtualaddr;
1526
	struct lbs_adapter *adapter = priv->adapter;
1527

1528
	lbs_deb_enter(LBS_DEB_HOST);
1529 1530 1531 1532

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

1533
	if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) {
1534
		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
1535 1536 1537 1538 1539 1540 1541 1542
		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++) {
1543
		if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) {
1544
			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
			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);
1555
		lbs_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
1556 1557 1558
	}

	ret = 0;
1559 1560

done:
1561
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1562 1563 1564 1565 1566 1567
	return ret;
}

/**
 *  @brief This function frees the command buffer.
 *
1568
 *  @param priv		A pointer to struct lbs_private structure
1569 1570
 *  @return 		0 or -1
 */
1571
int lbs_free_cmd_buffer(struct lbs_private *priv)
1572
{
1573
	u32 ulbufsize; /* Someone needs to die for this. Slowly and painfully */
1574 1575
	unsigned int i;
	struct cmd_ctrl_node *tempcmd_array;
1576
	struct lbs_adapter *adapter = priv->adapter;
1577

1578
	lbs_deb_enter(LBS_DEB_HOST);
1579 1580 1581

	/* need to check if cmd array is allocated or not */
	if (adapter->cmd_array == NULL) {
1582
		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
		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:
1604
	lbs_deb_leave(LBS_DEB_HOST);
1605 1606 1607 1608 1609 1610 1611
	return 0;
}

/**
 *  @brief This function gets a free command node if available in
 *  command free queue.
 *
1612
 *  @param priv		A pointer to struct lbs_private structure
1613 1614
 *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
 */
1615
struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
1616 1617
{
	struct cmd_ctrl_node *tempnode;
1618
	struct lbs_adapter *adapter = priv->adapter;
1619 1620
	unsigned long flags;

1621 1622
	lbs_deb_enter(LBS_DEB_HOST);

1623 1624 1625 1626 1627 1628
	if (!adapter)
		return NULL;

	spin_lock_irqsave(&adapter->driver_lock, flags);

	if (!list_empty(&adapter->cmdfreeq)) {
1629 1630 1631
		tempnode = list_first_entry(&adapter->cmdfreeq,
					    struct cmd_ctrl_node, list);
		list_del(&tempnode->list);
1632
	} else {
1633
		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
1634 1635 1636 1637 1638
		tempnode = NULL;
	}

	spin_unlock_irqrestore(&adapter->driver_lock, flags);

1639
	if (tempnode)
1640 1641
		cleanup_cmdnode(tempnode);

1642
	lbs_deb_leave(LBS_DEB_HOST);
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
	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)
{
1654 1655
	lbs_deb_enter(LBS_DEB_HOST);

1656 1657 1658 1659 1660 1661
	if (!ptempnode)
		return;
	ptempnode->cmdwaitqwoken = 1;
	wake_up_interruptible(&ptempnode->cmdwait_q);
	ptempnode->wait_option = 0;
	ptempnode->pdata_buf = NULL;
1662 1663
	ptempnode->pdata_size = NULL;
	ptempnode->callback = NULL;
1664 1665 1666

	if (ptempnode->bufvirtualaddr != NULL)
		memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
1667 1668

	lbs_deb_leave(LBS_DEB_HOST);
1669 1670 1671 1672 1673
}

/**
 *  @brief This function initializes the command node.
 *
1674
 *  @param priv		A pointer to struct lbs_private structure
1675 1676 1677 1678 1679
 *  @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
 */
1680
void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
1681
		    struct cmd_ctrl_node *ptempnode,
1682
		    u16 wait_option, void *pdata_buf)
1683
{
1684
	lbs_deb_enter(LBS_DEB_HOST);
1685 1686 1687 1688 1689 1690

	if (!ptempnode)
		return;

	ptempnode->wait_option = wait_option;
	ptempnode->pdata_buf = pdata_buf;
1691 1692
	ptempnode->pdata_size = NULL;
	ptempnode->callback = NULL;
1693

1694
	lbs_deb_leave(LBS_DEB_HOST);
1695 1696 1697 1698 1699 1700 1701
}

/**
 *  @brief This function executes next command in command
 *  pending queue. It will put fimware back to PS mode
 *  if applicable.
 *
1702
 *  @param priv     A pointer to struct lbs_private structure
1703 1704
 *  @return 	   0 or -1
 */
1705
int lbs_execute_next_command(struct lbs_private *priv)
1706
{
1707
	struct lbs_adapter *adapter = priv->adapter;
1708 1709 1710 1711 1712
	struct cmd_ctrl_node *cmdnode = NULL;
	struct cmd_ds_command *cmdptr;
	unsigned long flags;
	int ret = 0;

1713
	// Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
1714
	// only caller to us is lbs_thread() and we get even when a
1715 1716
	// data packet is received
	lbs_deb_enter(LBS_DEB_THREAD);
1717 1718 1719 1720

	spin_lock_irqsave(&adapter->driver_lock, flags);

	if (adapter->cur_cmd) {
1721
		lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
1722 1723 1724 1725 1726 1727
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		ret = -1;
		goto done;
	}

	if (!list_empty(&adapter->cmdpendingq)) {
1728 1729
		cmdnode = list_first_entry(&adapter->cmdpendingq,
					   struct cmd_ctrl_node, list);
1730 1731 1732 1733 1734 1735 1736 1737
	}

	spin_unlock_irqrestore(&adapter->driver_lock, flags);

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

		if (is_command_allowed_in_ps(cmdptr->command)) {
1738 1739
			if ((adapter->psstate == PS_STATE_SLEEP) ||
			    (adapter->psstate == PS_STATE_PRE_SLEEP)) {
1740 1741
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
1742 1743
				       le16_to_cpu(cmdptr->command),
				       adapter->psstate);
1744 1745 1746
				ret = -1;
				goto done;
			}
1747 1748
			lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
			       "0x%04x in psstate %d\n",
1749 1750
				    le16_to_cpu(cmdptr->command),
				    adapter->psstate);
1751 1752 1753 1754
		} else if (adapter->psstate != PS_STATE_FULL_POWER) {
			/*
			 * 1. Non-PS command:
			 * Queue it. set needtowakeup to TRUE if current state
1755
			 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
1756 1757 1758 1759 1760 1761 1762 1763
			 * 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 !=
1764
			    cpu_to_le16(CMD_802_11_PS_MODE)) {
1765 1766 1767 1768 1769 1770 1771 1772 1773
				/*  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
1774
					lbs_ps_wakeup(priv, 0);
1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785

				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;

1786 1787
				lbs_deb_host(
				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
1788 1789
				       psm->action);
				if (psm->action !=
1790
				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1791 1792
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
1793
					list_del(&cmdnode->list);
1794
					lbs_cleanup_and_insert_cmd(priv, cmdnode);
1795 1796 1797 1798 1799

					ret = 0;
					goto done;
				}

1800 1801
				if ((adapter->psstate == PS_STATE_SLEEP) ||
				    (adapter->psstate == PS_STATE_PRE_SLEEP)) {
1802 1803
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
1804
					list_del(&cmdnode->list);
1805
					lbs_cleanup_and_insert_cmd(priv, cmdnode);
1806 1807 1808 1809 1810 1811
					adapter->needtowakeup = 1;

					ret = 0;
					goto done;
				}

1812 1813
				lbs_deb_host(
				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
1814 1815
			}
		}
1816
		list_del(&cmdnode->list);
1817
		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
1818
			    le16_to_cpu(cmdptr->command));
1819 1820 1821 1822 1823 1824
		DownloadcommandToStation(priv, cmdnode);
	} else {
		/*
		 * check if in power save mode, if yes, put the device back
		 * to PS mode
		 */
1825
		if ((adapter->psmode != LBS802_11POWERMODECAM) &&
1826
		    (adapter->psstate == PS_STATE_FULL_POWER) &&
1827 1828
		    ((adapter->connect_status == LBS_CONNECTED) ||
		    (adapter->mesh_connect_status == LBS_CONNECTED))) {
1829 1830
			if (adapter->secinfo.WPAenabled ||
			    adapter->secinfo.WPA2enabled) {
1831
				/* check for valid WPA group keys */
1832 1833
				if (adapter->wpa_mcast_key.len ||
				    adapter->wpa_unicast_key.len) {
1834
					lbs_deb_host(
1835 1836
					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
					       " go back to PS_SLEEP");
1837
					lbs_ps_sleep(priv, 0);
1838 1839
				}
			} else {
1840 1841 1842
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cmdpendingq empty, "
				       "go back to PS_SLEEP");
1843
				lbs_ps_sleep(priv, 0);
1844 1845 1846 1847 1848 1849
			}
		}
	}

	ret = 0;
done:
1850
	lbs_deb_leave(LBS_DEB_THREAD);
1851 1852 1853
	return ret;
}

1854
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
1855 1856 1857 1858
{
	union iwreq_data iwrq;
	u8 buf[50];

1859
	lbs_deb_enter(LBS_DEB_WEXT);
1860 1861 1862 1863 1864 1865 1866 1867 1868

	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 */
1869 1870 1871
	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);
1872

1873
	wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
1874

1875
	lbs_deb_leave(LBS_DEB_WEXT);
1876 1877
}

1878
static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
1879 1880
{
	unsigned long flags;
1881
	struct lbs_adapter *adapter = priv->adapter;
1882 1883
	int ret = 0;

1884
	lbs_deb_enter(LBS_DEB_HOST);
1885

1886
	lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
1887 1888
	       size);

1889
	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
1890

1891
	ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
1892
	priv->dnld_sent = DNLD_RES_RECEIVED;
1893 1894 1895

	spin_lock_irqsave(&adapter->driver_lock, flags);
	if (adapter->intcounter || adapter->currenttxskb)
1896
		lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907
		       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 {
1908
			lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
1909 1910 1911 1912
			       adapter->intcounter);
		}
		spin_unlock_irqrestore(&adapter->driver_lock, flags);

1913
		lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
1914 1915
	}

1916
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1917 1918 1919
	return ret;
}

1920
void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
1921
{
1922
	lbs_deb_enter(LBS_DEB_HOST);
1923 1924 1925 1926 1927 1928

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

1929
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1930
			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
1931

1932
	lbs_deb_leave(LBS_DEB_HOST);
1933 1934 1935
}

/**
1936
 *  @brief This function sends Exit_PS command to firmware.
1937
 *
1938
 *  @param priv    	A pointer to struct lbs_private structure
1939 1940 1941
 *  @param wait_option	wait response or not
 *  @return 	   	n/a
 */
1942
void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
1943
{
1944
	__le32 Localpsmode;
1945

1946
	lbs_deb_enter(LBS_DEB_HOST);
1947

1948
	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
1949

1950
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1951
			      CMD_SUBCMD_EXIT_PS,
1952 1953
			      wait_option, 0, &Localpsmode);

1954
	lbs_deb_leave(LBS_DEB_HOST);
1955 1956 1957 1958 1959 1960
}

/**
 *  @brief This function checks condition and prepares to
 *  send sleep confirm command to firmware if ok.
 *
1961
 *  @param priv    	A pointer to struct lbs_private structure
1962 1963 1964
 *  @param psmode  	Power Saving mode
 *  @return 	   	n/a
 */
1965
void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode)
1966 1967
{
	unsigned long flags =0;
1968
	struct lbs_adapter *adapter = priv->adapter;
1969 1970
	u8 allowed = 1;

1971
	lbs_deb_enter(LBS_DEB_HOST);
1972

1973
	if (priv->dnld_sent) {
1974
		allowed = 0;
1975
		lbs_deb_host("dnld_sent was set");
1976 1977 1978 1979 1980
	}

	spin_lock_irqsave(&adapter->driver_lock, flags);
	if (adapter->cur_cmd) {
		allowed = 0;
1981
		lbs_deb_host("cur_cmd was set");
1982 1983 1984
	}
	if (adapter->intcounter > 0) {
		allowed = 0;
1985
		lbs_deb_host("intcounter %d", adapter->intcounter);
1986 1987 1988 1989
	}
	spin_unlock_irqrestore(&adapter->driver_lock, flags);

	if (allowed) {
1990 1991
		lbs_deb_host("sending lbs_ps_confirm_sleep\n");
		sendconfirmsleep(priv, (u8 *) & adapter->lbs_ps_confirm_sleep,
1992 1993
				 sizeof(struct PS_CMD_ConfirmSleep));
	} else {
1994
		lbs_deb_host("sleep confirm has been delayed\n");
1995 1996
	}

1997
	lbs_deb_leave(LBS_DEB_HOST);
1998
}
1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016


/**
 *  @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
 */
2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036

static int lbs_cmd_callback(uint16_t respcmd, struct cmd_ds_command *resp, struct lbs_private *priv)
{ 
	struct cmd_ds_gen *r = (struct cmd_ds_gen *)resp;
	struct lbs_adapter *adapter = priv->adapter;
	u16 sz = cpu_to_le16(resp->size) - S_DS_GEN;

	if (sz > *adapter->cur_cmd->pdata_size) {
		lbs_pr_err("response 0x%04x doesn't fit into buffer (%d > %d)\n",
			   respcmd, sz, *adapter->cur_cmd->pdata_size);
		sz = *adapter->cur_cmd->pdata_size;
	}
	memcpy(adapter->cur_cmd->pdata_buf, r->cmdresp, sz);
	*adapter->cur_cmd->pdata_size = sz;

	return 0;
}

int lbs_cmd(struct lbs_private *priv, u16 command, void *cmd, int cmd_size,
	    void *rsp, int *rsp_size)
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
{
	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;
2074
	cmdnode->callback = lbs_cmd_callback;
2075 2076 2077 2078

	/* Set sequence number, clean result, move to buffer */
	adapter->seqnum++;
	cmdptr->command = cpu_to_le16(command);
2079
	cmdptr->size    = cpu_to_le16(cmd_size + S_DS_GEN);
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 2108 2109 2110 2111
	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);