Merge nommu branch
[pandora-kernel.git] / drivers / net / wireless / zd1211rw / zd_mac.c
index d6f3e02..1989f1c 100644 (file)
@@ -127,11 +127,9 @@ out:
 
 void zd_mac_clear(struct zd_mac *mac)
 {
-       /* Aquire the lock. */
-       spin_lock(&mac->lock);
-       spin_unlock(&mac->lock);
        zd_chip_clear(&mac->chip);
-       memset(mac, 0, sizeof(*mac));
+       ZD_ASSERT(!spin_is_locked(&mac->lock));
+       ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
 }
 
 static int reset_mode(struct zd_mac *mac)
@@ -716,7 +714,7 @@ struct zd_rt_hdr {
        u8  rt_rate;
        u16 rt_channel;
        u16 rt_chbitmask;
-} __attribute__((packed));
+};
 
 static void fill_rt_header(void *buffer, struct zd_mac *mac,
                           const struct ieee80211_rx_stats *stats,
@@ -816,13 +814,25 @@ static int filter_rx(struct ieee80211_device *ieee,
        return -EINVAL;
 }
 
-static void update_qual_rssi(struct zd_mac *mac, u8 qual_percent, u8 rssi)
+static void update_qual_rssi(struct zd_mac *mac,
+                            const u8 *buffer, unsigned int length,
+                            u8 qual_percent, u8 rssi_percent)
 {
        unsigned long flags;
+       struct ieee80211_hdr_3addr *hdr;
+       int i;
+
+       hdr = (struct ieee80211_hdr_3addr *)buffer;
+       if (length < offsetof(struct ieee80211_hdr_3addr, addr3))
+               return;
+       if (memcmp(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid, ETH_ALEN) != 0)
+               return;
 
        spin_lock_irqsave(&mac->lock, flags);
-       mac->qual_average = (7 * mac->qual_average + qual_percent) / 8;
-       mac->rssi_average = (7 * mac->rssi_average + rssi) / 8;
+       i = mac->stats_count % ZD_MAC_STATS_BUFFER_SIZE;
+       mac->qual_buffer[i] = qual_percent;
+       mac->rssi_buffer[i] = rssi_percent;
+       mac->stats_count++;
        spin_unlock_irqrestore(&mac->lock, flags);
 }
 
@@ -853,7 +863,6 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
        if (stats->rate)
                stats->mask |= IEEE80211_STATMASK_RATE;
 
-       update_qual_rssi(mac, stats->signal, stats->rssi);
        return 0;
 }
 
@@ -877,6 +886,8 @@ int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length)
                  sizeof(struct rx_status);
        buffer += ZD_PLCP_HEADER_SIZE;
 
+       update_qual_rssi(mac, buffer, length, stats.signal, stats.rssi);
+
        r = filter_rx(ieee, buffer, length, &stats);
        if (r <= 0)
                return r;
@@ -981,17 +992,31 @@ struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev)
 {
        struct zd_mac *mac = zd_netdev_mac(ndev);
        struct iw_statistics *iw_stats = &mac->iw_stats;
+       unsigned int i, count, qual_total, rssi_total;
 
        memset(iw_stats, 0, sizeof(struct iw_statistics));
        /* We are not setting the status, because ieee->state is not updated
         * at all and this driver doesn't track authentication state.
         */
        spin_lock_irq(&mac->lock);
-       iw_stats->qual.qual = mac->qual_average;
-       iw_stats->qual.level = mac->rssi_average;
-       iw_stats->qual.updated = IW_QUAL_QUAL_UPDATED|IW_QUAL_LEVEL_UPDATED|
-                                IW_QUAL_NOISE_INVALID;
+       count = mac->stats_count < ZD_MAC_STATS_BUFFER_SIZE ?
+               mac->stats_count : ZD_MAC_STATS_BUFFER_SIZE;
+       qual_total = rssi_total = 0;
+       for (i = 0; i < count; i++) {
+               qual_total += mac->qual_buffer[i];
+               rssi_total += mac->rssi_buffer[i];
+       }
        spin_unlock_irq(&mac->lock);
+       iw_stats->qual.updated = IW_QUAL_NOISE_INVALID;
+       if (count > 0) {
+               iw_stats->qual.qual = qual_total / count;
+               iw_stats->qual.level = rssi_total / count;
+               iw_stats->qual.updated |=
+                       IW_QUAL_QUAL_UPDATED|IW_QUAL_LEVEL_UPDATED;
+       } else {
+               iw_stats->qual.updated |=
+                       IW_QUAL_QUAL_INVALID|IW_QUAL_LEVEL_INVALID;
+       }
        /* TODO: update counter */
        return iw_stats;
 }