Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / drivers / net / wireless / rtlwifi / usb.c
index a461822..a6049d7 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2009-2011  Realtek Corporation. All rights reserved.
+ * Copyright(c) 2009-2012  Realtek Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
  *
  *****************************************************************************/
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/usb.h>
-#include "core.h"
 #include "wifi.h"
+#include "core.h"
 #include "usb.h"
 #include "base.h"
 #include "ps.h"
 #include "rtl8192c/fw_common.h"
+#include <linux/export.h>
 
 #define        REALTEK_USB_VENQT_READ                  0xC0
 #define        REALTEK_USB_VENQT_WRITE                 0x40
@@ -82,6 +80,7 @@ static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
        dr->wValue = cpu_to_le16(value);
        dr->wIndex = cpu_to_le16(index);
        dr->wLength = cpu_to_le16(len);
+       /* data are already in little-endian order */
        memcpy(buf, pdata, len);
        usb_fill_control_urb(urb, udev, pipe,
                             (unsigned char *)dr, buf, len,
@@ -101,11 +100,12 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request,
        int status;
        u8 reqtype;
        int vendorreq_times = 0;
+       static int count;
 
        pipe = usb_rcvctrlpipe(udev, 0); /* read_in */
        reqtype =  REALTEK_USB_VENQT_READ;
 
-       while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) {
+       do {
                status = usb_control_msg(udev, pipe, request, reqtype, value,
                                         index, pdata, len, 0); /*max. timeout*/
                if (status < 0) {
@@ -116,53 +116,46 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request,
                } else {
                        break;
                }
-       }
-       if (status < 0)
+       } while (++vendorreq_times < MAX_USBCTRL_VENDORREQ_TIMES);
+
+       if (status < 0 && count++ < 4)
                pr_err("reg 0x%x, usbctrl_vendorreq TimeOut! status:0x%x value=0x%x\n",
-                      value, status, *(u32 *)pdata);
+                      value, status, le32_to_cpu(*(u32 *)pdata));
        return status;
 }
 
-static u32 _usb_read_sync(struct usb_device *udev, u32 addr, u16 len)
+static u32 _usb_read_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len)
 {
+       struct device *dev = rtlpriv->io.dev;
+       struct usb_device *udev = to_usb_device(dev);
        u8 request;
        u16 wvalue;
        u16 index;
-       u32 *data;
-       u32 ret;
+       __le32 *data = &rtlpriv->usb_data[rtlpriv->usb_data_index];
 
-       data = kmalloc(sizeof(u32), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
        request = REALTEK_USB_VENQT_CMD_REQ;
        index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */
 
        wvalue = (u16)addr;
        _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len);
-       ret = *data;
-       kfree(data);
-       return ret;
+       if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT)
+               rtlpriv->usb_data_index = 0;
+       return le32_to_cpu(*data);
 }
 
 static u8 _usb_read8_sync(struct rtl_priv *rtlpriv, u32 addr)
 {
-       struct device *dev = rtlpriv->io.dev;
-
-       return (u8)_usb_read_sync(to_usb_device(dev), addr, 1);
+       return (u8)_usb_read_sync(rtlpriv, addr, 1);
 }
 
 static u16 _usb_read16_sync(struct rtl_priv *rtlpriv, u32 addr)
 {
-       struct device *dev = rtlpriv->io.dev;
-
-       return (u16)_usb_read_sync(to_usb_device(dev), addr, 2);
+       return (u16)_usb_read_sync(rtlpriv, addr, 2);
 }
 
 static u32 _usb_read32_sync(struct rtl_priv *rtlpriv, u32 addr)
 {
-       struct device *dev = rtlpriv->io.dev;
-
-       return _usb_read_sync(to_usb_device(dev), addr, 4);
+       return _usb_read_sync(rtlpriv, addr, 4);
 }
 
 static void _usb_write_async(struct usb_device *udev, u32 addr, u32 val,
@@ -171,12 +164,12 @@ static void _usb_write_async(struct usb_device *udev, u32 addr, u32 val,
        u8 request;
        u16 wvalue;
        u16 index;
-       u32 data;
+       __le32 data;
 
        request = REALTEK_USB_VENQT_CMD_REQ;
        index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */
        wvalue = (u16)(addr&0x0000ffff);
-       data = val;
+       data = cpu_to_le32(val);
        _usbctrl_vendorreq_async_write(udev, request, wvalue, index, &data,
                                       len);
 }
@@ -272,14 +265,14 @@ static int _rtl_usb_init_tx(struct ieee80211_hw *hw)
                                                    ? USB_HIGH_SPEED_BULK_SIZE
                                                    : USB_FULL_SPEED_BULK_SIZE;
 
-       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("USB Max Bulk-out Size=%d\n",
-                rtlusb->max_bulk_out_size));
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "USB Max Bulk-out Size=%d\n",
+                rtlusb->max_bulk_out_size);
 
        for (i = 0; i < __RTL_TXQ_NUM; i++) {
                u32 ep_num = rtlusb->ep_map.ep_mapping[i];
                if (!ep_num) {
                        RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
-                                ("Invalid endpoint map setting!\n"));
+                                "Invalid endpoint map setting!\n");
                        return -EINVAL;
                }
        }
@@ -341,13 +334,18 @@ static int _rtl_usb_init(struct ieee80211_hw *hw)
                        rtlusb->out_ep_nums++;
 
                RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
-                        ("USB EP(0x%02x), MaxPacketSize=%d ,Interval=%d.\n",
+                        "USB EP(0x%02x), MaxPacketSize=%d, Interval=%d\n",
                         pep_desc->bEndpointAddress, pep_desc->wMaxPacketSize,
-                        pep_desc->bInterval));
+                        pep_desc->bInterval);
+       }
+       if (rtlusb->in_ep_nums <  rtlpriv->cfg->usb_interface_cfg->in_ep_num) {
+               pr_err("Too few input end points found\n");
+               return -EINVAL;
+       }
+       if (rtlusb->out_ep_nums == 0) {
+               pr_err("No output end points found\n");
+               return -EINVAL;
        }
-       if (rtlusb->in_ep_nums <  rtlpriv->cfg->usb_interface_cfg->in_ep_num)
-               return -EINVAL ;
-
        /* usb endpoint mapping */
        err = rtlpriv->cfg->usb_interface_cfg->usb_endpoint_mapping(hw);
        rtlusb->usb_mq_to_hwq =  rtlpriv->cfg->usb_interface_cfg->usb_mq_to_hwq;
@@ -356,7 +354,7 @@ static int _rtl_usb_init(struct ieee80211_hw *hw)
        return err;
 }
 
-static int _rtl_usb_init_sw(struct ieee80211_hw *hw)
+static void rtl_usb_init_sw(struct ieee80211_hw *hw)
 {
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -391,7 +389,6 @@ static int _rtl_usb_init_sw(struct ieee80211_hw *hw)
        /* HIMR_EX - turn all on */
        rtlusb->irq_mask[1] = 0xFFFFFFFF;
        rtlusb->disableHWSM =  true;
-       return 0;
 }
 
 #define __RADIO_TAP_SIZE_RSV   32
@@ -410,7 +407,7 @@ static struct sk_buff *_rtl_prep_rx_urb(struct ieee80211_hw *hw,
                               gfp_mask);
        if (!skb) {
                RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
-                        ("Failed to __dev_alloc_skb!!\n"))
+                        "Failed to __dev_alloc_skb!!\n");
                return ERR_PTR(-ENOMEM);
        }
 
@@ -516,12 +513,14 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw,
                        u8 *pdata;
 
                        uskb = dev_alloc_skb(skb->len + 128);
