pcmcia: Fix up legacy driver IRQs
[safe/jmp/linux-2.6] / drivers / net / wireless / rtl8187_dev.c
index bdea1d8..e990261 100644 (file)
@@ -31,6 +31,8 @@ MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver");
 MODULE_LICENSE("GPL");
 
 static struct usb_device_id rtl8187_table[] __devinitdata = {
+       /* Asus */
+       {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187},
        /* Realtek */
        {USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187},
        {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B},
@@ -38,6 +40,7 @@ static struct usb_device_id rtl8187_table[] __devinitdata = {
        /* Netgear */
        {USB_DEVICE(0x0846, 0x6100), .driver_info = DEVICE_RTL8187},
        {USB_DEVICE(0x0846, 0x6a00), .driver_info = DEVICE_RTL8187},
+       {USB_DEVICE(0x0846, 0x4260), .driver_info = DEVICE_RTL8187B},
        /* HP */
        {USB_DEVICE(0x03f0, 0xca02), .driver_info = DEVICE_RTL8187},
        /* Sitecom */
@@ -169,6 +172,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
        struct rtl8187_priv *priv = dev->priv;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
        unsigned int ep;
        void *buf;
        struct urb *urb;
@@ -183,18 +187,18 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        }
 
        flags = skb->len;
-       flags |= RTL8187_TX_FLAG_NO_ENCRYPT;
+       flags |= RTL818X_TX_DESC_FLAG_NO_ENC;
 
        flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
        if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control))
-               flags |= RTL8187_TX_FLAG_MORE_FRAG;
+               flags |= RTL818X_TX_DESC_FLAG_MOREFRAG;
        if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
-               flags |= RTL8187_TX_FLAG_RTS;
+               flags |= RTL818X_TX_DESC_FLAG_RTS;
                flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
                rts_dur = ieee80211_rts_duration(dev, priv->vif,
                                                 skb->len, info);
        } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
-               flags |= RTL8187_TX_FLAG_CTS;
+               flags |= RTL818X_TX_DESC_FLAG_CTS;
                flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
        }
 
@@ -234,6 +238,20 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
                        ep = epmap[skb_get_queue_mapping(skb)];
        }
 
+       /* FIXME: The sequence that follows is needed for this driver to
+        * work with mac80211 since "mac80211: fix TX sequence numbers".
+        * As with the temporary code in rt2x00, changes will be needed
+        * to get proper sequence numbers on beacons. In addition, this
+        * patch places the sequence number in the hardware state, which
+        * limits us to a single virtual state.
+        */
+       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+               if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+                       priv->seqno += 0x10;
+               ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+               ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
+       }
+
        info->driver_data[0] = dev;
        info->driver_data[1] = urb;
 
@@ -257,6 +275,7 @@ static void rtl8187_rx_cb(struct urb *urb)
        struct ieee80211_rx_status rx_status = { 0 };
        int rate, signal;
        u32 flags;
+       u32 quality;
 
        spin_lock(&priv->rx_queue.lock);
        if (skb->next)
@@ -280,49 +299,62 @@ static void rtl8187_rx_cb(struct urb *urb)
                flags = le32_to_cpu(hdr->flags);
                signal = hdr->signal & 0x7f;
                rx_status.antenna = (hdr->signal >> 7) & 1;
-               rx_status.signal = signal;
                rx_status.noise = hdr->noise;
                rx_status.mactime = le64_to_cpu(hdr->mac_time);
-               priv->signal = signal;
                priv->quality = signal;
+               rx_status.qual = priv->quality;
                priv->noise = hdr->noise;
