X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Fiwlwifi%2Fiwl-core.c;h=d8a226e68ed1645a23cef1c0de7dbe7db7444124;hb=df39e8ba56a788733d369068c7319e04b1da3cd5;hp=9ca539861db284bcbde35eb25c58f289c8c99681;hpb=76fef2b6bffa13ad7ccd54c0493b053295721b9a;p=linux-2.6 diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 9ca539861d..d8a226e68e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -29,17 +29,251 @@ #include #include #include +#include -#include "iwl-4965-debug.h" +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" + MODULE_DESCRIPTION("iwl core"); MODULE_VERSION(IWLWIFI_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); -MODULE_LICENSE("GPL/BSD"); +MODULE_LICENSE("GPL"); -#ifdef CONFIG_IWL4965_DEBUG -u32 iwl4965_debug_level; -EXPORT_SYMBOL(iwl4965_debug_level); +#ifdef CONFIG_IWLWIFI_DEBUG +u32 iwl_debug_level; +EXPORT_SYMBOL(iwl_debug_level); #endif + +/* This function both allocates and initializes hw and priv. */ +struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, + struct ieee80211_ops *hw_ops) +{ + struct iwl_priv *priv; + + /* mac80211 allocates memory for this device instance, including + * space for this driver's private structure */ + struct ieee80211_hw *hw = + ieee80211_alloc_hw(sizeof(struct iwl_priv), hw_ops); + if (hw == NULL) { + IWL_ERROR("Can not allocate network device\n"); + goto out; + } + + priv = hw->priv; + priv->hw = hw; + +out: + return hw; +} +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); +