]> 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 8124fd9b1353523c603e679914d2fd839ac6f97b..5fef05f3cd008774699199f0ac77578277ae43ab 100644 (file)
@@ -4,6 +4,7 @@
   */
 
 #include <net/iw_handler.h>
+#include <net/ieee80211.h>
 #include <linux/kfifo.h>
 #include "host.h"
 #include "hostcmd.h"
@@ -109,7 +110,7 @@ int lbs_update_hw_spec(struct lbs_private *priv)
         * 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",
+       lbs_pr_info("%s, fw %u.%u.%up%u, cap 0x%08x\n",
                print_mac(mac, cmd.permanentaddr),
                priv->fwrelease >> 24 & 0xff,
                priv->fwrelease >> 16 & 0xff,
@@ -613,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,
@@ -675,58 +696,60 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
        return 0;
 }
 
-static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
-                                             struct cmd_ds_command *cmd,
-                                             u16 cmd_action)
+static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
 {
-       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;
+/*             Bit     Rate
+*              15:13 Reserved
+*              12    54 Mbps
+*              11    48 Mbps
+*              10    36 Mbps
+*              9     24 Mbps
+*              8     18 Mbps
+*              7     12 Mbps
+*              6     9 Mbps
+*              5     6 Mbps
+*              4     Reserved
+*              3     11 Mbps
+*              2     5.5 Mbps
+*              1     2 Mbps
+*              0     1 Mbps
+**/
+
+       uint16_t ratemask;
+       int i = lbs_data_rate_to_fw_index(rate);
+       if (lower_rates_ok)
+               ratemask = (0x1fef >> (12 - i));
+       else
+               ratemask = (1 << i);
+       return cpu_to_le16(ratemask);
 }
 
-/**
- *  @brief Get the current data rate
- *
- *  @param priv        A pointer to struct lbs_private structure
- *
- *  @return            The data rate on success, error on failure
- */
-int lbs_get_data_rate(struct lbs_private *priv)
+int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+                                     uint16_t cmd_action)
 {
-       struct cmd_ds_802_11_data_rate cmd;
-       int ret = -1;
+       struct cmd_ds_802_11_rate_adapt_rateset 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;
+       if (!priv->cur_rate && !priv->enablehwauto)
+               return -EINVAL;
 
-       lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
+       cmd.hdr.size = cpu_to_le16(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_action);
+       cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
+       cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
+       ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
+       if (!ret && cmd_action == CMD_ACT_GET) {
+               priv->ratebitmap = le16_to_cpu(cmd.bitmap);
+               priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
+       }
 
-out:
        lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
        return ret;
 }
+EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset);
 
 /**
  *  @brief Set the data rate
@@ -778,28 +801,6 @@ out:
        return ret;
 }
 
-static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
-                                     struct cmd_ds_command *cmd,
-                                     u16 cmd_action)
-{
-       struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
-
-       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);
-
-       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);
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
 /**
  *  @brief Get the radio channel
  *
@@ -1052,24 +1053,82 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
        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)
+{
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG);
+       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);
+
+       lbs_deb_leave(LBS_DEB_CMD);
+       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
+ * 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;
 
        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));
-
-       if (enable) {
-               cmd.length = cpu_to_le16(priv->mesh_ssid_len);
-               memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len);
+       ie = (struct mrvl_meshie *)cmd.data;
+
+       switch (action) {
+       case CMD_ACT_MESH_CONFIG_START:
+               ie->hdr.id = MFIE_TYPE_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->hdr.len = sizeof(struct mrvl_meshie_val) -
+                       IW_ESSID_MAX_SIZE + 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 enable %d TLV %x channel %d SSID %s\n",
-                   enable, priv->mesh_tlv, chan,
+       lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
+                   action, priv->mesh_tlv, chan,
                    escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
-       return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd);
+
+       return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
 }
 
 static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
@@ -1144,7 +1203,7 @@ static void lbs_submit_command(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);
@@ -1162,7 +1221,7 @@ static void lbs_submit_command(struct lbs_private *priv,
        /* These commands take longer */
        if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
            command == CMD_802_11_AUTHENTICATE)
-               timeo = 10 * HZ;
+               timeo = 5 * HZ;
 
        lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
                     command, le16_to_cpu(cmd->seqnum), cmdsize);
@@ -1174,7 +1233,7 @@ static void lbs_submit_command(struct lbs_private *priv,
                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 */
@@ -1230,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;
 }
@@ -1279,8 +1344,7 @@ void lbs_set_mac_control(struct lbs_private *priv)
        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);
 }
@@ -1355,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;
@@ -1382,37 +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_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_SET_AFC:
        case CMD_802_11_GET_AFC:
 
@@ -1484,7 +1518,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
                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;
        }
@@ -1937,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 *),