cmd.c 57.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/**
  * This file contains the handling of command.
  * It prepares command and sends it to firmware when it is ready.
  */

#include <net/iw_handler.h>
#include "host.h"
#include "hostcmd.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
#include "join.h"
#include "wext.h"
14
#include "cmd.h"
15 16

static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
17 18
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
static void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
19 20 21
		    struct cmd_ctrl_node *ptempnode,
		    u16 wait_option, void *pdata_buf);

22 23

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

40 41 42 43 44 45 46 47
/**
 *  @brief Updates the hardware details like MAC address and regulatory region
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_update_hw_spec(struct lbs_private *priv)
48
{
49 50 51 52
	struct cmd_ds_get_hw_spec cmd;
	int ret = -1;
	u32 i;
	DECLARE_MAC_BUF(mac);
53

54
	lbs_deb_enter(LBS_DEB_CMD);
55

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
	ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, cmd);
	if (ret)
		goto out;

	priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
	memcpy(priv->fwreleasenumber, cmd.fwreleasenumber, 4);

	lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n",
		    priv->fwreleasenumber[2], priv->fwreleasenumber[1],
		    priv->fwreleasenumber[0], priv->fwreleasenumber[3]);
	lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n",
		    print_mac(mac, cmd.permanentaddr));
	lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
		    cmd.hwifversion, cmd.version);

	/* Clamp region code to 8-bit since FW spec indicates that it should
	 * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
	 * returns non-zero high 8 bits here.
	 */
	priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;

	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
		/* use the region code to search for the index */
		if (priv->regioncode == lbs_region_code_to_index[i])
			break;
	}

	/* if it's unidentified region code, use the default (USA) */
	if (i >= MRVDRV_MAX_REGION_CODE) {
		priv->regioncode = 0x10;
		lbs_pr_info("unidentified region code; using the default (USA)\n");
	}

	if (priv->current_addr[0] == 0xff)
		memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
94

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
	memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN);
	if (priv->mesh_dev)
		memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);

	if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
		ret = -1;
		goto out;
	}

	if (lbs_set_universaltable(priv, 0)) {
		ret = -1;
		goto out;
	}

out:
110
	lbs_deb_leave(LBS_DEB_CMD);
111
	return ret;
112 113
}

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
		       uint8_t gpio, uint8_t gap)
{
	struct cmd_ds_host_sleep cmd_config;
	int ret;

	cmd_config.criteria = cpu_to_le32(criteria);
	cmd_config.gpio = gpio;
	cmd_config.gap = gap;

	ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, cmd_config);
	if (ret) {
		lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
		return ret;
	}
	return ret;
}
EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);

133
static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv,
134 135 136 137 138
				   struct cmd_ds_command *cmd,
				   u16 cmd_action)
{
	struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;

139
	lbs_deb_enter(LBS_DEB_CMD);
140

141
	cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
142 143
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
				S_DS_GEN);
144 145
	psm->action = cpu_to_le16(cmd_action);
	psm->multipledtim = 0;
146
	switch (cmd_action) {
147
	case CMD_SUBCMD_ENTER_PS:
148
		lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
149

150
		psm->locallisteninterval = 0;
151
		psm->nullpktinterval = 0;
152
		psm->multipledtim =
153
		    cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
154 155
		break;

156
	case CMD_SUBCMD_EXIT_PS:
157
		lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
158 159
		break;

160
	case CMD_SUBCMD_SLEEP_CONFIRMED:
161
		lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
162 163 164 165 166 167
		break;

	default:
		break;
	}

168
	lbs_deb_leave(LBS_DEB_CMD);
169 170 171
	return 0;
}

172
static int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
173 174 175 176 177
					      struct cmd_ds_command *cmd,
					      u16 cmd_action, void *pdata_buf)
{
	u16 *timeout = pdata_buf;

178 179
	lbs_deb_enter(LBS_DEB_CMD);

180
	cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
181 182 183 184 185 186 187
	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)
188
		cmd->params.inactivity_timeout.timeout = cpu_to_le16(*timeout);
189 190 191
	else
		cmd->params.inactivity_timeout.timeout = 0;

192
	lbs_deb_leave(LBS_DEB_CMD);
193 194 195
	return 0;
}

196
static int lbs_cmd_802_11_sleep_params(struct lbs_private *priv,
197 198 199 200 201
					struct cmd_ds_command *cmd,
					u16 cmd_action)
{
	struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;

202
	lbs_deb_enter(LBS_DEB_CMD);
203

204 205
	cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
				S_DS_GEN);
206
	cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS);
207

208
	if (cmd_action == CMD_ACT_GET) {
209
		memset(&priv->sp, 0, sizeof(struct sleep_params));
210 211
		memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
		sp->action = cpu_to_le16(cmd_action);
212
	} else if (cmd_action == CMD_ACT_SET) {
213
		sp->action = cpu_to_le16(cmd_action);
214 215 216 217 218 219
		sp->error = cpu_to_le16(priv->sp.sp_error);
		sp->offset = cpu_to_le16(priv->sp.sp_offset);
		sp->stabletime = cpu_to_le16(priv->sp.sp_stabletime);
		sp->calcontrol = (u8) priv->sp.sp_calcontrol;
		sp->externalsleepclk = (u8) priv->sp.sp_extsleepclk;
		sp->reserved = cpu_to_le16(priv->sp.sp_reserved);
220 221
	}

222
	lbs_deb_leave(LBS_DEB_CMD);
223 224 225
	return 0;
}

226
static int lbs_cmd_802_11_set_wep(struct lbs_private *priv,
227 228 229 230 231 232 233 234
                                   struct cmd_ds_command *cmd,
                                   u32 cmd_act,
                                   void * pdata_buf)
{
	struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
	int ret = 0;
	struct assoc_request * assoc_req = pdata_buf;

235
	lbs_deb_enter(LBS_DEB_CMD);
236

237
	cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
238
	cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
239

240
	if (cmd_act == CMD_ACT_ADD) {
241 242 243
		int i;

		if (!assoc_req) {
244
			lbs_deb_cmd("Invalid association request!\n");
245 246 247 248
			ret = -1;
			goto done;
		}

249
		wep->action = cpu_to_le16(CMD_ACT_ADD);
250 251

		/* default tx key index */
252
		wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
253
						  (u32)CMD_WEP_KEY_INDEX_MASK));
254 255 256

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

			switch (pkey->len) {
			case KEY_LEN_WEP_40:
H
Holger Schurig 已提交
261
				wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
262 263
				memmove(&wep->keymaterial[i], pkey->key,
				        pkey->len);
264
				lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
265 266
				break;
			case KEY_LEN_WEP_104:
H
Holger Schurig 已提交
267
				wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
268 269
				memmove(&wep->keymaterial[i], pkey->key,
				        pkey->len);
270
				lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
271 272 273 274
				break;
			case 0:
				break;
			default:
275
				lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
276 277 278 279 280 281
				       i, pkey->len);
				ret = -1;
				goto done;
				break;
			}
		}
