Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-hcmd.c
index 559ff73..8fa991b 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/version.h>
 #include <net/mac80211.h>
 
-#include "iwl-4965.h" /* FIXME: remove */
+#include "iwl-dev.h" /* FIXME: remove */
 #include "iwl-debug.h"
 #include "iwl-eeprom.h"
 #include "iwl-core.h"
@@ -51,10 +51,12 @@ const char *get_cmd_string(u8 cmd)
                IWL_CMD(REPLY_ADD_STA);
                IWL_CMD(REPLY_REMOVE_STA);
                IWL_CMD(REPLY_REMOVE_ALL_STA);
+               IWL_CMD(REPLY_WEPKEY);
                IWL_CMD(REPLY_TX);
                IWL_CMD(REPLY_RATE_SCALE);
                IWL_CMD(REPLY_LEDS_CMD);
                IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+               IWL_CMD(COEX_PRIORITY_TABLE_CMD);
                IWL_CMD(RADAR_NOTIFICATION);
                IWL_CMD(REPLY_QUIET_CMD);
                IWL_CMD(REPLY_CHANNEL_SWITCH);
@@ -88,6 +90,10 @@ const char *get_cmd_string(u8 cmd)
                IWL_CMD(REPLY_RX_MPDU_CMD);
                IWL_CMD(REPLY_RX);
                IWL_CMD(REPLY_COMPRESSED_BA);
+               IWL_CMD(CALIBRATION_CFG_CMD);
+               IWL_CMD(CALIBRATION_RES_NOTIFICATION);
+               IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
+               IWL_CMD(REPLY_TX_POWER_DBM_CMD);
        default:
                return "UNKNOWN";
 
@@ -97,6 +103,31 @@ EXPORT_SYMBOL(get_cmd_string);
 
 #define HOST_COMPLETE_TIMEOUT (HZ / 2)
 
+static int iwl_generic_cmd_callback(struct iwl_priv *priv,
+                                   struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+       struct iwl_rx_packet *pkt = NULL;
+
+       if (!skb) {
+               IWL_ERROR("Error: Response NULL in %s.\n",
+                               get_cmd_string(cmd->hdr.cmd));
+               return 1;
+       }
+
+       pkt = (struct iwl_rx_packet *)skb->data;
+       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+               IWL_ERROR("Bad return from %s (0x%08X)\n",
+                       get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
+               return 1;
+       }
+
+       IWL_DEBUG_HC("back from %s (0x%08X)\n",
+                       get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
+
+       /* Let iwl_tx_complete free the response skb */
+       return 1;
+}
+
 static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 {
        int ret;
@@ -106,13 +137,14 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        /* An asynchronous command can not expect an SKB to be set. */
        BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
 
-       /* An asynchronous command MUST have a callback. */
-       BUG_ON(!cmd->meta.u.callback);
+       /* Assign a generic callback if one is not provided */
+       if (!cmd->meta.u.callback)
+               cmd->meta.u.callback = iwl_generic_cmd_callback;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return -EBUSY;
 
-       ret = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd);
+       ret = iwl_enqueue_hcmd(priv, cmd);
        if (ret < 0) {
                IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n",
                          get_cmd_string(cmd->id), ret);
@@ -125,17 +157,17 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 {
        int cmd_idx;
        int ret;
-       static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */
 
        BUG_ON(cmd->meta.flags & CMD_ASYNC);
 
         /* A synchronous command can not have a callback set. */
        BUG_ON(cmd->meta.u.callback != NULL);
 
-       if (atomic_xchg(&entry, 1)) {
+       if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
                IWL_ERROR("Error sending %s: Already sending a host command\n",
                          get_cmd_string(cmd->id));
-               return -EBUSY;
+               ret = -EBUSY;
+               goto out;
        }
 
        set_bit(STATUS_HCMD_ACTIVE, &priv->status);
@@ -143,7 +175,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        if (cmd->meta.flags & CMD_WANT_SKB)
                cmd->meta.source = &cmd->meta;
 
-       cmd_idx = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd);
+       cmd_idx = iwl_enqueue_hcmd(priv, cmd);
        if (cmd_idx < 0) {
                ret = cmd_idx;
                IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n",
@@ -205,7 +237,7 @@ fail:
                cmd->meta.u.skb = NULL;
        }
 out:
-       atomic_set(&entry, 0);
+       clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
        return ret;
 }
 EXPORT_SYMBOL(iwl_send_cmd_sync);