+               rate = (flags >> 20) & 0xF;
+               if (rate > 3) { /* OFDM rate */
+                       if (signal > 90)
+                               signal = 90;
+                       else if (signal < 25)
+                               signal = 25;
+                       signal = 90 - signal;
+               } else {        /* CCK rate */
+                       if (signal > 95)
+                               signal = 95;
+                       else if (signal < 30)
+                               signal = 30;
+                       signal = 95 - signal;
+               }
+               rx_status.signal = signal;
+               priv->signal = signal;
        } else {
                struct rtl8187b_rx_hdr *hdr =
                        (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
+               /* The Realtek datasheet for the RTL8187B shows that the RX
+                * header contains the following quantities: signal quality,
+                * RSSI, AGC, the received power in dB, and the measured SNR.
+                * 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
+                * 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);
-               signal = hdr->agc >> 1;
-               rx_status.antenna = (hdr->signal >> 7) & 1;
-               rx_status.signal = 64 - min(hdr->noise, (u8)64);
-               rx_status.noise = hdr->noise;
+               quality = 170 - hdr->agc;
+               if (quality > 100)
+                       quality = 100;
+               signal = 14 - hdr->agc / 2;
+               rx_status.qual = quality;
+               priv->quality = quality;
+               rx_status.signal = signal;
+               priv->signal = signal;
+               rx_status.antenna = (hdr->rssi >> 7) & 1;
                rx_status.mactime = le64_to_cpu(hdr->mac_time);
-               priv->signal = hdr->signal;
-               priv->quality = hdr->agc >> 1;
-               priv->noise = hdr->noise;
+               rate = (flags >> 20) & 0xF;
        }
 
        skb_trim(skb, flags & 0x0FFF);
-       rate = (flags >> 20) & 0xF;
-       if (rate > 3) { /* OFDM rate */
-               if (signal > 90)
-                       signal = 90;
-               else if (signal < 25)
-                       signal = 25;
-               signal = 90 - signal;
-       } else {        /* CCK rate */
-               if (signal > 95)
-                       signal = 95;
-               else if (signal < 30)
-                       signal = 30;
-               signal = 95 - signal;
-       }
-
-       rx_status.qual = priv->quality;
-       rx_status.signal = signal;
        rx_status.rate_idx = rate;
        rx_status.freq = dev->conf.channel->center_freq;
        rx_status.band = dev->conf.channel->band;
        rx_status.flag |= RX_FLAG_TSFT;
-       if (flags & (1 << 13))
+       if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
                rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
        ieee80211_rx_irqsafe(dev, skb, &rx_status);
 
@@ -430,8 +462,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
        reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
        rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg |
                         RTL818X_CONFIG3_ANAPARAM_WRITE);
-       rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
-       rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+                         RTL8187_RTL8225_ANAPARAM_ON);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+                         RTL8187_RTL8225_ANAPARAM2_ON);
        rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg &
                         ~RTL818X_CONFIG3_ANAPARAM_WRITE);
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
@@ -453,8 +487,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
        reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
        rtl818x_iowrite8(priv, &priv->map->CONFIG3,
                        reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
-       rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
-       rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+                         RTL8187_RTL8225_ANAPARAM_ON);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+                         RTL8187_RTL8225_ANAPARAM2_ON);
        rtl818x_iowrite8(priv, &priv->map->CONFIG3,
                        reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
@@ -566,9 +602,12 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
        reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
        reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT;
        rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
-       rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, 0x727f3f52);
-       rtl818x_iowrite32(priv, &priv->map->ANAPARAM, 0x45090658);
-       rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, 0);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+                         RTL8187B_RTL8225_ANAPARAM2_ON);
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+                         RTL8187B_RTL8225_ANAPARAM_ON);
+       rtl818x_iowrite8(priv, &priv->map->ANAPARAM3,
+                        RTL8187B_RTL8225_ANAPARAM3_ON);
 
        rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10);
        reg = rtl818x_ioread8(priv, (u8 *)0xFF62);
@@ -690,6 +729,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
        if (ret)
                return ret;
 
+       mutex_lock(&priv->conf_mutex);
        if (priv->is_rtl8187b) {
                reg = RTL818X_RX_CONF_MGMT |
                      RTL818X_RX_CONF_DATA |
@@ -711,6 +751,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
                                  (7 << 0  /* long retry limit */) |
                                  (7 << 21 /* MAX TX DMA */));
                rtl8187_init_urbs(dev);
+               mutex_unlock(&priv->conf_mutex);
                return 0;
        }
 
@@ -754,6 +795,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
        reg |= RTL818X_CMD_TX_ENABLE;
        reg |= RTL818X_CMD_RX_ENABLE;
        rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+       mutex_unlock(&priv->conf_mutex);
 
        return 0;
 }
