]> err.no Git - linux-2.6/blobdiff - drivers/net/wireless/zd1211rw/zd_mac.c
orinoco: more reliable scan handling
[linux-2.6] / drivers / net / wireless / zd1211rw / zd_mac.c
index 26869d107e52acbc4c04b322272b0806cea74ca2..5298a8bf11298496fa2496544355ef29649a9e89 100644 (file)
@@ -28,7 +28,6 @@
 #include "zd_ieee80211.h"
 #include "zd_netdev.h"
 #include "zd_rf.h"
-#include "zd_util.h"
 
 static void ieee_init(struct ieee80211_device *ieee);
 static void softmac_init(struct ieee80211softmac_device *sm);
@@ -161,13 +160,33 @@ void zd_mac_clear(struct zd_mac *mac)
        ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
 }
 
-static int reset_mode(struct zd_mac *mac)
+static int set_rx_filter(struct zd_mac *mac)
 {
        struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
        u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER;
        return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
 }
 
+static int set_sniffer(struct zd_mac *mac)
+{
+       struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+       return zd_iowrite32(&mac->chip, CR_SNIFFER_ON,
+               ieee->iw_mode == IW_MODE_MONITOR ? 1 : 0);
+       return 0;
+}
+
+static int set_mc_hash(struct zd_mac *mac)
+{
+       struct zd_mc_hash hash;
+       struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+       zd_mc_clear(&hash);
+       if (ieee->iw_mode == IW_MODE_MONITOR)
+               zd_mc_add_all(&hash);
+
+       return zd_chip_set_multicast_hash(&mac->chip, &hash);
+}
+
 int zd_mac_open(struct net_device *netdev)
 {
        struct zd_mac *mac = zd_netdev_mac(netdev);
@@ -194,7 +213,13 @@ int zd_mac_open(struct net_device *netdev)
        r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);
        if (r < 0)
                goto disable_int;
-       r = reset_mode(mac);
+       r = set_rx_filter(mac);
+       if (r)
+               goto disable_int;
+       r = set_sniffer(mac);
+       if (r)
+               goto disable_int;
+       r = set_mc_hash(mac);
        if (r)
                goto disable_int;
        r = zd_chip_switch_radio_on(chip);
@@ -263,12 +288,13 @@ int zd_mac_set_mac_address(struct net_device *netdev, void *p)
        struct sockaddr *addr = p;
        struct zd_mac *mac = zd_netdev_mac(netdev);
        struct zd_chip *chip = &mac->chip;
+       DECLARE_MAC_BUF(mac2);
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
        dev_dbg_f(zd_mac_dev(mac),
-                 "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data));
+                 "Setting MAC to %s\n", print_mac(mac2, addr->sa_data));
 
        if (netdev->flags & IFF_UP) {
                r = zd_write_mac_addr(chip, addr->sa_data);
@@ -298,18 +324,21 @@ static void set_multicast_hash_handler(struct work_struct *work)
 
 void zd_mac_set_multicast_list(struct net_device *dev)
 {
-       struct zd_mc_hash hash;
        struct zd_mac *mac = zd_netdev_mac(dev);
+       struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+       struct zd_mc_hash hash;
        struct dev_mc_list *mc;
        unsigned long flags;
+       DECLARE_MAC_BUF(mac2);
 
-       if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) {
+       if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI) ||
+                       ieee->iw_mode == IW_MODE_MONITOR) {
                zd_mc_add_all(&hash);
        } else {
                zd_mc_clear(&hash);
                for (mc = dev->mc_list; mc; mc = mc->next) {
-                       dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n",
-                                 MAC_ARG(mc->dmi_addr));
+                       dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n",
+                                 print_mac(mac2, mc->dmi_addr));
                        zd_mc_add_addr(&hash, mc->dmi_addr);
                }
        }
@@ -582,28 +611,6 @@ u8 zd_mac_get_channel(struct zd_mac *mac)
        return channel;
 }
 
