cmd.c 54.3 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);
H
Holger Schurig 已提交
434
		pSNMPMIB->bufsize = cpu_to_le16(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
			if (cmd_action == CMD_ACT_SET) {
H
Holger Schurig 已提交
454 455
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
456
				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;
H
Holger Schurig 已提交
487
			pSNMPMIB->oid = cpu_to_le16(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

H
Holger Schurig 已提交
762
	switch (le16_to_cpu(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. */
H
Holger Schurig 已提交
1002
	if (le16_to_cpu(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
	else
1015
		list_add(&cmdnode->list, &adapter->cmdpendingq);
1016 1017 1018

	spin_unlock_irqrestore(&adapter->driver_lock, flags);

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

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

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

1043
	lbs_deb_enter(LBS_DEB_HOST);
1044 1045

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

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

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

H
Holger Schurig 已提交
1064 1065
	cmdsize = le16_to_cpu(cmdptr->size);
	command = le16_to_cpu(cmdptr->command);
1066

1067
	lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n",
H
Holger Schurig 已提交
1068
		    command, cmdsize, jiffies);
1069 1070
	lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize);

1071 1072
	cmdnode->cmdwaitqwoken = 0;

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

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

1085
	lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
1086 1087

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

	ret = 0;

1096
done:
1097
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1098 1099 1100
	return ret;
}

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

1106
	lbs_deb_enter(LBS_DEB_CMD);
1107

1108
	cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
1109
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
1110 1111
	mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);

1112
	lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
1113
		    le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
1114

1115
	lbs_deb_leave(LBS_DEB_CMD);
1116 1117 1118 1119 1120 1121 1122
	return 0;
}

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

	if (!ptempcmd)
1129
		return;
1130 1131

	cleanup_cmdnode(ptempcmd);
1132
	list_add_tail(&ptempcmd->list, &adapter->cmdfreeq);
1133 1134
}

1135 1136
static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1137 1138 1139 1140
{
	unsigned long flags;

	spin_lock_irqsave(&priv->adapter->driver_lock, flags);
1141
	__lbs_cleanup_and_insert_cmd(priv, ptempcmd);
1142 1143 1144
	spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
}

1145
int lbs_set_radio_control(struct lbs_private *priv)
1146 1147 1148
{
	int ret = 0;

1149
	lbs_deb_enter(LBS_DEB_CMD);
1150

1151
	ret = lbs_prepare_and_send_command(priv,
1152 1153 1154
				    CMD_802_11_RADIO_CONTROL,
				    CMD_ACT_SET,
				    CMD_OPTION_WAITFORRSP, 0, NULL);
1155

1156
	lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n",
1157 1158
	       priv->adapter->radioon, priv->adapter->preamble);

1159
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1160 1161 1162
	return ret;
}

