* It prepares command and sends it to firmware when it is ready.
*/
-#include <net/iw_handler.h>
+#include <net/lib80211.h>
+#include <linux/kfifo.h>
+#include <linux/sched.h>
+
#include "host.h"
-#include "hostcmd.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
-#include "join.h"
+#include "assoc.h"
#include "wext.h"
+#include "scan.h"
#include "cmd.h"
-static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
+static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
/**
* @brief Simple callback that copies response back into command
}
/**
+ * @brief This function checks if the command is allowed.
+ *
+ * @param priv A pointer to lbs_private structure
+ * @return allowed or not allowed.
+ */
+
+static int lbs_is_cmd_allowed(struct lbs_private *priv)
+{
+ int ret = 1;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (!priv->is_auto_deep_sleep_enabled) {
+ if (priv->is_deep_sleep) {
+ lbs_deb_cmd("command not allowed in deep sleep\n");
+ ret = 0;
+ }
+ }
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
+}
+
+/**
* @brief Updates the hardware details like MAC address and regulatory region
*
* @param priv A pointer to struct lbs_private structure
struct cmd_ds_get_hw_spec cmd;
int ret = -1;
u32 i;
- DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_CMD);
* CF card firmware 5.0.16p0: cap 0x00000303
* USB dongle firmware 5.110.17p2: cap 0x00000303
*/
- printk("libertas: %s, fw %u.%u.%up%u, cap 0x%08x\n",
- print_mac(mac, cmd.permanentaddr),
+ lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n",
+ cmd.permanentaddr,
priv->fwrelease >> 24 & 0xff,
priv->fwrelease >> 16 & 0xff,
priv->fwrelease >> 8 & 0xff,
lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
cmd.hwifversion, cmd.version);
+ /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
+ /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
+ /* 5.110.22 have mesh command with 0xa3 command id */
+ /* 10.0.0.p0 FW brings in mesh config command with different id */
+ /* Check FW version MSB and initialize mesh_fw_ver */
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
+ priv->mesh_fw_ver = MESH_FW_OLD;
+ else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
+ (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK))
+ priv->mesh_fw_ver = MESH_FW_NEW;
+ else
+ priv->mesh_fw_ver = MESH_NONE;
+
/* 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.
+ *
+ * Firmware version 4.0.102 used in CF8381 has region code shifted. We
+ * need to check for this problem and handle it properly.
*/
- priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V4)
+ priv->regioncode = (le16_to_cpu(cmd.regioncode) >> 8) & 0xFF;
+ else
+ 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 */
goto out;
}
- if (lbs_set_universaltable(priv, 0)) {
- ret = -1;
- goto out;
- }
-
out:
lbs_deb_leave(LBS_DEB_CMD);
return ret;
}
-int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria)
+int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
+ struct wol_config *p_wol_config)
{
struct cmd_ds_host_sleep cmd_config;
int ret;
cmd_config.gpio = priv->wol_gpio;
cmd_config.gap = priv->wol_gap;
+ if (p_wol_config != NULL)
+ memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config,
+ sizeof(struct wol_config));
+ else
+ cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;
+
ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
if (!ret) {
- lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
- priv->wol_criteria = criteria;
+ if (criteria) {
+ lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
+ priv->wol_criteria = criteria;
+ } else
+ memcpy((uint8_t *) p_wol_config,
+ (uint8_t *)&cmd_config.wol_conf,
+ sizeof(struct wol_config));
} else {
lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
}
cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
psm->action = cpu_to_le16(cmd_action);
psm->multipledtim = 0;
switch (cmd_action) {
return 0;
}
-int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
- uint16_t cmd_action, uint16_t *timeout)
-{
- struct cmd_ds_802_11_inactivity_timeout cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- cmd.hdr.command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_SET)
- cmd.timeout = cpu_to_le16(*timeout);
- else
- cmd.timeout = 0;
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_INACTIVITY_TIMEOUT, &cmd);
-
- if (!ret)
- *timeout = le16_to_cpu(cmd.timeout);
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return 0;
-}
-
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
struct sleep_params *sp)
{
return 0;
}
-int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc)
+static int lbs_wait_for_ds_awake(struct lbs_private *priv)
{
- struct cmd_ds_802_11_set_wep cmd;
int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
- cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_ADD) {
- int i;
-
- /* default tx key index */
- cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
- CMD_WEP_KEY_INDEX_MASK);
-
- /* Copy key types and material to host command structure */
- for (i = 0; i < 4; i++) {
- struct enc_key *pkey = &assoc->wep_keys[i];
-
- switch (pkey->len) {
- case KEY_LEN_WEP_40:
- cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
- memmove(cmd.keymaterial[i], pkey->key, pkey->len);
- lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
- break;
- case KEY_LEN_WEP_104:
- cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
- memmove(cmd.keymaterial[i], pkey->key, pkey->len);
- lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
- break;
- case 0:
- break;
- default:
- lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
- i, pkey->len);
- ret = -1;
- goto done;
- break;
- }
+ if (priv->is_deep_sleep) {
+ if (!wait_event_interruptible_timeout(priv->ds_awake_q,
+ !priv->is_deep_sleep, (10 * HZ))) {
+ lbs_pr_err("ds_awake_q: timer expired\n");
+ ret = -1;
}
- } else if (cmd_action == CMD_ACT_REMOVE) {
- /* ACT_REMOVE clears _all_ WEP keys */
-
- /* default tx key index */
- cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
- CMD_WEP_KEY_INDEX_MASK);
- lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
}
- ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
-done:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
-int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
- uint16_t *enable)
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
{
- struct cmd_ds_802_11_enable_rsn cmd;
- int ret;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_SET) {
- if (*enable)
- cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
- else
- cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
- lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
- }
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
- if (!ret && cmd_action == CMD_ACT_GET)
- *enable = le16_to_cpu(cmd.enable);
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
- struct enc_key *key)
-{
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (key->flags & KEY_INFO_WPA_ENABLED)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
- if (key->flags & KEY_INFO_WPA_UNICAST)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
- if (key->flags & KEY_INFO_WPA_MCAST)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
-
- keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
- keyparam->keytypeid = cpu_to_le16(key->type);
- keyparam->keylen = cpu_to_le16(key->len);
- memcpy(keyparam->key, key->key, key->len);
-
- /* Length field doesn't include the {type,length} header */
- keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
- lbs_deb_leave(LBS_DEB_CMD);
-}
-
-int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc)
-{
- struct cmd_ds_802_11_key_material cmd;
- int ret = 0;
- int index = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- cmd.action = cpu_to_le16(cmd_action);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- if (cmd_action == CMD_ACT_GET) {
- cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2);
- } else {
- memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
-
- if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
- set_one_wpa_key(&cmd.keyParamSet[index],
- &assoc->wpa_unicast_key);
- index++;
- }
-
- if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
- set_one_wpa_key(&cmd.keyParamSet[index],
- &assoc->wpa_mcast_key);
- index++;
+ if (deep_sleep) {
+ if (priv->is_deep_sleep != 1) {
+ lbs_deb_cmd("deep sleep: sleep\n");
+ BUG_ON(!priv->enter_deep_sleep);
+ ret = priv->enter_deep_sleep(priv);
+ if (!ret) {
+ netif_stop_queue(priv->dev);
+ netif_carrier_off(priv->dev);
+ }
+ } else {
+ lbs_pr_err("deep sleep: already enabled\n");
}
-
- /* The common header and as many keys as we included */
- cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
- keyParamSet[index]));
- }
- ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
- /* Copy the returned key to driver private data */
- if (!ret && cmd_action == CMD_ACT_GET) {
- void *buf_ptr = cmd.keyParamSet;
- void *resp_end = &(&cmd)[1];
-
- while (buf_ptr < resp_end) {
- struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
- struct enc_key *key;
- uint16_t param_set_len = le16_to_cpu(keyparam->length);
- uint16_t key_len = le16_to_cpu(keyparam->keylen);
- uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
- uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
- void *end;
-
- end = (void *)keyparam + sizeof(keyparam->type)
- + sizeof(keyparam->length) + param_set_len;
-
- /* Make sure we don't access past the end of the IEs */
- if (end > resp_end)
- break;
-
- if (key_flags & KEY_INFO_WPA_UNICAST)
- key = &priv->wpa_unicast_key;
- else if (key_flags & KEY_INFO_WPA_MCAST)
- key = &priv->wpa_mcast_key;
- else
- break;
-
- /* Copy returned key into driver */
- memset(key, 0, sizeof(struct enc_key));
- if (key_len > sizeof(key->key))
- break;
- key->type = key_type;
- key->flags = key_flags;
- key->len = key_len;
- memcpy(key->key, keyparam->key, key->len);
-
- buf_ptr = end + 1;
+ } else {
+ if (priv->is_deep_sleep) {
+ lbs_deb_cmd("deep sleep: wakeup\n");
+ BUG_ON(!priv->exit_deep_sleep);
+ ret = priv->exit_deep_sleep(priv);
+ if (!ret) {
+ ret = lbs_wait_for_ds_awake(priv);
+ if (ret)
+ lbs_pr_err("deep sleep: wakeup"
+ "failed\n");
+ }
}
}
return ret;
}
-static int lbs_cmd_802_11_reset(struct cmd_ds_command *cmd, int cmd_action)
-{
- struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- cmd->command = cpu_to_le16(CMD_802_11_RESET);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
- reset->action = cpu_to_le16(cmd_action);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
-static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
- struct cmd_ds_command *cmd,
- int cmd_action,
- int cmd_oid, void *pdata_buf)
+/**
+ * @brief Set an SNMP MIB value
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param oid The OID to set in the firmware
+ * @param val Value to set the OID to
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
{
- struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
- u8 ucTemp;
+ struct cmd_ds_802_11_snmp_mib cmd;
+ int ret;
lbs_deb_enter(LBS_DEB_CMD);
- lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
-
- cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
- cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
-
- switch (cmd_oid) {
- case OID_802_11_INFRASTRUCTURE_MODE:
- {
- u8 mode = (u8) (size_t) pdata_buf;
- pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
- pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
- pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8));
- if (mode == IW_MODE_ADHOC) {
- ucTemp = SNMP_MIB_VALUE_ADHOC;
- } else {
- /* Infra and Auto modes */
- ucTemp = SNMP_MIB_VALUE_INFRA;
- }
-
- memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));
+ memset(&cmd, 0, sizeof (cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
+ cmd.oid = cpu_to_le16((u16) oid);
+ switch (oid) {
+ case SNMP_MIB_OID_BSS_TYPE:
+ cmd.bufsize = cpu_to_le16(sizeof(u8));
+ cmd.value[0] = (val == IW_MODE_ADHOC) ? 2 : 1;
break;
- }
-
- case OID_802_11D_ENABLE:
- {
- u32 ulTemp;
-
- pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
-
- if (cmd_action == CMD_ACT_SET) {
- pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
- pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
- ulTemp = *(u32 *)pdata_buf;
- *((__le16 *)(pSNMPMIB->value)) =
- cpu_to_le16((u16) ulTemp);
- }
- break;
- }
-
- case OID_802_11_FRAGMENTATION_THRESHOLD:
- {
- u32 ulTemp;
-
- pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
-
- 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);
- pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
- ulTemp = *((u32 *) pdata_buf);
- *((__le16 *)(pSNMPMIB->value)) =
- cpu_to_le16((u16) ulTemp);
-
- }
-
- break;
- }
-
- case OID_802_11_RTS_THRESHOLD:
- {
-
- u32 ulTemp;
- pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I);
-
- 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);
- pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
- ulTemp = *((u32 *)pdata_buf);
- *(__le16 *)(pSNMPMIB->value) =
- cpu_to_le16((u16) ulTemp);
-
- }
- break;
- }
- case OID_802_11_TX_RETRYCOUNT:
- pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);
-
- 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);
- pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
- *((__le16 *)(pSNMPMIB->value)) =
- cpu_to_le16((u16) priv->txretrycount);
- }
-
+ case SNMP_MIB_OID_11D_ENABLE:
+ case SNMP_MIB_OID_FRAG_THRESHOLD:
+ case SNMP_MIB_OID_RTS_THRESHOLD:
+ case SNMP_MIB_OID_SHORT_RETRY_LIMIT:
+ case SNMP_MIB_OID_LONG_RETRY_LIMIT:
+ cmd.bufsize = cpu_to_le16(sizeof(u16));
+ *((__le16 *)(&cmd.value)) = cpu_to_le16(val);
break;
default:
- break;
+ lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid);
+ ret = -EINVAL;
+ goto out;
}
- lbs_deb_cmd(
- "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
- le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
- le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
+ lbs_deb_cmd("SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x\n",
+ le16_to_cpu(cmd.oid), le16_to_cpu(cmd.bufsize), val);
- lbs_deb_cmd(
- "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
- le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
- le16_to_cpu(pSNMPMIB->bufsize),
- le16_to_cpu(*(__le16 *) pSNMPMIB->value));
+ ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
}
-static int lbs_cmd_802_11_rf_tx_power(struct cmd_ds_command *cmd,
- u16 cmd_action, void *pdata_buf)
+/**
+ * @brief Get an SNMP MIB value
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param oid The OID to retrieve from the firmware
+ * @param out_val Location for the returned value
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
{
-
- struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
+ struct cmd_ds_802_11_snmp_mib cmd;
+ int ret;
lbs_deb_enter(LBS_DEB_CMD);
- cmd->size =
- cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
- cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
- prtp->action = cpu_to_le16(cmd_action);
-
- 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));
+ memset(&cmd, 0, sizeof (cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_GET);
+ cmd.oid = cpu_to_le16(oid);
- switch (cmd_action) {
- case CMD_ACT_TX_POWER_OPT_GET:
- prtp->action = cpu_to_le16(CMD_ACT_GET);
- prtp->currentlevel = 0;
- break;
+ ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
+ if (ret)
+ goto out;
- 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);
+ switch (le16_to_cpu(cmd.bufsize)) {
+ case sizeof(u8):
+ if (oid == SNMP_MIB_OID_BSS_TYPE) {
+ if (cmd.value[0] == 2)
+ *out_val = IW_MODE_ADHOC;
+ else
+ *out_val = IW_MODE_INFRA;
+ } else
+ *out_val = cmd.value[0];
break;
-
- 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);
+ case sizeof(u16):
+ *out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
break;
-
- case CMD_ACT_TX_POWER_OPT_SET_LOW:
- prtp->action = cpu_to_le16(CMD_ACT_SET);
- prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
+ default:
+ lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n",
+ oid, le16_to_cpu(cmd.bufsize));
break;
}
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
-static int lbs_cmd_802_11_monitor_mode(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;
-}
-
-static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
- struct cmd_ds_command *cmd,
- u16 cmd_action)
-{
- struct cmd_ds_802_11_rate_adapt_rateset
- *rateadapt = &cmd->params.rateset;
-
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->size =
- cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
- + S_DS_GEN);
- cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
-
- rateadapt->action = cpu_to_le16(cmd_action);
- rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
- rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
}
/**
- * @brief Get the current data rate
+ * @brief Get the min, max, and current TX power
*
* @param priv A pointer to struct lbs_private structure
+ * @param curlevel Current power level in dBm
+ * @param minlevel Minimum supported power level in dBm (optional)
+ * @param maxlevel Maximum supported power level in dBm (optional)
*
- * @return The data rate on success, error on failure
+ * @return 0 on success, error on failure
*/
-int lbs_get_data_rate(struct lbs_private *priv)
+int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
+ s16 *maxlevel)
{
- struct cmd_ds_802_11_data_rate cmd;
- int ret = -1;
+ struct cmd_ds_802_11_rf_tx_power cmd;
+ int ret;
lbs_deb_enter(LBS_DEB_CMD);
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);
+ cmd.action = cpu_to_le16(CMD_ACT_GET);
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
+ if (ret == 0) {
+ *curlevel = le16_to_cpu(cmd.curlevel);
+ if (minlevel)
+ *minlevel = cmd.minlevel;
+ if (maxlevel)
+ *maxlevel = cmd.maxlevel;
+ }
-out:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave(LBS_DEB_CMD);
return ret;
}
/**
- * @brief Set the data rate
+ * @brief Set the TX power
*
* @param priv A pointer to struct lbs_private structure
- * @param rate The desired data rate, or 0 to clear a locked rate
+ * @param dbm The desired power level in dBm
*
* @return 0 on success, error on failure
*/
-int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
+int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
{
- struct cmd_ds_802_11_data_rate cmd;
- int ret = 0;
+ struct cmd_ds_802_11_rf_tx_power cmd;
+ int ret;
lbs_deb_enter(LBS_DEB_CMD);
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
+ cmd.curlevel = cpu_to_le16(dbm);
- 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);
- lbs_deb_cmd("DATA_RATE: setting auto\n");
- }
-
- 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));
+ lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm);
- /* 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);
+ ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
-out:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave(LBS_DEB_CMD);
return ret;
}
-static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
- struct cmd_ds_command *cmd,
- u16 cmd_action)
+static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
{
- struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
+ struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
- S_DS_GEN);
- cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
+ cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
+ sizeof(struct cmd_header));
- lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
- pMCastAdr->action = cpu_to_le16(cmd_action);
- pMCastAdr->nr_of_adrs =
- cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
- memcpy(pMCastAdr->maclist, priv->multicastlist,
- priv->nr_of_multicastmacaddr * ETH_ALEN);
+ monitor->action = cpu_to_le16(cmd_action);
+ if (cmd_action == CMD_ACT_SET) {
+ monitor->mode =
+ cpu_to_le16((u16) (*(u32 *) pdata_buf));
+ }
- lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
*
* @return The channel on success, error on failure
*/
-int lbs_get_channel(struct lbs_private *priv)
+static int lbs_get_channel(struct lbs_private *priv)
{
struct cmd_ds_802_11_rf_channel cmd;
int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
+ memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
return ret;
}
+int lbs_update_channel(struct lbs_private *priv)
+{
+ int ret;
+
+ /* the channel in f/w could be out of sync; get the current channel */
+ lbs_deb_enter(LBS_DEB_ASSOC);
+
+ ret = lbs_get_channel(priv);
+ if (ret > 0) {
+ priv->channel = ret;
+ ret = 0;
+ }
+ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+ return ret;
+}
+
/**
* @brief Set the radio channel
*
int lbs_set_channel(struct lbs_private *priv, u8 channel)
{
struct cmd_ds_802_11_rf_channel cmd;
- u8 old_channel = priv->curbssparams.channel;
+#ifdef DEBUG
+ u8 old_channel = priv->channel;
+#endif
int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
+ memset(&cmd, 0, sizeof(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);
if (ret)
goto out;
- priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel);
+ priv->channel = (uint8_t) le16_to_cpu(cmd.channel);
lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
- priv->curbssparams.channel);
+ priv->channel);
out:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
-static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
- struct cmd_ds_command *cmd)
-{
-
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(CMD_802_11_RSSI);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
- cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
-
- /* reset Beacon SNR/NF/RSSI values */
- 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;
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
u8 cmd_action, void *pdata_buf)
{
cmdptr->size =
cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
- + S_DS_GEN);
+ + sizeof(struct cmd_header));
macreg =
(struct cmd_ds_mac_reg_access *)&cmdptr->params.
macreg;
cmdptr->size =
cpu_to_le16(sizeof
(struct cmd_ds_bbp_reg_access)
- + S_DS_GEN);
+ + sizeof(struct cmd_header));
bbpreg =
(struct cmd_ds_bbp_reg_access *)&cmdptr->params.
bbpreg;
cmdptr->size =
cpu_to_le16(sizeof
(struct cmd_ds_rf_reg_access) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
rfreg =
(struct cmd_ds_rf_reg_access *)&cmdptr->params.
rfreg;
return 0;
}
-static int lbs_cmd_802_11_mac_address(struct lbs_private *priv,
- struct cmd_ds_command *cmd,
- u16 cmd_action)
-{
-
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
- S_DS_GEN);
- cmd->result = 0;
-
- cmd->params.macadd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_SET) {
- memcpy(cmd->params.macadd.macadd,
- priv->current_addr, ETH_ALEN);
- lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6);
- }
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
-static int lbs_cmd_802_11_eeprom_access(struct cmd_ds_command *cmd,
- void *pdata_buf)
-{
- struct lbs_ioctl_regrdwr *ea = pdata_buf;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
- S_DS_GEN);
- 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;
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
static int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
u16 cmd_action, void *pdata_buf)
{
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
cmd->command = cpu_to_le16(CMD_BT_ACCESS);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) +
+ sizeof(struct cmd_header));
cmd->result = 0;
bt_access->action = cpu_to_le16(cmd_action);
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) +
+ sizeof(struct cmd_header));
cmd->result = 0;
if (pdata_buf)
return ret;
}
-int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan)
+static int __lbs_mesh_config_send(struct lbs_private *priv,
+ struct cmd_ds_mesh_config *cmd,
+ uint16_t action, uint16_t type)
{
- struct cmd_ds_mesh_config cmd;
+ int ret;
+ u16 command = CMD_MESH_CONFIG_OLD;
- memset(&cmd, 0, sizeof(cmd));
- cmd.action = cpu_to_le16(enable);
- cmd.channel = cpu_to_le16(chan);
- cmd.type = cpu_to_le16(priv->mesh_tlv);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ lbs_deb_enter(LBS_DEB_CMD);
- if (enable) {
- cmd.length = cpu_to_le16(priv->mesh_ssid_len);
- memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len);
- }
- lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n",
- enable, priv->mesh_tlv, chan,
- escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
- return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd);
+ /*
+ * Command id is 0xac for v10 FW along with mesh interface
+ * id in bits 14-13-12.
+ */
+ if (priv->mesh_fw_ver == MESH_FW_NEW)
+ command = CMD_MESH_CONFIG |
+ (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
+
+ cmd->hdr.command = cpu_to_le16(command);
+ cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
+ cmd->hdr.result = 0;
+
+ cmd->type = cpu_to_le16(type);
+ cmd->action = cpu_to_le16(action);
+
+ ret = lbs_cmd_with_response(priv, command, cmd);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
}
-static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
- struct cmd_ds_command *cmd,
- u16 cmd_action)
+int lbs_mesh_config_send(struct lbs_private *priv,
+ struct cmd_ds_mesh_config *cmd,
+ uint16_t action, uint16_t type)
{
- struct cmd_ds_802_11_beacon_control
- *bcn_ctrl = &cmd->params.bcn_ctrl;
+ int ret;
- 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);
+ if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
+ return -EOPNOTSUPP;
+
+ ret = __lbs_mesh_config_send(priv, cmd, action, type);
+ return ret;
+}
- bcn_ctrl->action = cpu_to_le16(cmd_action);
- bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
- bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
+/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
+ * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
+ * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
+ * lbs_mesh_config_send.
+ */
+int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
+{
+ struct cmd_ds_mesh_config cmd;
+ struct mrvl_meshie *ie;
+ DECLARE_SSID_BUF(ssid);
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.channel = cpu_to_le16(chan);
+ ie = (struct mrvl_meshie *)cmd.data;
+
+ switch (action) {
+ case CMD_ACT_MESH_CONFIG_START:
+ ie->id = WLAN_EID_GENERIC;
+ ie->val.oui[0] = 0x00;
+ ie->val.oui[1] = 0x50;
+ ie->val.oui[2] = 0x43;
+ ie->val.type = MARVELL_MESH_IE_TYPE;
+ ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
+ ie->val.version = MARVELL_MESH_IE_VERSION;
+ ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
+ ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
+ ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
+ ie->val.mesh_id_len = priv->mesh_ssid_len;
+ memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
+ ie->len = sizeof(struct mrvl_meshie_val) -
+ IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
+ cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
+ break;
+ case CMD_ACT_MESH_CONFIG_STOP:
+ break;
+ default:
+ return -1;
+ }
+ lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
+ action, priv->mesh_tlv, chan,
+ print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
+
+ return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
}
static void lbs_queue_cmd(struct lbs_private *priv,
struct cmd_header *cmd;
uint16_t cmdsize;
uint16_t command;
- int timeo = 5 * HZ;
+ int timeo = 3 * HZ;
int ret;
lbs_deb_enter(LBS_DEB_HOST);
command = le16_to_cpu(cmd->command);
/* These commands take longer */
- if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
- command == CMD_802_11_AUTHENTICATE)
- timeo = 10 * HZ;
+ if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE)
+ timeo = 5 * HZ;
- lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n",
- command, le16_to_cpu(cmd->seqnum), cmdsize, jiffies);
+ lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
+ command, le16_to_cpu(cmd->seqnum), cmdsize);
lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
/* Let the timer kick in and retry, and potentially reset
the whole thing if the condition persists */
- timeo = HZ;
+ timeo = HZ/4;
}
- /* Setup the timer after transmit command */
- mod_timer(&priv->command_timer, jiffies + timeo);
+ if (command == CMD_802_11_DEEP_SLEEP) {
+ if (priv->is_auto_deep_sleep_enabled) {
+ priv->wakeup_dev_required = 1;
+ priv->dnld_sent = 0;
+ }
+ priv->is_deep_sleep = 1;
+ lbs_complete_command(priv, cmdnode, 0);
+ } else {
+ /* Setup the timer after transmit command */
+ mod_timer(&priv->command_timer, jiffies + timeo);
+ }
lbs_deb_leave(LBS_DEB_HOST);
}
priv->cur_cmd = NULL;
}
-int lbs_set_radio_control(struct lbs_private *priv)
+int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
{
- int ret = 0;
struct cmd_ds_802_11_radio_control cmd;
+ int ret = -EINVAL;
lbs_deb_enter(LBS_DEB_CMD);
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_SET);
- switch (priv->preamble) {
- case CMD_TYPE_SHORT_PREAMBLE:
- cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE);
- break;
-
- case CMD_TYPE_LONG_PREAMBLE:
- cmd.control = cpu_to_le16(SET_LONG_PREAMBLE);
- break;
+ /* Only v8 and below support setting the preamble */
+ if (priv->fwrelease < 0x09000000) {
+ switch (preamble) {
+ case RADIO_PREAMBLE_SHORT:
+ if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
+ goto out;
+ /* Fall through */
+ case RADIO_PREAMBLE_AUTO:
+ case RADIO_PREAMBLE_LONG:
+ cmd.control = cpu_to_le16(preamble);
+ break;
+ default:
+ goto out;
+ }
+ }
- case CMD_TYPE_AUTO_PREAMBLE:
- default:
- cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE);
- break;
+ if (radio_on)
+ cmd.control |= cpu_to_le16(0x1);
+ else {
+ cmd.control &= cpu_to_le16(~0x1);
+ priv->txpower_cur = 0;
}
- if (priv->radioon)
- cmd.control |= cpu_to_le16(TURN_ON_RF);
- else
- cmd.control &= cpu_to_le16(~TURN_ON_RF);
+ lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n",
+ radio_on ? "ON" : "OFF", preamble);
- lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon,
- priv->preamble);
+ priv->radio_on = radio_on;
ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
+out:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
cmd.action = cpu_to_le16(priv->mac_control);
cmd.reserved = 0;
- lbs_cmd_async(priv, CMD_MAC_CONTROL,
- &cmd.hdr, sizeof(cmd));
+ lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
lbs_deb_leave(LBS_DEB_CMD);
}
goto done;
}
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto done;
+ }
+
cmdnode = lbs_get_cmd_ctrl_node(priv);
if (cmdnode == NULL) {
ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action);
break;
- case CMD_802_11_ASSOCIATE:
- case CMD_802_11_REASSOCIATE:
- ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
- break;
-
- case CMD_802_11_DEAUTHENTICATE:
- ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
- break;
-
- case CMD_802_11_AD_HOC_START:
- ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
- break;
-
- case CMD_802_11_RESET:
- ret = lbs_cmd_802_11_reset(cmdptr, cmd_action);
- break;
-
- case CMD_802_11_AUTHENTICATE:
- ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
- break;
-
- case CMD_802_11_SNMP_MIB:
- ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
- cmd_action, cmd_oid, pdata_buf);
- break;
-
case CMD_MAC_REG_ACCESS:
case CMD_BBP_REG_ACCESS:
case CMD_RF_REG_ACCESS:
ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf);
break;
- case CMD_802_11_RF_TX_POWER:
- ret = lbs_cmd_802_11_rf_tx_power(cmdptr,
- cmd_action, pdata_buf);
- break;
-
- case CMD_802_11_RATE_ADAPT_RATESET:
- ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
- cmdptr, cmd_action);
- break;
-
- case CMD_MAC_MULTICAST_ADR:
- ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
- break;
-
case CMD_802_11_MONITOR_MODE:
ret = lbs_cmd_802_11_monitor_mode(cmdptr,
cmd_action, pdata_buf);
break;
- case CMD_802_11_AD_HOC_JOIN:
- ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
- break;
-
case CMD_802_11_RSSI:
ret = lbs_cmd_802_11_rssi(priv, cmdptr);
break;
- case CMD_802_11_AD_HOC_STOP:
- ret = lbs_cmd_80211_ad_hoc_stop(cmdptr);
- break;
-
- case CMD_802_11_MAC_ADDRESS:
- ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
- break;
-
- case CMD_802_11_EEPROM_ACCESS:
- ret = lbs_cmd_802_11_eeprom_access(cmdptr, pdata_buf);
- break;
-
case CMD_802_11_SET_AFC:
case CMD_802_11_GET_AFC:
cmdptr->command = cpu_to_le16(cmd_no);
cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
memmove(&cmdptr->params.afc,
pdata_buf, sizeof(struct cmd_ds_802_11_afc));
ret = 0;
goto done;
- case CMD_802_11D_DOMAIN_INFO:
- ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
- cmd_no, cmd_action);
- break;
-
case CMD_802_11_TPC_CFG:
cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
cmdptr->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
memmove(&cmdptr->params.tpccfg,
pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
ret = 0;
break;
- case CMD_802_11_LED_GPIO_CTRL:
- {
- 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 =
- cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
-
-#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
- cmdptr->size =
- cpu_to_le16(le16_to_cpu(gpio->header.len)
- + S_DS_GEN
- + ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
- gpio->header.len = gpio->header.len;
-
- ret = 0;
- break;
- }
case CMD_BT_ACCESS:
ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
break;
- case CMD_GET_TSF:
- cmdptr->command = cpu_to_le16(CMD_GET_TSF);
- cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
- S_DS_GEN);
- ret = 0;
- break;
case CMD_802_11_BEACON_CTRL:
ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
break;
+ case CMD_802_11_DEEP_SLEEP:
+ cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
+ cmdptr->size = cpu_to_le16(sizeof(struct cmd_header));
+ break;
default:
- lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
+ lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
ret = -1;
break;
}
/**
* @brief This function executes next command in command
- * pending queue. It will put fimware back to PS mode
+ * pending queue. It will put firmware back to PS mode
* if applicable.
*
* @param priv A pointer to struct lbs_private structure
return ret;
}
-void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
-{
- union iwreq_data iwrq;
- u8 buf[50];
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- 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 */
- 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);
-
- wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
-
- lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
+static void lbs_send_confirmsleep(struct lbs_private *priv)
{
unsigned long flags;
- int ret = 0;
+ int ret;
lbs_deb_enter(LBS_DEB_HOST);
- lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
+ lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,
+ sizeof(confirm_sleep));
- ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
+ ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
+ sizeof(confirm_sleep));
+ if (ret) {
+ lbs_pr_alert("confirm_sleep failed\n");
+ goto out;
+ }
spin_lock_irqsave(&priv->driver_lock, flags);
- if (priv->intcounter || priv->currenttxskb)
- lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
- priv->intcounter, priv->currenttxskb);
- spin_unlock_irqrestore(&priv->driver_lock, flags);
- if (ret) {
- lbs_pr_alert(
- "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
- } else {
- spin_lock_irqsave(&priv->driver_lock, flags);
- if (!priv->intcounter) {
- priv->psstate = PS_STATE_SLEEP;
- } else {
- lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
- priv->intcounter);
- }
- spin_unlock_irqrestore(&priv->driver_lock, flags);
- }
+ /* We don't get a response on the sleep-confirmation */
+ priv->dnld_sent = DNLD_RES_RECEIVED;
- lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
- return ret;
+ /* If nothing to do, go back to sleep (?) */
+ if (!__kfifo_len(priv->event_fifo) && !priv->resp_len[priv->resp_idx])
+ priv->psstate = PS_STATE_SLEEP;
+
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+out:
+ lbs_deb_leave(LBS_DEB_HOST);
}
void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
lbs_deb_enter(LBS_DEB_HOST);
+ spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->dnld_sent) {
allowed = 0;
lbs_deb_host("dnld_sent was set\n");
}
- spin_lock_irqsave(&priv->driver_lock, flags);
+ /* In-progress command? */
if (priv->cur_cmd) {
allowed = 0;
lbs_deb_host("cur_cmd was set\n");
}
- if (priv->intcounter > 0) {
+
+ /* Pending events or command responses? */
+ if (__kfifo_len(priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
allowed = 0;
- lbs_deb_host("intcounter %d\n", priv->intcounter);
+ lbs_deb_host("pending events or command responses\n");
}
spin_unlock_irqrestore(&priv->driver_lock, flags);
if (allowed) {
lbs_deb_host("sending lbs_ps_confirm_sleep\n");
- sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep,
- sizeof(struct PS_CMD_ConfirmSleep));
+ lbs_send_confirmsleep(priv);
} else {
lbs_deb_host("sleep confirm has been delayed\n");
}
}
-static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
+/**
+ * @brief Configures the transmission power control functionality.
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param enable Transmission power control enable
+ * @param p0 Power level when link quality is good (dBm).
+ * @param p1 Power level when link quality is fair (dBm).
+ * @param p2 Power level when link quality is poor (dBm).
+ * @param usesnr Use Signal to Noise Ratio in TPC
+ *
+ * @return 0 on success
+ */
+int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
+ int8_t p2, int usesnr)
+{
+ struct cmd_ds_802_11_tpc_cfg cmd;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
+ cmd.enable = !!enable;
+ cmd.usesnr = !!usesnr;
+ cmd.P0 = p0;
+ cmd.P1 = p1;
+ cmd.P2 = p2;
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd);
+
+ return ret;
+}
+
+/**
+ * @brief Configures the power adaptation settings.
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param enable Power adaptation enable
+ * @param p0 Power level for 1, 2, 5.5 and 11 Mbps (dBm).
+ * @param p1 Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
+ * @param p2 Power level for 48 and 54 Mbps (dBm).
+ *
+ * @return 0 on Success
+ */
+
+int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
+ int8_t p1, int8_t p2)
+{
+ struct cmd_ds_802_11_pa_cfg cmd;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
+ cmd.enable = !!enable;
+ cmd.P0 = p0;
+ cmd.P1 = p1;
+ cmd.P2 = p2;
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd);
+
+ return ret;
+}
+
+
+struct cmd_ctrl_node *__lbs_cmd_async(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 *),
unsigned long callback_arg)
goto done;
}
+ if (!lbs_is_cmd_allowed(priv)) {
+ cmdnode = ERR_PTR(-EBUSY);
+ goto done;
+ }
+
cmdnode = lbs_get_cmd_ctrl_node(priv);
if (cmdnode == NULL) {
lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
return ret;
}
EXPORT_SYMBOL_GPL(__lbs_cmd);
-
-