]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/iwlwifi/iwl-core.c
Merge git://git.infradead.org/battery-2.6
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / iwlwifi / iwl-core.c
index 244318af53fcb3043fea520884a06c85418a96c1..2dfd982d7d1f6977c6de528ea11fbc31ab365fd3 100644 (file)
 struct iwl_priv; /* FIXME: remove */
 #include "iwl-debug.h"
 #include "iwl-eeprom.h"
+#include "iwl-4965.h" /* FIXME: remove */
 #include "iwl-core.h"
+#include "iwl-rfkill.h"
 
-#include "iwl-4965.h" /* FIXME: remove */
 
 MODULE_DESCRIPTION("iwl core");
 MODULE_VERSION(IWLWIFI_VERSION);
@@ -71,3 +72,221 @@ out:
 }
 EXPORT_SYMBOL(iwl_alloc_all);
 
+/**
+ * iwlcore_clear_stations_table - Clear the driver's station table
+ *
+ * NOTE:  This does not clear or otherwise alter the device's station table.
+ */
+void iwlcore_clear_stations_table(struct iwl_priv *priv)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+
+       priv->num_stations = 0;
+       memset(priv->stations, 0, sizeof(priv->stations));
+
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+EXPORT_SYMBOL(iwlcore_clear_stations_table);
+
+void iwlcore_reset_qos(struct iwl_priv *priv)
+{
+       u16 cw_min = 15;
+       u16 cw_max = 1023;
+       u8 aifs = 2;
+       u8 is_legacy = 0;
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->qos_data.qos_active = 0;
+
+       if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+               if (priv->qos_data.qos_enable)
+                       priv->qos_data.qos_active = 1;
+               if (!(priv->active_rate & 0xfff0)) {
+                       cw_min = 31;
+                       is_legacy = 1;
+               }
+       } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+               if (priv->qos_data.qos_enable)
+                       priv->qos_data.qos_active = 1;
+       } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+               cw_min = 31;
+               is_legacy = 1;
+       }
+
+       if (priv->qos_data.qos_active)
+               aifs = 3;
+
+       priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
+       priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
+       priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
+       priv->qos_data.def_qos_parm.ac[0].edca_txop = 0;
+       priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
+
+       if (priv->qos_data.qos_active) {
+               i = 1;
+               priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
+               priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
+               priv->qos_data.def_qos_parm.ac[i].aifsn = 7;
+               priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+               priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+               i = 2;
+               priv->qos_data.def_qos_parm.ac[i].cw_min =
+                       cpu_to_le16((cw_min + 1) / 2 - 1);
+               priv->qos_data.def_qos_parm.ac[i].cw_max =
+                       cpu_to_le16(cw_max);
+               priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+               if (is_legacy)
+                       priv->qos_data.def_qos_parm.ac[i].edca_txop =
+                               cpu_to_le16(6016);
+               else
+                       priv->qos_data.def_qos_parm.ac[i].edca_txop =
+                               cpu_to_le16(3008);
+               priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+               i = 3;
+               priv->qos_data.def_qos_parm.ac[i].cw_min =
+                       cpu_to_le16((cw_min + 1) / 4 - 1);
+               priv->qos_data.def_qos_parm.ac[i].cw_max =
+                       cpu_to_le16((cw_max + 1) / 2 - 1);
+               priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+               priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+               if (is_legacy)
+                       priv->qos_data.def_qos_parm.ac[i].edca_txop =
+                               cpu_to_le16(3264);
+               else
+                       priv->qos_data.def_qos_parm.ac[i].edca_txop =
+                               cpu_to_le16(1504);
+       } else {
+               for (i = 1; i < 4; i++) {
+                       priv->qos_data.def_qos_parm.ac[i].cw_min =
+                               cpu_to_le16(cw_min);
+                       priv->qos_data.def_qos_parm.ac[i].cw_max =
+                               cpu_to_le16(cw_max);
+                       priv->qos_data.def_qos_parm.ac[i].aifsn = aifs;
+                       priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+                       priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+               }
+       }
+       IWL_DEBUG_QOS("set QoS to default \n");
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(iwlcore_reset_qos);
+
+/**
+ * iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON
+ * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
+ * @channel: Any channel valid for the requested phymode
+
+ * In addition to setting the staging RXON, priv->phymode is also set.
+ *
+ * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
+ * in the staging RXON flag structure based on the phymode
+ */
+int iwlcore_set_rxon_channel(struct iwl_priv *priv,
+                               enum ieee80211_band band,
+                               u16 channel)
+{
+       if (!iwl_get_channel_info(priv, band, channel)) {
+               IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
+                              channel, band);
+               return -EINVAL;
+       }
+
+       if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
+           (priv->band == band))
+               return 0;
+
+       priv->staging_rxon.channel = cpu_to_le16(channel);
+       if (band == IEEE80211_BAND_5GHZ)
+               priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
+       else
+               priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+
+       priv->band = band;
+
+       IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, band);
+
+       return 0;
+}
+EXPORT_SYMBOL(iwlcore_set_rxon_channel);
+
+static void iwlcore_init_hw(struct iwl_priv *priv)
+{
+       struct ieee80211_hw *hw = priv->hw;
+       hw->rate_control_algorithm = "iwl-4965-rs";
+
+       /* Tell mac80211 and its clients (e.g. Wireless Extensions)
+        *       the range of signal quality values that we'll provide.
+        * Negative values for level/noise indicate that we'll provide dBm.
+        * For WE, at least, non-0 values here *enable* display of values
+        *       in app (iwconfig). */
+       hw->max_rssi = -20; /* signal level, negative indicates dBm */
+       hw->max_noise = -20;    /* noise level, negative indicates dBm */
+       hw->max_signal = 100;   /* link quality indication (%) */
+
+       /* Tell mac80211 our Tx characteristics */
+       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+
+       /* Default value; 4 EDCA QOS priorities */
+       hw->queues = 4;
+#ifdef CONFIG_IWL4965_HT
+       /* Enhanced value; more queues, to support 11n aggregation */
+       hw->queues = 16;
+#endif /* CONFIG_IWL4965_HT */
+}
+
+int iwl_setup(struct iwl_priv *priv)
+{
+       int ret = 0;
+       iwlcore_init_hw(priv);
+       ret = priv->cfg->ops->lib->init_drv(priv);
+       return ret;
+}
+EXPORT_SYMBOL(iwl_setup);
+
+/* Low level driver call this function to update iwlcore with
+ * driver status.
+ */
+int iwlcore_low_level_notify(struct iwl_priv *priv,
+                             enum iwlcore_card_notify notify)
+{
+       int ret;
+       switch (notify) {
+       case IWLCORE_INIT_EVT:
+               ret = iwl_rfkill_init(priv);
+               if (ret)
+                       IWL_ERROR("Unable to initialize RFKILL system. "
+                                 "Ignoring error: %d\n", ret);
+               break;
+       case IWLCORE_START_EVT:
+               break;
+       case IWLCORE_STOP_EVT:
+               break;
+       case IWLCORE_REMOVE_EVT:
+               iwl_rfkill_unregister(priv);
+               break;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(iwlcore_low_level_notify);
+
+int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
+{
+       u32 stat_flags = 0;
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_STATISTICS_CMD,
+               .meta.flags = flags,
+               .len = sizeof(stat_flags),
+               .data = (u8 *) &stat_flags,
+       };
+       return iwl_send_cmd(priv, &cmd);
+}
+EXPORT_SYMBOL(iwl_send_statistics_request);
+