1163
int lbs_set_mac_packet_filter(struct lbs_private *priv)
1164 1165 1166
{
	int ret = 0;

1167
	lbs_deb_enter(LBS_DEB_CMD);
1168 1169

	/* Send MAC control command to station */
1170
	ret = lbs_prepare_and_send_command(priv,
1171
				    CMD_MAC_CONTROL, 0, 0, 0, NULL);
1172

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

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

1199
	lbs_deb_enter(LBS_DEB_HOST);
1200 1201

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

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

1213
	cmdnode = lbs_get_cmd_ctrl_node(priv);
1214 1215

	if (cmdnode == NULL) {
1216
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1217 1218

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

1224
	lbs_set_cmd_ctrl_node(priv, cmdnode, wait_option, pdata_buf);
1225 1226 1227

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

1228
	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
1229 1230

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

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

1241
	cmdptr->command = cpu_to_le16(cmd_no);
1242 1243 1244
	cmdptr->result = 0;

	switch (cmd_no) {
1245
	case CMD_GET_HW_SPEC:
1246
		ret = lbs_cmd_hw_spec(priv, cmdptr);
1247
		break;
1248
	case CMD_802_11_PS_MODE:
1249
		ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
1250 1251
		break;

1252
	case CMD_802_11_SCAN:
1253
		ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
1254 1255
		break;

1256
	case CMD_MAC_CONTROL:
1257
		ret = lbs_cmd_mac_control(priv, cmdptr);
1258 1259
		break;

1260 1261
	case CMD_802_11_ASSOCIATE:
	case CMD_802_11_REASSOCIATE:
1262
		ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
1263 1264
		break;

1265
	case CMD_802_11_DEAUTHENTICATE:
1266
		ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
1267 1268
		break;

1269
	case CMD_802_11_SET_WEP:
1270
		ret = lbs_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
1271 1272
		break;

1273
	case CMD_802_11_AD_HOC_START:
1274
		ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
1275
		break;
1276
	case CMD_CODE_DNLD:
1277 1278
		break;

1279
	case CMD_802_11_RESET:
1280
		ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
1281 1282
		break;

1283
	case CMD_802_11_GET_LOG:
1284
		ret = lbs_cmd_802_11_get_log(priv, cmdptr);
1285 1286
		break;

1287
	case CMD_802_11_AUTHENTICATE:
1288
		ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
1289 1290
		break;

1291
	case CMD_802_11_GET_STAT:
1292
		ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
1293 1294
		break;

1295
	case CMD_802_11_SNMP_MIB:
1296
		ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
1297 1298 1299
					       cmd_action, cmd_oid, pdata_buf);
		break;

1300 1301 1302
	case CMD_MAC_REG_ACCESS:
	case CMD_BBP_REG_ACCESS:
	case CMD_RF_REG_ACCESS:
1303
		ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
1304 1305
		break;

1306
	case CMD_802_11_RF_CHANNEL:
1307
		ret = lbs_cmd_802_11_rf_channel(priv, cmdptr,
1308 1309 1310
						 cmd_action, pdata_buf);
		break;

1311
	case CMD_802_11_RF_TX_POWER:
1312
		ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
1313 1314 1315
						  cmd_action, pdata_buf);
		break;

1316
	case CMD_802_11_RADIO_CONTROL:
1317
		ret = lbs_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
1318 1319
		break;

1320
	case CMD_802_11_DATA_RATE:
1321
		ret = lbs_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
1322
		break;
1323
	case CMD_802_11_RATE_ADAPT_RATESET:
1324
		ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
1325 1326 1327
							 cmdptr, cmd_action);
		break;

1328
	case CMD_MAC_MULTICAST_ADR:
1329
		ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
1330 1331
		break;

1332
	case CMD_802_11_MONITOR_MODE:
1333
		ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
1334 1335 1336
				          cmd_action, pdata_buf);
		break;

1337
	case CMD_802_11_AD_HOC_JOIN:
1338
		ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
1339 1340
		break;

1341
	case CMD_802_11_RSSI:
1342
		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
1343 1344
		break;

1345
	case CMD_802_11_AD_HOC_STOP:
1346
		ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
1347 1348
		break;

1349
	case CMD_802_11_ENABLE_RSN:
1350
		ret = lbs_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
1351
				pdata_buf);
1352 1353
		break;

1354
	case CMD_802_11_KEY_MATERIAL:
1355
		ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
1356
				cmd_oid, pdata_buf);
1357 1358
		break;

1359
	case CMD_802_11_PAIRWISE_TSC:
1360
		break;
1361
	case CMD_802_11_GROUP_TSC:
1362 1363
		break;

1364
	case CMD_802_11_MAC_ADDRESS:
1365
		ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
1366 1367
		break;

1368
	case CMD_802_11_EEPROM_ACCESS:
1369
		ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
1370 1371 1372
						    cmd_action, pdata_buf);
		break;

1373 1374
	case CMD_802_11_SET_AFC:
	case CMD_802_11_GET_AFC:
1375 1376

		cmdptr->command = cpu_to_le16(cmd_no);
1377 1378
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
					   S_DS_GEN);
1379 1380 1381 1382 1383 1384 1385

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

		ret = 0;
		goto done;

1386
	case CMD_802_11D_DOMAIN_INFO:
1387
		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
1388 1389 1390
						   cmd_no, cmd_action);
		break;

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

1400 1401
	case CMD_802_11_TPC_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1402 1403 1404 1405 1406 1407 1408 1409 1410
		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;
