summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/libertas/cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/libertas/cmd.c')
-rw-r--r--drivers/net/wireless/libertas/cmd.c767
1 files changed, 407 insertions, 360 deletions
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index cdb9b9650d7..70745928f3f 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -6,18 +6,14 @@
#include <linux/kfifo.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/if_arp.h>
-#include "host.h"
#include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "assoc.h"
-#include "wext.h"
-#include "scan.h"
+#include "cfg.h"
#include "cmd.h"
-
-static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
+#define CAL_NF(nf) ((s32)(-(s32)(nf)))
+#define CAL_RSSI(snr, nf) ((s32)((s32)(snr) + CAL_NF(nf)))
/**
* @brief Simple callback that copies response back into command
@@ -70,6 +66,8 @@ static u8 is_command_allowed_in_ps(u16 cmd)
switch (cmd) {
case CMD_802_11_RSSI:
return 1;
+ case CMD_802_11_HOST_SLEEP_CFG:
+ return 1;
default:
break;
}
@@ -77,30 +75,6 @@ static u8 is_command_allowed_in_ps(u16 cmd)
}
/**
- * @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
@@ -175,16 +149,28 @@ int lbs_update_hw_spec(struct lbs_private *priv)
if (priv->mesh_dev)
memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
- if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
- ret = -1;
- goto out;
- }
-
out:
lbs_deb_leave(LBS_DEB_CMD);
return ret;
}
+static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
+ struct cmd_header *resp)
+{
+ lbs_deb_enter(LBS_DEB_CMD);
+ if (priv->is_host_sleep_activated) {
+ priv->is_host_sleep_configured = 0;
+ if (priv->psstate == PS_STATE_FULL_POWER) {
+ priv->is_host_sleep_activated = 0;
+ wake_up_interruptible(&priv->host_sleep_q);
+ }
+ } else {
+ priv->is_host_sleep_configured = 1;
+ }
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
struct wol_config *p_wol_config)
{
@@ -202,12 +188,11 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
else
cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;
- ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
+ ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config.hdr,
+ le16_to_cpu(cmd_config.hdr.size),
+ lbs_ret_host_sleep_cfg, 0);
if (!ret) {
- if (criteria) {
- lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
- priv->wol_criteria = criteria;
- } else
+ if (p_wol_config)
memcpy((uint8_t *) p_wol_config,
(uint8_t *)&cmd_config.wol_conf,
sizeof(struct wol_config));
@@ -219,42 +204,49 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
}
EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
-static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
- u16 cmd_action)
+/**
+ * @brief Sets the Power Save mode
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param cmd_action The Power Save operation (PS_MODE_ACTION_ENTER_PS or
+ * PS_MODE_ACTION_EXIT_PS)
+ * @param block Whether to block on a response or not
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
{
- struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
+ struct cmd_ds_802_11_ps_mode cmd;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
- sizeof(struct cmd_header));
- psm->action = cpu_to_le16(cmd_action);
- psm->multipledtim = 0;
- switch (cmd_action) {
- case CMD_SUBCMD_ENTER_PS:
- lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
-
- psm->locallisteninterval = 0;
- psm->nullpktinterval = 0;
- psm->multipledtim =
- cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
- break;
-
- case CMD_SUBCMD_EXIT_PS:
- lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
- break;
-
- case CMD_SUBCMD_SLEEP_CONFIRMED:
- lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
- break;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(cmd_action);
- default:
- break;
+ if (cmd_action == PS_MODE_ACTION_ENTER_PS) {
+ lbs_deb_cmd("PS_MODE: action ENTER_PS\n");
+ cmd.multipledtim = cpu_to_le16(1); /* Default DTIM multiple */
+ } else if (cmd_action == PS_MODE_ACTION_EXIT_PS) {
+ lbs_deb_cmd("PS_MODE: action EXIT_PS\n");
+ } else {
+ /* We don't handle CONFIRM_SLEEP here because it needs to
+ * be fastpathed to the firmware.
+ */
+ lbs_deb_cmd("PS_MODE: unknown action 0x%X\n", cmd_action);
+ ret = -EOPNOTSUPP;
+ goto out;
}
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
+ if (block)
+ ret = lbs_cmd_with_response(priv, CMD_802_11_PS_MODE, &cmd);
+ else
+ lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd));
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
}
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
@@ -353,6 +345,65 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
return ret;
}
+static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
+ unsigned long dummy,
+ struct cmd_header *cmd)
+{
+ lbs_deb_enter(LBS_DEB_FW);
+ priv->is_host_sleep_activated = 1;
+ wake_up_interruptible(&priv->host_sleep_q);
+ lbs_deb_leave(LBS_DEB_FW);
+ return 0;
+}
+
+int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
+{
+ struct cmd_header cmd;
+ int ret = 0;
+ uint32_t criteria = EHS_REMOVE_WAKEUP;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (host_sleep) {
+ if (priv->is_host_sleep_activated != 1) {
+ memset(&cmd, 0, sizeof(cmd));
+ ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
+ (struct wol_config *)NULL);
+ if (ret) {
+ lbs_pr_info("Host sleep configuration failed: "
+ "%d\n", ret);
+ return ret;
+ }
+ if (priv->psstate == PS_STATE_FULL_POWER) {
+ ret = __lbs_cmd(priv,
+ CMD_802_11_HOST_SLEEP_ACTIVATE,
+ &cmd,
+ sizeof(cmd),
+ lbs_ret_host_sleep_activate, 0);
+ if (ret)
+ lbs_pr_info("HOST_SLEEP_ACTIVATE "
+ "failed: %d\n", ret);
+ }
+
+ if (!wait_event_interruptible_timeout(
+ priv->host_sleep_q,
+ priv->is_host_sleep_activated,
+ (10 * HZ))) {
+ lbs_pr_err("host_sleep_q: timer expired\n");
+ ret = -1;
+ }
+ } else {
+ lbs_pr_err("host sleep: already enabled\n");
+ }
+ } else {
+ if (priv->is_host_sleep_activated)
+ ret = lbs_host_sleep_cfg(priv, criteria,
+ (struct wol_config *)NULL);
+ }
+
+ return ret;
+}
+
/**
* @brief Set an SNMP MIB value
*
@@ -509,23 +560,35 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
return ret;
}
-static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
- u16 cmd_action, void *pdata_buf)
+/**
+ * @brief Enable or disable monitor mode (only implemented on OLPC usb8388 FW)
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param enable 1 to enable monitor mode, 0 to disable
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
{
- struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;
+ struct cmd_ds_802_11_monitor_mode cmd;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
+ if (enable)
+ cmd.mode = cpu_to_le16(0x1);
- 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("SET_MONITOR_MODE: %d\n", enable);
- monitor->action = cpu_to_le16(cmd_action);
- if (cmd_action == CMD_ACT_SET) {
- monitor->mode =
- cpu_to_le16((u16) (*(u32 *) pdata_buf));
+ ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd);
+ if (ret == 0) {
+ priv->dev->type = enable ? ARPHRD_IEEE80211_RADIOTAP :
+ ARPHRD_ETHER;
}
- return 0;
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
}
/**
@@ -610,78 +673,242 @@ out:
return ret;
}
-static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
- u8 cmd_action, void *pdata_buf)
+/**
+ * @brief Get current RSSI and noise floor
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param rssi On successful return, signal level in mBm
+ *
+ * @return The channel on success, error on failure
+ */
+int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
{
- struct lbs_offset_value *offval;
+ struct cmd_ds_802_11_rssi cmd;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
- offval = (struct lbs_offset_value *)pdata_buf;
+ BUG_ON(rssi == NULL);
+ BUG_ON(nf == NULL);
- switch (le16_to_cpu(cmdptr->command)) {
- case CMD_MAC_REG_ACCESS:
- {
- struct cmd_ds_mac_reg_access *macreg;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ /* Average SNR over last 8 beacons */
+ cmd.n_or_snr = cpu_to_le16(8);
- cmdptr->size =
- cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
- + sizeof(struct cmd_header));
- macreg =
- (struct cmd_ds_mac_reg_access *)&cmdptr->params.
- macreg;
+ ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd);
+ if (ret == 0) {
+ *nf = CAL_NF(le16_to_cpu(cmd.nf));
+ *rssi = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), le16_to_cpu(cmd.nf));
+ }
- macreg->action = cpu_to_le16(cmd_action);
- macreg->offset = cpu_to_le16((u16) offval->offset);
- macreg->value = cpu_to_le32(offval->value);
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
- break;
- }
+/**
+ * @brief Send regulatory and 802.11d domain information to the firmware
+ *
+ * @param priv pointer to struct lbs_private
+ * @param request cfg80211 regulatory request structure
+ * @param bands the device's supported bands and channels
+ *
+ * @return 0 on success, error code on failure
+*/
+int lbs_set_11d_domain_info(struct lbs_private *priv,
+ struct regulatory_request *request,
+ struct ieee80211_supported_band **bands)
+{
+ struct cmd_ds_802_11d_domain_info cmd;
+ struct mrvl_ie_domain_param_set *domain = &cmd.domain;
+ struct ieee80211_country_ie_triplet *t;
+ enum ieee80211_band band;
+ struct ieee80211_channel *ch;
+ u8 num_triplet = 0;
+ u8 num_parsed_chan = 0;
+ u8 first_channel = 0, next_chan = 0, max_pwr = 0;
+ u8 i, flag = 0;
+ size_t triplet_size;
+ int ret;
- case CMD_BBP_REG_ACCESS:
- {
- struct cmd_ds_bbp_reg_access *bbpreg;
+ lbs_deb_enter(LBS_DEB_11D);
- cmdptr->size =
- cpu_to_le16(sizeof
- (struct cmd_ds_bbp_reg_access)
- + sizeof(struct cmd_header));
- bbpreg =
- (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
- bbpreg;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
- bbpreg->action = cpu_to_le16(cmd_action);
- bbpreg->offset = cpu_to_le16((u16) offval->offset);
- bbpreg->value = (u8) offval->value;
+ lbs_deb_11d("Setting country code '%c%c'\n",
+ request->alpha2[0], request->alpha2[1]);
- break;
- }
+ domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
- case CMD_RF_REG_ACCESS:
- {
- struct cmd_ds_rf_reg_access *rfreg;
+ /* Set country code */
+ domain->country_code[0] = request->alpha2[0];
+ domain->country_code[1] = request->alpha2[1];
+ domain->country_code[2] = ' ';
- cmdptr->size =
- cpu_to_le16(sizeof
- (struct cmd_ds_rf_reg_access) +
- sizeof(struct cmd_header));
- rfreg =
- (struct cmd_ds_rf_reg_access *)&cmdptr->params.
- rfreg;
+ /* Now set up the channel triplets; firmware is somewhat picky here
+ * and doesn't validate channel numbers and spans; hence it would
+ * interpret a triplet of (36, 4, 20) as channels 36, 37, 38, 39. Since
+ * the last 3 aren't valid channels, the driver is responsible for
+ * splitting that up into 4 triplet pairs of (36, 1, 20) + (40, 1, 20)
+ * etc.
+ */
+ for (band = 0;
+ (band < IEEE80211_NUM_BANDS) && (num_triplet < MAX_11D_TRIPLETS);
+ band++) {
+
+ if (!bands[band])
+ continue;
+
+ for (i = 0;
+ (i < bands[band]->n_channels) && (num_triplet < MAX_11D_TRIPLETS);
+ i++) {
+ ch = &bands[band]->channels[i];
+ if (ch->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ if (!flag) {
+ flag = 1;
+ next_chan = first_channel = (u32) ch->hw_value;
+ max_pwr = ch->max_power;
+ num_parsed_chan = 1;
+ continue;
+ }
- rfreg->action = cpu_to_le16(cmd_action);
- rfreg->offset = cpu_to_le16((u16) offval->offset);
- rfreg->value = (u8) offval->value;
+ if ((ch->hw_value == next_chan + 1) &&
+ (ch->max_power == max_pwr)) {
+ /* Consolidate adjacent channels */
+ next_chan++;
+ num_parsed_chan++;
+ } else {
+ /* Add this triplet */
+ lbs_deb_11d("11D triplet (%d, %d, %d)\n",
+ first_channel, num_parsed_chan,
+ max_pwr);
+ t = &domain->triplet[num_triplet];
+ t->chans.first_channel = first_channel;
+ t->chans.num_channels = num_parsed_chan;
+ t->chans.max_power = max_pwr;
+ num_triplet++;
+ flag = 0;
+ }
+ }
- break;
+ if (flag) {
+ /* Add last triplet */
+ lbs_deb_11d("11D triplet (%d, %d, %d)\n", first_channel,
+ num_parsed_chan, max_pwr);
+ t = &domain->triplet[num_triplet];
+ t->chans.first_channel = first_channel;
+ t->chans.num_channels = num_parsed_chan;
+ t->chans.max_power = max_pwr;
+ num_triplet++;
}
+ }
- default:
- break;
+ lbs_deb_11d("# triplets %d\n", num_triplet);
+
+ /* Set command header sizes */
+ triplet_size = num_triplet * sizeof(struct ieee80211_country_ie_triplet);
+ domain->header.len = cpu_to_le16(sizeof(domain->country_code) +
+ triplet_size);
+
+ lbs_deb_hex(LBS_DEB_11D, "802.11D domain param set",
+ (u8 *) &cmd.domain.country_code,
+ le16_to_cpu(domain->header.len));
+
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd.hdr) +
+ sizeof(cmd.action) +
+ sizeof(cmd.domain.header) +
+ sizeof(cmd.domain.country_code) +
+ triplet_size);
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);
+
+ lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * @brief Read a MAC, Baseband, or RF register
+ *
+ * @param priv pointer to struct lbs_private
+ * @param cmd register command, one of CMD_MAC_REG_ACCESS,
+ * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ * @param offset byte offset of the register to get
+ * @param value on success, the value of the register at 'offset'
+ *
+ * @return 0 on success, error code on failure
+*/
+int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
+{
+ struct cmd_ds_reg_access cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ BUG_ON(value == NULL);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_GET);
+
+ if (reg != CMD_MAC_REG_ACCESS &&
+ reg != CMD_BBP_REG_ACCESS &&
+ reg != CMD_RF_REG_ACCESS) {
+ ret = -EINVAL;
+ goto out;
}
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
+ ret = lbs_cmd_with_response(priv, reg, &cmd);
+ if (ret) {
+ if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
+ *value = cmd.value.bbp_rf;
+ else if (reg == CMD_MAC_REG_ACCESS)
+ *value = le32_to_cpu(cmd.value.mac);
+ }
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * @brief Write a MAC, Baseband, or RF register
+ *
+ * @param priv pointer to struct lbs_private
+ * @param cmd register command, one of CMD_MAC_REG_ACCESS,
+ * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ * @param offset byte offset of the register to set
+ * @param value the value to write to the register at 'offset'
+ *
+ * @return 0 on success, error code on failure
+*/
+int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
+{
+ struct cmd_ds_reg_access 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_ACT_SET);
+
+ if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
+ cmd.value.bbp_rf = (u8) (value & 0xFF);
+ else if (reg == CMD_MAC_REG_ACCESS)
+ cmd.value.mac = cpu_to_le32(value);
+ else {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = lbs_cmd_with_response(priv, reg, &cmd);
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
}
static void lbs_queue_cmd(struct lbs_private *priv,
@@ -704,14 +931,17 @@ static void lbs_queue_cmd(struct lbs_private *priv,
/* Exit_PS command needs to be queued in the header always. */
if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
- struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf[1];
+ struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf;
- if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
+ if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
if (priv->psstate != PS_STATE_FULL_POWER)
addtail = 0;
}
}
+ if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_WAKEUP_CONFIRM)
+ addtail = 0;
+
spin_lock_irqsave(&priv->driver_lock, flags);
if (addtail)
@@ -744,7 +974,6 @@ static void lbs_submit_command(struct lbs_private *priv,
spin_lock_irqsave(&priv->driver_lock, flags);
priv->cur_cmd = cmdnode;
- priv->cur_cmd_retcode = 0;
spin_unlock_irqrestore(&priv->driver_lock, flags);
cmdsize = le16_to_cpu(cmd->size);
@@ -817,9 +1046,6 @@ static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
int result)
{
- if (cmd == priv->cur_cmd)
- priv->cur_cmd_retcode = result;
-
cmd->result = result;
cmd->cmdwaitqwoken = 1;
wake_up_interruptible(&cmd->cmdwait_q);
@@ -887,175 +1113,6 @@ void lbs_set_mac_control(struct lbs_private *priv)
}
/**
- * @brief This function prepare the command before send to firmware.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param cmd_no command number
- * @param cmd_action command action: GET or SET
- * @param wait_option wait option: wait response or not
- * @param cmd_oid cmd oid: treated as sub command
- * @param pdata_buf A pointer to informaion buffer
- * @return 0 or -1
- */
-int lbs_prepare_and_send_command(struct lbs_private *priv,
- u16 cmd_no,
- u16 cmd_action,
- u16 wait_option, u32 cmd_oid, void *pdata_buf)
-{
- int ret = 0;
- struct cmd_ctrl_node *cmdnode;
- struct cmd_ds_command *cmdptr;
- unsigned long flags;
-
- lbs_deb_enter(LBS_DEB_HOST);
-
- if (!priv) {
- lbs_deb_host("PREP_CMD: priv is NULL\n");
- ret = -1;
- goto done;
- }
-
- if (priv->surpriseremoved) {
- lbs_deb_host("PREP_CMD: card removed\n");
- ret = -1;
- goto done;
- }
-
- if (!lbs_is_cmd_allowed(priv)) {
- ret = -EBUSY;
- goto done;
- }
-
- cmdnode = lbs_get_cmd_ctrl_node(priv);
-
- if (cmdnode == NULL) {
- lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
-
- /* Wake up main thread to execute next command */
- wake_up_interruptible(&priv->waitq);
- ret = -1;
- goto done;
- }
-
- cmdnode->callback = NULL;
- cmdnode->callback_arg = (unsigned long)pdata_buf;
-
- cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
-
- lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
-
- /* Set sequence number, command and INT option */
- priv->seqnum++;
- cmdptr->seqnum = cpu_to_le16(priv->seqnum);
-
- cmdptr->command = cpu_to_le16(cmd_no);
- cmdptr->result = 0;
-
- switch (cmd_no) {
- case CMD_802_11_PS_MODE:
- ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action);
- 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_MONITOR_MODE:
- ret = lbs_cmd_802_11_monitor_mode(cmdptr,
- cmd_action, pdata_buf);
- break;
-
- case CMD_802_11_RSSI:
- ret = lbs_cmd_802_11_rssi(priv, cmdptr);
- 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) +
- sizeof(struct cmd_header));
-
- memmove(&cmdptr->params.afc,
- pdata_buf, sizeof(struct cmd_ds_802_11_afc));
-
- ret = 0;
- goto done;
-
- 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) +
- sizeof(struct cmd_header));
-
- memmove(&cmdptr->params.tpccfg,
- pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
-
- ret = 0;
- break;
-
-#ifdef CONFIG_LIBERTAS_MESH
-
- case CMD_BT_ACCESS:
- ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
- break;
-
- case CMD_FWT_ACCESS:
- ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
- break;
-
-#endif
-
- 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_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
- ret = -1;
- break;
- }
-
- /* return error, since the command preparation failed */
- if (ret != 0) {
- lbs_deb_host("PREP_CMD: command preparation failed\n");
- lbs_cleanup_and_insert_cmd(priv, cmdnode);
- ret = -1;
- goto done;
- }
-
- cmdnode->cmdwaitqwoken = 0;
-
- lbs_queue_cmd(priv, cmdnode);
- wake_up_interruptible(&priv->waitq);
-
- if (wait_option & CMD_OPTION_WAITFORRSP) {
- lbs_deb_host("PREP_CMD: wait for response\n");
- might_sleep();
- wait_event_interruptible(cmdnode->cmdwait_q,
- cmdnode->cmdwaitqwoken);
- }
-
- spin_lock_irqsave(&priv->driver_lock, flags);
- if (priv->cur_cmd_retcode) {
- lbs_deb_host("PREP_CMD: command failed with return code %d\n",
- priv->cur_cmd_retcode);
- priv->cur_cmd_retcode = 0;
- ret = -1;
- }
- spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-done:
- lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
- return ret;
-}
-
-/**
* @brief This function allocates the command buffer and link
* it to command free queue.
*
@@ -1148,7 +1205,7 @@ done:
* @param priv A pointer to struct lbs_private structure
* @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
*/
-static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
+static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
{
struct cmd_ctrl_node *tempnode;
unsigned long flags;
@@ -1231,10 +1288,10 @@ int lbs_execute_next_command(struct lbs_private *priv)
/*
* 1. Non-PS command:
* Queue it. set needtowakeup to TRUE if current state
- * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
- * 2. PS command but not Exit_PS:
+ * is SLEEP, otherwise call send EXIT_PS.
+ * 2. PS command but not EXIT_PS:
* Ignore it.
- * 3. PS command Exit_PS:
+ * 3. PS command EXIT_PS:
* Set needtowakeup to TRUE if current state is SLEEP,
* otherwise send this command down to firmware
* immediately.
@@ -1248,8 +1305,11 @@ int lbs_execute_next_command(struct lbs_private *priv)
/* w/ new scheme, it will not reach here.
since it is blocked in main_thread. */
priv->needtowakeup = 1;
- } else
- lbs_ps_wakeup(priv, 0);
+ } else {
+ lbs_set_ps_mode(priv,
+ PS_MODE_ACTION_EXIT_PS,
+ false);
+ }
ret = 0;
goto done;
@@ -1264,7 +1324,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
"EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
psm->action);
if (psm->action !=
- cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
+ cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
lbs_deb_host(
"EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
list_del(&cmdnode->list);
@@ -1303,6 +1363,15 @@ int lbs_execute_next_command(struct lbs_private *priv)
* check if in power save mode, if yes, put the device back
* to PS mode
*/
+#ifdef TODO
+ /*
+ * This was the old code for libertas+wext. Someone that
+ * understands this beast should re-code it in a sane way.
+ *
+ * I actually don't understand why this is related to WPA
+ * and to connection status, shouldn't powering should be
+ * independ of such things?
+ */
if ((priv->psmode != LBS802_11POWERMODECAM) &&
(priv->psstate == PS_STATE_FULL_POWER) &&
((priv->connect_status == LBS_CONNECTED) ||
@@ -1315,15 +1384,19 @@ int lbs_execute_next_command(struct lbs_private *priv)
lbs_deb_host(
"EXEC_NEXT_CMD: WPA enabled and GTK_SET"
" go back to PS_SLEEP");
- lbs_ps_sleep(priv, 0);
+ lbs_set_ps_mode(priv,
+ PS_MODE_ACTION_ENTER_PS,
+ false);
}
} else {
lbs_deb_host(
"EXEC_NEXT_CMD: cmdpendingq empty, "
"go back to PS_SLEEP");
- lbs_ps_sleep(priv, 0);
+ lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
+ false);
}
}
+#endif
}
ret = 0;
@@ -1353,6 +1426,11 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
/* We don't get a response on the sleep-confirmation */
priv->dnld_sent = DNLD_RES_RECEIVED;
+ if (priv->is_host_sleep_configured) {
+ priv->is_host_sleep_activated = 1;
+ wake_up_interruptible(&priv->host_sleep_q);
+ }
+
/* 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;
@@ -1363,43 +1441,6 @@ out:
lbs_deb_leave(LBS_DEB_HOST);
}
-void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
-{
- lbs_deb_enter(LBS_DEB_HOST);
-
- /*
- * PS is currently supported only in Infrastructure mode
- * Remove this check if it is to be supported in IBSS mode also
- */
-
- lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
- CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
-
- lbs_deb_leave(LBS_DEB_HOST);
-}
-
-/**
- * @brief This function sends Exit_PS command to firmware.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param wait_option wait response or not
- * @return n/a
- */
-void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
-{
- __le32 Localpsmode;
-
- lbs_deb_enter(LBS_DEB_HOST);
-
- Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
-
- lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
- CMD_SUBCMD_EXIT_PS,
- wait_option, 0, &Localpsmode);
-
- lbs_deb_leave(LBS_DEB_HOST);
-}
-
/**
* @brief This function checks condition and prepares to
* send sleep confirm command to firmware if ok.
@@ -1524,12 +1565,18 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
goto done;
}
- if (!lbs_is_cmd_allowed(priv)) {
- cmdnode = ERR_PTR(-EBUSY);
- goto done;
+ /* No commands are allowed in Deep Sleep until we toggle the GPIO
+ * to wake up the card and it has signaled that it's ready.
+ */
+ if (!priv->is_auto_deep_sleep_enabled) {
+ if (priv->is_deep_sleep) {
+ lbs_deb_cmd("command not allowed in deep sleep\n");
+ cmdnode = ERR_PTR(-EBUSY);
+ goto done;
+ }
}
- cmdnode = lbs_get_cmd_ctrl_node(priv);
+ cmdnode = lbs_get_free_cmd_node(priv);
if (cmdnode == NULL) {
lbs_deb_host("PREP_CMD: cmdnode is NULL\n");