Merge nommu branch
[pandora-kernel.git] / drivers / net / wireless / zd1211rw / zd_mac.c
index 3bdc54d..1989f1c 100644 (file)
@@ -108,7 +108,9 @@ int zd_mac_init_hw(struct zd_mac *mac, u8 device_type)
        if (r)
                goto disable_int;
 
-       r = zd_set_encryption_type(chip, NO_WEP);
+       /* We must inform the device that we are doing encryption/decryption in
+        * software at the moment. */
+       r = zd_set_encryption_type(chip, ENC_SNIFFER);
        if (r)
                goto disable_int;
 
@@ -125,21 +127,17 @@ 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)
 {
        struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
        struct zd_ioreq32 ioreqs[3] = {
-               { CR_RX_FILTER, RX_FILTER_BEACON|RX_FILTER_PROBE_RESPONSE|
-                               RX_FILTER_AUTH|RX_FILTER_ASSOC_RESPONSE },
+               { CR_RX_FILTER, STA_RX_FILTER },
                { CR_SNIFFER_ON, 0U },
-               { CR_ENCRYPTION_TYPE, NO_WEP },
        };
 
        if (ieee->iw_mode == IW_MODE_MONITOR) {
@@ -713,9 +711,9 @@ static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
 struct zd_rt_hdr {
        struct ieee80211_radiotap_header rt_hdr;
        u8  rt_flags;
+       u8  rt_rate;
        u16 rt_channel;
        u16 rt_chbitmask;
-       u16 rt_rate;
 };
 
 static void fill_rt_header(void *buffer, struct zd_mac *mac,
@@ -735,14 +733,14 @@ static void fill_rt_header(void *buffer, struct zd_mac *mac,
        if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256))
                hdr->rt_flags |= IEEE80211_RADIOTAP_F_WEP;
 
+       hdr->rt_rate = stats->rate / 5;
+
        /* FIXME: 802.11a */
        hdr->rt_channel = cpu_to_le16(ieee80211chan2mhz(
                                             _zd_chip_get_channel(&mac->chip)));
        hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ |
                ((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) ==
                ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK));
-
-       hdr->rt_rate = stats->rate / 5;
 }
 
 /* Returns 1 if the data packet is for us and 0 otherwise. */
@@ -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;
 }