Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
   1/*
   2 * Marvell Wireless LAN device driver: station command handling
   3 *
   4 * Copyright (C) 2011, Marvell International Ltd.
   5 *
   6 * This software file (the "File") is distributed by Marvell International
   7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
   8 * (the "License").  You may use, redistribute and/or modify this File in
   9 * accordance with the terms and conditions of the License, a copy of which
  10 * is available by writing to the Free Software Foundation, Inc.,
  11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
  12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
  13 *
  14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
  15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
  16 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
  17 * this warranty disclaimer.
  18 */
  19
  20#include "decl.h"
  21#include "ioctl.h"
  22#include "util.h"
  23#include "fw.h"
  24#include "main.h"
  25#include "wmm.h"
  26#include "11n.h"
  27
  28/*
  29 * This function prepares command to set/get RSSI information.
  30 *
  31 * Preparation includes -
  32 *      - Setting command ID, action and proper size
  33 *      - Setting data/beacon average factors
  34 *      - Resetting SNR/NF/RSSI values in private structure
  35 *      - Ensuring correct endian-ness
  36 */
  37static int
  38mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv,
  39			     struct host_cmd_ds_command *cmd, u16 cmd_action)
  40{
  41	cmd->command = cpu_to_le16(HostCmd_CMD_RSSI_INFO);
  42	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rssi_info) +
  43				S_DS_GEN);
  44	cmd->params.rssi_info.action = cpu_to_le16(cmd_action);
  45	cmd->params.rssi_info.ndata = cpu_to_le16(priv->data_avg_factor);
  46	cmd->params.rssi_info.nbcn = cpu_to_le16(priv->bcn_avg_factor);
  47
  48	/* Reset SNR/NF/RSSI values in private structure */
  49	priv->data_rssi_last = 0;
  50	priv->data_nf_last = 0;
  51	priv->data_rssi_avg = 0;
  52	priv->data_nf_avg = 0;
  53	priv->bcn_rssi_last = 0;
  54	priv->bcn_nf_last = 0;
  55	priv->bcn_rssi_avg = 0;
  56	priv->bcn_nf_avg = 0;
  57
  58	return 0;
  59}
  60
  61/*
  62 * This function prepares command to set MAC control.
  63 *
  64 * Preparation includes -
  65 *      - Setting command ID, action and proper size
  66 *      - Ensuring correct endian-ness
  67 */
  68static int mwifiex_cmd_mac_control(struct mwifiex_private *priv,
  69				   struct host_cmd_ds_command *cmd,
  70				   u16 cmd_action, u16 *action)
  71{
  72	struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl;
  73
  74	if (cmd_action != HostCmd_ACT_GEN_SET) {
  75		dev_err(priv->adapter->dev,
  76			"mac_control: only support set cmd\n");
  77		return -1;
  78	}
  79
  80	cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
  81	cmd->size =
  82		cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN);
  83	mac_ctrl->action = cpu_to_le16(*action);
  84
  85	return 0;
  86}
  87
  88/*
  89 * This function prepares command to set/get SNMP MIB.
  90 *
  91 * Preparation includes -
  92 *      - Setting command ID, action and proper size
  93 *      - Setting SNMP MIB OID number and value
  94 *        (as required)
  95 *      - Ensuring correct endian-ness
  96 *
  97 * The following SNMP MIB OIDs are supported -
  98 *      - FRAG_THRESH_I     : Fragmentation threshold
  99 *      - RTS_THRESH_I      : RTS threshold
 100 *      - SHORT_RETRY_LIM_I : Short retry limit
 101 *      - DOT11D_I          : 11d support
 102 */
 103static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv,
 104				       struct host_cmd_ds_command *cmd,
 105				       u16 cmd_action, u32 cmd_oid,
 106				       u16 *ul_temp)
 107{
 108	struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib;
 109
 110	dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
 111	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
 112	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib)
 113				- 1 + S_DS_GEN);
 114
 115	snmp_mib->oid = cpu_to_le16((u16)cmd_oid);
 116	if (cmd_action == HostCmd_ACT_GEN_GET) {
 117		snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET);
 118		snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE);
 119		le16_add_cpu(&cmd->size, MAX_SNMP_BUF_SIZE);
 120	} else if (cmd_action == HostCmd_ACT_GEN_SET) {
 121		snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
 122		snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
 123		*((__le16 *) (snmp_mib->value)) = cpu_to_le16(*ul_temp);
 124		le16_add_cpu(&cmd->size, sizeof(u16));
 125	}
 126
 127	dev_dbg(priv->adapter->dev,
 128		"cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x,"
 129		" Value=0x%x\n",
 130		cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size),
 131		le16_to_cpu(*(__le16 *) snmp_mib->value));
 132	return 0;
 133}
 134
 135/*
 136 * This function prepares command to get log.
 137 *
 138 * Preparation includes -
 139 *      - Setting command ID and proper size
 140 *      - Ensuring correct endian-ness
 141 */
 142static int
 143mwifiex_cmd_802_11_get_log(struct host_cmd_ds_command *cmd)
 144{
 145	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
 146	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) +
 147				S_DS_GEN);
 148	return 0;
 149}
 150
 151/*
 152 * This function prepares command to set/get Tx data rate configuration.
 153 *
 154 * Preparation includes -
 155 *      - Setting command ID, action and proper size
 156 *      - Setting configuration index, rate scope and rate drop pattern
 157 *        parameters (as required)
 158 *      - Ensuring correct endian-ness
 159 */
 160static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv,
 161				   struct host_cmd_ds_command *cmd,
 162				   u16 cmd_action, u16 *pbitmap_rates)
 163{
 164	struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg;
 165	struct mwifiex_rate_scope *rate_scope;
 166	struct mwifiex_rate_drop_pattern *rate_drop;
 167	u32 i;
 168
 169	cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG);
 170
 171	rate_cfg->action = cpu_to_le16(cmd_action);
 172	rate_cfg->cfg_index = 0;
 173
 174	rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg +
 175		      sizeof(struct host_cmd_ds_tx_rate_cfg));
 176	rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE);
 177	rate_scope->length = cpu_to_le16
 178		(sizeof(*rate_scope) - sizeof(struct mwifiex_ie_types_header));
 179	if (pbitmap_rates != NULL) {
 180		rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]);
 181		rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]);
 182		for (i = 0;
 183		     i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16);
 184		     i++)
 185			rate_scope->ht_mcs_rate_bitmap[i] =
 186				cpu_to_le16(pbitmap_rates[2 + i]);
 187	} else {
 188		rate_scope->hr_dsss_rate_bitmap =
 189			cpu_to_le16(priv->bitmap_rates[0]);
 190		rate_scope->ofdm_rate_bitmap =
 191			cpu_to_le16(priv->bitmap_rates[1]);
 192		for (i = 0;
 193		     i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16);
 194		     i++)
 195			rate_scope->ht_mcs_rate_bitmap[i] =
 196				cpu_to_le16(priv->bitmap_rates[2 + i]);
 197	}
 198
 199	rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope +
 200					     sizeof(struct mwifiex_rate_scope));
 201	rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL);
 202	rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode));
 203	rate_drop->rate_drop_mode = 0;
 204
 205	cmd->size =
 206		cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) +
 207			    sizeof(struct mwifiex_rate_scope) +
 208			    sizeof(struct mwifiex_rate_drop_pattern));
 209
 210	return 0;
 211}
 212
 213/*
 214 * This function prepares command to set/get Tx power configuration.
 215 *
 216 * Preparation includes -
 217 *      - Setting command ID, action and proper size
 218 *      - Setting Tx power mode, power group TLV
 219 *        (as required)
 220 *      - Ensuring correct endian-ness
 221 */
 222static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd,
 223				    u16 cmd_action,
 224				    struct host_cmd_ds_txpwr_cfg *txp)
 225{
 226	struct mwifiex_types_power_group *pg_tlv;
 227	struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg;
 228
 229	cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG);
 230	cmd->size =
 231		cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg));
 232	switch (cmd_action) {
 233	case HostCmd_ACT_GEN_SET:
 234		if (txp->mode) {
 235			pg_tlv = (struct mwifiex_types_power_group
 236				  *) ((unsigned long) txp +
 237				     sizeof(struct host_cmd_ds_txpwr_cfg));
 238			memmove(cmd_txp_cfg, txp,
 239				sizeof(struct host_cmd_ds_txpwr_cfg) +
 240				sizeof(struct mwifiex_types_power_group) +
 241				pg_tlv->length);
 242
 243			pg_tlv = (struct mwifiex_types_power_group *) ((u8 *)
 244				  cmd_txp_cfg +
 245				  sizeof(struct host_cmd_ds_txpwr_cfg));
 246			cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) +
 247				  sizeof(struct mwifiex_types_power_group) +
 248				  pg_tlv->length);
 249		} else {
 250			memmove(cmd_txp_cfg, txp, sizeof(*txp));
 251		}
 252		cmd_txp_cfg->action = cpu_to_le16(cmd_action);
 253		break;
 254	case HostCmd_ACT_GEN_GET:
 255		cmd_txp_cfg->action = cpu_to_le16(cmd_action);
 256		break;
 257	}
 258
 259	return 0;
 260}
 261
 262/*
 263 * This function prepares command to set Host Sleep configuration.
 264 *
 265 * Preparation includes -
 266 *      - Setting command ID and proper size
 267 *      - Setting Host Sleep action, conditions, ARP filters
 268 *        (as required)
 269 *      - Ensuring correct endian-ness
 270 */
 271static int
 272mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
 273			  struct host_cmd_ds_command *cmd,
 274			  u16 cmd_action,
 275			  struct mwifiex_hs_config_param *hscfg_param)
 276{
 277	struct mwifiex_adapter *adapter = priv->adapter;
 278	struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg;
 279	u16 hs_activate = false;
 280
 281	if (!hscfg_param)
 282		/* New Activate command */
 283		hs_activate = true;
 284	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
 285
 286	if (!hs_activate &&
 287	    (hscfg_param->conditions != cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) &&
 288	    ((adapter->arp_filter_size > 0) &&
 289	     (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
 290		dev_dbg(adapter->dev,
 291			"cmd: Attach %d bytes ArpFilter to HSCfg cmd\n",
 292			adapter->arp_filter_size);
 293		memcpy(((u8 *) hs_cfg) +
 294		       sizeof(struct host_cmd_ds_802_11_hs_cfg_enh),
 295		       adapter->arp_filter, adapter->arp_filter_size);
 296		cmd->size = cpu_to_le16
 297				(adapter->arp_filter_size +
 298				 sizeof(struct host_cmd_ds_802_11_hs_cfg_enh)
 299				+ S_DS_GEN);
 300	} else {
 301		cmd->size = cpu_to_le16(S_DS_GEN + sizeof(struct
 302						host_cmd_ds_802_11_hs_cfg_enh));
 303	}
 304	if (hs_activate) {
 305		hs_cfg->action = cpu_to_le16(HS_ACTIVATE);
 306		hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED;
 307	} else {
 308		hs_cfg->action = cpu_to_le16(HS_CONFIGURE);
 309		hs_cfg->params.hs_config.conditions = hscfg_param->conditions;
 310		hs_cfg->params.hs_config.gpio = hscfg_param->gpio;
 311		hs_cfg->params.hs_config.gap = hscfg_param->gap;
 312		dev_dbg(adapter->dev,
 313			"cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
 314		       hs_cfg->params.hs_config.conditions,
 315		       hs_cfg->params.hs_config.gpio,
 316		       hs_cfg->params.hs_config.gap);
 317	}
 318
 319	return 0;
 320}
 321
 322/*
 323 * This function prepares command to set/get MAC address.
 324 *
 325 * Preparation includes -
 326 *      - Setting command ID, action and proper size
 327 *      - Setting MAC address (for SET only)
 328 *      - Ensuring correct endian-ness
 329 */
 330static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv,
 331					  struct host_cmd_ds_command *cmd,
 332					  u16 cmd_action)
 333{
 334	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
 335	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) +
 336				S_DS_GEN);
 337	cmd->result = 0;
 338
 339	cmd->params.mac_addr.action = cpu_to_le16(cmd_action);
 340
 341	if (cmd_action == HostCmd_ACT_GEN_SET)
 342		memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr,
 343		       ETH_ALEN);
 344	return 0;
 345}
 346
 347/*
 348 * This function prepares command to set MAC multicast address.
 349 *
 350 * Preparation includes -
 351 *      - Setting command ID, action and proper size
 352 *      - Setting MAC multicast address
 353 *      - Ensuring correct endian-ness
 354 */
 355static int
 356mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd,
 357			      u16 cmd_action,
 358			      struct mwifiex_multicast_list *mcast_list)
 359{
 360	struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr;
 361
 362	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) +
 363				S_DS_GEN);
 364	cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
 365
 366	mcast_addr->action = cpu_to_le16(cmd_action);
 367	mcast_addr->num_of_adrs =
 368		cpu_to_le16((u16) mcast_list->num_multicast_addr);
 369	memcpy(mcast_addr->mac_list, mcast_list->mac_list,
 370	       mcast_list->num_multicast_addr * ETH_ALEN);
 371
 372	return 0;
 373}
 374
 375/*
 376 * This function prepares command to deauthenticate.
 377 *
 378 * Preparation includes -
 379 *      - Setting command ID and proper size
 380 *      - Setting AP MAC address and reason code
 381 *      - Ensuring correct endian-ness
 382 */
 383static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv,
 384					     struct host_cmd_ds_command *cmd,
 385					     u8 *mac)
 386{
 387	struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth;
 388
 389	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
 390	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate)
 391				+ S_DS_GEN);
 392
 393	/* Set AP MAC address */
 394	memcpy(deauth->mac_addr, mac, ETH_ALEN);
 395
 396	dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr);
 397
 398	deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
 399
 400	return 0;
 401}
 402
 403/*
 404 * This function prepares command to stop Ad-Hoc network.
 405 *
 406 * Preparation includes -
 407 *      - Setting command ID and proper size
 408 *      - Ensuring correct endian-ness
 409 */
 410static int mwifiex_cmd_802_11_ad_hoc_stop(struct host_cmd_ds_command *cmd)
 411{
 412	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
 413	cmd->size = cpu_to_le16(S_DS_GEN);
 414	return 0;
 415}
 416
 417/*
 418 * This function sets WEP key(s) to key parameter TLV(s).
 419 *
 420 * Multi-key parameter TLVs are supported, so we can send multiple
 421 * WEP keys in a single buffer.
 422 */
 423static int
 424mwifiex_set_keyparamset_wep(struct mwifiex_private *priv,
 425			    struct mwifiex_ie_type_key_param_set *key_param_set,
 426			    u16 *key_param_len)
 427{
 428	int cur_key_param_len;
 429	u8 i;
 430
 431	/* Multi-key_param_set TLV is supported */
 432	for (i = 0; i < NUM_WEP_KEYS; i++) {
 433		if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) ||
 434		    (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) {
 435			key_param_set->type =
 436				cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
 437/* Key_param_set WEP fixed length */
 438#define KEYPARAMSET_WEP_FIXED_LEN 8
 439			key_param_set->length = cpu_to_le16((u16)
 440					(priv->wep_key[i].
 441					 key_length +
 442					 KEYPARAMSET_WEP_FIXED_LEN));
 443			key_param_set->key_type_id =
 444				cpu_to_le16(KEY_TYPE_ID_WEP);
 445			key_param_set->key_info =
 446				cpu_to_le16(KEY_ENABLED | KEY_UNICAST |
 447					    KEY_MCAST);
 448			key_param_set->key_len =
 449				cpu_to_le16(priv->wep_key[i].key_length);
 450			/* Set WEP key index */
 451			key_param_set->key[0] = i;
 452			/* Set default Tx key flag */
 453			if (i ==
 454			    (priv->
 455			     wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK))
 456				key_param_set->key[1] = 1;
 457			else
 458				key_param_set->key[1] = 0;
 459			memmove(&key_param_set->key[2],
 460				priv->wep_key[i].key_material,
 461				priv->wep_key[i].key_length);
 462
 463			cur_key_param_len = priv->wep_key[i].key_length +
 464				KEYPARAMSET_WEP_FIXED_LEN +
 465				sizeof(struct mwifiex_ie_types_header);
 466			*key_param_len += (u16) cur_key_param_len;
 467			key_param_set =
 468				(struct mwifiex_ie_type_key_param_set *)
 469						((u8 *)key_param_set +
 470						 cur_key_param_len);
 471		} else if (!priv->wep_key[i].key_length) {
 472			continue;
 473		} else {
 474			dev_err(priv->adapter->dev,
 475				"key%d Length = %d is incorrect\n",
 476			       (i + 1), priv->wep_key[i].key_length);
 477			return -1;
 478		}
 479	}
 480
 481	return 0;
 482}
 483
 484/*
 485 * This function prepares command to set/get/reset network key(s).
 486 *
 487 * Preparation includes -
 488 *      - Setting command ID, action and proper size
 489 *      - Setting WEP keys, WAPI keys or WPA keys along with required
 490 *        encryption (TKIP, AES) (as required)
 491 *      - Ensuring correct endian-ness
 492 */
 493static int
 494mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
 495				struct host_cmd_ds_command *cmd,
 496				u16 cmd_action, u32 cmd_oid,
 497				struct mwifiex_ds_encrypt_key *enc_key)
 498{
 499	struct host_cmd_ds_802_11_key_material *key_material =
 500		&cmd->params.key_material;
 501	struct host_cmd_tlv_mac_addr *tlv_mac;
 502	u16 key_param_len = 0, cmd_size;
 503	int ret = 0;
 504	const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 505
 506	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
 507	key_material->action = cpu_to_le16(cmd_action);
 508
 509	if (cmd_action == HostCmd_ACT_GEN_GET) {
 510		cmd->size =
 511			cpu_to_le16(sizeof(key_material->action) + S_DS_GEN);
 512		return ret;
 513	}
 514
 515	if (!enc_key) {
 516		memset(&key_material->key_param_set, 0,
 517		       (NUM_WEP_KEYS *
 518			sizeof(struct mwifiex_ie_type_key_param_set)));
 519		ret = mwifiex_set_keyparamset_wep(priv,
 520						  &key_material->key_param_set,
 521						  &key_param_len);
 522		cmd->size = cpu_to_le16(key_param_len +
 523				    sizeof(key_material->action) + S_DS_GEN);
 524		return ret;
 525	} else
 526		memset(&key_material->key_param_set, 0,
 527		       sizeof(struct mwifiex_ie_type_key_param_set));
 528	if (enc_key->is_wapi_key) {
 529		dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n");
 530		key_material->key_param_set.key_type_id =
 531						cpu_to_le16(KEY_TYPE_ID_WAPI);
 532		if (cmd_oid == KEY_INFO_ENABLED)
 533			key_material->key_param_set.key_info =
 534						cpu_to_le16(KEY_ENABLED);
 535		else
 536			key_material->key_param_set.key_info =
 537						cpu_to_le16(!KEY_ENABLED);
 538
 539		key_material->key_param_set.key[0] = enc_key->key_index;
 540		if (!priv->sec_info.wapi_key_on)
 541			key_material->key_param_set.key[1] = 1;
 542		else
 543			/* set 0 when re-key */
 544			key_material->key_param_set.key[1] = 0;
 545
 546		if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) {
 547			/* WAPI pairwise key: unicast */
 548			key_material->key_param_set.key_info |=
 549				cpu_to_le16(KEY_UNICAST);
 550		} else {	/* WAPI group key: multicast */
 551			key_material->key_param_set.key_info |=
 552				cpu_to_le16(KEY_MCAST);
 553			priv->sec_info.wapi_key_on = true;
 554		}
 555
 556		key_material->key_param_set.type =
 557					cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
 558		key_material->key_param_set.key_len =
 559						cpu_to_le16(WAPI_KEY_LEN);
 560		memcpy(&key_material->key_param_set.key[2],
 561		       enc_key->key_material, enc_key->key_len);
 562		memcpy(&key_material->key_param_set.key[2 + enc_key->key_len],
 563		       enc_key->wapi_rxpn, WAPI_RXPN_LEN);
 564		key_material->key_param_set.length =
 565			cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
 566
 567		key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
 568				 sizeof(struct mwifiex_ie_types_header);
 569		cmd->size = cpu_to_le16(sizeof(key_material->action)
 570					+ S_DS_GEN +  key_param_len);
 571		return ret;
 572	}
 573	if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
 574		dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
 575		key_material->key_param_set.key_type_id =
 576						cpu_to_le16(KEY_TYPE_ID_AES);
 577		if (cmd_oid == KEY_INFO_ENABLED)
 578			key_material->key_param_set.key_info =
 579						cpu_to_le16(KEY_ENABLED);
 580		else
 581			key_material->key_param_set.key_info =
 582						cpu_to_le16(!KEY_ENABLED);
 583
 584		if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
 585				/* AES pairwise key: unicast */
 586			key_material->key_param_set.key_info |=
 587						cpu_to_le16(KEY_UNICAST);
 588		else		/* AES group key: multicast */
 589			key_material->key_param_set.key_info |=
 590							cpu_to_le16(KEY_MCAST);
 591	} else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
 592		dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
 593		key_material->key_param_set.key_type_id =
 594						cpu_to_le16(KEY_TYPE_ID_TKIP);
 595		key_material->key_param_set.key_info =
 596						cpu_to_le16(KEY_ENABLED);
 597
 598		if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
 599				/* TKIP pairwise key: unicast */
 600			key_material->key_param_set.key_info |=
 601						cpu_to_le16(KEY_UNICAST);
 602		else		/* TKIP group key: multicast */
 603			key_material->key_param_set.key_info |=
 604							cpu_to_le16(KEY_MCAST);
 605	}
 606
 607	if (key_material->key_param_set.key_type_id) {
 608		key_material->key_param_set.type =
 609					cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
 610		key_material->key_param_set.key_len =
 611					cpu_to_le16((u16) enc_key->key_len);
 612		memcpy(key_material->key_param_set.key, enc_key->key_material,
 613		       enc_key->key_len);
 614		key_material->key_param_set.length =
 615			cpu_to_le16((u16) enc_key->key_len +
 616				    KEYPARAMSET_FIXED_LEN);
 617
 618		key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN)
 619				+ sizeof(struct mwifiex_ie_types_header);
 620
 621		cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN
 622					+ key_param_len);
 623
 624		if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
 625			tlv_mac = (void *)((u8 *)&key_material->key_param_set +
 626					   key_param_len);
 627			tlv_mac->tlv.type = cpu_to_le16(TLV_TYPE_STA_MAC_ADDR);
 628			tlv_mac->tlv.len = cpu_to_le16(ETH_ALEN);
 629			memcpy(tlv_mac->mac_addr, enc_key->mac_addr, ETH_ALEN);
 630			cmd_size = key_param_len + S_DS_GEN +
 631				   sizeof(key_material->action) +
 632				   sizeof(struct host_cmd_tlv_mac_addr);
 633		} else {
 634			cmd_size = key_param_len + S_DS_GEN +
 635				   sizeof(key_material->action);
 636		}
 637		cmd->size = cpu_to_le16(cmd_size);
 638	}
 639
 640	return ret;
 641}
 642
 643/*
 644 * This function prepares command to set/get 11d domain information.
 645 *
 646 * Preparation includes -
 647 *      - Setting command ID, action and proper size
 648 *      - Setting domain information fields (for SET only)
 649 *      - Ensuring correct endian-ness
 650 */
 651static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv,
 652					   struct host_cmd_ds_command *cmd,
 653					   u16 cmd_action)
 654{
 655	struct mwifiex_adapter *adapter = priv->adapter;
 656	struct host_cmd_ds_802_11d_domain_info *domain_info =
 657		&cmd->params.domain_info;
 658	struct mwifiex_ietypes_domain_param_set *domain =
 659		&domain_info->domain;
 660	u8 no_of_triplet = adapter->domain_reg.no_of_triplet;
 661
 662	dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet);
 663
 664	cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
 665	domain_info->action = cpu_to_le16(cmd_action);
 666	if (cmd_action == HostCmd_ACT_GEN_GET) {
 667		cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
 668		return 0;
 669	}
 670
 671	/* Set domain info fields */
 672	domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY);
 673	memcpy(domain->country_code, adapter->domain_reg.country_code,
 674	       sizeof(domain->country_code));
 675
 676	domain->header.len =
 677		cpu_to_le16((no_of_triplet *
 678			     sizeof(struct ieee80211_country_ie_triplet))
 679			    + sizeof(domain->country_code));
 680
 681	if (no_of_triplet) {
 682		memcpy(domain->triplet, adapter->domain_reg.triplet,
 683		       no_of_triplet * sizeof(struct
 684					      ieee80211_country_ie_triplet));
 685
 686		cmd->size = cpu_to_le16(sizeof(domain_info->action) +
 687					le16_to_cpu(domain->header.len) +
 688					sizeof(struct mwifiex_ie_types_header)
 689					+ S_DS_GEN);
 690	} else {
 691		cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
 692	}
 693
 694	return 0;
 695}
 696
 697/*
 698 * This function prepares command to set/get RF channel.
 699 *
 700 * Preparation includes -
 701 *      - Setting command ID, action and proper size
 702 *      - Setting RF type and current RF channel (for SET only)
 703 *      - Ensuring correct endian-ness
 704 */
 705static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv,
 706					 struct host_cmd_ds_command *cmd,
 707					 u16 cmd_action, u16 *channel)
 708{
 709	struct host_cmd_ds_802_11_rf_channel *rf_chan =
 710		&cmd->params.rf_channel;
 711	uint16_t rf_type = le16_to_cpu(rf_chan->rf_type);
 712
 713	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
 714	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rf_channel)
 715				+ S_DS_GEN);
 716
 717	if (cmd_action == HostCmd_ACT_GEN_SET) {
 718		if ((priv->adapter->adhoc_start_band & BAND_A) ||
 719		    (priv->adapter->adhoc_start_band & BAND_AN))
 720			rf_chan->rf_type =
 721				cpu_to_le16(HostCmd_SCAN_RADIO_TYPE_A);
 722
 723		rf_type = le16_to_cpu(rf_chan->rf_type);
 724		SET_SECONDARYCHAN(rf_type, priv->adapter->sec_chan_offset);
 725		rf_chan->current_channel = cpu_to_le16(*channel);
 726	}
 727	rf_chan->action = cpu_to_le16(cmd_action);
 728	return 0;
 729}
 730
 731/*
 732 * This function prepares command to set/get IBSS coalescing status.
 733 *
 734 * Preparation includes -
 735 *      - Setting command ID, action and proper size
 736 *      - Setting status to enable or disable (for SET only)
 737 *      - Ensuring correct endian-ness
 738 */
 739static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd,
 740					      u16 cmd_action, u16 *enable)
 741{
 742	struct host_cmd_ds_802_11_ibss_status *ibss_coal =
 743		&(cmd->params.ibss_coalescing);
 744
 745	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
 746	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) +
 747				S_DS_GEN);
 748	cmd->result = 0;
 749	ibss_coal->action = cpu_to_le16(cmd_action);
 750
 751	switch (cmd_action) {
 752	case HostCmd_ACT_GEN_SET:
 753		if (enable)
 754			ibss_coal->enable = cpu_to_le16(*enable);
 755		else
 756			ibss_coal->enable = 0;
 757		break;
 758
 759		/* In other case.. Nothing to do */
 760	case HostCmd_ACT_GEN_GET:
 761	default:
 762		break;
 763	}
 764
 765	return 0;
 766}
 767
 768/*
 769 * This function prepares command to set/get register value.
 770 *
 771 * Preparation includes -
 772 *      - Setting command ID, action and proper size
 773 *      - Setting register offset (for both GET and SET) and
 774 *        register value (for SET only)
 775 *      - Ensuring correct endian-ness
 776 *
 777 * The following type of registers can be accessed with this function -
 778 *      - MAC register
 779 *      - BBP register
 780 *      - RF register
 781 *      - PMIC register
 782 *      - CAU register
 783 *      - EEPROM
 784 */
 785static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
 786				  u16 cmd_action, void *data_buf)
 787{
 788	struct mwifiex_ds_reg_rw *reg_rw = data_buf;
 789
 790	switch (le16_to_cpu(cmd->command)) {
 791	case HostCmd_CMD_MAC_REG_ACCESS:
 792	{
 793		struct host_cmd_ds_mac_reg_access *mac_reg;
 794
 795		cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN);
 796		mac_reg = (struct host_cmd_ds_mac_reg_access *) &cmd->
 797								params.mac_reg;
 798		mac_reg->action = cpu_to_le16(cmd_action);
 799		mac_reg->offset =
 800			cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
 801		mac_reg->value = reg_rw->value;
 802		break;
 803	}
 804	case HostCmd_CMD_BBP_REG_ACCESS:
 805	{
 806		struct host_cmd_ds_bbp_reg_access *bbp_reg;
 807
 808		cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN);
 809		bbp_reg = (struct host_cmd_ds_bbp_reg_access *)
 810							&cmd->params.bbp_reg;
 811		bbp_reg->action = cpu_to_le16(cmd_action);
 812		bbp_reg->offset =
 813			cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
 814		bbp_reg->value = (u8) le32_to_cpu(reg_rw->value);
 815		break;
 816	}
 817	case HostCmd_CMD_RF_REG_ACCESS:
 818	{
 819		struct host_cmd_ds_rf_reg_access *rf_reg;
 820
 821		cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN);
 822		rf_reg = (struct host_cmd_ds_rf_reg_access *)
 823							&cmd->params.rf_reg;
 824		rf_reg->action = cpu_to_le16(cmd_action);
 825		rf_reg->offset = cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
 826		rf_reg->value = (u8) le32_to_cpu(reg_rw->value);
 827		break;
 828	}
 829	case HostCmd_CMD_PMIC_REG_ACCESS:
 830	{
 831		struct host_cmd_ds_pmic_reg_access *pmic_reg;
 832
 833		cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN);
 834		pmic_reg = (struct host_cmd_ds_pmic_reg_access *) &cmd->
 835				params.pmic_reg;
 836		pmic_reg->action = cpu_to_le16(cmd_action);
 837		pmic_reg->offset =
 838				cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
 839		pmic_reg->value = (u8) le32_to_cpu(reg_rw->value);
 840		break;
 841	}
 842	case HostCmd_CMD_CAU_REG_ACCESS:
 843	{
 844		struct host_cmd_ds_rf_reg_access *cau_reg;
 845
 846		cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN);
 847		cau_reg = (struct host_cmd_ds_rf_reg_access *)
 848							&cmd->params.rf_reg;
 849		cau_reg->action = cpu_to_le16(cmd_action);
 850		cau_reg->offset =
 851				cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
 852		cau_reg->value = (u8) le32_to_cpu(reg_rw->value);
 853		break;
 854	}
 855	case HostCmd_CMD_802_11_EEPROM_ACCESS:
 856	{
 857		struct mwifiex_ds_read_eeprom *rd_eeprom = data_buf;
 858		struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom =
 859			(struct host_cmd_ds_802_11_eeprom_access *)
 860			&cmd->params.eeprom;
 861
 862		cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN);
 863		cmd_eeprom->action = cpu_to_le16(cmd_action);
 864		cmd_eeprom->offset = rd_eeprom->offset;
 865		cmd_eeprom->byte_count = rd_eeprom->byte_count;
 866		cmd_eeprom->value = 0;
 867		break;
 868	}
 869	default:
 870		return -1;
 871	}
 872
 873	return 0;
 874}
 875
 876/*
 877 * This function prepares command to set PCI-Express
 878 * host buffer configuration
 879 *
 880 * Preparation includes -
 881 *      - Setting command ID, action and proper size
 882 *      - Setting host buffer configuration
 883 *      - Ensuring correct endian-ness
 884 */
 885static int
 886mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv,
 887			   struct host_cmd_ds_command *cmd, u16 action)
 888{
 889	struct host_cmd_ds_pcie_details *host_spec =
 890					&cmd->params.pcie_host_spec;
 891	struct pcie_service_card *card = priv->adapter->card;
 892	phys_addr_t *buf_pa;
 893
 894	cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS);
 895	cmd->size = cpu_to_le16(sizeof(struct
 896					host_cmd_ds_pcie_details) + S_DS_GEN);
 897	cmd->result = 0;
 898
 899	memset(host_spec, 0, sizeof(struct host_cmd_ds_pcie_details));
 900
 901	if (action != HostCmd_ACT_GEN_SET)
 902		return 0;
 903
 904	/* Send the ring base addresses and count to firmware */
 905	host_spec->txbd_addr_lo = (u32)(card->txbd_ring_pbase);
 906	host_spec->txbd_addr_hi = (u32)(((u64)card->txbd_ring_pbase)>>32);
 907	host_spec->txbd_count = MWIFIEX_MAX_TXRX_BD;
 908	host_spec->rxbd_addr_lo = (u32)(card->rxbd_ring_pbase);
 909	host_spec->rxbd_addr_hi = (u32)(((u64)card->rxbd_ring_pbase)>>32);
 910	host_spec->rxbd_count = MWIFIEX_MAX_TXRX_BD;
 911	host_spec->evtbd_addr_lo = (u32)(card->evtbd_ring_pbase);
 912	host_spec->evtbd_addr_hi = (u32)(((u64)card->evtbd_ring_pbase)>>32);
 913	host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD;
 914	if (card->sleep_cookie) {
 915		buf_pa = MWIFIEX_SKB_PACB(card->sleep_cookie);
 916		host_spec->sleep_cookie_addr_lo = (u32) *buf_pa;
 917		host_spec->sleep_cookie_addr_hi = (u32) (((u64)*buf_pa) >> 32);
 918		dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: 0x%x\n",
 919			host_spec->sleep_cookie_addr_lo);
 920	}
 921
 922	return 0;
 923}
 924
 925/*
 926 * This function prepares command for event subscription, configuration
 927 * and query. Events can be subscribed or unsubscribed. Current subscribed
 928 * events can be queried. Also, current subscribed events are reported in
 929 * every FW response.
 930 */
 931static int
 932mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
 933			     struct host_cmd_ds_command *cmd,
 934			     struct mwifiex_ds_misc_subsc_evt *subsc_evt_cfg)
 935{
 936	struct host_cmd_ds_802_11_subsc_evt *subsc_evt = &cmd->params.subsc_evt;
 937	struct mwifiex_ie_types_rssi_threshold *rssi_tlv;
 938	u16 event_bitmap;
 939	u8 *pos;
 940
 941	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SUBSCRIBE_EVENT);
 942	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_subsc_evt) +
 943				S_DS_GEN);
 944
 945	subsc_evt->action = cpu_to_le16(subsc_evt_cfg->action);
 946	dev_dbg(priv->adapter->dev, "cmd: action: %d\n", subsc_evt_cfg->action);
 947
 948	/*For query requests, no configuration TLV structures are to be added.*/
 949	if (subsc_evt_cfg->action == HostCmd_ACT_GEN_GET)
 950		return 0;
 951
 952	subsc_evt->events = cpu_to_le16(subsc_evt_cfg->events);
 953
 954	event_bitmap = subsc_evt_cfg->events;
 955	dev_dbg(priv->adapter->dev, "cmd: event bitmap : %16x\n",
 956		event_bitmap);
 957
 958	if (((subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR) ||
 959	     (subsc_evt_cfg->action == HostCmd_ACT_BITWISE_SET)) &&
 960	    (event_bitmap == 0)) {
 961		dev_dbg(priv->adapter->dev, "Error: No event specified "
 962			"for bitwise action type\n");
 963		return -EINVAL;
 964	}
 965
 966	/*
 967	 * Append TLV structures for each of the specified events for
 968	 * subscribing or re-configuring. This is not required for
 969	 * bitwise unsubscribing request.
 970	 */
 971	if (subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR)
 972		return 0;
 973
 974	pos = ((u8 *)subsc_evt) +
 975			sizeof(struct host_cmd_ds_802_11_subsc_evt);
 976
 977	if (event_bitmap & BITMASK_BCN_RSSI_LOW) {
 978		rssi_tlv = (struct mwifiex_ie_types_rssi_threshold *) pos;
 979
 980		rssi_tlv->header.type = cpu_to_le16(TLV_TYPE_RSSI_LOW);
 981		rssi_tlv->header.len =
 982		    cpu_to_le16(sizeof(struct mwifiex_ie_types_rssi_threshold) -
 983				sizeof(struct mwifiex_ie_types_header));
 984		rssi_tlv->abs_value = subsc_evt_cfg->bcn_l_rssi_cfg.abs_value;
 985		rssi_tlv->evt_freq = subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq;
 986
 987		dev_dbg(priv->adapter->dev, "Cfg Beacon Low Rssi event, "
 988			"RSSI:-%d dBm, Freq:%d\n",
 989			subsc_evt_cfg->bcn_l_rssi_cfg.abs_value,
 990			subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq);
 991
 992		pos += sizeof(struct mwifiex_ie_types_rssi_threshold);
 993		le16_add_cpu(&cmd->size,
 994			     sizeof(struct mwifiex_ie_types_rssi_threshold));
 995	}
 996
 997	if (event_bitmap & BITMASK_BCN_RSSI_HIGH) {
 998		rssi_tlv = (struct mwifiex_ie_types_rssi_threshold *) pos;
 999
1000		rssi_tlv->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
1001		rssi_tlv->header.len =
1002		    cpu_to_le16(sizeof(struct mwifiex_ie_types_rssi_threshold) -
1003				sizeof(struct mwifiex_ie_types_header));
1004		rssi_tlv->abs_value = subsc_evt_cfg->bcn_h_rssi_cfg.abs_value;
1005		rssi_tlv->evt_freq = subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq;
1006
1007		dev_dbg(priv->adapter->dev, "Cfg Beacon High Rssi event, "
1008			"RSSI:-%d dBm, Freq:%d\n",
1009			subsc_evt_cfg->bcn_h_rssi_cfg.abs_value,
1010			subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq);
1011
1012		pos += sizeof(struct mwifiex_ie_types_rssi_threshold);
1013		le16_add_cpu(&cmd->size,
1014			     sizeof(struct mwifiex_ie_types_rssi_threshold));
1015	}
1016
1017	return 0;
1018}
1019
1020/*
1021 * This function prepares the commands before sending them to the firmware.
1022 *
1023 * This is a generic function which calls specific command preparation
1024 * routines based upon the command number.
1025 */
1026int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
1027			    u16 cmd_action, u32 cmd_oid,
1028			    void *data_buf, void *cmd_buf)
1029{
1030	struct host_cmd_ds_command *cmd_ptr = cmd_buf;
1031	int ret = 0;
1032
1033	/* Prepare command */
1034	switch (cmd_no) {
1035	case HostCmd_CMD_GET_HW_SPEC:
1036		ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr);
1037		break;
1038	case HostCmd_CMD_MAC_CONTROL:
1039		ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
1040					      data_buf);
1041		break;
1042	case HostCmd_CMD_802_11_MAC_ADDRESS:
1043		ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr,
1044						     cmd_action);
1045		break;
1046	case HostCmd_CMD_MAC_MULTICAST_ADR:
1047		ret = mwifiex_cmd_mac_multicast_adr(cmd_ptr, cmd_action,
1048						    data_buf);
1049		break;
1050	case HostCmd_CMD_TX_RATE_CFG:
1051		ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action,
1052					      data_buf);
1053		break;
1054	case HostCmd_CMD_TXPWR_CFG:
1055		ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action,
1056					       data_buf);
1057		break;
1058	case HostCmd_CMD_802_11_PS_MODE_ENH:
1059		ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action,
1060						 (uint16_t)cmd_oid, data_buf);
1061		break;
1062	case HostCmd_CMD_802_11_HS_CFG_ENH:
1063		ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action,
1064				(struct mwifiex_hs_config_param *) data_buf);
1065		break;
1066	case HostCmd_CMD_802_11_SCAN:
1067		ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf);
1068		break;
1069	case HostCmd_CMD_802_11_BG_SCAN_QUERY:
1070		ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr);
1071		break;
1072	case HostCmd_CMD_802_11_ASSOCIATE:
1073		ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf);
1074		break;
1075	case HostCmd_CMD_802_11_DEAUTHENTICATE:
1076		ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr,
1077							data_buf);
1078		break;
1079	case HostCmd_CMD_802_11_AD_HOC_START:
1080		ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr,
1081						      data_buf);
1082		break;
1083	case HostCmd_CMD_802_11_GET_LOG:
1084		ret = mwifiex_cmd_802_11_get_log(cmd_ptr);
1085		break;
1086	case HostCmd_CMD_802_11_AD_HOC_JOIN:
1087		ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr,
1088						     data_buf);
1089		break;
1090	case HostCmd_CMD_802_11_AD_HOC_STOP:
1091		ret = mwifiex_cmd_802_11_ad_hoc_stop(cmd_ptr);
1092		break;
1093	case HostCmd_CMD_RSSI_INFO:
1094		ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action);
1095		break;
1096	case HostCmd_CMD_802_11_SNMP_MIB:
1097		ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action,
1098						  cmd_oid, data_buf);
1099		break;
1100	case HostCmd_CMD_802_11_TX_RATE_QUERY:
1101		cmd_ptr->command =
1102			cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
1103		cmd_ptr->size =
1104			cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) +
1105				    S_DS_GEN);
1106		priv->tx_rate = 0;
1107		ret = 0;
1108		break;
1109	case HostCmd_CMD_VERSION_EXT:
1110		cmd_ptr->command = cpu_to_le16(cmd_no);
1111		cmd_ptr->params.verext.version_str_sel =
1112			(u8) (*((u32 *) data_buf));
1113		memcpy(&cmd_ptr->params, data_buf,
1114		       sizeof(struct host_cmd_ds_version_ext));
1115		cmd_ptr->size =
1116			cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) +
1117				    S_DS_GEN);
1118		ret = 0;
1119		break;
1120	case HostCmd_CMD_802_11_RF_CHANNEL:
1121		ret = mwifiex_cmd_802_11_rf_channel(priv, cmd_ptr, cmd_action,
1122						    data_buf);
1123		break;
1124	case HostCmd_CMD_FUNC_INIT:
1125		if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET)
1126			priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY;
1127		cmd_ptr->command = cpu_to_le16(cmd_no);
1128		cmd_ptr->size = cpu_to_le16(S_DS_GEN);
1129		break;
1130	case HostCmd_CMD_FUNC_SHUTDOWN:
1131		priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET;
1132		cmd_ptr->command = cpu_to_le16(cmd_no);
1133		cmd_ptr->size = cpu_to_le16(S_DS_GEN);
1134		break;
1135	case HostCmd_CMD_11N_ADDBA_REQ:
1136		ret = mwifiex_cmd_11n_addba_req(cmd_ptr, data_buf);
1137		break;
1138	case HostCmd_CMD_11N_DELBA:
1139		ret = mwifiex_cmd_11n_delba(cmd_ptr, data_buf);
1140		break;
1141	case HostCmd_CMD_11N_ADDBA_RSP:
1142		ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf);
1143		break;
1144	case HostCmd_CMD_802_11_KEY_MATERIAL:
1145		ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr,
1146						      cmd_action, cmd_oid,
1147						      data_buf);
1148		break;
1149	case HostCmd_CMD_802_11D_DOMAIN_INFO:
1150		ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr,
1151						      cmd_action);
1152		break;
1153	case HostCmd_CMD_RECONFIGURE_TX_BUFF:
1154		ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action,
1155					       data_buf);
1156		break;
1157	case HostCmd_CMD_AMSDU_AGGR_CTRL:
1158		ret = mwifiex_cmd_amsdu_aggr_ctrl(cmd_ptr, cmd_action,
1159						  data_buf);
1160		break;
1161	case HostCmd_CMD_11N_CFG:
1162		ret = mwifiex_cmd_11n_cfg(cmd_ptr, cmd_action, data_buf);
1163		break;
1164	case HostCmd_CMD_WMM_GET_STATUS:
1165		dev_dbg(priv->adapter->dev,
1166			"cmd: WMM: WMM_GET_STATUS cmd sent\n");
1167		cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
1168		cmd_ptr->size =
1169			cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) +
1170				    S_DS_GEN);
1171		ret = 0;
1172		break;
1173	case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
1174		ret = mwifiex_cmd_ibss_coalescing_status(cmd_ptr, cmd_action,
1175							 data_buf);
1176		break;
1177	case HostCmd_CMD_MAC_REG_ACCESS:
1178	case HostCmd_CMD_BBP_REG_ACCESS:
1179	case HostCmd_CMD_RF_REG_ACCESS:
1180	case HostCmd_CMD_PMIC_REG_ACCESS:
1181	case HostCmd_CMD_CAU_REG_ACCESS:
1182	case HostCmd_CMD_802_11_EEPROM_ACCESS:
1183		ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf);
1184		break;
1185	case HostCmd_CMD_SET_BSS_MODE:
1186		cmd_ptr->command = cpu_to_le16(cmd_no);
1187		if (priv->bss_mode == NL80211_IFTYPE_ADHOC)
1188			cmd_ptr->params.bss_mode.con_type =
1189				CONNECTION_TYPE_ADHOC;
1190		else if (priv->bss_mode == NL80211_IFTYPE_STATION)
1191			cmd_ptr->params.bss_mode.con_type =
1192				CONNECTION_TYPE_INFRA;
1193		cmd_ptr->size = cpu_to_le16(sizeof(struct
1194				host_cmd_ds_set_bss_mode) + S_DS_GEN);
1195		ret = 0;
1196		break;
1197	case HostCmd_CMD_PCIE_DESC_DETAILS:
1198		ret = mwifiex_cmd_pcie_host_spec(priv, cmd_ptr, cmd_action);
1199		break;
1200	case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
1201		ret = mwifiex_cmd_802_11_subsc_evt(priv, cmd_ptr, data_buf);
1202		break;
1203	default:
1204		dev_err(priv->adapter->dev,
1205			"PREP_CMD: unknown cmd- %#x\n", cmd_no);
1206		ret = -1;
1207		break;
1208	}
1209	return ret;
1210}
1211
1212/*
1213 * This function issues commands to initialize firmware.
1214 *
1215 * This is called after firmware download to bring the card to
1216 * working state.
1217 *
1218 * The following commands are issued sequentially -
1219 *      - Set PCI-Express host buffer configuration (PCIE only)
1220 *      - Function init (for first interface only)
1221 *      - Read MAC address (for first interface only)
1222 *      - Reconfigure Tx buffer size (for first interface only)
1223 *      - Enable auto deep sleep (for first interface only)
1224 *      - Get Tx rate
1225 *      - Get Tx power
1226 *      - Set IBSS coalescing status
1227 *      - Set AMSDU aggregation control
1228 *      - Set 11d control
1229 *      - Set MAC control (this must be the last command to initialize firmware)
1230 */
1231int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
1232{
1233	int ret;
1234	u16 enable = true;
1235	struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
1236	struct mwifiex_ds_auto_ds auto_ds;
1237	enum state_11d_t state_11d;
1238	struct mwifiex_ds_11n_tx_cfg tx_cfg;
1239
1240	if (first_sta) {
1241		if (priv->adapter->iface_type == MWIFIEX_PCIE) {
1242			ret = mwifiex_send_cmd_async(priv,
1243						HostCmd_CMD_PCIE_DESC_DETAILS,
1244						HostCmd_ACT_GEN_SET, 0, NULL);
1245			if (ret)
1246				return -1;
1247		}
1248
1249		ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT,
1250					     HostCmd_ACT_GEN_SET, 0, NULL);
1251		if (ret)
1252			return -1;
1253		/* Read MAC address from HW */
1254		ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_GET_HW_SPEC,
1255					     HostCmd_ACT_GEN_GET, 0, NULL);
1256		if (ret)
1257			return -1;
1258
1259		/* Reconfigure tx buf size */
1260		ret = mwifiex_send_cmd_async(priv,
1261					     HostCmd_CMD_RECONFIGURE_TX_BUFF,
1262					     HostCmd_ACT_GEN_SET, 0,
1263					     &priv->adapter->tx_buf_size);
1264		if (ret)
1265			return -1;
1266
1267		if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
1268			/* Enable IEEE PS by default */
1269			priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
1270			ret = mwifiex_send_cmd_async(
1271					priv, HostCmd_CMD_802_11_PS_MODE_ENH,
1272					EN_AUTO_PS, BITMAP_STA_PS, NULL);
1273			if (ret)
1274				return -1;
1275		}
1276	}
1277
1278	/* get tx rate */
1279	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TX_RATE_CFG,
1280				     HostCmd_ACT_GEN_GET, 0, NULL);
1281	if (ret)
1282		return -1;
1283	priv->data_rate = 0;
1284
1285	/* get tx power */
1286	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TXPWR_CFG,
1287				     HostCmd_ACT_GEN_GET, 0, NULL);
1288	if (ret)
1289		return -1;
1290
1291	if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) {
1292		/* set ibss coalescing_status */
1293		ret = mwifiex_send_cmd_async(
1294				priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
1295				HostCmd_ACT_GEN_SET, 0, &enable);
1296		if (ret)
1297			return -1;
1298	}
1299
1300	memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
1301	amsdu_aggr_ctrl.enable = true;
1302	/* Send request to firmware */
1303	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
1304				     HostCmd_ACT_GEN_SET, 0,
1305				     &amsdu_aggr_ctrl);
1306	if (ret)
1307		return -1;
1308	/* MAC Control must be the last command in init_fw */
1309	/* set MAC Control */
1310	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
1311				     HostCmd_ACT_GEN_SET, 0,
1312				     &priv->curr_pkt_filter);
1313	if (ret)
1314		return -1;
1315
1316	if (first_sta && priv->adapter->iface_type != MWIFIEX_USB &&
1317	    priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
1318		/* Enable auto deep sleep */
1319		auto_ds.auto_ds = DEEP_SLEEP_ON;
1320		auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
1321		ret = mwifiex_send_cmd_async(priv,
1322					     HostCmd_CMD_802_11_PS_MODE_ENH,
1323					     EN_AUTO_PS, BITMAP_AUTO_DS,
1324					     &auto_ds);
1325		if (ret)
1326			return -1;
1327	}
1328
1329	if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
1330		/* Send cmd to FW to enable/disable 11D function */
1331		state_11d = ENABLE_11D;
1332		ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB,
1333					     HostCmd_ACT_GEN_SET, DOT11D_I,
1334					     &state_11d);
1335		if (ret)
1336			dev_err(priv->adapter->dev,
1337				"11D: failed to enable 11D\n");
1338	}
1339
1340	/* Send cmd to FW to configure 11n specific configuration
1341	 * (Short GI, Channel BW, Green field support etc.) for transmit
1342	 */
1343	tx_cfg.tx_htcap = MWIFIEX_FW_DEF_HTTXCFG;
1344	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_CFG,
1345				     HostCmd_ACT_GEN_SET, 0, &tx_cfg);
1346
1347	/* set last_init_cmd */
1348	priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG;
1349	ret = -EINPROGRESS;
1350
1351	return ret;
1352}