]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/wireless/rtlwifi/usb.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
[karo-tx-linux.git] / drivers / net / wireless / rtlwifi / usb.c
index 54cb8a60514d582e6bf5ae07fdf3d2b212aa2c2c..ad109adcabcb0c3f4f2ff56f0ffd85e2c71f7937 100644 (file)
 #include "usb.h"
 #include "base.h"
 #include "ps.h"
+#include "rtl8192c/fw_common.h"
 
 #define        REALTEK_USB_VENQT_READ                  0xC0
 #define        REALTEK_USB_VENQT_WRITE                 0x40
 #define REALTEK_USB_VENQT_CMD_REQ              0x05
 #define        REALTEK_USB_VENQT_CMD_IDX               0x00
 
-#define REALTEK_USB_VENQT_MAX_BUF_SIZE         254
+#define MAX_USBCTRL_VENDORREQ_TIMES            10
 
 static void usbctrl_async_callback(struct urb *urb)
 {
@@ -82,6 +83,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,
@@ -100,16 +102,27 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request,
        unsigned int pipe;
        int status;
        u8 reqtype;
+       int vendorreq_times = 0;
+       static int count;
 
        pipe = usb_rcvctrlpipe(udev, 0); /* read_in */
        reqtype =  REALTEK_USB_VENQT_READ;
 
-       status = usb_control_msg(udev, pipe, request, reqtype, value, index,
-                                pdata, len, 0); /* max. timeout */
-
-       if (status < 0)
+       while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) {
+               status = usb_control_msg(udev, pipe, request, reqtype, value,
+                                        index, pdata, len, 0); /*max. timeout*/
+               if (status < 0) {
+                       /* firmware download is checksumed, don't retry */
+                       if ((value >= FW_8192C_START_ADDRESS &&
+                           value <= FW_8192C_END_ADDRESS))
+                               break;
+               } else {
+                       break;
+               }
+       }
+       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;
 }
 
@@ -129,7 +142,7 @@ static u32 _usb_read_sync(struct usb_device *udev, u32 addr, u16 len)
 
        wvalue = (u16)addr;
        _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len);
-       ret = *data;
+       ret = le32_to_cpu(*data);
        kfree(data);
        return ret;
 }
@@ -161,12 +174,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);
 }
@@ -192,6 +205,30 @@ static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val)
        _usb_write_async(to_usb_device(dev), addr, val, 4);
 }
 
+static void _usb_writeN_sync(struct rtl_priv *rtlpriv, u32 addr, void *data,
+                            u16 len)
+{
+       struct device *dev = rtlpriv->io.dev;
+       struct usb_device *udev = to_usb_device(dev);
+       u8 request = REALTEK_USB_VENQT_CMD_REQ;
+       u8 reqtype =  REALTEK_USB_VENQT_WRITE;
+       u16 wvalue;
+       u16 index = REALTEK_USB_VENQT_CMD_IDX;
+       int pipe = usb_sndctrlpipe(udev, 0); /* write_out */
+       u8 *buffer;
+       dma_addr_t dma_addr;
+
+       wvalue = (u16)(addr&0x0000ffff);
+       buffer = usb_alloc_coherent(udev, (size_t)len, GFP_ATOMIC, &dma_addr);
+       if (!buffer)
+               return;
+       memcpy(buffer, data, len);
+       usb_control_msg(udev, pipe, request, reqtype, wvalue,
+                       index, buffer, len, 50);
+
+       usb_free_coherent(udev, (size_t)len, buffer, dma_addr);
+}
+
 static void _rtl_usb_io_handler_init(struct device *dev,
                                     struct ieee80211_hw *hw)
 {
@@ -205,6 +242,7 @@ static void _rtl_usb_io_handler_init(struct device *dev,
        rtlpriv->io.read8_sync          = _usb_read8_sync;
        rtlpriv->io.read16_sync         = _usb_read16_sync;
        rtlpriv->io.read32_sync         = _usb_read32_sync;
+       rtlpriv->io.writeN_sync         = _usb_writeN_sync;
 }
 
 static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw)