|  | /****************************************************************************** | 
|  | * | 
|  | * GPL LICENSE SUMMARY | 
|  | * | 
|  | * Copyright(c) 2008 Intel Corporation. All rights reserved. | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or modify | 
|  | * it under the terms of version 2 of the GNU General Public License as | 
|  | * published by the Free Software Foundation. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, but | 
|  | * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License | 
|  | * along with this program; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | 
|  | * USA | 
|  | * | 
|  | * The full GNU General Public License is included in this distribution | 
|  | * in the file called LICENSE.GPL. | 
|  | * | 
|  | * Contact Information: | 
|  | * Tomas Winkler <tomas.winkler@intel.com> | 
|  | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 
|  | *****************************************************************************/ | 
|  |  | 
|  | #include <linux/kernel.h> | 
|  | #include <linux/module.h> | 
|  | #include <linux/version.h> | 
|  | #include <net/mac80211.h> | 
|  |  | 
|  | struct iwl_priv; /* FIXME: remove */ | 
|  | #include "iwl-debug.h" | 
|  | #include "iwl-eeprom.h" | 
|  | #include "iwl-core.h" | 
|  |  | 
|  | #include "iwl-4965.h" /* FIXME: remove */ | 
|  |  | 
|  | MODULE_DESCRIPTION("iwl core"); | 
|  | MODULE_VERSION(IWLWIFI_VERSION); | 
|  | MODULE_AUTHOR(DRV_COPYRIGHT); | 
|  | MODULE_LICENSE("GPL"); | 
|  |  | 
|  | #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); | 
|  |  |