diff options
Diffstat (limited to 'drivers/net/wireless/ipw2x00/ipw2200.c')
| -rw-r--r-- | drivers/net/wireless/ipw2x00/ipw2200.c | 231 |
1 files changed, 115 insertions, 116 deletions
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 4fcdac63a30..c5aa404069f 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -34,6 +34,7 @@ #include <linux/slab.h> #include <net/cfg80211-wext.h> #include "ipw2200.h" +#include "ipw.h" #ifndef KBUILD_EXTMOD @@ -2191,6 +2192,7 @@ static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) { int rc = 0; unsigned long flags; + unsigned long now, end; spin_lock_irqsave(&priv->lock, flags); if (priv->status & STATUS_HCMD_ACTIVE) { @@ -2232,10 +2234,20 @@ static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) } spin_unlock_irqrestore(&priv->lock, flags); + now = jiffies; + end = now + HOST_COMPLETE_TIMEOUT; +again: rc = wait_event_interruptible_timeout(priv->wait_command_queue, !(priv-> status & STATUS_HCMD_ACTIVE), - HOST_COMPLETE_TIMEOUT); + end - now); + if (rc < 0) { + now = jiffies; + if (time_before(now, end)) + goto again; + rc = 0; + } + if (rc == 0) { spin_lock_irqsave(&priv->lock, flags); if (priv->status & STATUS_HCMD_ACTIVE) { @@ -2686,7 +2698,21 @@ static u16 eeprom_read_u16(struct ipw_priv *priv, u8 addr) /* data's copy of the eeprom data */ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac) { - memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], 6); + memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], ETH_ALEN); +} + +static void ipw_read_eeprom(struct ipw_priv *priv) +{ + int i; + __le16 *eeprom = (__le16 *) priv->eeprom; + + IPW_DEBUG_TRACE(">>\n"); + + /* read entire contents of eeprom into private buffer */ + for (i = 0; i < 128; i++) + eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i)); + + IPW_DEBUG_TRACE("<<\n"); } /* @@ -2700,14 +2726,9 @@ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac) static void ipw_eeprom_init_sram(struct ipw_priv *priv) { int i; - __le16 *eeprom = (__le16 *) priv->eeprom; IPW_DEBUG_TRACE(">>\n"); - /* read entire contents of eeprom into private buffer */ - for (i = 0; i < 128; i++) - eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i)); - /* If the data looks correct, then copy it to our private copy. Otherwise let the firmware know to perform the operation @@ -2991,7 +3012,7 @@ static void ipw_remove_current_network(struct ipw_priv *priv) spin_lock_irqsave(&priv->ieee->lock, flags); list_for_each_safe(element, safe, &priv->ieee->network_list) { network = list_entry(element, struct libipw_network, list); - if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { + if (ether_addr_equal(network->bssid, priv->bssid)) { list_del(element); list_add_tail(&network->list, &priv->ieee->network_free_list); @@ -3527,6 +3548,7 @@ static int ipw_load(struct ipw_priv *priv) ipw_rx_queue_reset(priv, priv->rxq); if (!priv->rxq) { IPW_ERROR("Unable to initialize Rx queue\n"); + rc = -ENOMEM; goto error; } @@ -3631,8 +3653,10 @@ static int ipw_load(struct ipw_priv *priv) /* ack fw init done interrupt */ ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE); - /* read eeprom data and initialize the eeprom region of sram */ + /* read eeprom data */ priv->eeprom_delay = 1; + ipw_read_eeprom(priv); + /* initialize the eeprom region of sram */ ipw_eeprom_init_sram(priv); /* enable interrupts */ @@ -3657,8 +3681,7 @@ static int ipw_load(struct ipw_priv *priv) priv->rxq = NULL; } ipw_tx_queue_free(priv); - if (raw) - release_firmware(raw); + release_firmware(raw); #ifdef CONFIG_PM fw_loaded = 0; raw = NULL; @@ -3898,7 +3921,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) int i; for (i = 0; i < priv->num_stations; i++) { - if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) { + if (ether_addr_equal(priv->stations[i], bssid)) { /* Another node is active in network */ priv->missed_adhoc_beacons = 0; if (!(priv->config & CFG_STATIC_CHANNEL)) @@ -3930,7 +3953,7 @@ static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid) int i; for (i = 0; i < priv->num_stations; i++) - if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) + if (ether_addr_equal(priv->stations[i], bssid)) return i; return IPW_INVALID_STATION; @@ -4458,18 +4481,11 @@ static void handle_scan_event(struct ipw_priv *priv) { /* Only userspace-requested scan completion events go out immediately */ if (!priv->user_requested_scan) { - if (!delayed_work_pending(&priv->scan_event)) - schedule_delayed_work(&priv->scan_event, - round_jiffies_relative(msecs_to_jiffies(4000))); + schedule_delayed_work(&priv->scan_event, + round_jiffies_relative(msecs_to_jiffies(4000))); } else { - union iwreq_data wrqu; - priv->user_requested_scan = 0; - cancel_delayed_work(&priv->scan_event); - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); + mod_delayed_work(system_wq, &priv->scan_event, 0); } } @@ -5606,7 +5622,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, return 0; } - if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { + if (ether_addr_equal(network->bssid, priv->bssid)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of the same BSSID match: %pM" ".\n", print_ssid(ssid, network->ssid, @@ -5833,7 +5849,7 @@ static int ipw_best_network(struct ipw_priv *priv, } if ((priv->config & CFG_STATIC_BSSID) && - memcmp(network->bssid, priv->bssid, ETH_ALEN)) { + !ether_addr_equal(network->bssid, priv->bssid)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of BSSID mismatch: %pM.\n", print_ssid(ssid, network->ssid, @@ -6790,7 +6806,6 @@ static int ipw_wx_get_auth(struct net_device *dev, struct libipw_device *ieee = priv->ieee; struct lib80211_crypt_data *crypt; struct iw_param *param = &wrqu->param; - int ret = 0; switch (param->flags & IW_AUTH_INDEX) { case IW_AUTH_WPA_VERSION: @@ -6800,8 +6815,7 @@ static int ipw_wx_get_auth(struct net_device *dev, /* * wpa_supplicant will control these internally */ - ret = -EOPNOTSUPP; - break; + return -EOPNOTSUPP; case IW_AUTH_TKIP_COUNTERMEASURES: crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; @@ -6974,7 +6988,7 @@ static int ipw_qos_handle_probe_response(struct ipw_priv *priv, } if ((priv->status & STATUS_ASSOCIATED) && (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) { - if (memcmp(network->bssid, priv->bssid, ETH_ALEN)) + if (!ether_addr_equal(network->bssid, priv->bssid)) if (network->capability & WLAN_CAPABILITY_IBSS) if ((network->ssid_len == priv->assoc_network->ssid_len) && @@ -7024,7 +7038,7 @@ static int ipw_qos_activate(struct ipw_priv *priv, cpu_to_le16(burst_duration); } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) { if (type == IEEE_B) { - IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n", + IPW_DEBUG_QOS("QoS activate IBSS network mode %d\n", type); if (priv->qos_data.qos_enable == 0) active_one = &def_parameters_CCK; @@ -7058,9 +7072,7 @@ static int ipw_qos_activate(struct ipw_priv *priv, } IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n"); - err = ipw_send_qos_params_command(priv, - (struct libipw_qos_parameters *) - &(qos_parameters[0])); + err = ipw_send_qos_params_command(priv, &qos_parameters[0]); if (err) IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n"); @@ -8198,29 +8210,29 @@ static int is_network_packet(struct ipw_priv *priv, switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */ /* packets from our adapter are dropped (echo) */ - if (!memcmp(header->addr2, priv->net_dev->dev_addr, ETH_ALEN)) + if (ether_addr_equal(header->addr2, priv->net_dev->dev_addr)) return 0; /* {broad,multi}cast packets to our BSSID go through */ if (is_multicast_ether_addr(header->addr1)) - return !memcmp(header->addr3, priv->bssid, ETH_ALEN); + return ether_addr_equal(header->addr3, priv->bssid); /* packets to our adapter go through */ - return !memcmp(header->addr1, priv->net_dev->dev_addr, - ETH_ALEN); + return ether_addr_equal(header->addr1, + priv->net_dev->dev_addr); case IW_MODE_INFRA: /* Header: Dest. | BSSID | Source */ /* packets from our adapter are dropped (echo) */ - if (!memcmp(header->addr3, priv->net_dev->dev_addr, ETH_ALEN)) + if (ether_addr_equal(header->addr3, priv->net_dev->dev_addr)) return 0; /* {broad,multi}cast packets to our BSS go through */ if (is_multicast_ether_addr(header->addr1)) - return !memcmp(header->addr2, priv->bssid, ETH_ALEN); + return ether_addr_equal(header->addr2, priv->bssid); /* packets to our adapter go through */ - return !memcmp(header->addr1, priv->net_dev->dev_addr, - ETH_ALEN); + return ether_addr_equal(header->addr1, + priv->net_dev->dev_addr); } return 1; @@ -8245,10 +8257,10 @@ static int is_duplicate_packet(struct ipw_priv *priv, u8 *mac = header->addr2; int index = mac[5] % IPW_IBSS_MAC_HASH_SIZE; - __list_for_each(p, &priv->ibss_mac_hash[index]) { + list_for_each(p, &priv->ibss_mac_hash[index]) { entry = list_entry(p, struct ipw_ibss_seq, list); - if (!memcmp(entry->mac, mac, ETH_ALEN)) + if (ether_addr_equal(entry->mac, mac)) break; } if (p == &priv->ibss_mac_hash[index]) { @@ -8317,7 +8329,7 @@ static void ipw_handle_mgmt_packet(struct ipw_priv *priv, IEEE80211_STYPE_PROBE_RESP) || (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) == IEEE80211_STYPE_BEACON))) { - if (!memcmp(header->addr3, priv->bssid, ETH_ALEN)) + if (ether_addr_equal(header->addr3, priv->bssid)) ipw_add_station(priv, header->addr2); } @@ -9017,18 +9029,11 @@ static int ipw_wx_set_wap(struct net_device *dev, { struct ipw_priv *priv = libipw_priv(dev); - static const unsigned char any[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; - static const unsigned char off[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) return -EINVAL; mutex_lock(&priv->mutex); - if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) || - !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) { + if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data) || + is_zero_ether_addr(wrqu->ap_addr.sa_data)) { /* we disable mandatory BSSID association */ IPW_DEBUG_WX("Setting AP BSSID to ANY\n"); priv->config &= ~CFG_STATIC_BSSID; @@ -9040,7 +9045,7 @@ static int ipw_wx_set_wap(struct net_device *dev, } priv->config |= CFG_STATIC_BSSID; - if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) { + if (ether_addr_equal(priv->bssid, wrqu->ap_addr.sa_data)) { IPW_DEBUG_WX("BSSID set to current BSSID.\n"); mutex_unlock(&priv->mutex); return 0; @@ -9164,7 +9169,7 @@ static int ipw_wx_set_nick(struct net_device *dev, if (wrqu->data.length > IW_ESSID_MAX_SIZE) return -E2BIG; mutex_lock(&priv->mutex); - wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); + wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick)); memset(priv->nick, 0, sizeof(priv->nick)); memcpy(priv->nick, extra, wrqu->data.length); IPW_DEBUG_TRACE("<<\n"); @@ -10459,7 +10464,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, } else len = src->len; - dst = alloc_skb(len + sizeof(*rt_hdr), GFP_ATOMIC); + dst = alloc_skb(len + sizeof(*rt_hdr) + sizeof(u16)*2, GFP_ATOMIC); if (!dst) continue; @@ -10761,7 +10766,7 @@ static void ipw_bg_link_down(struct work_struct *work) mutex_unlock(&priv->mutex); } -static int __devinit ipw_setup_deferred_work(struct ipw_priv *priv) +static int ipw_setup_deferred_work(struct ipw_priv *priv) { int ret = 0; @@ -11256,10 +11261,31 @@ static const struct libipw_geo ipw_geos[] = { } }; +static void ipw_set_geo(struct ipw_priv *priv) +{ + int j; + + for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) { + if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE], + ipw_geos[j].name, 3)) + break; + } + + if (j == ARRAY_SIZE(ipw_geos)) { + IPW_WARNING("SKU [%c%c%c] not recognized.\n", + priv->eeprom[EEPROM_COUNTRY_CODE + 0], + priv->eeprom[EEPROM_COUNTRY_CODE + 1], + priv->eeprom[EEPROM_COUNTRY_CODE + 2]); + j = 0; + } + + libipw_set_geo(priv->ieee, &ipw_geos[j]); +} + #define MAX_HW_RESTARTS 5 static int ipw_up(struct ipw_priv *priv) { - int rc, i, j; + int rc, i; /* Age scan list entries found before suspend */ if (priv->suspend_time) { @@ -11295,24 +11321,8 @@ static int ipw_up(struct ipw_priv *priv) if (!(priv->config & CFG_CUSTOM_MAC)) eeprom_parse_mac(priv, priv->mac_addr); memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); - memcpy(priv->net_dev->perm_addr, priv->mac_addr, ETH_ALEN); - for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) { - if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE], - ipw_geos[j].name, 3)) - break; - } - if (j == ARRAY_SIZE(ipw_geos)) { - IPW_WARNING("SKU [%c%c%c] not recognized.\n", - priv->eeprom[EEPROM_COUNTRY_CODE + 0], - priv->eeprom[EEPROM_COUNTRY_CODE + 1], - priv->eeprom[EEPROM_COUNTRY_CODE + 2]); - j = 0; - } - if (libipw_set_geo(priv->ieee, &ipw_geos[j])) { - IPW_WARNING("Could not set geography."); - return 0; - } + ipw_set_geo(priv); if (priv->status & STATUS_RF_KILL_SW) { IPW_WARNING("Radio disabled by module parameter.\n"); @@ -11432,20 +11442,6 @@ static void ipw_bg_down(struct work_struct *work) mutex_unlock(&priv->mutex); } -/* Called by register_netdev() */ -static int ipw_net_init(struct net_device *dev) -{ - int rc = 0; - struct ipw_priv *priv = libipw_priv(dev); - - mutex_lock(&priv->mutex); - if (ipw_up(priv)) - rc = -EIO; - mutex_unlock(&priv->mutex); - - return rc; -} - static int ipw_wdev_init(struct net_device *dev) { int i, rc = 0; @@ -11476,10 +11472,10 @@ static int ipw_wdev_init(struct net_device *dev) bg_band->channels[i].max_power = geo->bg[i].max_power; if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) bg_band->channels[i].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS) bg_band->channels[i].flags |= - IEEE80211_CHAN_NO_IBSS; + IEEE80211_CHAN_NO_IR; if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT) bg_band->channels[i].flags |= IEEE80211_CHAN_RADAR; @@ -11507,18 +11503,18 @@ static int ipw_wdev_init(struct net_device *dev) rc = -ENOMEM; goto out; } - /* translate geo->bg to a_band.channels */ + /* translate geo->a to a_band.channels */ for (i = 0; i < geo->a_channels; i++) { - a_band->channels[i].band = IEEE80211_BAND_2GHZ; + a_band->channels[i].band = IEEE80211_BAND_5GHZ; a_band->channels[i].center_freq = geo->a[i].freq; a_band->channels[i].hw_value = geo->a[i].channel; a_band->channels[i].max_power = geo->a[i].max_power; if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY) a_band->channels[i].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; if (geo->a[i].flags & LIBIPW_CH_NO_IBSS) a_band->channels[i].flags |= - IEEE80211_CHAN_NO_IBSS; + IEEE80211_CHAN_NO_IR; if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT) a_band->channels[i].flags |= IEEE80211_CHAN_RADAR; @@ -11533,6 +11529,9 @@ static int ipw_wdev_init(struct net_device *dev) wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = a_band; } + wdev->wiphy->cipher_suites = ipw_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites); + set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); /* With that information in place, we can now register the wiphy... */ @@ -11711,7 +11710,6 @@ static void ipw_prom_free(struct ipw_priv *priv) #endif static const struct net_device_ops ipw_netdev_ops = { - .ndo_init = ipw_net_init, .ndo_open = ipw_net_open, .ndo_stop = ipw_net_stop, .ndo_set_rx_mode = ipw_net_set_multicast_list, @@ -11721,7 +11719,7 @@ static const struct net_device_ops ipw_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -static int __devinit ipw_pci_probe(struct pci_dev *pdev, +static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; @@ -11826,10 +11824,6 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, net_dev->wireless_data = &priv->wireless_data; net_dev->wireless_handlers = &ipw_wx_handler_def; net_dev->ethtool_ops = &ipw_ethtool_ops; - net_dev->irq = pdev->irq; - net_dev->base_addr = (unsigned long)priv->hw_base; - net_dev->mem_start = pci_resource_start(pdev, 0); - net_dev->mem_end = net_dev->mem_start + pci_resource_len(pdev, 0) - 1; err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group); if (err) { @@ -11838,17 +11832,24 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, goto out_release_irq; } - mutex_unlock(&priv->mutex); - err = register_netdev(net_dev); - if (err) { - IPW_ERROR("failed to register network device\n"); + if (ipw_up(priv)) { + mutex_unlock(&priv->mutex); + err = -EIO; goto out_remove_sysfs; } + mutex_unlock(&priv->mutex); + err = ipw_wdev_init(net_dev); if (err) { IPW_ERROR("failed to register wireless device\n"); - goto out_unregister_netdev; + goto out_remove_sysfs; + } + + err = register_netdev(net_dev); + if (err) { + IPW_ERROR("failed to register network device\n"); + goto out_unregister_wiphy; } #ifdef CONFIG_IPW2200_PROMISCUOUS @@ -11857,10 +11858,8 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, if (err) { IPW_ERROR("Failed to register promiscuous network " "device (error %d).\n", err); - wiphy_unregister(priv->ieee->wdev.wiphy); - kfree(priv->ieee->a_band.channels); - kfree(priv->ieee->bg_band.channels); - goto out_unregister_netdev; + unregister_netdev(priv->net_dev); + goto out_unregister_wiphy; } } #endif @@ -11872,8 +11871,10 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, return 0; - out_unregister_netdev: - unregister_netdev(priv->net_dev); + out_unregister_wiphy: + wiphy_unregister(priv->ieee->wdev.wiphy); + kfree(priv->ieee->a_band.channels); + kfree(priv->ieee->bg_band.channels); out_remove_sysfs: sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); out_release_irq: @@ -11884,14 +11885,13 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, pci_release_regions(pdev); out_pci_disable_device: pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); out_free_libipw: free_libipw(priv->net_dev, 0); out: return err; } -static void __devexit ipw_pci_remove(struct pci_dev *pdev) +static void ipw_pci_remove(struct pci_dev *pdev) { struct ipw_priv *priv = pci_get_drvdata(pdev); struct list_head *p, *q; @@ -11965,7 +11965,6 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev) iounmap(priv->hw_base); pci_release_regions(pdev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); /* wiphy_unregister needs to be here, before free_libipw */ wiphy_unregister(priv->ieee->wdev.wiphy); kfree(priv->ieee->a_band.channels); @@ -12053,7 +12052,7 @@ static struct pci_driver ipw_driver = { .name = DRV_NAME, .id_table = card_ids, .probe = ipw_pci_probe, - .remove = __devexit_p(ipw_pci_remove), + .remove = ipw_pci_remove, #ifdef CONFIG_PM .suspend = ipw_pci_suspend, .resume = ipw_pci_resume, |
