Search Linux Wireless

Re: rtl8187 diversity

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello.

This is reworked patch for antenna diversity in rtl8187 compat wireless.
 - removed proc file system functionality 
 - reworked calculation of agc 
 - fixed codestyle
Next step I will create for 2.6.30 RC2 

-- 
BR, Eugene Sobol

diff -urN compat-wireless-2.6-old.orig/drivers/net/wireless/rtl8187_dev.c compat-wireless-2.6-old/drivers/net/wireless/rtl8187_dev.c
--- compat-wireless-2.6-old.orig/drivers/net/wireless/rtl8187_dev.c     2008-09-15 19:57:24.000000000 +0300
+++ compat-wireless-2.6-old/drivers/net/wireless/rtl8187_dev.c  2009-04-22 18:04:01.000000000 +0300
@@ -45,6 +45,9 @@
        {USB_DEVICE(0x03f0, 0xca02), .driver_info = DEVICE_RTL8187},
        /* Sitecom */
        {USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187},
+
+       {USB_DEVICE(0x13d1, 0xabe6), .driver_info = DEVICE_RTL8187},
+
        {}
 };

@@ -257,6 +260,7 @@

        usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep),
                          buf, skb->len, rtl8187_tx_cb, skb);
+       urb->transfer_flags |= URB_ZERO_PACKET;
        rc = usb_submit_urb(urb, GFP_ATOMIC);
        if (rc < 0) {
                usb_free_urb(urb);
@@ -320,6 +324,9 @@
                }
                rx_status.signal = signal;
                priv->signal = signal;
+
+               if (priv->ant_diversity_enabled)
+                       add_to_average_array(priv, hdr->agc);
        } else {
                struct rtl8187b_rx_hdr *hdr =
                        (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
@@ -555,6 +562,13 @@
        rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60);
        rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);

+       if (priv->ant_diversity_enabled) {
+               INIT_DELAYED_WORK(&priv->antenna_work,
+                       sw_antenna_work_item_callback);
+               priv->ant_diversity.switch_to = 0;
+               switch_antenna(priv);
+       }
+
        return 0;
 }

@@ -724,6 +738,8 @@
        u32 reg;
        int ret;

+       priv->hw = dev;
+
        ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) :
                                     rtl8187b_init_hw(dev);
        if (ret)
@@ -836,6 +852,9 @@
        struct rtl8187_priv *priv = dev->priv;
        int i;

+       if (priv->ant_diversity_enabled)
+               sw_antenna_diversity_timer_callback(priv);
+
        if (priv->mode != NL80211_IFTYPE_MONITOR)
                return -EOPNOTSUPP;

@@ -867,6 +886,12 @@
        mutex_lock(&priv->conf_mutex);
        priv->mode = NL80211_IFTYPE_MONITOR;
        priv->vif = NULL;
+
+       if (priv->ant_diversity_enabled) {
+               del_timer_sync(&priv->sw_antenna_diversity_timer);
+               cancel_delayed_work(&priv->antenna_work);
+       }
+
        mutex_unlock(&priv->conf_mutex);
 }

@@ -970,6 +995,85 @@
        rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf);
 }

