Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[linux-2.6.git] / drivers / net / wireless / rtl818x / rtl8187_dev.c
index 3f22cc0..0fb850e 100644 (file)
@@ -32,6 +32,7 @@
 #ifdef CONFIG_RTL8187_LEDS
 #include "rtl8187_leds.h"
 #endif
+#include "rtl8187_rfkill.h"
 
 MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
 MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
@@ -64,6 +65,7 @@ static struct usb_device_id rtl8187_table[] __devinitdata = {
        /* Sitecom */
        {USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187},
        {USB_DEVICE(0x0df6, 0x0028), .driver_info = DEVICE_RTL8187B},
+       {USB_DEVICE(0x0df6, 0x0029), .driver_info = DEVICE_RTL8187B},
        /* Sphairon Access Systems GmbH */
        {USB_DEVICE(0x114B, 0x0150), .driver_info = DEVICE_RTL8187},
        /* Dick Smith Electronics */
@@ -74,6 +76,8 @@ static struct usb_device_id rtl8187_table[] __devinitdata = {
        {USB_DEVICE(0x18E8, 0x6232), .driver_info = DEVICE_RTL8187},
        /* AirLive */
        {USB_DEVICE(0x1b75, 0x8187), .driver_info = DEVICE_RTL8187},
+       /* Linksys */
+       {USB_DEVICE(0x1737, 0x0073), .driver_info = DEVICE_RTL8187B},
        {}
 };
 
@@ -218,7 +222,7 @@ static void rtl8187_tx_cb(struct urb *urb)
                 * reading a register in the device. We are in interrupt mode
                 * here, thus queue the skb and finish on a work queue. */
                skb_queue_tail(&priv->b_tx_status.queue, skb);
-               queue_delayed_work(hw->workqueue, &priv->work, 0);
+               ieee80211_queue_delayed_work(hw, &priv->work, 0);
        }
 }
 
@@ -317,7 +321,6 @@ static void rtl8187_rx_cb(struct urb *urb)
        struct ieee80211_rx_status rx_status = { 0 };
        int rate, signal;
        u32 flags;
-       u32 quality;
        unsigned long f;
 
        spin_lock_irqsave(&priv->rx_queue.lock, f);
@@ -335,10 +338,9 @@ static void rtl8187_rx_cb(struct urb *urb)
                        (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
                flags = le32_to_cpu(hdr->flags);
                /* As with the RTL8187B below, the AGC is used to calculate
-                * signal strength and quality. In this case, the scaling
+                * signal strength. In this case, the scaling
                 * constants are derived from the output of p54usb.
                 */
-               quality = 130 - ((41 * hdr->agc) >> 6);
                signal = -4 - ((27 * hdr->agc) >> 6);
                rx_status.antenna = (hdr->signal >> 7) & 1;
                rx_status.mactime = le64_to_cpu(hdr->mac_time);
@@ -351,23 +353,18 @@ static void rtl8187_rx_cb(struct urb *urb)
                 * In testing, none of these quantities show qualitative
                 * agreement with AP signal strength, except for the AGC,
                 * which is inversely proportional to the strength of the
-                * signal. In the following, the quality and signal strength
-                * are derived from the AGC. The arbitrary scaling constants
+                * signal. In the following, the signal strength
+                * is derived from the AGC. The arbitrary scaling constants
                 * are chosen to make the results close to the values obtained
                 * for a BCM4312 using b43 as the driver. The noise is ignored
                 * for now.
                 */
                flags = le32_to_cpu(hdr->flags);
-               quality = 170 - hdr->agc;
                signal = 14 - hdr->agc / 2;
                rx_status.antenna = (hdr->rssi >> 7) & 1;
                rx_status.mactime = le64_to_cpu(hdr->mac_time);
        }
 
-       if (quality > 100)
-               quality = 100;
-       rx_status.qual = quality;
-       priv->quality = quality;
        rx_status.signal = signal;
        priv->signal = signal;
        rate = (flags >> 20) & 0xF;
@@ -378,7 +375,8 @@ static void rtl8187_rx_cb(struct urb *urb)
        rx_status.flag |= RX_FLAG_TSFT;
        if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
                rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
