aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2x00dev.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-05-05 17:09:28 -0400
committerDavid S. Miller <davem@davemloft.net>2011-05-05 17:09:28 -0400
commit90864fbc7639d7a2300c67a18c9fb9fbcf7d51d2 (patch)
tree6951c8d0e529dbfc7c4cec75d4cec63350e39b7c /drivers/net/wireless/rt2x00/rt2x00dev.c
parent228e548e602061b08ee8e8966f567c12aa079682 (diff)
parenta70171dce9cd44cb06c7d299eba9fa87a8933045 (diff)
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00dev.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c88
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
144static 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}
417EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo); 427EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo);
418 428
429static 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
449static 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
419static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, 500static 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.