@@ -765,6 +807,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
        struct sk_buff *skb;
        u32 reg;
 
+       mutex_lock(&priv->conf_mutex);
        rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
 
        reg = rtl818x_ioread8(priv, &priv->map->CMD);
@@ -784,7 +827,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
                usb_kill_urb(info->urb);
                kfree_skb(skb);
        }
-       return;
+       mutex_unlock(&priv->conf_mutex);
 }
 
 static int rtl8187_add_interface(struct ieee80211_hw *dev,
@@ -793,17 +836,18 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
        struct rtl8187_priv *priv = dev->priv;
        int i;
 
-       if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+       if (priv->mode != NL80211_IFTYPE_MONITOR)
                return -EOPNOTSUPP;
 
        switch (conf->type) {
-       case IEEE80211_IF_TYPE_STA:
+       case NL80211_IFTYPE_STATION:
                priv->mode = conf->type;
                break;
        default:
                return -EOPNOTSUPP;
        }
 
+       mutex_lock(&priv->conf_mutex);
        priv->vif = conf->vif;
 
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
@@ -812,6 +856,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
                                 ((u8 *)conf->mac_addr)[i]);
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
+       mutex_unlock(&priv->conf_mutex);
        return 0;
 }
 
@@ -819,8 +864,10 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev,
                                     struct ieee80211_if_init_conf *conf)
 {
        struct rtl8187_priv *priv = dev->priv;
-       priv->mode = IEEE80211_IF_TYPE_MNTR;
+       mutex_lock(&priv->conf_mutex);
+       priv->mode = NL80211_IFTYPE_MONITOR;
        priv->vif = NULL;
+       mutex_unlock(&priv->conf_mutex);
 }
 
 static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
@@ -828,6 +875,7 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
        struct rtl8187_priv *priv = dev->priv;
        u32 reg;
 
+       mutex_lock(&priv->conf_mutex);
        reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
        /* Enable TX loopback on MAC level to avoid TX during channel
         * changes, as this has be seen to causes problems and the
@@ -860,6 +908,7 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
        rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100);
        rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
        rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100);
+       mutex_unlock(&priv->conf_mutex);
        return 0;
 }
 
@@ -871,6 +920,7 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
        int i;
        u8 reg;
 
+       mutex_lock(&priv->conf_mutex);
        for (i = 0; i < ETH_ALEN; i++)
                rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
 
@@ -884,6 +934,7 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
                rtl818x_iowrite8(priv, &priv->map->MSR, reg);
        }
 
+       mutex_unlock(&priv->conf_mutex);
        return 0;
 }
 
@@ -1006,11 +1057,9 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
        dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
 
 
-       priv->mode = IEEE80211_IF_TYPE_MNTR;
+       priv->mode = NL80211_IFTYPE_MONITOR;
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-                    IEEE80211_HW_RX_INCLUDES_FCS |
-                    IEEE80211_HW_SIGNAL_UNSPEC;
-       dev->max_signal = 65;
+                    IEEE80211_HW_RX_INCLUDES_FCS;
 
        eeprom.data = dev;
        eeprom.register_read = rtl8187_eeprom_register_read;
@@ -1125,10 +1174,18 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
                (*channel++).hw_value = txpwr >> 8;
        }
 
-       if (priv->is_rtl8187b)
+       if (priv->is_rtl8187b) {
                printk(KERN_WARNING "rtl8187: 8187B chip detected. Support "
                        "is EXPERIMENTAL, and could damage your\n"
                        "         hardware, use at your own risk\n");
+               dev->flags |= IEEE80211_HW_SIGNAL_DBM;
+       } else {
+               dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
+               dev->max_signal = 65;
+       }
+
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
        if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
                printk(KERN_INFO "rtl8187: inconsistency between id with OEM"
                       " info!\n");
@@ -1147,6 +1204,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
                printk(KERN_ERR "rtl8187: Cannot register device\n");
                goto err_free_dev;
        }
+       mutex_init(&priv->conf_mutex);
 
        printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n",
               wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),