diff options
Diffstat (limited to 'drivers/net/wireless/rtlwifi/usb.c')
-rw-r--r-- | drivers/net/wireless/rtlwifi/usb.c | 161 |
1 files changed, 73 insertions, 88 deletions
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index dbcf5a9..17e6429 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -24,7 +24,11 @@ * Hsinchu 300, Taiwan. * *****************************************************************************/ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/usb.h> +#include <linux/export.h> #include "core.h" #include "wifi.h" #include "usb.h" @@ -40,8 +44,12 @@ static void usbctrl_async_callback(struct urb *urb) { - if (urb) - kfree(urb->context); + if (urb) { + /* free dr */ + kfree(urb->setup_packet); + /* free databuf */ + kfree(urb->transfer_buffer); + } } static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, @@ -53,38 +61,46 @@ static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, u8 reqtype; struct usb_ctrlrequest *dr; struct urb *urb; - struct rtl819x_async_write_data { - u8 data[REALTEK_USB_VENQT_MAX_BUF_SIZE]; - struct usb_ctrlrequest dr; - } *buf; + const u16 databuf_maxlen = REALTEK_USB_VENQT_MAX_BUF_SIZE; + u8 *databuf; + + if (WARN_ON_ONCE(len > databuf_maxlen)) + len = databuf_maxlen; pipe = usb_sndctrlpipe(udev, 0); /* write_out */ reqtype = REALTEK_USB_VENQT_WRITE; - buf = kmalloc(sizeof(*buf), GFP_ATOMIC); - if (!buf) + dr = kmalloc(sizeof(*dr), GFP_ATOMIC); + if (!dr) + return -ENOMEM; + + databuf = kmalloc(databuf_maxlen, GFP_ATOMIC); + if (!databuf) { + kfree(dr); return -ENOMEM; + } urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { - kfree(buf); + kfree(databuf); + kfree(dr); return -ENOMEM; } - dr = &buf->dr; - dr->bRequestType = reqtype; dr->bRequest = request; dr->wValue = cpu_to_le16(value); dr->wIndex = cpu_to_le16(index); dr->wLength = cpu_to_le16(len); - memcpy(buf, pdata, len); + memcpy(databuf, pdata, len); usb_fill_control_urb(urb, udev, pipe, - (unsigned char *)dr, buf, len, - usbctrl_async_callback, buf); + (unsigned char *)dr, databuf, len, + usbctrl_async_callback, NULL); rc = usb_submit_urb(urb, GFP_ATOMIC); - if (rc < 0) - kfree(buf); + if (rc < 0) { + kfree(databuf); + kfree(dr); + } usb_free_urb(urb); return rc; } @@ -101,55 +117,50 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, reqtype = REALTEK_USB_VENQT_READ; status = usb_control_msg(udev, pipe, request, reqtype, value, index, - pdata, len, 0); /* max. timeout */ + pdata, len, 1000); if (status < 0) - printk(KERN_ERR "reg 0x%x, usbctrl_vendorreq TimeOut! " - "status:0x%x value=0x%x\n", value, status, - *(u32 *)pdata); + pr_err("reg 0x%x, usbctrl_vendorreq TimeOut! status:0x%x value=0x%x\n", + value, status, *(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; - - data = kmalloc(sizeof(u32), GFP_KERNEL); - if (!data) - return -ENOMEM; + __le32 *data; + unsigned long flags; + + spin_lock_irqsave(&rtlpriv->locks.usb_lock, flags); + if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT) + rtlpriv->usb_data_index = 0; + data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; + spin_unlock_irqrestore(&rtlpriv->locks.usb_lock, flags); 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; + 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, @@ -189,44 +200,6 @@ static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val) _usb_write_async(to_usb_device(dev), addr, val, 4); } -static int _usb_nbytes_read_write(struct usb_device *udev, bool read, u32 addr, - u16 len, u8 *pdata) -{ - int status; - u8 request; - u16 wvalue; - u16 index; - - request = REALTEK_USB_VENQT_CMD_REQ; - index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ - wvalue = (u16)addr; - if (read) - status = _usbctrl_vendorreq_sync_read(udev, request, wvalue, - index, pdata, len); - else - status = _usbctrl_vendorreq_async_write(udev, request, wvalue, - index, pdata, len); - return status; -} - -static int _usb_readN_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len, - u8 *pdata) -{ - struct device *dev = rtlpriv->io.dev; - - return _usb_nbytes_read_write(to_usb_device(dev), true, addr, len, - pdata); -} - -static int _usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, u16 len, - u8 *pdata) -{ - struct device *dev = rtlpriv->io.dev; - - return _usb_nbytes_read_write(to_usb_device(dev), false, addr, len, - pdata); -} - static void _rtl_usb_io_handler_init(struct device *dev, struct ieee80211_hw *hw) { @@ -237,11 +210,9 @@ static void _rtl_usb_io_handler_init(struct device *dev, rtlpriv->io.write8_async = _usb_write8_async; rtlpriv->io.write16_async = _usb_write16_async; rtlpriv->io.write32_async = _usb_write32_async; - rtlpriv->io.writeN_async = _usb_writeN_async; rtlpriv->io.read8_sync = _usb_read8_sync; rtlpriv->io.read16_sync = _usb_read16_sync; rtlpriv->io.read32_sync = _usb_read32_sync; - rtlpriv->io.readN_sync = _usb_readN_sync; } static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) @@ -316,7 +287,7 @@ static int _rtl_usb_init_rx(struct ieee80211_hw *hw) rtlusb->usb_rx_segregate_hdl = rtlpriv->cfg->usb_interface_cfg->usb_rx_segregate_hdl; - printk(KERN_INFO "rtl8192cu: rx_max_size %d, rx_urb_num %d, in_ep %d\n", + pr_info("rx_max_size %d, rx_urb_num %d, in_ep %d\n", rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep); init_usb_anchor(&rtlusb->rx_submitted); return 0; @@ -518,12 +489,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); } @@ -580,7 +553,7 @@ static void _rtl_rx_completed(struct urb *_urb) } else{ /* TO DO */ _rtl_rx_pre_process(hw, skb); - printk(KERN_ERR "rtlwifi: rx agg not supported\n"); + pr_err("rx agg not supported\n"); } goto resubmit; } @@ -839,6 +812,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, if (unlikely(!_urb)) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Can't allocate urb. Drop skb!\n")); + kfree_skb(skb); return; } urb_list = &rtlusb->tx_pending[ep_num]; @@ -933,7 +907,8 @@ static struct rtl_intf_ops rtl_usb_ops = { }; int __devinit rtl_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) + const struct usb_device_id *id, + struct rtl_hal_cfg *rtl_hal_cfg) { int err; struct ieee80211_hw *hw = NULL; @@ -948,6 +923,15 @@ int __devinit rtl_usb_probe(struct usb_interface *intf, return -ENOMEM; } rtlpriv = hw->priv; + rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32), + GFP_KERNEL); + if (!rtlpriv->usb_data) + return -ENOMEM; + + /* this spin lock must be initialized early */ + spin_lock_init(&rtlpriv->locks.usb_lock); + + rtlpriv->usb_data_index = 0; SET_IEEE80211_DEV(hw, &intf->dev); udev = interface_to_usbdev(intf); usb_get_dev(udev); @@ -958,7 +942,7 @@ int __devinit rtl_usb_probe(struct usb_interface *intf, usb_set_intfdata(intf, hw); /* init cfg & intf_ops */ rtlpriv->rtlhal.interface = INTF_USB; - rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_info); + rtlpriv->cfg = rtl_hal_cfg; rtlpriv->intf_ops = &rtl_usb_ops; rtl_dbgp_flag_init(hw); /* Init IO handler */ @@ -1025,6 +1009,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); |