diff options
author | Reinette Chatre <reinette.chatre@intel.com> | 2008-01-23 10:15:18 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-31 19:26:41 -0800 |
commit | 849e0dcea6b28a900e4743c1ada6db752fced5a9 (patch) | |
tree | 91abfca69729ef1b633012412012b7bf64f7610f /drivers/net/wireless/iwlwifi/iwl3945-base.c | |
parent | 75849d287ce5d75f3c79f153eaf74759ae95511f (diff) | |
download | lwn-849e0dcea6b28a900e4743c1ada6db752fced5a9.tar.gz lwn-849e0dcea6b28a900e4743c1ada6db752fced5a9.zip |
iwlwifi: initialize geo/channel information during probe
The geo/channel information is obtained from the EEPROM, which is read
during probe. We can thus set up channel information at this time. This
helps us to support ioctl commands that rely on this before the interface
is brought up.
Clearly matches _init_channel_map with _free_channel_map and _init_geos
with _free_geos to ensure functions calling these routines can also call
their cleanup routines.
Fixes a few bugs:
- if channel information is not available when ioctl commands are
issued then we get a NULL pointer oops. Having channel information
set up during probe we can deal with ioctl commands without requiring
interface to be brought up.
This fixes bug: http://www.bughost.org/bugzilla/show_bug.cgi?id=1552
- Fix potential problem if user triggers probe/remove/probe sequence. The
value of priv->channel_count was used to determine if channel map is
set up. This value was never reset when channel map was removed.
- Fix memory leak: priv->modes need to be freed when device removed.
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl3945-base.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 54 |
1 files changed, 40 insertions, 14 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 0bfb925ebda8..f96a1a2e90f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -5146,6 +5146,15 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) return 0; } +/* + * iwl3945_free_channel_map - undo allocations in iwl3945_init_channel_map + */ +static void iwl3945_free_channel_map(struct iwl3945_priv *priv) +{ + kfree(priv->channel_info); + priv->channel_count = 0; +} + /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after * sending probe req. This should be set long enough to hear probe responses * from more than one AP. */ @@ -5471,6 +5480,17 @@ static int iwl3945_init_geos(struct iwl3945_priv *priv) return 0; } +/* + * iwl3945_free_geos - undo allocations in iwl3945_init_geos + */ +static void iwl3945_free_geos(struct iwl3945_priv *priv) +{ + kfree(priv->modes); + kfree(priv->ieee_channels); + kfree(priv->ieee_rates); + clear_bit(STATUS_GEO_CONFIGURED, &priv->status); +} + /****************************************************************************** * * uCode download functions @@ -6130,15 +6150,6 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) /* Clear out the uCode error bit if it is set */ clear_bit(STATUS_FW_ERROR, &priv->status); - rc = iwl3945_init_channel_map(priv); - if (rc) { - IWL_ERROR("initializing regulatory failed: %d\n", rc); - return; - } - - iwl3945_init_geos(priv); - iwl3945_reset_channel_flag(priv); - if (iwl3945_is_rfkill(priv)) return; @@ -8614,11 +8625,24 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); + err = iwl3945_init_channel_map(priv); + if (err) { + IWL_ERROR("initializing regulatory failed: %d\n", err); + goto out_remove_sysfs; + } + + err = iwl3945_init_geos(priv); + if (err) { + IWL_ERROR("initializing geos failed: %d\n", err); + goto out_free_channel_map; + } + iwl3945_reset_channel_flag(priv); + iwl3945_rate_control_register(priv->hw); err = ieee80211_register_hw(priv->hw); if (err) { IWL_ERROR("Failed to register network device (error %d)\n", err); - goto out_remove_sysfs; + goto out_free_geos; } priv->hw->conf.beacon_int = 100; @@ -8628,6 +8652,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return 0; + out_free_geos: + iwl3945_free_geos(priv); + out_free_channel_map: + iwl3945_free_channel_map(priv); out_remove_sysfs: sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); @@ -8702,10 +8730,8 @@ static void iwl3945_pci_remove(struct pci_dev *pdev) pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - kfree(priv->channel_info); - - kfree(priv->ieee_channels); - kfree(priv->ieee_rates); + iwl3945_free_channel_map(priv); + iwl3945_free_geos(priv); if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); |