-/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */
-static u8 zd_rate_typed(u8 zd_rate)
-{
-       static const u8 typed_rates[16] = {
-               [ZD_CCK_RATE_1M]        = ZD_CS_CCK|ZD_CCK_RATE_1M,
-               [ZD_CCK_RATE_2M]        = ZD_CS_CCK|ZD_CCK_RATE_2M,
-               [ZD_CCK_RATE_5_5M]      = ZD_CS_CCK|ZD_CCK_RATE_5_5M,
-               [ZD_CCK_RATE_11M]       = ZD_CS_CCK|ZD_CCK_RATE_11M,
-               [ZD_OFDM_RATE_6M]       = ZD_CS_OFDM|ZD_OFDM_RATE_6M,
-               [ZD_OFDM_RATE_9M]       = ZD_CS_OFDM|ZD_OFDM_RATE_9M,
-               [ZD_OFDM_RATE_12M]      = ZD_CS_OFDM|ZD_OFDM_RATE_12M,
-               [ZD_OFDM_RATE_18M]      = ZD_CS_OFDM|ZD_OFDM_RATE_18M,
-               [ZD_OFDM_RATE_24M]      = ZD_CS_OFDM|ZD_OFDM_RATE_24M,
-               [ZD_OFDM_RATE_36M]      = ZD_CS_OFDM|ZD_OFDM_RATE_36M,
-               [ZD_OFDM_RATE_48M]      = ZD_CS_OFDM|ZD_OFDM_RATE_48M,
-               [ZD_OFDM_RATE_54M]      = ZD_CS_OFDM|ZD_OFDM_RATE_54M,
-       };
-
-       ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f);
-       return typed_rates[zd_rate & ZD_CS_RATE_MASK];
-}
-
 int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
 {
        struct ieee80211_device *ieee;
@@ -628,8 +635,12 @@ int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
        ieee->iw_mode = mode;
        spin_unlock_irq(&ieee->lock);
 
-       if (netif_running(mac->netdev))
-               return reset_mode(mac);
+       if (netif_running(mac->netdev)) {
+               int r = set_rx_filter(mac);
+               if (r)
+                       return r;
+               return set_sniffer(mac);
+       }
 
        return 0;
 }
@@ -707,25 +718,30 @@ int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range)
 
 static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
 {
+       /* ZD_PURE_RATE() must be used to remove the modulation type flag of
+        * the zd-rate values. */
        static const u8 rate_divisor[] = {
-               [ZD_CCK_RATE_1M]        =  1,
-               [ZD_CCK_RATE_2M]        =  2,
-               [ZD_CCK_RATE_5_5M]      = 11, /* bits must be doubled */
-               [ZD_CCK_RATE_11M]       = 11,
-               [ZD_OFDM_RATE_6M]       =  6,
-               [ZD_OFDM_RATE_9M]       =  9,
-               [ZD_OFDM_RATE_12M]      = 12,
-               [ZD_OFDM_RATE_18M]      = 18,
-               [ZD_OFDM_RATE_24M]      = 24,
-               [ZD_OFDM_RATE_36M]      = 36,
-               [ZD_OFDM_RATE_48M]      = 48,
-               [ZD_OFDM_RATE_54M]      = 54,
+               [ZD_PURE_RATE(ZD_CCK_RATE_1M)]          =  1,
+               [ZD_PURE_RATE(ZD_CCK_RATE_2M)]          =  2,
+
+               /* bits must be doubled */
+               [ZD_PURE_RATE(ZD_CCK_RATE_5_5M)]        = 11,
+
+               [ZD_PURE_RATE(ZD_CCK_RATE_11M)]         = 11,
+               [ZD_PURE_RATE(ZD_OFDM_RATE_6M)]         =  6,
+               [ZD_PURE_RATE(ZD_OFDM_RATE_9M)]         =  9,
+               [ZD_PURE_RATE(ZD_OFDM_RATE_12M)]        = 12,
+               [ZD_PURE_RATE(ZD_OFDM_RATE_18M)]        = 18,
+               [ZD_PURE_RATE(ZD_OFDM_RATE_24M)]        = 24,
+               [ZD_PURE_RATE(ZD_OFDM_RATE_36M)]        = 36,
+               [ZD_PURE_RATE(ZD_OFDM_RATE_48M)]        = 48,
+               [ZD_PURE_RATE(ZD_OFDM_RATE_54M)]        = 54,
        };
 
        u32 bits = (u32)tx_length * 8;
        u32 divisor;
 
-       divisor = rate_divisor[zd_rate];
+       divisor = rate_divisor[ZD_PURE_RATE(zd_rate)];
        if (divisor == 0)
                return -EINVAL;
 
@@ -748,52 +764,24 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
        return bits/divisor;
 }
 