1411
	case CMD_802_11_LED_GPIO_CTRL:
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
		{
			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 =
1422
			    cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
1423 1424 1425

#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
			cmdptr->size =
H
Holger Schurig 已提交
1426 1427 1428 1429
			    cpu_to_le16(le16_to_cpu(gpio->header.len)
				+ S_DS_GEN
				+ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
			gpio->header.len = gpio->header.len;
1430 1431 1432 1433

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

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

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

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

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

	cmdnode->cmdwaitqwoken = 0;

1485
	lbs_queue_cmd(adapter, cmdnode, 1);
1486
	wake_up_interruptible(&priv->waitq);
1487

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

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

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

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

1526
	lbs_deb_enter(LBS_DEB_HOST);
1527 1528 1529 1530

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

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

	ret = 0;
1557 1558

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

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

1576
	lbs_deb_enter(LBS_DEB_HOST);
1577 1578 1579

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

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

1619 1620
	lbs_deb_enter(LBS_DEB_HOST);

1621 1622 1623 1624 1625 1626
	if (!adapter)
		return NULL;

	spin_lock_irqsave(&adapter->driver_lock, flags);

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

	spin_unlock_irqrestore(&adapter->driver_lock, flags);

1637
	if (tempnode)
1638 1639
		cleanup_cmdnode(tempnode);

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

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

	if (ptempnode->bufvirtualaddr != NULL)
		memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
1664 1665

	lbs_deb_leave(LBS_DEB_HOST);
1666 1667 1668 1669 1670
}

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

	if (!ptempnode)
		return;

	ptempnode->wait_option = wait_option;
	ptempnode->pdata_buf = pdata_buf;
1688
	ptempnode->callback = NULL;
1689

1690
	lbs_deb_leave(LBS_DEB_HOST);
1691 1692 1693 1694 1695 1696 1697
}

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

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

	spin_lock_irqsave(&adapter->driver_lock, flags);

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

	if (!list_empty(&adapter->cmdpendingq)) {
1724 1725
		cmdnode = list_first_entry(&adapter->cmdpendingq,
					   struct cmd_ctrl_node, list);
1726 1727 1728 1729 1730 1731 1732 1733
	}

	spin_unlock_irqrestore(&adapter->driver_lock, flags);

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

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

				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;

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

					ret = 0;
					goto done;
				}

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

					ret = 0;
					goto done;
				}

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

	ret = 0;
done:
1846
	lbs_deb_leave(LBS_DEB_THREAD);
1847 1848 1849
	return ret;
}

1850
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
1851 1852 1853 1854
{
	union iwreq_data iwrq;
	u8 buf[50];

1855
	lbs_deb_enter(LBS_DEB_WEXT);
1856 1857 1858 1859 1860 1861 1862 1863 1864

	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 */
1865 1866 1867
	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);
1868

1869
	wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
1870

1871
	lbs_deb_leave(LBS_DEB_WEXT);
1872 1873
}

1874
static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
1875 1876
{
	unsigned long flags;
1877
	struct lbs_adapter *adapter = priv->adapter;
1878 1879
	int ret = 0;

1880
	lbs_deb_enter(LBS_DEB_HOST);
1881

1882
	lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
1883 1884
	       size);

1885
	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
1886

1887
	ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
1888
	priv->dnld_sent = DNLD_RES_RECEIVED;
1889 1890 1891

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

1909
		lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
1910 1911
	}

1912
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1913 1914 1915
	return ret;
}

1916
void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
1917
{
1918
	lbs_deb_enter(LBS_DEB_HOST);
1919 1920 1921 1922 1923 1924

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

1925
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1926
			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
1927

1928
	lbs_deb_leave(LBS_DEB_HOST);
1929 1930 1931
}

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

1942
	lbs_deb_enter(LBS_DEB_HOST);
1943

1944
	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
1945

1946
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1947
			      CMD_SUBCMD_EXIT_PS,
1948 1949
			      wait_option, 0, &Localpsmode);

1950
	lbs_deb_leave(LBS_DEB_HOST);
1951 1952 1953 1954 1955 1956
}

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

1967
	lbs_deb_enter(LBS_DEB_HOST);
1968

1969
	if (priv->dnld_sent) {
1970
		allowed = 0;
1971
		lbs_deb_host("dnld_sent was set");
1972 1973 1974 1975 1976
	}

	spin_lock_irqsave(&adapter->driver_lock, flags);
	if (adapter->cur_cmd) {
		allowed = 0;
1977
		lbs_deb_host("cur_cmd was set");
1978 1979 1980
	}
	if (adapter->intcounter > 0) {
		allowed = 0;
1981
		lbs_deb_host("intcounter %d", adapter->intcounter);
1982 1983 1984 1985
	}
	spin_unlock_irqrestore(&adapter->driver_lock, flags);

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

1993
	lbs_deb_leave(LBS_DEB_HOST);
1994
}
1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012


/**
 *  @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
 */
2013

2014 2015
int lbs_cmd(struct lbs_private *priv, uint16_t command, void *cmd, int cmd_size,
	    int (*callback)(uint16_t, struct cmd_ds_command *, struct lbs_private *))
2016 2017 2018 2019 2020 2021 2022 2023 2024
{
	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);

2025
	if (!adapter) {
2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049
		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;
2050
	cmdnode->callback = callback;
2051 2052 2053 2054

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