-       ieee80211_rx_irqsafe(dev, skb, &rx_status);
+       memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+       ieee80211_rx_irqsafe(dev, skb);
 
        skb = dev_alloc_skb(RTL8187_MAX_RX);
        if (unlikely(!skb)) {
@@ -645,10 +643,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
 
        /* setup card */
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
-       rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
+       rtl818x_iowrite8(priv, &priv->map->GPIO0, 0);
 
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8));
-       rtl818x_iowrite8(priv, &priv->map->GPIO, 1);
+       rtl818x_iowrite8(priv, &priv->map->GPIO0, 1);
        rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
 
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
@@ -671,11 +669,11 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
 
        /* host_usb_init */
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
-       rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
+       rtl818x_iowrite8(priv, &priv->map->GPIO0, 0);
        reg = rtl818x_ioread8(priv, (u8 *)0xFE53);
        rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7));
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8));
-       rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20);
+       rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x20);
        rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
        rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80);
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80);
@@ -867,6 +865,9 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
        priv->aifsn[3] = 3; /* AIFSN[AC_BE] */
        rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0);
 
+       /* ENEDCA flag must always be set, transmit issues? */
+       rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_ENEDCA);
+
        return 0;
 }
 
@@ -904,12 +905,12 @@ static int rtl8187_start(struct ieee80211_hw *dev)
        u32 reg;
        int ret;
 
+       mutex_lock(&priv->conf_mutex);
+
        ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) :
                                     rtl8187b_init_hw(dev);
        if (ret)
-               return ret;
-
-       mutex_lock(&priv->conf_mutex);
+               goto rtl8187_start_exit;
 
        init_usb_anchor(&priv->anchored);
        priv->dev = dev;
@@ -936,8 +937,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
                                  (7 << 21 /* MAX TX DMA */));
                rtl8187_init_urbs(dev);
                rtl8187b_init_status_urb(dev);
-               mutex_unlock(&priv->conf_mutex);
-               return 0;
+               goto rtl8187_start_exit;
        }
 
        rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
@@ -981,9 +981,10 @@ static int rtl8187_start(struct ieee80211_hw *dev)
        reg |= RTL818X_CMD_RX_ENABLE;
        rtl818x_iowrite8(priv, &priv->map->CMD, reg);
        INIT_DELAYED_WORK(&priv->work, rtl8187_work);
-       mutex_unlock(&priv->conf_mutex);
 
-       return 0;
+rtl8187_start_exit:
+       mutex_unlock(&priv->conf_mutex);
+       return ret;
 }
 
 static void rtl8187_stop(struct ieee80211_hw *dev)
@@ -1011,37 +1012,37 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
                dev_kfree_skb_any(skb);
 
        usb_kill_anchored_urbs(&priv->anchored);
+       mutex_unlock(&priv->conf_mutex);
+
        if (!priv->is_rtl8187b)
                cancel_delayed_work_sync(&priv->work);
-       mutex_unlock(&priv->conf_mutex);
 }
 
 static int rtl8187_add_interface(struct ieee80211_hw *dev,
-                                struct ieee80211_if_init_conf *conf)
+                                struct ieee80211_vif *vif)
 {
        struct rtl8187_priv *priv = dev->priv;
        int i;
        int ret = -EOPNOTSUPP;
 
        mutex_lock(&priv->conf_mutex);
-       if (priv->mode != NL80211_IFTYPE_MONITOR)
+       if (priv->vif)
                goto exit;
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
-               priv->mode = conf->type;
                break;
        default:
                goto exit;
        }
 
        ret = 0;
-       priv->vif = conf->vif;
+       priv->vif = vif;
 
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
        for (i = 0; i < ETH_ALEN; i++)
                rtl818x_iowrite8(priv, &priv->map->MAC[i],
-                                ((u8 *)conf->mac_addr)[i]);
+                                ((u8 *)vif->addr)[i]);
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
 exit:
@@ -1050,11 +1051,10 @@ exit:
 }
 
 static void rtl8187_remove_interface(struct ieee80211_hw *dev,
-                                    struct ieee80211_if_init_conf *conf)
+                                    struct ieee80211_vif *vif)
 {
        struct rtl8187_priv *priv = dev->priv;
        mutex_lock(&priv->conf_mutex);
-       priv->mode = NL80211_IFTYPE_MONITOR;
        priv->vif = NULL;
        mutex_unlock(&priv->conf_mutex);
 }
@@ -1171,13 +1171,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
                        rtl818x_iowrite8(priv, &priv->map->BSSID[i],
                                         info->bssid[i]);
 