-                       memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status,
-                              sizeof(rx_status));
-                       pdata = (u8 *)skb_put(uskb, skb->len);
-                       memcpy(pdata, skb->data, skb->len);
+                       if (uskb) {     /* drop packet on allocation failure */
+                               memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status,
+                                      sizeof(rx_status));
+                               pdata = (u8 *)skb_put(uskb, skb->len);
+                               memcpy(pdata, skb->data, skb->len);
+                               ieee80211_rx_irqsafe(hw, uskb);
+                       }
                        dev_kfree_skb_any(skb);
-                       ieee80211_rx_irqsafe(hw, uskb);
                } else {
                        dev_kfree_skb_any(skb);
                }
@@ -571,7 +570,7 @@ static void _rtl_rx_completed(struct urb *_urb)
                        if (IS_ERR(_skb)) {
                                err = PTR_ERR(_skb);
                                RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
-                                       ("Can't allocate skb for bulk IN!\n"));
+                                        "Can't allocate skb for bulk IN!\n");
                                return;
                        }
                        skb = _skb;
@@ -628,14 +627,14 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw)
                urb = usb_alloc_urb(0, GFP_KERNEL);
                if (!urb) {
                        RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
-                                ("Failed to alloc URB!!\n"))
+                                "Failed to alloc URB!!\n");
                        goto err_out;
                }
 
                skb = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL);
                if (IS_ERR(skb)) {
                        RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
-                                ("Failed to prep_rx_urb!!\n"))
+                                "Failed to prep_rx_urb!!\n");
                        err = PTR_ERR(skb);
                        goto err_out;
                }
@@ -661,15 +660,17 @@ static int rtl_usb_start(struct ieee80211_hw *hw)
        struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
 
        err = rtlpriv->cfg->ops->hw_init(hw);
-       rtl_init_rx_config(hw);
+       if (!err) {
+               rtl_init_rx_config(hw);
 
-       /* Enable software */
-       SET_USB_START(rtlusb);
-       /* should after adapter start and interrupt enable. */
-       set_hal_start(rtlhal);
+               /* Enable software */
+               SET_USB_START(rtlusb);
+               /* should after adapter start and interrupt enable. */
+               set_hal_start(rtlhal);
 
-       /* Start bulk IN */
-       _rtl_usb_receive(hw);
+               /* Start bulk IN */
+               _rtl_usb_receive(hw);
+       }
 
        return err;
 }
@@ -741,7 +742,7 @@ static void _rtl_submit_tx_urb(struct ieee80211_hw *hw, struct urb *_urb)
                struct sk_buff *skb;
 
                RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
-                        ("Failed to submit urb.\n"));
+                        "Failed to submit urb\n");
                usb_unanchor_urb(_urb);
                skb = (struct sk_buff *)_urb->context;
                kfree_skb(skb);
@@ -764,7 +765,7 @@ static int _usb_tx_post(struct ieee80211_hw *hw, struct urb *urb,
 
        if (urb->status) {
                RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
-                        ("Urb has error status 0x%X\n", urb->status));
+                        "Urb has error status 0x%X\n", urb->status);
                goto out;
        }
        /*  TODO:       statistics */
@@ -801,7 +802,7 @@ static struct urb *_rtl_usb_tx_urb_setup(struct ieee80211_hw *hw,
        _urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!_urb) {
                RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
-                        ("Can't allocate URB for bulk out!\n"));
+                        "Can't allocate URB for bulk out!\n");
                kfree_skb(skb);
                return NULL;
        }
@@ -826,7 +827,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,
        WARN_ON(NULL == rtlusb->usb_tx_aggregate_hdl);
        if (unlikely(IS_USB_STOP(rtlusb))) {
                RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
-                        ("USB device is stopping...\n"));
+                        "USB device is stopping...\n");
                kfree_skb(skb);
                return;
        }
@@ -836,7 +837,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,
        _urb = _rtl_usb_tx_urb_setup(hw, _skb, ep_num);
        if (unlikely(!_urb)) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        ("Can't allocate urb. Drop skb!\n"));
+                        "Can't allocate urb. Drop skb!\n");
                return;
        }
        urb_list = &rtlusb->tx_pending[ep_num];
@@ -861,7 +862,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
        if (ieee80211_is_auth(fc)) {
-               RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n");
                rtl_ips_nic_on(hw);
        }
 
@@ -942,10 +943,16 @@ int __devinit rtl_usb_probe(struct usb_interface *intf,
        hw = ieee80211_alloc_hw(sizeof(struct rtl_priv) +
                                sizeof(struct rtl_usb_priv), &rtl_ops);
        if (!hw) {
-               RT_ASSERT(false, ("%s : ieee80211 alloc failed\n", __func__));
+               RT_ASSERT(false, "ieee80211 alloc failed\n");
                return -ENOMEM;
        }
        rtlpriv = hw->priv;
+       rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32),
+                                   GFP_KERNEL);
+       if (!rtlpriv->usb_data)
+               return -ENOMEM;
+       rtlpriv->usb_data_index = 0;
+       init_completion(&rtlpriv->firmware_loading_complete);
        SET_IEEE80211_DEV(hw, &intf->dev);
        udev = interface_to_usbdev(intf);
        usb_get_dev(udev);
@@ -964,40 +971,29 @@ int __devinit rtl_usb_probe(struct usb_interface *intf,
        rtlpriv->cfg->ops->read_chip_version(hw);
        /*like read eeprom and so on */
        rtlpriv->cfg->ops->read_eeprom_info(hw);
-       if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        ("Can't init_sw_vars.\n"));
-               goto error_out;
-       }
-       rtlpriv->cfg->ops->init_sw_leds(hw);
        err = _rtl_usb_init(hw);
-       err = _rtl_usb_init_sw(hw);
+       if (err)
+               goto error_out;
+       rtl_usb_init_sw(hw);
        /* Init mac80211 sw */
        err = rtl_init_core(hw);
        if (err) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        ("Can't allocate sw for mac80211.\n"));
+                        "Can't allocate sw for mac80211\n");
                goto error_out;
        }
-
-       /*init rfkill */
-       /* rtl_init_rfkill(hw); */
-
-       err = ieee80211_register_hw(hw);
-       if (err) {
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
-                        ("Can't register mac80211 hw.\n"));
+       if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n");
                goto error_out;
-       } else {
-               rtlpriv->mac80211.mac80211_registered = 1;
        }
-       set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
+       rtlpriv->cfg->ops->init_sw_leds(hw);
+
        return 0;
 error_out:
        rtl_deinit_core(hw);
        _rtl_usb_io_handler_release(hw);
-       ieee80211_free_hw(hw);
        usb_put_dev(udev);
+       complete(&rtlpriv->firmware_loading_complete);
        return -ENODEV;
 }
 EXPORT_SYMBOL(rtl_usb_probe);
@@ -1011,6 +1007,9 @@ void rtl_usb_disconnect(struct usb_interface *intf)
 
        if (unlikely(!rtlpriv))
                return;
+
+       /* just in case driver is removed before firmware callback */
+       wait_for_completion(&rtlpriv->firmware_loading_complete);
        /*ieee80211_unregister_hw will call ops_stop */
        if (rtlmac->mac80211_registered == 1) {
                ieee80211_unregister_hw(hw);
@@ -1023,6 +1022,7 @@ void rtl_usb_disconnect(struct usb_interface *intf)
        /* rtl_deinit_rfkill(hw); */
        rtl_usb_deinit(hw);
        rtl_deinit_core(hw);
+       kfree(rtlpriv->usb_data);
        rtlpriv->cfg->ops->deinit_sw_leds(hw);
        rtlpriv->cfg->ops->deinit_sw_vars(hw);
        _rtl_usb_io_handler_release(hw);