]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/libertas/cmd.c
libertas: Improvements on automatic tx power control via SIOCSIWTXPOW.
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / libertas / cmd.c
index 75427e61898dfbecb84d7db4024e34ae254e723b..5fef05f3cd008774699199f0ac77578277ae43ab 100644 (file)
@@ -614,47 +614,67 @@ static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
        return 0;
 }
 
-static int lbs_cmd_802_11_rf_tx_power(struct cmd_ds_command *cmd,
-                                      u16 cmd_action, void *pdata_buf)
+/**
+ *  @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            0 on success, error on failure
+ */
+int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
+                    s16 *maxlevel)
 {
-
-       struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
+       struct cmd_ds_802_11_rf_tx_power 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);
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       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 = le16_to_cpu(cmd.minlevel);
+               if (maxlevel)
+                       *maxlevel = le16_to_cpu(cmd.maxlevel);
+       }
 
-       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));
+       lbs_deb_leave(LBS_DEB_CMD);
+       return ret;
+}
 
-       switch (cmd_action) {
-       case CMD_ACT_TX_POWER_OPT_GET:
-               prtp->action = cpu_to_le16(CMD_ACT_GET);
-               prtp->currentlevel = 0;
-               break;
+/**
+ *  @brief Set the TX power
+ *
+ *  @param priv        A pointer to struct lbs_private structure
+ *  @param dbm         The desired power level in dBm
+ *
+ *  @return            0 on success, error on failure
+ */
+int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
+{
+       struct cmd_ds_802_11_rf_tx_power cmd;
+       int ret;
 
-       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);
-               break;
+       lbs_deb_enter(LBS_DEB_CMD);
 
-       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);
-               break;
+       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);
 
-       case CMD_ACT_TX_POWER_OPT_SET_LOW:
-               prtp->action = cpu_to_le16(CMD_ACT_SET);
-               prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
-               break;
-       }
+       lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
 
        lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
+       return ret;
 }
 
 static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
@@ -1033,9 +1053,9 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
        return ret;
 }
 
-int lbs_mesh_config_send(struct lbs_private *priv,
-                        struct cmd_ds_mesh_config *cmd,
-                        uint16_t action, uint16_t type)
+static int __lbs_mesh_config_send(struct lbs_private *priv,
+                                 struct cmd_ds_mesh_config *cmd,
+                                 uint16_t action, uint16_t type)
 {
        int ret;
 
@@ -1054,6 +1074,19 @@ int lbs_mesh_config_send(struct lbs_private *priv,
        return ret;
 }
 
+int lbs_mesh_config_send(struct lbs_private *priv,
+                        struct cmd_ds_mesh_config *cmd,
+                        uint16_t action, uint16_t type)
+{
+       int ret;
+
+       if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
+               return -EOPNOTSUPP;
+
+       ret = __lbs_mesh_config_send(priv, cmd, action, type);
+       return ret;
+}
+
 /* 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
@@ -1095,7 +1128,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
                    action, priv->mesh_tlv, chan,
                    escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
 
-       return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
+       return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
 }
 
 static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
@@ -1256,41 +1289,47 @@ void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
        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;
 }
@@ -1380,14 +1419,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                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;
@@ -1407,28 +1438,15 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                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_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_SET_AFC:
        case CMD_802_11_GET_AFC:
 
@@ -1953,6 +1971,70 @@ void lbs_ps_confirm_sleep(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 = !!enable;
+       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;
+}
+
+
 static 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 *),