-enum {
-       R2M_SHORT_PREAMBLE = 0x01,
-       R2M_11A            = 0x02,
-};
-
-static u8 zd_rate_to_modulation(u8 zd_rate, int flags)
-{
-       u8 modulation;
-
-       modulation = zd_rate_typed(zd_rate);
-       if (flags & R2M_SHORT_PREAMBLE) {
-               switch (ZD_CS_RATE(modulation)) {
-               case ZD_CCK_RATE_2M:
-               case ZD_CCK_RATE_5_5M:
-               case ZD_CCK_RATE_11M:
-                       modulation |= ZD_CS_CCK_PREA_SHORT;
-                       return modulation;
-               }
-       }
-       if (flags & R2M_11A) {
-               if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM)
-                       modulation |= ZD_CS_OFDM_MODE_11A;
-       }
-       return modulation;
-}
-
 static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs,
                              struct ieee80211_hdr_4addr *hdr)
 {
        struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev);
        u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl));
-       u8 rate, zd_rate;
+       u8 rate;
        int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0;
        int is_multicast = is_multicast_ether_addr(hdr->addr1);
        int short_preamble = ieee80211softmac_short_preamble_ok(softmac,
                is_multicast, is_mgt);
-       int flags = 0;
 
-       /* FIXME: 802.11a? */
        rate = ieee80211softmac_suggest_txrate(softmac, is_multicast, is_mgt);
+       cs->modulation = rate_to_zd_rate(rate);
 
-       if (short_preamble)
-               flags |= R2M_SHORT_PREAMBLE;
-
-       zd_rate = rate_to_zd_rate(rate);
-       cs->modulation = zd_rate_to_modulation(zd_rate, flags);
+       /* Set short preamble bit when appropriate */
+       if (short_preamble && ZD_MODULATION_TYPE(cs->modulation) == ZD_CCK
+           && cs->modulation != ZD_CCK_RATE_1M)
+               cs->modulation |= ZD_CCK_PREA_SHORT;
 }
 
 static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
@@ -832,7 +820,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
                cs->control |= ZD_CS_RTS;
 
        /* Use CTS-to-self protection if required */
-       if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM &&
+       if (ZD_MODULATION_TYPE(cs->modulation) == ZD_OFDM &&
                        ieee80211softmac_protection_needed(softmac)) {
                /* FIXME: avoid sending RTS *and* self-CTS, is that correct? */
                cs->control &= ~ZD_CS_RTS;
@@ -893,7 +881,7 @@ static int fill_ctrlset(struct zd_mac *mac,
         * - see line 53 of zdinlinef.h
         */
        cs->service = 0;
-       r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation),
+       r = zd_calc_tx_length_us(&cs->service, ZD_RATE(cs->modulation),
                                 le16_to_cpu(cs->tx_length));
        if (r < 0)
                return r;
@@ -902,7 +890,7 @@ static int fill_ctrlset(struct zd_mac *mac,
        if (next_frag_len == 0) {
                cs->next_frame_length = 0;
        } else {
-               r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation),
+               r = zd_calc_tx_length_us(NULL, ZD_RATE(cs->modulation),
                                         next_frag_len);
                if (r < 0)
                        return r;
@@ -1077,7 +1065,8 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
 {
        const struct rx_status *status;
 
-       *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
+       *pstatus = status = (struct rx_status *)
+               (buffer + (length - sizeof(struct rx_status)));
        if (status->frame_status & ZD_RX_ERROR) {
                struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
                ieee->stats.rx_errors++;
@@ -1141,6 +1130,8 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
        __skb_trim(skb, skb->len -
                        (IEEE80211_FCS_LEN + sizeof(struct rx_status)));
 
+       ZD_ASSERT(IS_ALIGNED((unsigned long)skb->data, 4));
+
        update_qual_rssi(mac, skb->data, skb->len, stats.signal,
                         status->signal_strength);
 
@@ -1177,15 +1168,19 @@ static void do_rx(unsigned long mac_ptr)
 int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length)
 {
        struct sk_buff *skb;
+       unsigned int reserved =
+               ALIGN(max_t(unsigned int,
+                           sizeof(struct zd_rt_hdr), ZD_PLCP_HEADER_SIZE), 4) -
+               ZD_PLCP_HEADER_SIZE;
 
-       skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
+       skb = dev_alloc_skb(reserved + length);
        if (!skb) {
                struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
                dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n");
                ieee->stats.rx_dropped++;
                return -ENOMEM;
        }
-       skb_reserve(skb, sizeof(struct zd_rt_hdr));
+       skb_reserve(skb, reserved);
        memcpy(__skb_put(skb, length), buffer, length);
        skb_queue_tail(&mac->rx_queue, skb);
        tasklet_schedule(&mac->rx_tasklet);