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.c183
1 files changed, 167 insertions, 16 deletions
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index cdb9b9650d7..749fbde4fd5 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -7,13 +7,8 @@
#include <linux/sched.h>
#include <linux/slab.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"
@@ -70,6 +65,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;
}
@@ -175,16 +172,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 +211,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));
@@ -353,6 +361,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
*
@@ -712,6 +779,10 @@ static void lbs_queue_cmd(struct lbs_private *priv,
}
}
+ if (le16_to_cpu(cmdnode->cmdbuf->command) ==
+ CMD_802_11_WAKEUP_CONFIRM)
+ addtail = 0;
+
spin_lock_irqsave(&priv->driver_lock, flags);
if (addtail)
@@ -887,6 +958,66 @@ void lbs_set_mac_control(struct lbs_private *priv)
}
/**
+ * @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ * @param priv pointer to struct lbs_private
+ * @param cmd pointer to cmd buffer
+ * @param cmdno cmd ID
+ * @param cmdOption cmd action
+ * @return 0
+*/
+int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmdoption)
+{
+ struct cmd_ds_802_11d_domain_info *pdomaininfo =
+ &cmd->params.domaininfo;
+ struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
+ u8 nr_triplet = priv->domain_reg.no_triplet;
+
+ lbs_deb_enter(LBS_DEB_11D);
+
+ lbs_deb_11d("nr_triplet=%x\n", nr_triplet);
+
+ pdomaininfo->action = cpu_to_le16(cmdoption);
+ if (cmdoption == CMD_ACT_GET) {
+ cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+ sizeof(struct cmd_header));
+ lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
+ le16_to_cpu(cmd->size));
+ goto done;
+ }
+
+ domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
+ memcpy(domain->countrycode, priv->domain_reg.country_code,
+ sizeof(domain->countrycode));
+
+ domain->header.len = cpu_to_le16(nr_triplet
+ * sizeof(struct ieee80211_country_ie_triplet)
+ + sizeof(domain->countrycode));
+
+ if (nr_triplet) {
+ memcpy(domain->triplet, priv->domain_reg.triplet,
+ nr_triplet *
+ sizeof(struct ieee80211_country_ie_triplet));
+
+ cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+ le16_to_cpu(domain->header.len) +
+ sizeof(struct mrvl_ie_header) +
+ sizeof(struct cmd_header));
+ } else {
+ cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+ sizeof(struct cmd_header));
+ }
+
+ lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
+ le16_to_cpu(cmd->size));
+
+done:
+ lbs_deb_enter(LBS_DEB_11D);
+ return 0;
+}
+
+/**
* @brief This function prepare the command before send to firmware.
*
* @param priv A pointer to struct lbs_private structure
@@ -984,6 +1115,11 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = 0;
goto done;
+ case CMD_802_11D_DOMAIN_INFO:
+ cmdptr->command = cpu_to_le16(cmd_no);
+ ret = lbs_cmd_802_11d_domain_info(priv, cmdptr, cmd_action);
+ break;
+
case CMD_802_11_TPC_CFG:
cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
cmdptr->size =
@@ -1303,6 +1439,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) ||
@@ -1324,6 +1469,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
lbs_ps_sleep(priv, 0);
}
}
+#endif
}
ret = 0;
@@ -1353,6 +1499,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;