summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rtl818x/rtl8187_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rtl818x/rtl8187_dev.c')
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c124
1 files changed, 66 insertions, 58 deletions
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index dbf52e8bbd7..74f5449b792 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -99,7 +99,6 @@ static const struct ieee80211_channel rtl818x_channels[] = {
static void rtl8187_iowrite_async_cb(struct urb *urb)
{
kfree(urb->context);
- usb_free_urb(urb);
}
static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
@@ -136,11 +135,13 @@ static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0),
(unsigned char *)dr, buf, len,
rtl8187_iowrite_async_cb, buf);
+ usb_anchor_urb(urb, &priv->anchored);
rc = usb_submit_urb(urb, GFP_ATOMIC);
if (rc < 0) {
kfree(buf);
- usb_free_urb(urb);
+ usb_unanchor_urb(urb);
}
+ usb_free_urb(urb);
}
static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv,
@@ -172,7 +173,6 @@ static void rtl8187_tx_cb(struct urb *urb)
struct ieee80211_hw *hw = info->rate_driver_data[0];
struct rtl8187_priv *priv = hw->priv;
- usb_free_urb(info->rate_driver_data[1]);
skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
sizeof(struct rtl8187_tx_hdr));
ieee80211_tx_info_clear_status(info);
@@ -273,11 +273,13 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep),
buf, skb->len, rtl8187_tx_cb, skb);
+ usb_anchor_urb(urb, &priv->anchored);
rc = usb_submit_urb(urb, GFP_ATOMIC);
if (rc < 0) {
- usb_free_urb(urb);
+ usb_unanchor_urb(urb);
kfree_skb(skb);
}
+ usb_free_urb(urb);
return 0;
}
@@ -301,41 +303,25 @@ static void rtl8187_rx_cb(struct urb *urb)
return;
}
spin_unlock(&priv->rx_queue.lock);
+ skb_put(skb, urb->actual_length);
if (unlikely(urb->status)) {
- usb_free_urb(urb);
dev_kfree_skb_irq(skb);
return;
}
- skb_put(skb, urb->actual_length);
if (!priv->is_rtl8187b) {
struct rtl8187_rx_hdr *hdr =
(typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
flags = le32_to_cpu(hdr->flags);
- signal = hdr->signal & 0x7f;
+ /* As with the RTL8187B below, the AGC is used to calculate
+ * signal strength and quality. 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.noise = hdr->noise;
rx_status.mactime = le64_to_cpu(hdr->mac_time);
- 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));
@@ -353,18 +339,18 @@ static void rtl8187_rx_cb(struct urb *urb)
*/
flags = le32_to_cpu(hdr->flags);
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);
- rate = (flags >> 20) & 0xF;
}
+ if (quality > 100)
+ quality = 100;
+ rx_status.qual = quality;
+ priv->quality = quality;
+ rx_status.signal = signal;
+ priv->signal = signal;
+ rate = (flags >> 20) & 0xF;
skb_trim(skb, flags & 0x0FFF);
rx_status.rate_idx = rate;
rx_status.freq = dev->conf.channel->center_freq;
@@ -376,7 +362,6 @@ static void rtl8187_rx_cb(struct urb *urb)
skb = dev_alloc_skb(RTL8187_MAX_RX);
if (unlikely(!skb)) {
- usb_free_urb(urb);
/* TODO check rx queue length and refill *somewhere* */
return;
}
@@ -388,24 +373,32 @@ static void rtl8187_rx_cb(struct urb *urb)
urb->context = skb;
skb_queue_tail(&priv->rx_queue, skb);
- usb_submit_urb(urb, GFP_ATOMIC);
+ usb_anchor_urb(urb, &priv->anchored);
+ if (usb_submit_urb(urb, GFP_ATOMIC)) {
+ usb_unanchor_urb(urb);
+ skb_unlink(skb, &priv->rx_queue);
+ dev_kfree_skb_irq(skb);
+ }
}
static int rtl8187_init_urbs(struct ieee80211_hw *dev)
{
struct rtl8187_priv *priv = dev->priv;
- struct urb *entry;
+ struct urb *entry = NULL;
struct sk_buff *skb;
struct rtl8187_rx_info *info;
+ int ret = 0;
while (skb_queue_len(&priv->rx_queue) < 8) {
skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL);
- if (!skb)
- break;
+ if (!skb) {
+ ret = -ENOMEM;
+ goto err;
+ }
entry = usb_alloc_urb(0, GFP_KERNEL);
if (!entry) {
- kfree_skb(skb);
- break;
+ ret = -ENOMEM;
+ goto err;
}
usb_fill_bulk_urb(entry, priv->udev,
usb_rcvbulkpipe(priv->udev,
@@ -416,10 +409,22 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
info->urb = entry;
info->dev = dev;
skb_queue_tail(&priv->rx_queue, skb);
- usb_submit_urb(entry, GFP_KERNEL);
+ usb_anchor_urb(entry, &priv->anchored);
+ ret = usb_submit_urb(entry, GFP_KERNEL);
+ if (ret) {
+ skb_unlink(skb, &priv->rx_queue);
+ usb_unanchor_urb(entry);
+ goto err;
+ }
+ usb_free_urb(entry);
}
+ return ret;
- return 0;
+err:
+ usb_free_urb(entry);
+ kfree_skb(skb);
+ usb_kill_anchored_urbs(&priv->anchored);
+ return ret;
}
static void rtl8187b_status_cb(struct urb *urb)
@@ -429,10 +434,8 @@ static void rtl8187b_status_cb(struct urb *urb)
u64 val;
unsigned int cmd_type;
- if (unlikely(urb->status)) {
- usb_free_urb(urb);
+ if (unlikely(urb->status))
return;
- }
/*
* Read from status buffer:
@@ -503,26 +506,32 @@ static void rtl8187b_status_cb(struct urb *urb)
spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags);
}
- usb_submit_urb(urb, GFP_ATOMIC);
+ usb_anchor_urb(urb, &priv->anchored);
+ if (usb_submit_urb(urb, GFP_ATOMIC))
+ usb_unanchor_urb(urb);
}
static int rtl8187b_init_status_urb(struct ieee80211_hw *dev)
{
struct rtl8187_priv *priv = dev->priv;
struct urb *entry;
+ int ret = 0;
entry = usb_alloc_urb(0, GFP_KERNEL);
if (!entry)
return -ENOMEM;
- priv->b_tx_status.urb = entry;
usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 9),
&priv->b_tx_status.buf, sizeof(priv->b_tx_status.buf),
rtl8187b_status_cb, dev);
- usb_submit_urb(entry, GFP_KERNEL);
+ usb_anchor_urb(entry, &priv->anchored);
+ ret = usb_submit_urb(entry, GFP_KERNEL);
+ if (ret)
+ usb_unanchor_urb(entry);
+ usb_free_urb(entry);
- return 0;
+ return ret;
}
static int rtl8187_cmd_reset(struct ieee80211_hw *dev)
@@ -856,6 +865,9 @@ static int rtl8187_start(struct ieee80211_hw *dev)
return ret;
mutex_lock(&priv->conf_mutex);
+
+ init_usb_anchor(&priv->anchored);
+
if (priv->is_rtl8187b) {
reg = RTL818X_RX_CONF_MGMT |
RTL818X_RX_CONF_DATA |
@@ -951,12 +963,12 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
while ((skb = skb_dequeue(&priv->rx_queue))) {
info = (struct rtl8187_rx_info *)skb->cb;
- usb_kill_urb(info->urb);
kfree_skb(skb);
}
while ((skb = skb_dequeue(&priv->b_tx_status.queue)))
dev_kfree_skb_any(skb);
- usb_kill_urb(priv->b_tx_status.urb);
+
+ usb_kill_anchored_urbs(&priv->anchored);
mutex_unlock(&priv->conf_mutex);
}
@@ -1293,6 +1305,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
priv->mode = NL80211_IFTYPE_MONITOR;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_RX_INCLUDES_FCS;
eeprom.data = dev;
@@ -1408,13 +1421,8 @@ 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.\n");
- dev->flags |= IEEE80211_HW_SIGNAL_DBM;
- } else {
- dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
- dev->max_signal = 65;
- }
/*
* XXX: Once this driver supports anything that requires