282
	} else if (cmd_act == CMD_ACT_REMOVE) {
283
		/* ACT_REMOVE clears _all_ WEP keys */
284
		wep->action = cpu_to_le16(CMD_ACT_REMOVE);
285 286

		/* default tx key index */
287
		wep->keyindex = cpu_to_le16((u16)(priv->wep_tx_keyidx &
288
						  (u32)CMD_WEP_KEY_INDEX_MASK));
289
		lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
290 291 292 293 294
	}

	ret = 0;

done:
295
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
296 297 298
	return ret;
}

299
static int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv,
300
				      struct cmd_ds_command *cmd,
301 302
				      u16 cmd_action,
				      void * pdata_buf)
303 304
{
	struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
305
	u32 * enable = pdata_buf;
306 307

	lbs_deb_enter(LBS_DEB_CMD);
308

309
	cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
310
	cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
311
	penableRSN->action = cpu_to_le16(cmd_action);
312

313
	if (cmd_action == CMD_ACT_SET) {
314
		if (*enable)
315
			penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
316
		else
317
			penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
318
		lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
319 320
	}

321
	lbs_deb_leave(LBS_DEB_CMD);
322 323 324 325
	return 0;
}


326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
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);
}

372
static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
373
                            struct enc_key * pkey)
374
{
375 376
	lbs_deb_enter(LBS_DEB_CMD);

377
	if (pkey->flags & KEY_INFO_WPA_ENABLED) {
378
		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
379 380 381
	}
	if (pkey->flags & KEY_INFO_WPA_UNICAST) {
		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
382 383
	}
	if (pkey->flags & KEY_INFO_WPA_MCAST) {
384 385 386 387
		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
	}

	pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
388
	pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
389 390 391 392 393 394
	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));
395
	lbs_deb_leave(LBS_DEB_CMD);
396 397
}

398
static int lbs_cmd_802_11_key_material(struct lbs_private *priv,
399 400 401 402 403 404
					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;
405
	struct assoc_request * assoc_req = pdata_buf;
406 407 408
	int ret = 0;
	int index = 0;

409
	lbs_deb_enter(LBS_DEB_CMD);
410

411
	cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
412 413
	pkeymaterial->action = cpu_to_le16(cmd_action);

414
	if (cmd_action == CMD_ACT_GET) {
415
		cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
416 417 418 419 420 421
		ret = 0;
		goto done;
	}

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

422
	if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
423
		set_one_wpa_key(&pkeymaterial->keyParamSet[index],
424
		                &assoc_req->wpa_unicast_key);
425 426 427
		index++;
	}

428
	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
429
		set_one_wpa_key(&pkeymaterial->keyParamSet[index],
430
		                &assoc_req->wpa_mcast_key);
431 432 433 434
		index++;
	}

	cmd->size = cpu_to_le16(  S_DS_GEN
435 436
	                        + sizeof (pkeymaterial->action)
	                        + (index * sizeof(struct MrvlIEtype_keyParamSet)));
437 438 439 440

	ret = 0;

done:
441
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
442 443 444
	return ret;
}

445
static int lbs_cmd_802_11_reset(struct lbs_private *priv,
446 447 448 449
				 struct cmd_ds_command *cmd, int cmd_action)
{
	struct cmd_ds_802_11_reset *reset = &cmd->params.reset;

450 451
	lbs_deb_enter(LBS_DEB_CMD);

452
	cmd->command = cpu_to_le16(CMD_802_11_RESET);
453 454 455
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
	reset->action = cpu_to_le16(cmd_action);

456
	lbs_deb_leave(LBS_DEB_CMD);
457 458 459
	return 0;
}

460
static int lbs_cmd_802_11_get_log(struct lbs_private *priv,
461 462
				   struct cmd_ds_command *cmd)
{
463
	lbs_deb_enter(LBS_DEB_CMD);
464
	cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
465 466 467
	cmd->size =
		cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);

468
	lbs_deb_leave(LBS_DEB_CMD);
469 470 471
	return 0;
}

472
static int lbs_cmd_802_11_get_stat(struct lbs_private *priv,
473 474
				    struct cmd_ds_command *cmd)
{
475
	lbs_deb_enter(LBS_DEB_CMD);
476
	cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
477
	cmd->size =
478
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
479

480
	lbs_deb_leave(LBS_DEB_CMD);
481 482 483
	return 0;
}

484
static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
485 486 487 488 489 490 491
				    struct cmd_ds_command *cmd,
				    int cmd_action,
				    int cmd_oid, void *pdata_buf)
{
	struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
	u8 ucTemp;

492
	lbs_deb_enter(LBS_DEB_CMD);
493

494
	lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
495

496
	cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
497
	cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
498 499 500 501

	switch (cmd_oid) {
	case OID_802_11_INFRASTRUCTURE_MODE:
	{
502
		u8 mode = (u8) (size_t) pdata_buf;
503 504
		pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
		pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
H
Holger Schurig 已提交
505
		pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8));
506
		if (mode == IW_MODE_ADHOC) {
507
			ucTemp = SNMP_MIB_VALUE_ADHOC;
508 509 510 511
		} else {
			/* Infra and Auto modes */
			ucTemp = SNMP_MIB_VALUE_INFRA;
		}
512 513 514 515 516 517 518 519 520 521

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

		break;
	}

	case OID_802_11D_ENABLE:
		{
			u32 ulTemp;

522
			pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
523

524
			if (cmd_action == CMD_ACT_SET) {
H
Holger Schurig 已提交
525 526
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
527
				ulTemp = *(u32 *)pdata_buf;
528
				*((__le16 *)(pSNMPMIB->value)) =
529 530 531 532 533 534 535 536 537
				    cpu_to_le16((u16) ulTemp);
			}
			break;
		}

	case OID_802_11_FRAGMENTATION_THRESHOLD:
		{
			u32 ulTemp;

538
			pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
539

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

			}

			break;
		}

	case OID_802_11_RTS_THRESHOLD:
		{

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

560 561 562 563
			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);
564 565 566
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
				ulTemp = *((u32 *)pdata_buf);
				*(__le16 *)(pSNMPMIB->value) =
567 568 569 570 571 572
				    cpu_to_le16((u16) ulTemp);

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

575 576 577 578
		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);
579
			pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
580
			*((__le16 *)(pSNMPMIB->value)) =
581
			    cpu_to_le16((u16) priv->txretrycount);
582 583 584 585 586 587 588
		}

		break;
	default:
		break;
	}

589
	lbs_deb_cmd(
590
	       "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
591 592
	       le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
	       le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
593

594
	lbs_deb_cmd(
595
	       "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
596 597 598
	       le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
	       le16_to_cpu(pSNMPMIB->bufsize),
	       le16_to_cpu(*(__le16 *) pSNMPMIB->value));
599

600
	lbs_deb_leave(LBS_DEB_CMD);
601 602 603
	return 0;
}

