diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00dev.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 7776d9f1f297..2eb5196977fd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -141,6 +141,16 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) | |||
141 | rt2x00dev); | 141 | rt2x00dev); |
142 | } | 142 | } |
143 | 143 | ||
144 | static void rt2x00lib_autowakeup(struct work_struct *work) | ||
145 | { | ||
146 | struct rt2x00_dev *rt2x00dev = | ||
147 | container_of(work, struct rt2x00_dev, autowakeup_work.work); | ||
148 | |||
149 | if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) | ||
150 | ERROR(rt2x00dev, "Device failed to wakeup.\n"); | ||
151 | clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); | ||
152 | } | ||
153 | |||
144 | /* | 154 | /* |
145 | * Interrupt context handlers. | 155 | * Interrupt context handlers. |
146 | */ | 156 | */ |
@@ -416,6 +426,77 @@ void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status) | |||
416 | } | 426 | } |
417 | EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo); | 427 | EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo); |
418 | 428 | ||
429 | static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie) | ||
430 | { | ||
431 | struct ieee80211_mgmt *mgmt = (void *)data; | ||
432 | u8 *pos, *end; | ||
433 | |||
434 | pos = (u8 *)mgmt->u.beacon.variable; | ||
435 | end = data + len; | ||
436 | while (pos < end) { | ||
437 | if (pos + 2 + pos[1] > end) | ||
438 | return NULL; | ||
439 | |||
440 | if (pos[0] == ie) | ||
441 | return pos; | ||
442 | |||
443 | pos += 2 + pos[1]; | ||
444 | } | ||
445 | |||
446 | return NULL; | ||
447 | } | ||
448 | |||
449 | static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, | ||
450 | struct sk_buff *skb, | ||
451 | struct rxdone_entry_desc *rxdesc) | ||
452 | { | ||
453 | struct ieee80211_hdr *hdr = (void *) skb->data; | ||
454 | struct ieee80211_tim_ie *tim_ie; | ||
455 | u8 *tim; | ||
456 | u8 tim_len; | ||
457 | bool cam; | ||
458 | |||
459 | /* If this is not a beacon, or if mac80211 has no powersaving | ||
460 | * configured, or if the device is already in powersaving mode | ||
461 | * we can exit now. */ | ||
462 | if (likely(!ieee80211_is_beacon(hdr->frame_control) || | ||
463 | !(rt2x00dev->hw->conf.flags & IEEE80211_CONF_PS))) | ||
464 | return; | ||
465 | |||
466 | /* min. beacon length + FCS_LEN */ | ||
467 | if (skb->len <= 40 + FCS_LEN) | ||
468 | return; | ||
469 | |||
470 | /* and only beacons from the associated BSSID, please */ | ||
471 | if (!(rxdesc->dev_flags & RXDONE_MY_BSS) || | ||
472 | !rt2x00dev->aid) | ||
473 | return; | ||
474 | |||
475 | rt2x00dev->last_beacon = jiffies; | ||
476 | |||
477 | tim = rt2x00lib_find_ie(skb->data, skb->len - FCS_LEN, WLAN_EID_TIM); | ||
478 | if (!tim) | ||
479 | return; | ||
480 | |||
481 | if (tim[1] < sizeof(*tim_ie)) | ||
482 | return; | ||
483 | |||
484 | tim_len = tim[1]; | ||
485 | tim_ie = (struct ieee80211_tim_ie *) &tim[2]; | ||
486 | |||
487 | /* Check whenever the PHY can be turned off again. */ | ||
488 | |||
489 | /* 1. What about buffered unicast traffic for our AID? */ | ||
490 | cam = ieee80211_check_tim(tim_ie, tim_len, rt2x00dev->aid); | ||
491 | |||
492 | /* 2. Maybe the AP wants to send multicast/broadcast data? */ | ||
493 | cam |= (tim_ie->bitmap_ctrl & 0x01); | ||
494 | |||
495 | if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) | ||
496 | rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, | ||
497 | IEEE80211_CONF_CHANGE_PS); | ||
498 | } | ||
499 | |||
419 | static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, | 500 | static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, |
420 | struct rxdone_entry_desc *rxdesc) | 501 | struct rxdone_entry_desc *rxdesc) |
421 | { | 502 | { |
@@ -531,6 +612,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry) | |||
531 | rxdesc.flags |= RX_FLAG_HT; | 612 | rxdesc.flags |= RX_FLAG_HT; |
532 | 613 | ||
533 | /* | 614 | /* |
615 | * Check if this is a beacon, and more frames have been | ||
616 | * buffered while we were in powersaving mode. | ||
617 | */ | ||
618 | rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc); | ||
619 | |||
620 | /* | ||
534 | * Update extra components | 621 | * Update extra components |
535 | */ | 622 | */ |
536 | rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc); | 623 | rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc); |
@@ -1017,6 +1104,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) | |||
1017 | } | 1104 | } |
1018 | 1105 | ||
1019 | INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); | 1106 | INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); |
1107 | INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); | ||
1020 | 1108 | ||
1021 | /* | 1109 | /* |
1022 | * Let the driver probe the device to detect the capabilities. | 1110 | * Let the driver probe the device to detect the capabilities. |