libertas: cleanup host.h and hostcmd.h
[safe/jmp/linux-2.6] / drivers / net / wireless / libertas / cmd.c
index 957fd5a..cced646 100644 (file)
@@ -7,7 +7,6 @@
 #include <net/lib80211.h>
 #include <linux/kfifo.h>
 #include "host.h"
-#include "hostcmd.h"
 #include "decl.h"
 #include "defs.h"
 #include "dev.h"
@@ -17,7 +16,6 @@
 
 static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
 
-
 /**
  *  @brief Simple callback that copies response back into command
  *
@@ -76,6 +74,30 @@ 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
@@ -119,11 +141,30 @@ int lbs_update_hw_spec(struct lbs_private *priv)
        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 */
@@ -159,7 +200,8 @@ out:
        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;
@@ -169,10 +211,21 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria)
        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);
        }
@@ -288,6 +341,60 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
        return 0;
 }
 
+static int lbs_wait_for_ds_awake(struct lbs_private *priv)
+{
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       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;
+               }
+       }
+
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
+{
+       int ret =  0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       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");
+               }
+       } 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");
+                       }
+               }
+       }
+
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
 int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
                           struct assoc_request *assoc)
 {
@@ -1024,17 +1131,26 @@ static int __lbs_mesh_config_send(struct lbs_private *priv,
                                  uint16_t action, uint16_t type)
 {
        int ret;
+       u16 command = CMD_MESH_CONFIG_OLD;
 
        lbs_deb_enter(LBS_DEB_CMD);
 
-       cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG);
+       /*
+        * 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, CMD_MESH_CONFIG, cmd);
+       ret = lbs_cmd_with_response(priv, command, cmd);
 
        lbs_deb_leave(LBS_DEB_CMD);
        return ret;
@@ -1186,8 +1302,7 @@ static void lbs_submit_command(struct lbs_private *priv,
        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)
+       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\n",
@@ -1203,8 +1318,17 @@ static void lbs_submit_command(struct lbs_private *priv,
                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);
 }
@@ -1351,6 +1475,11 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                goto done;
        }
 
+       if (!lbs_is_cmd_allowed(priv)) {
+               ret = -EBUSY;
+               goto done;
+       }
+
        cmdnode = lbs_get_cmd_ctrl_node(priv);
 
        if (cmdnode == NULL) {
@@ -1381,15 +1510,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                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_AUTHENTICATE:
-               ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
-               break;
-
        case CMD_MAC_REG_ACCESS:
        case CMD_BBP_REG_ACCESS:
        case CMD_RF_REG_ACCESS:
@@ -1436,8 +1556,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                break;
        case CMD_802_11_LED_GPIO_CTRL:
                {
-                       struct mrvlietypes_ledgpio *gpio =
-                           (struct mrvlietypes_ledgpio*)
+                       struct mrvl_ie_ledgpio *gpio =
+                           (struct mrvl_ie_ledgpio*)
                            cmdptr->params.ledgpio.data;
 
                        memmove(&cmdptr->params.ledgpio,
@@ -1475,6 +1595,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
        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(S_DS_GEN);
+               break;
        default:
                lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
                ret = -1;
@@ -1637,7 +1761,7 @@ static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
 
 /**
  *  @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
@@ -1993,7 +2117,7 @@ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
 }
 
 
-static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
+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)
@@ -2008,6 +2132,11 @@ static 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;
+       }
+
        cmdnode = lbs_get_cmd_ctrl_node(priv);
        if (cmdnode == NULL) {
                lbs_deb_host("PREP_CMD: cmdnode is NULL\n");