604
static int lbs_cmd_802_11_radio_control(struct lbs_private *priv,
605 606 607
					 struct cmd_ds_command *cmd,
					 int cmd_action)
{
608
	struct cmd_ds_802_11_radio_control *pradiocontrol = &cmd->params.radio;
609

610
	lbs_deb_enter(LBS_DEB_CMD);
611 612 613 614

	cmd->size =
	    cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
			     S_DS_GEN);
615
	cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL);
616 617 618

	pradiocontrol->action = cpu_to_le16(cmd_action);

619
	switch (priv->preamble) {
620
	case CMD_TYPE_SHORT_PREAMBLE:
621 622 623
		pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
		break;

624
	case CMD_TYPE_LONG_PREAMBLE:
625 626 627
		pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
		break;

628
	case CMD_TYPE_AUTO_PREAMBLE:
629 630 631 632 633
	default:
		pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
		break;
	}

634
	if (priv->radioon)
635 636 637 638
		pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
	else
		pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);

639
	lbs_deb_leave(LBS_DEB_CMD);
640 641 642
	return 0;
}

643
static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv,
644 645 646 647 648 649
				       struct cmd_ds_command *cmd,
				       u16 cmd_action, void *pdata_buf)
{

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

650
	lbs_deb_enter(LBS_DEB_CMD);
651 652

	cmd->size =
653
	    cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
654
	cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
655
	prtp->action = cpu_to_le16(cmd_action);
656

657 658 659
	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));
660 661

	switch (cmd_action) {
662 663
	case CMD_ACT_TX_POWER_OPT_GET:
		prtp->action = cpu_to_le16(CMD_ACT_GET);
664 665 666
		prtp->currentlevel = 0;
		break;

667 668 669
	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);
670 671
		break;

672 673 674
	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);
675 676
		break;

677 678
	case CMD_ACT_TX_POWER_OPT_SET_LOW:
		prtp->action = cpu_to_le16(CMD_ACT_SET);
679 680 681
		prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
		break;
	}
682 683

	lbs_deb_leave(LBS_DEB_CMD);
684 685 686
	return 0;
}

687
static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv,
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
				      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;
}

707
static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
708 709 710 711 712 713
					      struct cmd_ds_command *cmd,
					      u16 cmd_action)
{
	struct cmd_ds_802_11_rate_adapt_rateset
	*rateadapt = &cmd->params.rateset;

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

720
	rateadapt->action = cpu_to_le16(cmd_action);
721 722
	rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
	rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
723

724
	lbs_deb_leave(LBS_DEB_CMD);
725 726 727
	return 0;
}

728 729 730 731 732 733 734 735
/**
 *  @brief Get the current data rate
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *
 *  @return 	   	The data rate on success, error on failure
 */
int lbs_get_data_rate(struct lbs_private *priv)
736
{
737 738
	struct cmd_ds_802_11_data_rate cmd;
	int ret = -1;
739

740
	lbs_deb_enter(LBS_DEB_CMD);
741

742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_GET_TX_RATE);

	ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, cmd);
	if (ret)
		goto out;

	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));

	ret = (int) lbs_fw_index_to_data_rate(cmd.rates[0]);
	lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", ret);

out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}

/**
 *  @brief Set the data rate
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param rate  	The desired data rate, or 0 to clear a locked rate
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
{
	struct cmd_ds_802_11_data_rate cmd;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_CMD);

	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));

	if (rate > 0) {
		cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
		cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
		if (cmd.rates[0] == 0) {
			lbs_deb_cmd("DATA_RATE: invalid requested rate of"
			            " 0x%02X\n", rate);
			ret = 0;
			goto out;
		}
		lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
	} else {
		cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
790
		lbs_deb_cmd("DATA_RATE: setting auto\n");
791 792
	}

793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
	ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, cmd);
	if (ret)
		goto out;

	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));

	/* FIXME: get actual rates FW can do if this command actually returns
	 * all data rates supported.
	 */
	priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
	lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);

out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
808 809
}

810
static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
811 812 813 814 815
				      struct cmd_ds_command *cmd,
				      u16 cmd_action)
{
	struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;

816
	lbs_deb_enter(LBS_DEB_CMD);
817
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
818
			     S_DS_GEN);
819
	cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
820

821
	lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
822 823
	pMCastAdr->action = cpu_to_le16(cmd_action);
	pMCastAdr->nr_of_adrs =
824 825 826
	    cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
	memcpy(pMCastAdr->maclist, priv->multicastlist,
	       priv->nr_of_multicastmacaddr * ETH_ALEN);
827

828
	lbs_deb_leave(LBS_DEB_CMD);
829 830 831
	return 0;
}

832 833 834 835 836 837 838 839
/**
 *  @brief Get the radio channel
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *
 *  @return 	   	The channel on success, error on failure
 */
int lbs_get_channel(struct lbs_private *priv)
840
{
841 842
	struct cmd_ds_802_11_rf_channel cmd;
	int ret = 0;
843

844
	lbs_deb_enter(LBS_DEB_CMD);
845

846 847
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
848

849 850 851
	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, cmd);
	if (ret)
		goto out;
852

853 854
	ret = le16_to_cpu(cmd.channel);
	lbs_deb_cmd("current radio channel is %d\n", ret);
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884

out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}

/**
 *  @brief Set the radio channel
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param channel  	The desired channel, or 0 to clear a locked channel
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_set_channel(struct lbs_private *priv, u8 channel)
{
	struct cmd_ds_802_11_rf_channel cmd;
	u8 old_channel = priv->curbssparams.channel;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_CMD);

	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
	cmd.channel = cpu_to_le16(channel);

	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, cmd);
	if (ret)
		goto out;

885 886 887
	priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel);
	lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
		priv->curbssparams.channel);
888 889 890 891

out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
892 893
}

894
static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
895 896 897
				struct cmd_ds_command *cmd)
{

898
	lbs_deb_enter(LBS_DEB_CMD);
899
	cmd->command = cpu_to_le16(CMD_802_11_RSSI);
900
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
901
	cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
902 903

	/* reset Beacon SNR/NF/RSSI values */
904 905 906 907 908 909
	priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
	priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
	priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
	priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
	priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
	priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
910

911
	lbs_deb_leave(LBS_DEB_CMD);
912 913 914
	return 0;
}

915
static int lbs_cmd_reg_access(struct lbs_private *priv,
916 917 918
			       struct cmd_ds_command *cmdptr,
			       u8 cmd_action, void *pdata_buf)
{
919
	struct lbs_offset_value *offval;
920

921
	lbs_deb_enter(LBS_DEB_CMD);
922

923
	offval = (struct lbs_offset_value *)pdata_buf;
924

H
Holger Schurig 已提交
925
	switch (le16_to_cpu(cmdptr->command)) {
926
	case CMD_MAC_REG_ACCESS:
927 928 929 930
		{
			struct cmd_ds_mac_reg_access *macreg;

			cmdptr->size =
931 932
			    cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
					+ S_DS_GEN);
933 934 935 936 937 938 939 940 941 942 943
			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;
		}

944
	case CMD_BBP_REG_ACCESS:
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962
		{
			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;
		}

963
	case CMD_RF_REG_ACCESS:
964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985
		{
			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;
	}

986
	lbs_deb_leave(LBS_DEB_CMD);
987 988 989
	return 0;
}

