diff options
Diffstat (limited to 'drivers/net/wireless/rtl8187_dev.c')
-rw-r--r-- | drivers/net/wireless/rtl8187_dev.c | 110 |
1 files changed, 79 insertions, 31 deletions
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index d3067b1216ca..57376fb993ed 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c | |||
@@ -31,6 +31,8 @@ MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); | |||
31 | MODULE_LICENSE("GPL"); | 31 | MODULE_LICENSE("GPL"); |
32 | 32 | ||
33 | static struct usb_device_id rtl8187_table[] __devinitdata = { | 33 | static struct usb_device_id rtl8187_table[] __devinitdata = { |
34 | /* Asus */ | ||
35 | {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187}, | ||
34 | /* Realtek */ | 36 | /* Realtek */ |
35 | {USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187}, | 37 | {USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187}, |
36 | {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B}, | 38 | {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B}, |
@@ -169,6 +171,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
169 | { | 171 | { |
170 | struct rtl8187_priv *priv = dev->priv; | 172 | struct rtl8187_priv *priv = dev->priv; |
171 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 173 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
174 | struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; | ||
172 | unsigned int ep; | 175 | unsigned int ep; |
173 | void *buf; | 176 | void *buf; |
174 | struct urb *urb; | 177 | struct urb *urb; |
@@ -234,6 +237,20 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
234 | ep = epmap[skb_get_queue_mapping(skb)]; | 237 | ep = epmap[skb_get_queue_mapping(skb)]; |
235 | } | 238 | } |
236 | 239 | ||
240 | /* FIXME: The sequence that follows is needed for this driver to | ||
241 | * work with mac80211 since "mac80211: fix TX sequence numbers". | ||
242 | * As with the temporary code in rt2x00, changes will be needed | ||
243 | * to get proper sequence numbers on beacons. In addition, this | ||
244 | * patch places the sequence number in the hardware state, which | ||
245 | * limits us to a single virtual state. | ||
246 | */ | ||
247 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | ||
248 | if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) | ||
249 | priv->seqno += 0x10; | ||
250 | ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); | ||
251 | ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno); | ||
252 | } | ||
253 | |||
237 | info->driver_data[0] = dev; | 254 | info->driver_data[0] = dev; |
238 | info->driver_data[1] = urb; | 255 | info->driver_data[1] = urb; |
239 | 256 | ||
@@ -257,6 +274,7 @@ static void rtl8187_rx_cb(struct urb *urb) | |||
257 | struct ieee80211_rx_status rx_status = { 0 }; | 274 | struct ieee80211_rx_status rx_status = { 0 }; |
258 | int rate, signal; | 275 | int rate, signal; |
259 | u32 flags; | 276 | u32 flags; |
277 | u32 quality; | ||
260 | 278 | ||
261 | spin_lock(&priv->rx_queue.lock); | 279 | spin_lock(&priv->rx_queue.lock); |
262 | if (skb->next) | 280 | if (skb->next) |
@@ -280,44 +298,57 @@ static void rtl8187_rx_cb(struct urb *urb) | |||
280 | flags = le32_to_cpu(hdr->flags); | 298 | flags = le32_to_cpu(hdr->flags); |
281 | signal = hdr->signal & 0x7f; | 299 | signal = hdr->signal & 0x7f; |
282 | rx_status.antenna = (hdr->signal >> 7) & 1; | 300 | rx_status.antenna = (hdr->signal >> 7) & 1; |
283 | rx_status.signal = signal; | ||
284 | rx_status.noise = hdr->noise; | 301 | rx_status.noise = hdr->noise; |
285 | rx_status.mactime = le64_to_cpu(hdr->mac_time); | 302 | rx_status.mactime = le64_to_cpu(hdr->mac_time); |
286 | priv->signal = signal; | ||
287 | priv->quality = signal; | 303 | priv->quality = signal; |
304 | rx_status.qual = priv->quality; | ||
288 | priv->noise = hdr->noise; | 305 | priv->noise = hdr->noise; |
306 | rate = (flags >> 20) & 0xF; | ||
307 | if (rate > 3) { /* OFDM rate */ | ||
308 | if (signal > 90) | ||
309 | signal = 90; | ||
310 | else if (signal < 25) | ||
311 | signal = 25; | ||
312 | signal = 90 - signal; | ||
313 | } else { /* CCK rate */ | ||
314 | if (signal > 95) | ||
315 | signal = 95; | ||
316 | else if (signal < 30) | ||
317 | signal = 30; | ||
318 | signal = 95 - signal; | ||
319 | } | ||
320 | rx_status.signal = signal; | ||
321 | priv->signal = signal; | ||
289 | } else { | 322 | } else { |
290 | struct rtl8187b_rx_hdr *hdr = | 323 | struct rtl8187b_rx_hdr *hdr = |
291 | (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); | 324 | (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); |
325 | /* The Realtek datasheet for the RTL8187B shows that the RX | ||
326 | * header contains the following quantities: signal quality, | ||
327 | * RSSI, AGC, the received power in dB, and the measured SNR. | ||
328 | * In testing, none of these quantities show qualitative | ||
329 | * agreement with AP signal strength, except for the AGC, | ||
330 | * which is inversely proportional to the strength of the | ||
331 | * signal. In the following, the quality and signal strength | ||
332 | * are derived from the AGC. The arbitrary scaling constants | ||
333 | * are chosen to make the results close to the values obtained | ||
334 | * for a BCM4312 using b43 as the driver. The noise is ignored | ||
335 | * for now. | ||
336 | */ | ||
292 | flags = le32_to_cpu(hdr->flags); | 337 | flags = le32_to_cpu(hdr->flags); |
293 | signal = hdr->agc >> 1; | 338 | quality = 170 - hdr->agc; |
294 | rx_status.antenna = (hdr->signal >> 7) & 1; | 339 | if (quality > 100) |
295 | rx_status.signal = 64 - min(hdr->noise, (u8)64); | 340 | quality = 100; |
296 | rx_status.noise = hdr->noise; | 341 | signal = 14 - hdr->agc / 2; |
342 | rx_status.qual = quality; | ||
343 | priv->quality = quality; | ||
344 | rx_status.signal = signal; | ||
345 | priv->signal = signal; | ||
346 | rx_status.antenna = (hdr->rssi >> 7) & 1; | ||
297 | rx_status.mactime = le64_to_cpu(hdr->mac_time); | 347 | rx_status.mactime = le64_to_cpu(hdr->mac_time); |
298 | priv->signal = hdr->signal; | 348 | rate = (flags >> 20) & 0xF; |
299 | priv->quality = hdr->agc >> 1; | ||
300 | priv->noise = hdr->noise; | ||
301 | } | 349 | } |
302 | 350 | ||
303 | skb_trim(skb, flags & 0x0FFF); | 351 | skb_trim(skb, flags & 0x0FFF); |
304 | rate = (flags >> 20) & 0xF; | ||
305 | if (rate > 3) { /* OFDM rate */ | ||
306 | if (signal > 90) | ||
307 | signal = 90; | ||
308 | else if (signal < 25) | ||
309 | signal = 25; | ||
310 | signal = 90 - signal; | ||
311 | } else { /* CCK rate */ | ||
312 | if (signal > 95) | ||
313 | signal = 95; | ||
314 | else if (signal < 30) | ||
315 | signal = 30; | ||
316 | signal = 95 - signal; | ||
317 | } | ||
318 | |||
319 | rx_status.qual = priv->quality; | ||
320 | rx_status.signal = signal; | ||
321 | rx_status.rate_idx = rate; | 352 | rx_status.rate_idx = rate; |
322 | rx_status.freq = dev->conf.channel->center_freq; | 353 | rx_status.freq = dev->conf.channel->center_freq; |
323 | rx_status.band = dev->conf.channel->band; | 354 | rx_status.band = dev->conf.channel->band; |
@@ -697,6 +728,7 @@ static int rtl8187_start(struct ieee80211_hw *dev) | |||
697 | if (ret) | 728 | if (ret) |
698 | return ret; | 729 | return ret; |
699 | 730 | ||
731 | mutex_lock(&priv->conf_mutex); | ||
700 | if (priv->is_rtl8187b) { | 732 | if (priv->is_rtl8187b) { |
701 | reg = RTL818X_RX_CONF_MGMT | | 733 | reg = RTL818X_RX_CONF_MGMT | |
702 | RTL818X_RX_CONF_DATA | | 734 | RTL818X_RX_CONF_DATA | |
@@ -718,6 +750,7 @@ static int rtl8187_start(struct ieee80211_hw *dev) | |||
718 | (7 << 0 /* long retry limit */) | | 750 | (7 << 0 /* long retry limit */) | |
719 | (7 << 21 /* MAX TX DMA */)); | 751 | (7 << 21 /* MAX TX DMA */)); |
720 | rtl8187_init_urbs(dev); | 752 | rtl8187_init_urbs(dev); |
753 | mutex_unlock(&priv->conf_mutex); | ||
721 | return 0; | 754 | return 0; |
722 | } | 755 | } |
723 | 756 | ||
@@ -761,6 +794,7 @@ static int rtl8187_start(struct ieee80211_hw *dev) | |||
761 | reg |= RTL818X_CMD_TX_ENABLE; | 794 | reg |= RTL818X_CMD_TX_ENABLE; |
762 | reg |= RTL818X_CMD_RX_ENABLE; | 795 | reg |= RTL818X_CMD_RX_ENABLE; |
763 | rtl818x_iowrite8(priv, &priv->map->CMD, reg); | 796 | rtl818x_iowrite8(priv, &priv->map->CMD, reg); |
797 | mutex_unlock(&priv->conf_mutex); | ||
764 | 798 | ||
765 | return 0; | 799 | return 0; |
766 | } | 800 | } |
@@ -772,6 +806,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev) | |||
772 | struct sk_buff *skb; | 806 | struct sk_buff *skb; |
773 | u32 reg; | 807 | u32 reg; |
774 | 808 | ||
809 | mutex_lock(&priv->conf_mutex); | ||
775 | rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); | 810 | rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); |
776 | 811 | ||
777 | reg = rtl818x_ioread8(priv, &priv->map->CMD); | 812 | reg = rtl818x_ioread8(priv, &priv->map->CMD); |
@@ -791,7 +826,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev) | |||
791 | usb_kill_urb(info->urb); | 826 | usb_kill_urb(info->urb); |
792 | kfree_skb(skb); | 827 | kfree_skb(skb); |
793 | } | 828 | } |
794 | return; | 829 | mutex_unlock(&priv->conf_mutex); |
795 | } | 830 | } |
796 | 831 | ||
797 | static int rtl8187_add_interface(struct ieee80211_hw *dev, | 832 | static int rtl8187_add_interface(struct ieee80211_hw *dev, |
@@ -811,6 +846,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, | |||
811 | return -EOPNOTSUPP; | 846 | return -EOPNOTSUPP; |
812 | } | 847 | } |
813 | 848 | ||
849 | mutex_lock(&priv->conf_mutex); | ||
814 | priv->vif = conf->vif; | 850 | priv->vif = conf->vif; |
815 | 851 | ||
816 | rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); | 852 | rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); |
@@ -819,6 +855,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, | |||
819 | ((u8 *)conf->mac_addr)[i]); | 855 | ((u8 *)conf->mac_addr)[i]); |
820 | rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); | 856 | rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); |
821 | 857 | ||
858 | mutex_unlock(&priv->conf_mutex); | ||
822 | return 0; | 859 | return 0; |
823 | } | 860 | } |
824 | 861 | ||
@@ -826,8 +863,10 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, | |||
826 | struct ieee80211_if_init_conf *conf) | 863 | struct ieee80211_if_init_conf *conf) |
827 | { | 864 | { |
828 | struct rtl8187_priv *priv = dev->priv; | 865 | struct rtl8187_priv *priv = dev->priv; |
866 | mutex_lock(&priv->conf_mutex); | ||
829 | priv->mode = IEEE80211_IF_TYPE_MNTR; | 867 | priv->mode = IEEE80211_IF_TYPE_MNTR; |
830 | priv->vif = NULL; | 868 | priv->vif = NULL; |
869 | mutex_unlock(&priv->conf_mutex); | ||
831 | } | 870 | } |
832 | 871 | ||
833 | static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) | 872 | static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) |
@@ -835,6 +874,7 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) | |||
835 | struct rtl8187_priv *priv = dev->priv; | 874 | struct rtl8187_priv *priv = dev->priv; |
836 | u32 reg; | 875 | u32 reg; |
837 | 876 | ||
877 | mutex_lock(&priv->conf_mutex); | ||
838 | reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); | 878 | reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); |
839 | /* Enable TX loopback on MAC level to avoid TX during channel | 879 | /* Enable TX loopback on MAC level to avoid TX during channel |
840 | * changes, as this has be seen to causes problems and the | 880 | * changes, as this has be seen to causes problems and the |
@@ -867,6 +907,7 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) | |||
867 | rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100); | 907 | rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100); |
868 | rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); | 908 | rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); |
869 | rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100); | 909 | rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100); |
910 | mutex_unlock(&priv->conf_mutex); | ||
870 | return 0; | 911 | return 0; |
871 | } | 912 | } |
872 | 913 | ||
@@ -878,6 +919,7 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, | |||
878 | int i; | 919 | int i; |
879 | u8 reg; | 920 | u8 reg; |
880 | 921 | ||
922 | mutex_lock(&priv->conf_mutex); | ||
881 | for (i = 0; i < ETH_ALEN; i++) | 923 | for (i = 0; i < ETH_ALEN; i++) |
882 | rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); | 924 | rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); |
883 | 925 | ||
@@ -891,6 +933,7 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, | |||
891 | rtl818x_iowrite8(priv, &priv->map->MSR, reg); | 933 | rtl818x_iowrite8(priv, &priv->map->MSR, reg); |
892 | } | 934 | } |
893 | 935 | ||
936 | mutex_unlock(&priv->conf_mutex); | ||
894 | return 0; | 937 | return 0; |
895 | } | 938 | } |
896 | 939 | ||
@@ -1015,9 +1058,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, | |||
1015 | 1058 | ||
1016 | priv->mode = IEEE80211_IF_TYPE_MNTR; | 1059 | priv->mode = IEEE80211_IF_TYPE_MNTR; |
1017 | dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 1060 | dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
1018 | IEEE80211_HW_RX_INCLUDES_FCS | | 1061 | IEEE80211_HW_RX_INCLUDES_FCS; |
1019 | IEEE80211_HW_SIGNAL_UNSPEC; | ||
1020 | dev->max_signal = 65; | ||
1021 | 1062 | ||
1022 | eeprom.data = dev; | 1063 | eeprom.data = dev; |
1023 | eeprom.register_read = rtl8187_eeprom_register_read; | 1064 | eeprom.register_read = rtl8187_eeprom_register_read; |
@@ -1132,10 +1173,16 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, | |||
1132 | (*channel++).hw_value = txpwr >> 8; | 1173 | (*channel++).hw_value = txpwr >> 8; |
1133 | } | 1174 | } |
1134 | 1175 | ||
1135 | if (priv->is_rtl8187b) | 1176 | if (priv->is_rtl8187b) { |
1136 | printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " | 1177 | printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " |
1137 | "is EXPERIMENTAL, and could damage your\n" | 1178 | "is EXPERIMENTAL, and could damage your\n" |
1138 | " hardware, use at your own risk\n"); | 1179 | " hardware, use at your own risk\n"); |
1180 | dev->flags |= IEEE80211_HW_SIGNAL_DBM; | ||
1181 | } else { | ||
1182 | dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; | ||
1183 | dev->max_signal = 65; | ||
1184 | } | ||
1185 | |||
1139 | if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) | 1186 | if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) |
1140 | printk(KERN_INFO "rtl8187: inconsistency between id with OEM" | 1187 | printk(KERN_INFO "rtl8187: inconsistency between id with OEM" |
1141 | " info!\n"); | 1188 | " info!\n"); |
@@ -1154,6 +1201,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, | |||
1154 | printk(KERN_ERR "rtl8187: Cannot register device\n"); | 1201 | printk(KERN_ERR "rtl8187: Cannot register device\n"); |
1155 | goto err_free_dev; | 1202 | goto err_free_dev; |
1156 | } | 1203 | } |
1204 | mutex_init(&priv->conf_mutex); | ||
1157 | 1205 | ||
1158 | printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n", | 1206 | printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n", |
1159 | wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), | 1207 | wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), |