+               if (priv->is_rtl8187b)
+                       reg = RTL818X_MSR_ENEDCA;
+               else
+                       reg = 0;
+
                if (is_valid_ether_addr(info->bssid)) {
-                       reg = RTL818X_MSR_INFRA;
-                       if (priv->is_rtl8187b)
-                               reg |= RTL818X_MSR_ENEDCA;
+                       reg |= RTL818X_MSR_INFRA;
                        rtl818x_iowrite8(priv, &priv->map->MSR, reg);
                } else {
-                       reg = RTL818X_MSR_NO_LINK;
+                       reg |= RTL818X_MSR_NO_LINK;
                        rtl818x_iowrite8(priv, &priv->map->MSR, reg);
                }
 
@@ -1189,10 +1192,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
                                 info->use_short_preamble);
 }
 
+static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev,
+                                    int mc_count, struct dev_addr_list *mc_list)
+{
+       return mc_count;
+}
+
 static void rtl8187_configure_filter(struct ieee80211_hw *dev,
                                     unsigned int changed_flags,
                                     unsigned int *total_flags,
-                                    int mc_count, struct dev_addr_list *mclist)
+                                    u64 multicast)
 {
        struct rtl8187_priv *priv = dev->priv;
 
@@ -1202,7 +1211,7 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev,
                priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
        if (changed_flags & FIF_OTHER_BSS)
                priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
-       if (*total_flags & FIF_ALLMULTI || mc_count > 0)
+       if (*total_flags & FIF_ALLMULTI || multicast > 0)
                priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
        else
                priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
@@ -1257,6 +1266,14 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue,
        return 0;
 }
 
+static u64 rtl8187_get_tsf(struct ieee80211_hw *dev)
+{
+       struct rtl8187_priv *priv = dev->priv;
+
+       return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
+              (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
+}
+
 static const struct ieee80211_ops rtl8187_ops = {
        .tx                     = rtl8187_tx,
        .start                  = rtl8187_start,
@@ -1265,8 +1282,11 @@ static const struct ieee80211_ops rtl8187_ops = {
        .remove_interface       = rtl8187_remove_interface,
        .config                 = rtl8187_config,
        .bss_info_changed       = rtl8187_bss_info_changed,
+       .prepare_multicast      = rtl8187_prepare_multicast,
        .configure_filter       = rtl8187_configure_filter,
-       .conf_tx                = rtl8187_conf_tx
+       .conf_tx                = rtl8187_conf_tx,
+       .rfkill_poll            = rtl8187_rfkill_poll,
+       .get_tsf                = rtl8187_get_tsf,
 };
 
 static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -1310,6 +1330,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
        struct ieee80211_channel *channel;
        const char *chip_name;
        u16 txpwr, reg;
+       u16 product_id = le16_to_cpu(udev->descriptor.idProduct);
        int err, i;
 
        dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
@@ -1352,7 +1373,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
        dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
 
 
-       priv->mode = NL80211_IFTYPE_MONITOR;
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                     IEEE80211_HW_SIGNAL_DBM |
                     IEEE80211_HW_RX_INCLUDES_FCS;
@@ -1469,6 +1489,13 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
                (*channel++).hw_value = txpwr & 0xFF;
                (*channel++).hw_value = txpwr >> 8;
        }
+       /* Handle the differing rfkill GPIO bit in different models */
+       priv->rfkill_mask = RFKILL_MASK_8187_89_97;
+       if (product_id == 0x8197 || product_id == 0x8198) {
+               eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_SELECT_GPIO, &reg);
+               if (reg & 0xFF00)
+                       priv->rfkill_mask = RFKILL_MASK_8198;
+       }
 
        /*
         * XXX: Once this driver supports anything that requires
@@ -1497,15 +1524,16 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
        mutex_init(&priv->conf_mutex);
        skb_queue_head_init(&priv->b_tx_status.queue);
 
-       printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n",
+       printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s, rfkill mask %d\n",
               wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
-              chip_name, priv->asic_rev, priv->rf->name);
+              chip_name, priv->asic_rev, priv->rf->name, priv->rfkill_mask);
 
 #ifdef CONFIG_RTL8187_LEDS
        eeprom_93cx6_read(&eeprom, 0x3F, &reg);
        reg &= 0xFF;
        rtl8187_leds_init(dev, reg);
 #endif
+       rtl8187_rfkill_init(dev);
 
        return 0;
 
@@ -1529,6 +1557,7 @@ static void __devexit rtl8187_disconnect(struct usb_interface *intf)
 #ifdef CONFIG_RTL8187_LEDS
        rtl8187_leds_exit(dev);
 #endif
+       rtl8187_rfkill_exit(dev);
        ieee80211_unregister_hw(dev);
 
        priv = dev->priv;