990
static int lbs_cmd_802_11_mac_address(struct lbs_private *priv,
991 992 993 994
				       struct cmd_ds_command *cmd,
				       u16 cmd_action)
{

995
	lbs_deb_enter(LBS_DEB_CMD);
996
	cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
997
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
998 999 1000 1001 1002
			     S_DS_GEN);
	cmd->result = 0;

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

1003
	if (cmd_action == CMD_ACT_SET) {
1004
		memcpy(cmd->params.macadd.macadd,
1005 1006
		       priv->current_addr, ETH_ALEN);
		lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6);
1007 1008
	}

1009
	lbs_deb_leave(LBS_DEB_CMD);
1010 1011 1012
	return 0;
}

1013
static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv,
1014 1015 1016
					 struct cmd_ds_command *cmd,
					 int cmd_action, void *pdata_buf)
{
1017
	struct lbs_ioctl_regrdwr *ea = pdata_buf;
1018

1019
	lbs_deb_enter(LBS_DEB_CMD);
1020

1021
	cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
1022 1023
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
				S_DS_GEN);
1024 1025 1026 1027 1028 1029 1030
	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;

1031
	lbs_deb_leave(LBS_DEB_CMD);
1032 1033 1034
	return 0;
}

1035
static int lbs_cmd_bt_access(struct lbs_private *priv,
1036 1037 1038 1039
			       struct cmd_ds_command *cmd,
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
1040
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
1041

1042
	cmd->command = cpu_to_le16(CMD_BT_ACCESS);
1043
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
1044 1045 1046 1047
	cmd->result = 0;
	bt_access->action = cpu_to_le16(cmd_action);

	switch (cmd_action) {
1048
	case CMD_ACT_BT_ACCESS_ADD:
1049
		memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
1050
		lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
1051
		break;
1052
	case CMD_ACT_BT_ACCESS_DEL:
1053
		memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
1054
		lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
1055
		break;
1056
	case CMD_ACT_BT_ACCESS_LIST:
1057 1058
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
1059
	case CMD_ACT_BT_ACCESS_RESET:
1060
		break;
1061
	case CMD_ACT_BT_ACCESS_SET_INVERT:
1062 1063
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
1064
	case CMD_ACT_BT_ACCESS_GET_INVERT:
1065
		break;
1066 1067 1068
	default:
		break;
	}
1069
	lbs_deb_leave(LBS_DEB_CMD);
1070 1071 1072
	return 0;
}

1073
static int lbs_cmd_fwt_access(struct lbs_private *priv,
1074 1075 1076 1077
			       struct cmd_ds_command *cmd,
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
1078
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
1079

1080
	cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
1081
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
1082 1083 1084 1085 1086 1087 1088 1089 1090
	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);

1091
	lbs_deb_leave(LBS_DEB_CMD);
1092 1093 1094
	return 0;
}

1095 1096
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
		    struct cmd_ds_mesh_access *cmd)
1097
{
1098 1099
	int ret;

1100
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
1101

1102 1103 1104
	cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
	cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN);
	cmd->hdr.result = 0;
1105

1106
	cmd->action = cpu_to_le16(cmd_action);
1107

1108
	ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, (*cmd));
1109

1110
	lbs_deb_leave(LBS_DEB_CMD);
1111
	return ret;
1112
}
1113
EXPORT_SYMBOL_GPL(lbs_mesh_access);
1114

1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
int lbs_mesh_config(struct lbs_private *priv, int enable)
{
	struct cmd_ds_mesh_config cmd;

	memset(&cmd, 0, sizeof(cmd));
	cmd.action = cpu_to_le16(enable);
	cmd.channel = cpu_to_le16(priv->curbssparams.channel);
	cmd.type = cpu_to_le16(0x100 + 37);
	
	if (enable) {
		cmd.length = cpu_to_le16(priv->mesh_ssid_len);
		memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len);
	}
1128 1129 1130
	lbs_deb_cmd("mesh config channel %d SSID %s\n",
		    priv->curbssparams.channel,
		    escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
1131 1132 1133
	return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd);
}

1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
				struct cmd_ds_command *cmd,
				u16 cmd_action)
{
	struct cmd_ds_802_11_beacon_control
		*bcn_ctrl = &cmd->params.bcn_ctrl;

	lbs_deb_enter(LBS_DEB_CMD);
	cmd->size =
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
			     + S_DS_GEN);
	cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);

	bcn_ctrl->action = cpu_to_le16(cmd_action);
1148 1149
	bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
	bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
1150 1151 1152 1153 1154

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

1155
/*
1156
 * Note: NEVER use lbs_queue_cmd() with addtail==0 other than for
1157 1158
 * the command timer, because it does not account for queued commands.
 */
1159
void lbs_queue_cmd(struct lbs_private *priv,
1160 1161
	struct cmd_ctrl_node *cmdnode,
	u8 addtail)
1162 1163 1164
{
	unsigned long flags;

1165
	lbs_deb_enter(LBS_DEB_HOST);
1166

1167 1168
	if (!cmdnode || !cmdnode->cmdbuf) {
		lbs_deb_host("QUEUE_CMD: cmdnode or cmdbuf is NULL\n");
1169 1170 1171 1172
		goto done;
	}

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

1176
		if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1177
			if (priv->psstate != PS_STATE_FULL_POWER)
1178 1179 1180 1181
				addtail = 0;
		}
	}

1182
	spin_lock_irqsave(&priv->driver_lock, flags);
1183

1184
	if (addtail)
1185
		list_add_tail(&cmdnode->list, &priv->cmdpendingq);
1186
	else
1187
		list_add(&cmdnode->list, &priv->cmdpendingq);
1188

1189
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1190

1191
	lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
1192
	       le16_to_cpu(cmdnode->cmdbuf->command));
1193 1194

done:
1195
	lbs_deb_leave(LBS_DEB_HOST);
1196 1197 1198 1199
}

/*
 * TODO: Fix the issue when DownloadcommandToStation is being called the
1200
 * second time when the command times out. All the cmdptr->xxx are in little
1201 1202 1203 1204
 * 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
 */
1205
static int DownloadcommandToStation(struct lbs_private *priv,
1206 1207 1208
				    struct cmd_ctrl_node *cmdnode)
{
	unsigned long flags;
1209
	struct cmd_header *cmd;
1210
	int ret = -1;
1211 1212 1213
	u16 cmdsize;
	u16 command;

1214
	lbs_deb_enter(LBS_DEB_HOST);
1215

1216 1217
	if (!priv || !cmdnode) {
		lbs_deb_host("DNLD_CMD: priv or cmdmode is NULL\n");
1218 1219 1220
		goto done;
	}

1221
	cmd = cmdnode->cmdbuf;
1222

1223
	spin_lock_irqsave(&priv->driver_lock, flags);
1224
	if (!cmd || !cmd->size) {
1225
		lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n");
1226
		__lbs_cleanup_and_insert_cmd(priv, cmdnode);
1227
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1228 1229 1230
		goto done;
	}

1231 1232 1233
	priv->cur_cmd = cmdnode;
	priv->cur_cmd_retcode = 0;
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1234

1235 1236
	cmdsize = le16_to_cpu(cmd->size);
	command = le16_to_cpu(cmd->command);
1237

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

1242 1243
	cmdnode->cmdwaitqwoken = 0;

1244
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
1245 1246