+#define ANTENNA_DIVERSITY_TIMER_PERIOD 1000
+#define ANTENNA_SWITCH_TIMER_PERIOD    300
+#define ANTENNA_MAX_AGC_DIFF 15
+void sw_antenna_diversity_timer_callback(struct rtl8187_priv *priv)
+{
+       static int average_old;
+       int average_current = 0;
+       int i, sub;
+
+       if (!priv->ant_diversity_enabled)
+               return;
+       for (i = 0; i < VAL_ARRAY_SIZE; ++i)
+               average_current += priv->ant_diversity.agc_array[i];
+
+       average_current /= VAL_ARRAY_SIZE;
+       sub = average_current - average_old;
+       if (sub > ANTENNA_MAX_AGC_DIFF) {
+               priv->ant_diversity.switch_to ^= 1;
+               queue_delayed_work(priv->hw->workqueue, &priv->antenna_work,
+                               msecs_to_jiffies(ANTENNA_SWITCH_TIMER_PERIOD));
+       }
+
+       average_old = average_current;
+       priv->sw_antenna_diversity_timer.expires = jiffies +
+               msecs_to_jiffies(ANTENNA_DIVERSITY_TIMER_PERIOD);
+       add_timer(&priv->sw_antenna_diversity_timer);
+}
+
+/*
+ * Change Antenna Switch.
+ */
+u8 switch_antenna(struct rtl8187_priv *priv)
+{
+       u8 b_antenna_switched = 0;
+       u8 u1b_antenna_index = priv->ant_diversity.switch_to;
+
+       switch (u1b_antenna_index) {
+       case 0:
+               /* main antenna */
+               /* Rx CCK. */
+               rtl8187_write_phy(priv->hw, 0x10, 0x0001009b);
+               /* Rx OFDM. */
+               rtl8187_write_phy(priv->hw, 0x26, 0x00000090);
+               /* Tx Antenna. */
+               rtl818x_iowrite16(priv, (__le16 *)ANTSEL, 0x0003);
+
+               b_antenna_switched = 1;
+               printk(KERN_INFO "switch to ANT1 antenna\n");
+       break;
+       case 1: /* switch(u1bAntennaIndex) */
+               /* Rx CCK. */
+               rtl8187_write_phy(priv->hw, 0x10, 0x000100db);
+               /* Rx OFDM. */
+               rtl8187_write_phy(priv->hw, 0x26, 0x00000010);
+               /* Tx Antenna. */
+               rtl818x_iowrite16(priv, (__le16 *)ANTSEL, 0x0000);
+
+               b_antenna_switched = 1;
+               printk(KERN_INFO "switch to AUX antenna\n");
+       break;
+       default:
+               printk(KERN_WARNING "[%s] unkown u_1b_antenna_index(%d)\n",
+                       __func__, u1b_antenna_index);
+       break;
+       } /* switch(u1bAntennaIndex) */
+
+       if (b_antenna_switched)
+               priv->ant_diversity.curr_ant_index = u1b_antenna_index;
+
+       return b_antenna_switched;
+}
+
+void sw_antenna_work_item_callback(struct work_struct *work)
+{
+       struct rtl8187_priv *priv = container_of(work,
+                                       struct rtl8187_priv, antenna_work.work);
+       switch_antenna(priv);
+}
+
 static const struct ieee80211_ops rtl8187_ops = {
        .tx                     = rtl8187_tx,
        .start                  = rtl8187_start,
@@ -1034,6 +1138,8 @@
        priv = dev->priv;
        priv->is_rtl8187b = (id->driver_info == DEVICE_RTL8187B);

+       priv->ant_diversity_enabled = 0;
+
        SET_IEEE80211_DEV(dev, &intf->dev);
        usb_set_intfdata(intf, dev);
        priv->udev = udev;
@@ -1123,6 +1229,7 @@
                        break;
                default:
                        chip_name = "RTL8187vB (default)";
+                       priv->ant_diversity_enabled = 1;
                }
        } else {
                /*
@@ -1210,6 +1317,15 @@
               wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
               chip_name, priv->asic_rev, priv->rf->name);

+       if (priv->ant_diversity_enabled) {
+               init_timer(&priv->sw_antenna_diversity_timer);
+               memset(priv->ant_diversity.agc_array, 0,
+                               sizeof priv->ant_diversity);
+               priv->sw_antenna_diversity_timer.data = (unsigned long)priv;
+               priv->sw_antenna_diversity_timer.function =
+                               (void *)sw_antenna_diversity_timer_callback;
+       }
+
        return 0;

  err_free_dev:
diff -urN compat-wireless-2.6-old.orig/drivers/net/wireless/rtl8187.h compat-wireless-2.6-old/drivers/net/wireless/rtl8187.h
--- compat-wireless-2.6-old.orig/drivers/net/wireless/rtl8187.h 2008-09-04 00:04:20.000000000 +0300
+++ compat-wireless-2.6-old/drivers/net/wireless/rtl8187.h      2009-04-22 16:51:13.000000000 +0300
@@ -82,11 +82,24 @@
        DEVICE_RTL8187B
 };

+#define VAL_ARRAY_SIZE 10
+#define ANTSEL 0xFF9F
+
+struct rtl8187_ant_diversity {
+
+    int count;
+       u8 agc_array[VAL_ARRAY_SIZE];
+
+    u8 switch_to;
+    u8 curr_ant_index;
+} __attribute__ ((packed));
+
 struct rtl8187_priv {
        /* common between rtl818x drivers */
        struct rtl818x_csr *map;
        const struct rtl818x_rf_ops *rf;
        struct ieee80211_vif *vif;
+       struct ieee80211_hw *hw;
        int mode;
        /* The mutex protects the TX loopback state.
         * Any attempt to set channels concurrently locks the device.
@@ -112,8 +125,21 @@
        u8 signal;
        u8 quality;
        u8 noise;
+
+       u8 ant_diversity_enabled;
+       struct timer_list sw_antenna_diversity_timer;
+       struct rtl8187_ant_diversity ant_diversity;
+       struct delayed_work antenna_work;
+
 };

+static inline void add_to_average_array(struct rtl8187_priv *priv, u8 val)
+{
+       priv->ant_diversity.agc_array[priv->ant_diversity.count++] = val;
+       if (priv->ant_diversity.count >= VAL_ARRAY_SIZE)
+               priv->ant_diversity.count = 0;
+}
+
 void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);

 static inline u8 rtl818x_ioread8_idx(struct rtl8187_priv *priv,
@@ -218,4 +244,10 @@
        rtl818x_iowrite32_idx(priv, addr, val, 0);
 }

+void sw_antenna_diversity_timer_callback(struct rtl8187_priv *dev);
+
+u8 switch_antenna(struct rtl8187_priv *priv);
+
+void sw_antenna_work_item_callback(struct work_struct *work);
+
 #endif /* RTL8187_H */

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux