diff options
Diffstat (limited to 'drivers/net/wireless/orinoco/orinoco.c')
-rw-r--r-- | drivers/net/wireless/orinoco/orinoco.c | 60 |
1 files changed, 39 insertions, 21 deletions
diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c index bc84e2792f8a..45a04faa7818 100644 --- a/drivers/net/wireless/orinoco/orinoco.c +++ b/drivers/net/wireless/orinoco/orinoco.c | |||
@@ -1610,6 +1610,16 @@ static void orinoco_rx_isr_tasklet(unsigned long data) | |||
1610 | struct orinoco_rx_data *rx_data, *temp; | 1610 | struct orinoco_rx_data *rx_data, *temp; |
1611 | struct hermes_rx_descriptor *desc; | 1611 | struct hermes_rx_descriptor *desc; |
1612 | struct sk_buff *skb; | 1612 | struct sk_buff *skb; |
1613 | unsigned long flags; | ||
1614 | |||
1615 | /* orinoco_rx requires the driver lock, and we also need to | ||
1616 | * protect priv->rx_list, so just hold the lock over the | ||
1617 | * lot. | ||
1618 | * | ||
1619 | * If orinoco_lock fails, we've unplugged the card. In this | ||
1620 | * case just abort. */ | ||
1621 | if (orinoco_lock(priv, &flags) != 0) | ||
1622 | return; | ||
1613 | 1623 | ||
1614 | /* extract desc and skb from queue */ | 1624 | /* extract desc and skb from queue */ |
1615 | list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { | 1625 | list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { |
@@ -1622,6 +1632,8 @@ static void orinoco_rx_isr_tasklet(unsigned long data) | |||
1622 | 1632 | ||
1623 | kfree(desc); | 1633 | kfree(desc); |
1624 | } | 1634 | } |
1635 | |||
1636 | orinoco_unlock(priv, &flags); | ||
1625 | } | 1637 | } |
1626 | 1638 | ||
1627 | /********************************************************************/ | 1639 | /********************************************************************/ |
@@ -1661,7 +1673,7 @@ static void print_linkstatus(struct net_device *dev, u16 status) | |||
1661 | s = "UNKNOWN"; | 1673 | s = "UNKNOWN"; |
1662 | } | 1674 | } |
1663 | 1675 | ||
1664 | printk(KERN_INFO "%s: New link status: %s (%04x)\n", | 1676 | printk(KERN_DEBUG "%s: New link status: %s (%04x)\n", |
1665 | dev->name, s, status); | 1677 | dev->name, s, status); |
1666 | } | 1678 | } |
1667 | 1679 | ||
@@ -3645,12 +3657,22 @@ struct net_device | |||
3645 | void free_orinocodev(struct net_device *dev) | 3657 | void free_orinocodev(struct net_device *dev) |
3646 | { | 3658 | { |
3647 | struct orinoco_private *priv = netdev_priv(dev); | 3659 | struct orinoco_private *priv = netdev_priv(dev); |
3660 | struct orinoco_rx_data *rx_data, *temp; | ||
3648 | 3661 | ||
3649 | /* No need to empty priv->rx_list: if the tasklet is scheduled | 3662 | /* If the tasklet is scheduled when we call tasklet_kill it |
3650 | * when we call tasklet_kill it will run one final time, | 3663 | * will run one final time. However the tasklet will only |
3651 | * emptying the list */ | 3664 | * drain priv->rx_list if the hw is still available. */ |
3652 | tasklet_kill(&priv->rx_tasklet); | 3665 | tasklet_kill(&priv->rx_tasklet); |
3653 | 3666 | ||
3667 | /* Explicitly drain priv->rx_list */ | ||
3668 | list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { | ||
3669 | list_del(&rx_data->list); | ||
3670 | |||
3671 | dev_kfree_skb(rx_data->skb); | ||
3672 | kfree(rx_data->desc); | ||
3673 | kfree(rx_data); | ||
3674 | } | ||
3675 | |||
3654 | unregister_pm_notifier(&priv->pm_notifier); | 3676 | unregister_pm_notifier(&priv->pm_notifier); |
3655 | orinoco_uncache_fw(priv); | 3677 | orinoco_uncache_fw(priv); |
3656 | 3678 | ||
@@ -5046,33 +5068,30 @@ static int orinoco_ioctl_set_genie(struct net_device *dev, | |||
5046 | struct orinoco_private *priv = netdev_priv(dev); | 5068 | struct orinoco_private *priv = netdev_priv(dev); |
5047 | u8 *buf; | 5069 | u8 *buf; |
5048 | unsigned long flags; | 5070 | unsigned long flags; |
5049 | int err = 0; | ||
5050 | 5071 | ||
5051 | /* cut off at IEEE80211_MAX_DATA_LEN */ | 5072 | /* cut off at IEEE80211_MAX_DATA_LEN */ |
5052 | if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) || | 5073 | if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) || |
5053 | (wrqu->data.length && (extra == NULL))) | 5074 | (wrqu->data.length && (extra == NULL))) |
5054 | return -EINVAL; | 5075 | return -EINVAL; |
5055 | 5076 | ||
5056 | if (orinoco_lock(priv, &flags) != 0) | ||
5057 | return -EBUSY; | ||
5058 | |||
5059 | if (wrqu->data.length) { | 5077 | if (wrqu->data.length) { |
5060 | buf = kmalloc(wrqu->data.length, GFP_KERNEL); | 5078 | buf = kmalloc(wrqu->data.length, GFP_KERNEL); |
5061 | if (buf == NULL) { | 5079 | if (buf == NULL) |
5062 | err = -ENOMEM; | 5080 | return -ENOMEM; |
5063 | goto out; | ||
5064 | } | ||
5065 | 5081 | ||
5066 | memcpy(buf, extra, wrqu->data.length); | 5082 | memcpy(buf, extra, wrqu->data.length); |
5067 | kfree(priv->wpa_ie); | 5083 | } else |
5068 | priv->wpa_ie = buf; | 5084 | buf = NULL; |
5069 | priv->wpa_ie_len = wrqu->data.length; | 5085 | |
5070 | } else { | 5086 | if (orinoco_lock(priv, &flags) != 0) { |
5071 | kfree(priv->wpa_ie); | 5087 | kfree(buf); |
5072 | priv->wpa_ie = NULL; | 5088 | return -EBUSY; |
5073 | priv->wpa_ie_len = 0; | ||
5074 | } | 5089 | } |
5075 | 5090 | ||
5091 | kfree(priv->wpa_ie); | ||
5092 | priv->wpa_ie = buf; | ||
5093 | priv->wpa_ie_len = wrqu->data.length; | ||
5094 | |||
5076 | if (priv->wpa_ie) { | 5095 | if (priv->wpa_ie) { |
5077 | /* Looks like wl_lkm wants to check the auth alg, and | 5096 | /* Looks like wl_lkm wants to check the auth alg, and |
5078 | * somehow pass it to the firmware. | 5097 | * somehow pass it to the firmware. |
@@ -5081,9 +5100,8 @@ static int orinoco_ioctl_set_genie(struct net_device *dev, | |||
5081 | */ | 5100 | */ |
5082 | } | 5101 | } |
5083 | 5102 | ||
5084 | out: | ||
5085 | orinoco_unlock(priv, &flags); | 5103 | orinoco_unlock(priv, &flags); |
5086 | return err; | 5104 | return 0; |
5087 | } | 5105 | } |
5088 | 5106 | ||
5089 | static int orinoco_ioctl_get_genie(struct net_device *dev, | 5107 | static int orinoco_ioctl_get_genie(struct net_device *dev, |