	if (ret != 0) {
1247
		lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n");
1248 1249 1250 1251 1252
		spin_lock_irqsave(&priv->driver_lock, flags);
		priv->cur_cmd_retcode = ret;
		__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
		priv->cur_cmd = NULL;
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1253 1254 1255
		goto done;
	}

1256
	lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
1257 1258

	/* Setup the timer after transmit command */
1259 1260
	if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
	    || command == CMD_802_11_ASSOCIATE)
1261
		mod_timer(&priv->command_timer, jiffies + (10*HZ));
1262
	else
1263
		mod_timer(&priv->command_timer, jiffies + (5*HZ));
1264 1265 1266

	ret = 0;

1267
done:
1268
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1269 1270 1271
	return ret;
}

1272
static int lbs_cmd_mac_control(struct lbs_private *priv,
1273 1274 1275 1276
				struct cmd_ds_command *cmd)
{
	struct cmd_ds_mac_control *mac = &cmd->params.macctrl;

1277
	lbs_deb_enter(LBS_DEB_CMD);
1278

1279
	cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
1280
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
1281
	mac->action = cpu_to_le16(priv->currentpacketfilter);
1282

1283
	lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
1284
		    le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
1285

1286
	lbs_deb_leave(LBS_DEB_CMD);
1287 1288 1289 1290 1291
	return 0;
}

/**
 *  This function inserts command node to cmdfreeq
1292
 *  after cleans it. Requires priv->driver_lock held.
1293
 */
1294 1295
void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1296 1297 1298
{

	if (!ptempcmd)
1299
		return;
1300 1301

	cleanup_cmdnode(ptempcmd);
1302
	list_add_tail(&ptempcmd->list, &priv->cmdfreeq);
1303 1304
}

1305 1306
static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1307 1308 1309
{
	unsigned long flags;

1310
	spin_lock_irqsave(&priv->driver_lock, flags);
1311
	__lbs_cleanup_and_insert_cmd(priv, ptempcmd);
1312
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1313 1314
}

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

1319
	lbs_deb_enter(LBS_DEB_CMD);
1320

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

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

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

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

1337
	lbs_deb_enter(LBS_DEB_CMD);
1338 1339

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

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

/**
 *  @brief This function prepare the command before send to firmware.
 *
1350
 *  @param priv		A pointer to struct lbs_private structure
1351 1352 1353 1354 1355 1356 1357
 *  @param cmd_no	command number
 *  @param cmd_action	command action: GET or SET
 *  @param wait_option	wait option: wait response or not
 *  @param cmd_oid	cmd oid: treated as sub command
 *  @param pdata_buf	A pointer to informaion buffer
 *  @return 		0 or -1
 */
1358
int lbs_prepare_and_send_command(struct lbs_private *priv,
1359 1360 1361 1362 1363 1364 1365 1366 1367
			  u16 cmd_no,
			  u16 cmd_action,
			  u16 wait_option, u32 cmd_oid, void *pdata_buf)
{
	int ret = 0;
	struct cmd_ctrl_node *cmdnode;
	struct cmd_ds_command *cmdptr;
	unsigned long flags;

1368
	lbs_deb_enter(LBS_DEB_HOST);
1369

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

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

1382
	cmdnode = lbs_get_cmd_ctrl_node(priv);
1383 1384

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

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

1393
	lbs_set_cmd_ctrl_node(priv, cmdnode, wait_option, pdata_buf);
1394

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

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

	if (!cmdptr) {
1400
		lbs_deb_host("PREP_CMD: cmdptr is NULL\n");
1401
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1402 1403 1404 1405 1406
		ret = -1;
		goto done;
	}

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

1410
	cmdptr->command = cpu_to_le16(cmd_no);
1411 1412 1413
	cmdptr->result = 0;

	switch (cmd_no) {
1414
	case CMD_802_11_PS_MODE:
1415
		ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
1416 1417
		break;

1418
	case CMD_802_11_SCAN:
1419
		ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
1420 1421
		break;

1422
	case CMD_MAC_CONTROL:
1423
		ret = lbs_cmd_mac_control(priv, cmdptr);
1424 1425
		break;

1426 1427
	case CMD_802_11_ASSOCIATE:
	case CMD_802_11_REASSOCIATE:
1428
		ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
1429 1430
		break;

1431
	case CMD_802_11_DEAUTHENTICATE:
1432
		ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
1433 1434
		break;

1435
	case CMD_802_11_SET_WEP:
1436
		ret = lbs_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
1437 1438
		break;

1439
	case CMD_802_11_AD_HOC_START:
1440
		ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
1441
		break;
1442
	case CMD_CODE_DNLD:
1443 1444
		break;

1445
	case CMD_802_11_RESET:
1446
		ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
1447 1448
		break;

1449
	case CMD_802_11_GET_LOG:
1450
		ret = lbs_cmd_802_11_get_log(priv, cmdptr);
1451 1452
		break;

1453
	case CMD_802_11_AUTHENTICATE:
1454
		ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
1455 1456
		break;

1457
	case CMD_802_11_GET_STAT:
1458
		ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
1459 1460
		break;

1461
	case CMD_802_11_SNMP_MIB:
1462
		ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
1463 1464 1465
					       cmd_action, cmd_oid, pdata_buf);
		break;

1466 1467 1468
	case CMD_MAC_REG_ACCESS:
	case CMD_BBP_REG_ACCESS:
	case CMD_RF_REG_ACCESS:
1469
		ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
1470 1471
		break;

1472
	case CMD_802_11_RF_TX_POWER:
1473
		ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
1474 1475 1476
						  cmd_action, pdata_buf);
		break;

1477
	case CMD_802_11_RADIO_CONTROL:
1478
		ret = lbs_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
1479 1480
		break;

1481
	case CMD_802_11_RATE_ADAPT_RATESET:
1482
		ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
1483 1484 1485
							 cmdptr, cmd_action);
		break;

1486
	case CMD_MAC_MULTICAST_ADR:
1487
		ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
1488 1489
		break;

1490
	case CMD_802_11_MONITOR_MODE:
1491
		ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
1492 1493 1494
				          cmd_action, pdata_buf);
		break;

1495
	case CMD_802_11_AD_HOC_JOIN:
1496
		ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
1497 1498
		break;

1499
	case CMD_802_11_RSSI:
1500
		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
1501 1502
		break;

1503
	case CMD_802_11_AD_HOC_STOP:
1504
		ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
1505 1506
		break;

1507
	case CMD_802_11_ENABLE_RSN:
1508
		ret = lbs_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
1509
				pdata_buf);
1510 1511
		break;

1512
	case CMD_802_11_KEY_MATERIAL:
1513
		ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
1514
				cmd_oid, pdata_buf);
1515 1516
		break;

1517
	case CMD_802_11_PAIRWISE_TSC:
1518
		break;
1519
	case CMD_802_11_GROUP_TSC:
1520 1521
		break;

1522
	case CMD_802_11_MAC_ADDRESS:
1523
		ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
1524 1525
		break;

1526
	case CMD_802_11_EEPROM_ACCESS:
1527
		ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
1528 1529 1530
						    cmd_action, pdata_buf);
		break;

1531 1532
	case CMD_802_11_SET_AFC:
	case CMD_802_11_GET_AFC:
1533 1534

		cmdptr->command = cpu_to_le16(cmd_no);
1535 1536
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
					   S_DS_GEN);
1537 1538 1539 1540 1541 1542 1543

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

		ret = 0;
		goto done;

1544
	case CMD_802_11D_DOMAIN_INFO:
1545
		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
1546 1547 1548
						   cmd_no, cmd_action);
		break;

1549
	case CMD_802_11_SLEEP_PARAMS:
1550
		ret = lbs_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
1551
		break;
1552
	case CMD_802_11_INACTIVITY_TIMEOUT:
1553
		ret = lbs_cmd_802_11_inactivity_timeout(priv, cmdptr,
1554
							 cmd_action, pdata_buf);
1555
		lbs_set_cmd_ctrl_node(priv, cmdnode, 0, pdata_buf);
1556 1557
		break;

1558 1559
	case CMD_802_11_TPC_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1560 1561 1562 1563 1564 1565 1566 1567 1568
		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;
1569
	case CMD_802_11_LED_GPIO_CTRL:
1570 1571 1572 1573 1574 1575 1576 1577 1578 1579
		{
			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 =
1580
			    cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
1581 1582 1583

#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
			cmdptr->size =
H
Holger Schurig 已提交
1584 1585 1586 1587
			    cpu_to_le16(le16_to_cpu(gpio->header.len)
				+ S_DS_GEN
				+ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
			gpio->header.len = gpio->header.len;
1588 1589 1590 1591

			ret = 0;
			break;
		}
1592 1593 1594 1595
	case CMD_802_11_SUBSCRIBE_EVENT:
		lbs_cmd_802_11_subscribe_event(priv, cmdptr,
			cmd_action, pdata_buf);
		break;
1596 1597
	case CMD_802_11_PWR_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
1598 1599 1600 1601 1602 1603 1604 1605
		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;
1606
	case CMD_BT_ACCESS:
1607
		ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
1608 1609
		break;

1610
	case CMD_FWT_ACCESS:
1611
		ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
1612 1613
		break;

1614 1615
	case CMD_GET_TSF:
		cmdptr->command = cpu_to_le16(CMD_GET_TSF);
1616 1617
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
					   S_DS_GEN);
1618 1619
		ret = 0;
		break;
1620 1621 1622
	case CMD_802_11_BEACON_CTRL:
		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
		break;
1623
	default:
1624
		lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
1625 1626 1627 1628 1629 1630
		ret = -1;
		break;
	}

	/* return error, since the command preparation failed */
	if (ret != 0) {
1631
		lbs_deb_host("PREP_CMD: command preparation failed\n");
1632
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1633 1634 1635 1636 1637 1638
		ret = -1;
		goto done;
	}

	cmdnode->cmdwaitqwoken = 0;

1639
	lbs_queue_cmd(priv, cmdnode, 1);
1640
	wake_up_interruptible(&priv->waitq);
1641

1642
	if (wait_option & CMD_OPTION_WAITFORRSP) {
1643
		lbs_deb_host("PREP_CMD: wait for response\n");
1644 1645 1646 1647 1648
		might_sleep();
		wait_event_interruptible(cmdnode->cmdwait_q,
					 cmdnode->cmdwaitqwoken);
	}

1649 1650
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd_retcode) {
1651
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
1652 1653
		       priv->cur_cmd_retcode);
		priv->cur_cmd_retcode = 0;
1654 1655
		ret = -1;
	}
1656
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1657 1658

done:
1659
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1660 1661
	return ret;
}
1662
EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
1663 1664 1665 1666 1667

/**
 *  @brief This function allocates the command buffer and link
 *  it to command free queue.
 *
1668
 *  @param priv		A pointer to struct lbs_private structure
1669 1670
 *  @return 		0 or -1
 */
1671
int lbs_allocate_cmd_buffer(struct lbs_private *priv)
1672 1673
{
	int ret = 0;
1674
	u32 bufsize;
1675
	u32 i;
1676
	struct cmd_ctrl_node *cmdarray;
1677

1678
	lbs_deb_enter(LBS_DEB_HOST);
1679

1680 1681 1682
	/* Allocate and initialize the command array */
	bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
	if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
1683
		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
1684 1685 1686
		ret = -1;
		goto done;
	}
1687
	priv->cmd_array = cmdarray;
1688

1689 1690 1691 1692
	/* Allocate and initialize each command buffer in the command array */
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
		if (!cmdarray[i].cmdbuf) {
1693
			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
1694 1695 1696 1697 1698
			ret = -1;
			goto done;
		}
	}

1699 1700 1701
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		init_waitqueue_head(&cmdarray[i].cmdwait_q);
		lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
1702 1703
	}
	ret = 0;
1704 1705

done:
1706
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1707 1708 1709 1710 1711 1712
	return ret;
}

/**
 *  @brief This function frees the command buffer.
 *
1713
 *  @param priv		A pointer to struct lbs_private structure
1714 1715
 *  @return 		0 or -1
 */
1716
int lbs_free_cmd_buffer(struct lbs_private *priv)
1717
{
1718
	struct cmd_ctrl_node *cmdarray;
1719 1720
	unsigned int i;

1721
	lbs_deb_enter(LBS_DEB_HOST);
1722 1723

	/* need to check if cmd array is allocated or not */
1724
	if (priv->cmd_array == NULL) {
1725
		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
1726 1727 1728
		goto done;
	}

1729
	cmdarray = priv->cmd_array;
1730 1731

	/* Release shared memory buffers */
1732 1733 1734 1735
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		if (cmdarray[i].cmdbuf) {
			kfree(cmdarray[i].cmdbuf);
			cmdarray[i].cmdbuf = NULL;
1736 1737 1738 1739
		}
	}

	/* Release cmd_ctrl_node */
1740 1741 1742
	if (priv->cmd_array) {
		kfree(priv->cmd_array);
		priv->cmd_array = NULL;
1743 1744 1745
	}

done:
1746
	lbs_deb_leave(LBS_DEB_HOST);
1747 1748 1749 1750 1751 1752 1753
	return 0;
}

/**
 *  @brief This function gets a free command node if available in
 *  command free queue.
 *
1754
 *  @param priv		A pointer to struct lbs_private structure
1755 1756
 *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
 */
1757
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
1758 1759 1760 1761
{
	struct cmd_ctrl_node *tempnode;
	unsigned long flags;

1762 1763
	lbs_deb_enter(LBS_DEB_HOST);

1764
	if (!priv)
1765 1766
		return NULL;

1767
	spin_lock_irqsave(&priv->driver_lock, flags);
1768

1769 1770
	if (!list_empty(&priv->cmdfreeq)) {
		tempnode = list_first_entry(&priv->cmdfreeq,
1771 1772
					    struct cmd_ctrl_node, list);
		list_del(&tempnode->list);
1773
	} else {
1774
		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
1775 1776 1777
		tempnode = NULL;
	}

1778
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1779

1780
	if (tempnode)
1781 1782
		cleanup_cmdnode(tempnode);

1783
	lbs_deb_leave(LBS_DEB_HOST);
1784 1785 1786 1787 1788 1789 1790 1791 1792
	return tempnode;
}

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

1797
	if (!cmdnode)
1798
		return;
1799 1800 1801 1802 1803 1804
	cmdnode->cmdwaitqwoken = 1;
	wake_up_interruptible(&cmdnode->cmdwait_q);
	cmdnode->wait_option = 0;
	cmdnode->pdata_buf = NULL;
	cmdnode->callback = NULL;
	cmdnode->callback_arg = 0;
1805

1806 1807
	if (cmdnode->cmdbuf != NULL)
		memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
1808 1809

	lbs_deb_leave(LBS_DEB_HOST);
1810 1811 1812 1813 1814
}

/**
 *  @brief This function initializes the command node.
 *
1815
 *  @param priv		A pointer to struct lbs_private structure
1816 1817 1818 1819 1820
 *  @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
 */
1821 1822 1823
static void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
				  struct cmd_ctrl_node *ptempnode,
				  u16 wait_option, void *pdata_buf)
1824
{
1825
	lbs_deb_enter(LBS_DEB_HOST);
1826 1827 1828 1829 1830 1831

	if (!ptempnode)
		return;

	ptempnode->wait_option = wait_option;
	ptempnode->pdata_buf = pdata_buf;
1832
	ptempnode->callback = NULL;
1833
	ptempnode->callback_arg = 0;
1834

1835
	lbs_deb_leave(LBS_DEB_HOST);
1836 1837 1838 1839 1840 1841 1842
}

/**
 *  @brief This function executes next command in command
 *  pending queue. It will put fimware back to PS mode
 *  if applicable.
 *
1843
 *  @param priv     A pointer to struct lbs_private structure
1844 1845
 *  @return 	   0 or -1
 */
1846
int lbs_execute_next_command(struct lbs_private *priv)
1847 1848
{
	struct cmd_ctrl_node *cmdnode = NULL;
1849
	struct cmd_header *cmd;
1850 1851 1852
	unsigned long flags;
	int ret = 0;

1853
	// Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
1854
	// only caller to us is lbs_thread() and we get even when a
1855 1856
	// data packet is received
	lbs_deb_enter(LBS_DEB_THREAD);
1857

1858
	spin_lock_irqsave(&priv->driver_lock, flags);
1859

1860
	if (priv->cur_cmd) {
1861
		lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
1862
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1863 1864 1865 1866
		ret = -1;
		goto done;
	}

1867 1868
	if (!list_empty(&priv->cmdpendingq)) {
		cmdnode = list_first_entry(&priv->cmdpendingq,
1869
					   struct cmd_ctrl_node, list);
1870 1871
	}

1872
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1873 1874

	if (cmdnode) {
1875
		cmd = cmdnode->cmdbuf;
1876

1877
		if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
1878 1879
			if ((priv->psstate == PS_STATE_SLEEP) ||
			    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1880 1881
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
1882
				       le16_to_cpu(cmd->command),
1883
				       priv->psstate);
1884 1885 1886
				ret = -1;
				goto done;
			}
1887
			lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
1888 1889
				     "0x%04x in psstate %d\n",
				     le16_to_cpu(cmd->command), priv->psstate);
1890
		} else if (priv->psstate != PS_STATE_FULL_POWER) {
1891 1892 1893
			/*
			 * 1. Non-PS command:
			 * Queue it. set needtowakeup to TRUE if current state
1894
			 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
1895 1896 1897 1898 1899 1900 1901
			 * 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.
			 */
1902
			if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
1903 1904
				/*  Prepare to send Exit PS,
				 *  this non PS command will be sent later */
1905 1906
				if ((priv->psstate == PS_STATE_SLEEP)
				    || (priv->psstate == PS_STATE_PRE_SLEEP)
1907 1908 1909
				    ) {
					/* w/ new scheme, it will not reach here.
					   since it is blocked in main_thread. */
1910
					priv->needtowakeup = 1;
1911
				} else
1912
					lbs_ps_wakeup(priv, 0);
1913 1914 1915 1916 1917 1918 1919 1920

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

1923 1924
				lbs_deb_host(
				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
1925 1926
				       psm->action);
				if (psm->action !=
1927
				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1928 1929
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
1930
					list_del(&cmdnode->list);
1931
					lbs_cleanup_and_insert_cmd(priv, cmdnode);
1932 1933 1934 1935 1936

					ret = 0;
					goto done;
				}

1937 1938
				if ((priv->psstate == PS_STATE_SLEEP) ||
				    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1939 1940
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
1941
					list_del(&cmdnode->list);
1942
					lbs_cleanup_and_insert_cmd(priv, cmdnode);
1943
					priv->needtowakeup = 1;
1944 1945 1946 1947 1948

					ret = 0;
					goto done;
				}

1949 1950
				lbs_deb_host(
				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
1951 1952
			}
		}
1953
		list_del(&cmdnode->list);
1954
		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
1955
			    le16_to_cpu(cmd->command));
1956 1957 1958 1959 1960 1961
		DownloadcommandToStation(priv, cmdnode);
	} else {
		/*
		 * check if in power save mode, if yes, put the device back
		 * to PS mode
		 */
1962 1963 1964 1965 1966 1967
		if ((priv->psmode != LBS802_11POWERMODECAM) &&
		    (priv->psstate == PS_STATE_FULL_POWER) &&
		    ((priv->connect_status == LBS_CONNECTED) ||
		    (priv->mesh_connect_status == LBS_CONNECTED))) {
			if (priv->secinfo.WPAenabled ||
			    priv->secinfo.WPA2enabled) {
1968
				/* check for valid WPA group keys */
1969 1970
				if (priv->wpa_mcast_key.len ||
				    priv->wpa_unicast_key.len) {
1971
					lbs_deb_host(
1972 1973
					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
					       " go back to PS_SLEEP");
1974
					lbs_ps_sleep(priv, 0);
1975 1976
				}
			} else {
1977 1978 1979
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cmdpendingq empty, "
				       "go back to PS_SLEEP");
1980
				lbs_ps_sleep(priv, 0);
1981 1982 1983 1984 1985 1986
			}
		}
	}

	ret = 0;
done:
1987
	lbs_deb_leave(LBS_DEB_THREAD);
1988 1989 1990
	return ret;
}

1991
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
1992 1993 1994 1995
{
	union iwreq_data iwrq;
	u8 buf[50];

1996
	lbs_deb_enter(LBS_DEB_WEXT);
1997 1998 1999 2000 2001 2002 2003 2004 2005

	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 */
2006 2007 2008
	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);
2009

2010
	wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
2011

2012
	lbs_deb_leave(LBS_DEB_WEXT);
2013 2014
}

2015
static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
2016 2017 2018 2019
{
	unsigned long flags;
	int ret = 0;

2020
	lbs_deb_enter(LBS_DEB_HOST);
2021

2022
	lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
2023 2024
	       size);

2025
	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
2026

2027
	ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
2028
	priv->dnld_sent = DNLD_RES_RECEIVED;
2029

2030 2031
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->intcounter || priv->currenttxskb)
2032
		lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
2033 2034
		       priv->intcounter, priv->currenttxskb);
	spin_unlock_irqrestore(&priv->driver_lock, flags);
2035 2036 2037 2038 2039

	if (ret) {
		lbs_pr_alert(
		       "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
	} else {
2040 2041 2042
		spin_lock_irqsave(&priv->driver_lock, flags);
		if (!priv->intcounter) {
			priv->psstate = PS_STATE_SLEEP;
2043
		} else {
2044
			lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
2045
			       priv->intcounter);
2046
		}
2047
		spin_unlock_irqrestore(&priv->driver_lock, flags);
2048

2049
		lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
2050 2051
	}

2052
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
2053 2054 2055
	return ret;
}

2056
void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
2057
{
2058
	lbs_deb_enter(LBS_DEB_HOST);
2059 2060 2061 2062 2063 2064

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

2065
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
2066
			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
2067

2068
	lbs_deb_leave(LBS_DEB_HOST);
2069 2070 2071
}

/**
2072
 *  @brief This function sends Exit_PS command to firmware.
2073
 *
2074
 *  @param priv    	A pointer to struct lbs_private structure
2075 2076 2077
 *  @param wait_option	wait response or not
 *  @return 	   	n/a
 */
2078
void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
2079
{
2080
	__le32 Localpsmode;
2081

2082
	lbs_deb_enter(LBS_DEB_HOST);
2083

2084
	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
2085

2086
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
2087
			      CMD_SUBCMD_EXIT_PS,
2088 2089
			      wait_option, 0, &Localpsmode);

2090
	lbs_deb_leave(LBS_DEB_HOST);
2091 2092 2093 2094 2095 2096
}

/**
 *  @brief This function checks condition and prepares to
 *  send sleep confirm command to firmware if ok.
 *
2097
 *  @param priv    	A pointer to struct lbs_private structure
2098 2099 2100
 *  @param psmode  	Power Saving mode
 *  @return 	   	n/a
 */
2101
void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode)
2102 2103 2104 2105
{
	unsigned long flags =0;
	u8 allowed = 1;

2106
	lbs_deb_enter(LBS_DEB_HOST);
2107

2108
	if (priv->dnld_sent) {
2109
		allowed = 0;
2110
		lbs_deb_host("dnld_sent was set\n");
2111 2112
	}

2113 2114
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd) {
2115
		allowed = 0;
2116
		lbs_deb_host("cur_cmd was set\n");
2117
	}
2118
	if (priv->intcounter > 0) {
2119
		allowed = 0;
2120
		lbs_deb_host("intcounter %d\n", priv->intcounter);
2121
	}
2122
	spin_unlock_irqrestore(&priv->driver_lock, flags);
2123 2124

	if (allowed) {
2125
		lbs_deb_host("sending lbs_ps_confirm_sleep\n");
2126
		sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep,
2127 2128
				 sizeof(struct PS_CMD_ConfirmSleep));
	} else {
2129
		lbs_deb_host("sleep confirm has been delayed\n");
2130 2131
	}

2132
	lbs_deb_leave(LBS_DEB_HOST);
2133
}
2134 2135


2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146
/**
 *  @brief Simple callback that copies response back into command
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param extra  	A pointer to the original command structure for which
 *                      'resp' is a response
 *  @param resp         A pointer to the command response
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
2147
		     struct cmd_header *resp)
2148 2149 2150 2151 2152 2153 2154 2155
{
	struct cmd_header *buf = (void *)extra;
	uint16_t copy_len;

	lbs_deb_enter(LBS_DEB_CMD);

	copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
	lbs_deb_cmd("Copying back %u bytes; command response was %u bytes, "
2156 2157
		    "copy back buffer was %u bytes\n", copy_len,
		    le16_to_cpu(resp->size), le16_to_cpu(buf->size));
2158 2159 2160 2161 2162 2163
	memcpy(buf, resp, copy_len);

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179
/**
 *  @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
 */
2180 2181 2182
int __lbs_cmd(struct lbs_private *priv, uint16_t command,
	      struct cmd_header *in_cmd, int in_cmd_size,
	      int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
2183
	      unsigned long callback_arg)
2184 2185 2186 2187 2188 2189 2190
{
	struct cmd_ctrl_node *cmdnode;
	unsigned long flags;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_HOST);

2191 2192
	if (!priv) {
		lbs_deb_host("PREP_CMD: priv is NULL\n");
2193 2194 2195 2196
		ret = -1;
		goto done;
	}

2197
	if (priv->surpriseremoved) {
2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213
		lbs_deb_host("PREP_CMD: card removed\n");
		ret = -1;
		goto done;
	}

	cmdnode = lbs_get_cmd_ctrl_node(priv);
	if (cmdnode == NULL) {
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");

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

	cmdnode->wait_option = CMD_OPTION_WAITFORRSP;
2214
	cmdnode->callback = callback;
2215
	cmdnode->callback_arg = callback_arg;
2216

2217
	/* Copy the incoming command to the buffer */
2218
	memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
2219

2220
	/* Set sequence number, clean result, move to buffer */
2221
	priv->seqnum++;
2222 2223 2224 2225
	cmdnode->cmdbuf->command = cpu_to_le16(command);
	cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
	cmdnode->cmdbuf->seqnum  = cpu_to_le16(priv->seqnum);
	cmdnode->cmdbuf->result  = 0;
2226 2227 2228 2229 2230 2231 2232

	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;
2233
	lbs_queue_cmd(priv, cmdnode, 1);
2234 2235 2236 2237 2238
	wake_up_interruptible(&priv->waitq);

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

2239 2240
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd_retcode) {
2241
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
2242 2243
		       priv->cur_cmd_retcode);
		priv->cur_cmd_retcode = 0;
2244 2245
		ret = -1;
	}
2246
	spin_unlock_irqrestore(&priv->driver_lock, flags);
2247 2248 2249 2250 2251

done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
	return ret;
}
2252
EXPORT_SYMBOL_GPL(__lbs_cmd);
2253 2254