18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 2009-2012 Realtek Corporation.*/ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "wifi.h" 58c2ecf20Sopenharmony_ci#include "core.h" 68c2ecf20Sopenharmony_ci#include "usb.h" 78c2ecf20Sopenharmony_ci#include "base.h" 88c2ecf20Sopenharmony_ci#include "ps.h" 98c2ecf20Sopenharmony_ci#include "rtl8192c/fw_common.h" 108c2ecf20Sopenharmony_ci#include <linux/export.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ciMODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); 148c2ecf20Sopenharmony_ciMODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); 158c2ecf20Sopenharmony_ciMODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>"); 168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 178c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("USB basic driver for rtlwifi"); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define REALTEK_USB_VENQT_READ 0xC0 208c2ecf20Sopenharmony_ci#define REALTEK_USB_VENQT_WRITE 0x40 218c2ecf20Sopenharmony_ci#define REALTEK_USB_VENQT_CMD_REQ 0x05 228c2ecf20Sopenharmony_ci#define REALTEK_USB_VENQT_CMD_IDX 0x00 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define MAX_USBCTRL_VENDORREQ_TIMES 10 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic void usbctrl_async_callback(struct urb *urb) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci if (urb) { 298c2ecf20Sopenharmony_ci /* free dr */ 308c2ecf20Sopenharmony_ci kfree(urb->setup_packet); 318c2ecf20Sopenharmony_ci /* free databuf */ 328c2ecf20Sopenharmony_ci kfree(urb->transfer_buffer); 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, 378c2ecf20Sopenharmony_ci u16 value, u16 index, void *pdata, 388c2ecf20Sopenharmony_ci u16 len) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci int rc; 418c2ecf20Sopenharmony_ci unsigned int pipe; 428c2ecf20Sopenharmony_ci u8 reqtype; 438c2ecf20Sopenharmony_ci struct usb_ctrlrequest *dr; 448c2ecf20Sopenharmony_ci struct urb *urb; 458c2ecf20Sopenharmony_ci const u16 databuf_maxlen = REALTEK_USB_VENQT_MAX_BUF_SIZE; 468c2ecf20Sopenharmony_ci u8 *databuf; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(len > databuf_maxlen)) 498c2ecf20Sopenharmony_ci len = databuf_maxlen; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci pipe = usb_sndctrlpipe(udev, 0); /* write_out */ 528c2ecf20Sopenharmony_ci reqtype = REALTEK_USB_VENQT_WRITE; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci dr = kzalloc(sizeof(*dr), GFP_ATOMIC); 558c2ecf20Sopenharmony_ci if (!dr) 568c2ecf20Sopenharmony_ci return -ENOMEM; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci databuf = kzalloc(databuf_maxlen, GFP_ATOMIC); 598c2ecf20Sopenharmony_ci if (!databuf) { 608c2ecf20Sopenharmony_ci kfree(dr); 618c2ecf20Sopenharmony_ci return -ENOMEM; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 658c2ecf20Sopenharmony_ci if (!urb) { 668c2ecf20Sopenharmony_ci kfree(databuf); 678c2ecf20Sopenharmony_ci kfree(dr); 688c2ecf20Sopenharmony_ci return -ENOMEM; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci dr->bRequestType = reqtype; 728c2ecf20Sopenharmony_ci dr->bRequest = request; 738c2ecf20Sopenharmony_ci dr->wValue = cpu_to_le16(value); 748c2ecf20Sopenharmony_ci dr->wIndex = cpu_to_le16(index); 758c2ecf20Sopenharmony_ci dr->wLength = cpu_to_le16(len); 768c2ecf20Sopenharmony_ci /* data are already in little-endian order */ 778c2ecf20Sopenharmony_ci memcpy(databuf, pdata, len); 788c2ecf20Sopenharmony_ci usb_fill_control_urb(urb, udev, pipe, 798c2ecf20Sopenharmony_ci (unsigned char *)dr, databuf, len, 808c2ecf20Sopenharmony_ci usbctrl_async_callback, NULL); 818c2ecf20Sopenharmony_ci rc = usb_submit_urb(urb, GFP_ATOMIC); 828c2ecf20Sopenharmony_ci if (rc < 0) { 838c2ecf20Sopenharmony_ci kfree(databuf); 848c2ecf20Sopenharmony_ci kfree(dr); 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci usb_free_urb(urb); 878c2ecf20Sopenharmony_ci return rc; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, 918c2ecf20Sopenharmony_ci u16 value, u16 index, void *pdata, 928c2ecf20Sopenharmony_ci u16 len) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci unsigned int pipe; 958c2ecf20Sopenharmony_ci int status; 968c2ecf20Sopenharmony_ci u8 reqtype; 978c2ecf20Sopenharmony_ci int vendorreq_times = 0; 988c2ecf20Sopenharmony_ci static int count; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ 1018c2ecf20Sopenharmony_ci reqtype = REALTEK_USB_VENQT_READ; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci do { 1048c2ecf20Sopenharmony_ci status = usb_control_msg(udev, pipe, request, reqtype, value, 1058c2ecf20Sopenharmony_ci index, pdata, len, 1000); 1068c2ecf20Sopenharmony_ci if (status < 0) { 1078c2ecf20Sopenharmony_ci /* firmware download is checksumed, don't retry */ 1088c2ecf20Sopenharmony_ci if ((value >= FW_8192C_START_ADDRESS && 1098c2ecf20Sopenharmony_ci value <= FW_8192C_END_ADDRESS)) 1108c2ecf20Sopenharmony_ci break; 1118c2ecf20Sopenharmony_ci } else { 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci } while (++vendorreq_times < MAX_USBCTRL_VENDORREQ_TIMES); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (status < 0 && count++ < 4) 1178c2ecf20Sopenharmony_ci pr_err("reg 0x%x, usbctrl_vendorreq TimeOut! status:0x%x value=0x%x\n", 1188c2ecf20Sopenharmony_ci value, status, *(u32 *)pdata); 1198c2ecf20Sopenharmony_ci return status; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic u32 _usb_read_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct device *dev = rtlpriv->io.dev; 1258c2ecf20Sopenharmony_ci struct usb_device *udev = to_usb_device(dev); 1268c2ecf20Sopenharmony_ci u8 request; 1278c2ecf20Sopenharmony_ci u16 wvalue; 1288c2ecf20Sopenharmony_ci u16 index; 1298c2ecf20Sopenharmony_ci __le32 *data; 1308c2ecf20Sopenharmony_ci unsigned long flags; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci spin_lock_irqsave(&rtlpriv->locks.usb_lock, flags); 1338c2ecf20Sopenharmony_ci if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT) 1348c2ecf20Sopenharmony_ci rtlpriv->usb_data_index = 0; 1358c2ecf20Sopenharmony_ci data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; 1368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rtlpriv->locks.usb_lock, flags); 1378c2ecf20Sopenharmony_ci request = REALTEK_USB_VENQT_CMD_REQ; 1388c2ecf20Sopenharmony_ci index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci wvalue = (u16)addr; 1418c2ecf20Sopenharmony_ci _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len); 1428c2ecf20Sopenharmony_ci return le32_to_cpu(*data); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic u8 _usb_read8_sync(struct rtl_priv *rtlpriv, u32 addr) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci return (u8)_usb_read_sync(rtlpriv, addr, 1); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic u16 _usb_read16_sync(struct rtl_priv *rtlpriv, u32 addr) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci return (u16)_usb_read_sync(rtlpriv, addr, 2); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic u32 _usb_read32_sync(struct rtl_priv *rtlpriv, u32 addr) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return _usb_read_sync(rtlpriv, addr, 4); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void _usb_write_async(struct usb_device *udev, u32 addr, u32 val, 1618c2ecf20Sopenharmony_ci u16 len) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci u8 request; 1648c2ecf20Sopenharmony_ci u16 wvalue; 1658c2ecf20Sopenharmony_ci u16 index; 1668c2ecf20Sopenharmony_ci __le32 data; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci request = REALTEK_USB_VENQT_CMD_REQ; 1698c2ecf20Sopenharmony_ci index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ 1708c2ecf20Sopenharmony_ci wvalue = (u16)(addr&0x0000ffff); 1718c2ecf20Sopenharmony_ci data = cpu_to_le32(val); 1728c2ecf20Sopenharmony_ci _usbctrl_vendorreq_async_write(udev, request, wvalue, index, &data, 1738c2ecf20Sopenharmony_ci len); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void _usb_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct device *dev = rtlpriv->io.dev; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci _usb_write_async(to_usb_device(dev), addr, val, 1); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic void _usb_write16_async(struct rtl_priv *rtlpriv, u32 addr, u16 val) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct device *dev = rtlpriv->io.dev; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci _usb_write_async(to_usb_device(dev), addr, val, 2); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct device *dev = rtlpriv->io.dev; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci _usb_write_async(to_usb_device(dev), addr, val, 4); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic void _usb_writen_sync(struct rtl_priv *rtlpriv, u32 addr, void *data, 1988c2ecf20Sopenharmony_ci u16 len) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct device *dev = rtlpriv->io.dev; 2018c2ecf20Sopenharmony_ci struct usb_device *udev = to_usb_device(dev); 2028c2ecf20Sopenharmony_ci u8 request = REALTEK_USB_VENQT_CMD_REQ; 2038c2ecf20Sopenharmony_ci u8 reqtype = REALTEK_USB_VENQT_WRITE; 2048c2ecf20Sopenharmony_ci u16 wvalue; 2058c2ecf20Sopenharmony_ci u16 index = REALTEK_USB_VENQT_CMD_IDX; 2068c2ecf20Sopenharmony_ci int pipe = usb_sndctrlpipe(udev, 0); /* write_out */ 2078c2ecf20Sopenharmony_ci u8 *buffer; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci wvalue = (u16)(addr & 0x0000ffff); 2108c2ecf20Sopenharmony_ci buffer = kmemdup(data, len, GFP_ATOMIC); 2118c2ecf20Sopenharmony_ci if (!buffer) 2128c2ecf20Sopenharmony_ci return; 2138c2ecf20Sopenharmony_ci usb_control_msg(udev, pipe, request, reqtype, wvalue, 2148c2ecf20Sopenharmony_ci index, buffer, len, 50); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci kfree(buffer); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic void _rtl_usb_io_handler_init(struct device *dev, 2208c2ecf20Sopenharmony_ci struct ieee80211_hw *hw) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci rtlpriv->io.dev = dev; 2258c2ecf20Sopenharmony_ci mutex_init(&rtlpriv->io.bb_mutex); 2268c2ecf20Sopenharmony_ci rtlpriv->io.write8_async = _usb_write8_async; 2278c2ecf20Sopenharmony_ci rtlpriv->io.write16_async = _usb_write16_async; 2288c2ecf20Sopenharmony_ci rtlpriv->io.write32_async = _usb_write32_async; 2298c2ecf20Sopenharmony_ci rtlpriv->io.read8_sync = _usb_read8_sync; 2308c2ecf20Sopenharmony_ci rtlpriv->io.read16_sync = _usb_read16_sync; 2318c2ecf20Sopenharmony_ci rtlpriv->io.read32_sync = _usb_read32_sync; 2328c2ecf20Sopenharmony_ci rtlpriv->io.writen_sync = _usb_writen_sync; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct rtl_priv __maybe_unused *rtlpriv = rtl_priv(hw); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci mutex_destroy(&rtlpriv->io.bb_mutex); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* Default aggregation handler. Do nothing and just return the oldest skb. */ 2438c2ecf20Sopenharmony_cistatic struct sk_buff *_none_usb_tx_aggregate_hdl(struct ieee80211_hw *hw, 2448c2ecf20Sopenharmony_ci struct sk_buff_head *list) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci return skb_dequeue(list); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci#define IS_HIGH_SPEED_USB(udev) \ 2508c2ecf20Sopenharmony_ci ((USB_SPEED_HIGH == (udev)->speed) ? true : false) 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int _rtl_usb_init_tx(struct ieee80211_hw *hw) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci u32 i; 2558c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 2568c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci rtlusb->max_bulk_out_size = IS_HIGH_SPEED_USB(rtlusb->udev) 2598c2ecf20Sopenharmony_ci ? USB_HIGH_SPEED_BULK_SIZE 2608c2ecf20Sopenharmony_ci : USB_FULL_SPEED_BULK_SIZE; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "USB Max Bulk-out Size=%d\n", 2638c2ecf20Sopenharmony_ci rtlusb->max_bulk_out_size); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci for (i = 0; i < __RTL_TXQ_NUM; i++) { 2668c2ecf20Sopenharmony_ci u32 ep_num = rtlusb->ep_map.ep_mapping[i]; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (!ep_num) { 2698c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, 2708c2ecf20Sopenharmony_ci "Invalid endpoint map setting!\n"); 2718c2ecf20Sopenharmony_ci return -EINVAL; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci rtlusb->usb_tx_post_hdl = 2768c2ecf20Sopenharmony_ci rtlpriv->cfg->usb_interface_cfg->usb_tx_post_hdl; 2778c2ecf20Sopenharmony_ci rtlusb->usb_tx_cleanup = 2788c2ecf20Sopenharmony_ci rtlpriv->cfg->usb_interface_cfg->usb_tx_cleanup; 2798c2ecf20Sopenharmony_ci rtlusb->usb_tx_aggregate_hdl = 2808c2ecf20Sopenharmony_ci (rtlpriv->cfg->usb_interface_cfg->usb_tx_aggregate_hdl) 2818c2ecf20Sopenharmony_ci ? rtlpriv->cfg->usb_interface_cfg->usb_tx_aggregate_hdl 2828c2ecf20Sopenharmony_ci : &_none_usb_tx_aggregate_hdl; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci init_usb_anchor(&rtlusb->tx_submitted); 2858c2ecf20Sopenharmony_ci for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) { 2868c2ecf20Sopenharmony_ci skb_queue_head_init(&rtlusb->tx_skb_queue[i]); 2878c2ecf20Sopenharmony_ci init_usb_anchor(&rtlusb->tx_pending[i]); 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci return 0; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic void _rtl_rx_work(struct tasklet_struct *t); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int _rtl_usb_init_rx(struct ieee80211_hw *hw) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 2978c2ecf20Sopenharmony_ci struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); 2988c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci rtlusb->rx_max_size = rtlpriv->cfg->usb_interface_cfg->rx_max_size; 3018c2ecf20Sopenharmony_ci rtlusb->rx_urb_num = rtlpriv->cfg->usb_interface_cfg->rx_urb_num; 3028c2ecf20Sopenharmony_ci rtlusb->in_ep = rtlpriv->cfg->usb_interface_cfg->in_ep_num; 3038c2ecf20Sopenharmony_ci rtlusb->usb_rx_hdl = rtlpriv->cfg->usb_interface_cfg->usb_rx_hdl; 3048c2ecf20Sopenharmony_ci rtlusb->usb_rx_segregate_hdl = 3058c2ecf20Sopenharmony_ci rtlpriv->cfg->usb_interface_cfg->usb_rx_segregate_hdl; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci pr_info("rx_max_size %d, rx_urb_num %d, in_ep %d\n", 3088c2ecf20Sopenharmony_ci rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep); 3098c2ecf20Sopenharmony_ci init_usb_anchor(&rtlusb->rx_submitted); 3108c2ecf20Sopenharmony_ci init_usb_anchor(&rtlusb->rx_cleanup_urbs); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci skb_queue_head_init(&rtlusb->rx_queue); 3138c2ecf20Sopenharmony_ci rtlusb->rx_work_tasklet.func = (void(*))_rtl_rx_work; 3148c2ecf20Sopenharmony_ci rtlusb->rx_work_tasklet.data = (unsigned long)&rtlusb->rx_work_tasklet; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci return 0; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic int _rtl_usb_init(struct ieee80211_hw *hw) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 3228c2ecf20Sopenharmony_ci struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); 3238c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); 3248c2ecf20Sopenharmony_ci int err; 3258c2ecf20Sopenharmony_ci u8 epidx; 3268c2ecf20Sopenharmony_ci struct usb_interface *usb_intf = rtlusb->intf; 3278c2ecf20Sopenharmony_ci u8 epnums = usb_intf->cur_altsetting->desc.bNumEndpoints; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci rtlusb->out_ep_nums = rtlusb->in_ep_nums = 0; 3308c2ecf20Sopenharmony_ci for (epidx = 0; epidx < epnums; epidx++) { 3318c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *pep_desc; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci pep_desc = &usb_intf->cur_altsetting->endpoint[epidx].desc; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (usb_endpoint_dir_in(pep_desc)) 3368c2ecf20Sopenharmony_ci rtlusb->in_ep_nums++; 3378c2ecf20Sopenharmony_ci else if (usb_endpoint_dir_out(pep_desc)) 3388c2ecf20Sopenharmony_ci rtlusb->out_ep_nums++; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, 3418c2ecf20Sopenharmony_ci "USB EP(0x%02x), MaxPacketSize=%d, Interval=%d\n", 3428c2ecf20Sopenharmony_ci pep_desc->bEndpointAddress, pep_desc->wMaxPacketSize, 3438c2ecf20Sopenharmony_ci pep_desc->bInterval); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci if (rtlusb->in_ep_nums < rtlpriv->cfg->usb_interface_cfg->in_ep_num) { 3468c2ecf20Sopenharmony_ci pr_err("Too few input end points found\n"); 3478c2ecf20Sopenharmony_ci return -EINVAL; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci if (rtlusb->out_ep_nums == 0) { 3508c2ecf20Sopenharmony_ci pr_err("No output end points found\n"); 3518c2ecf20Sopenharmony_ci return -EINVAL; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci /* usb endpoint mapping */ 3548c2ecf20Sopenharmony_ci err = rtlpriv->cfg->usb_interface_cfg->usb_endpoint_mapping(hw); 3558c2ecf20Sopenharmony_ci rtlusb->usb_mq_to_hwq = rtlpriv->cfg->usb_interface_cfg->usb_mq_to_hwq; 3568c2ecf20Sopenharmony_ci _rtl_usb_init_tx(hw); 3578c2ecf20Sopenharmony_ci _rtl_usb_init_rx(hw); 3588c2ecf20Sopenharmony_ci return err; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic void rtl_usb_init_sw(struct ieee80211_hw *hw) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 3648c2ecf20Sopenharmony_ci struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 3658c2ecf20Sopenharmony_ci struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 3668c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci rtlhal->hw = hw; 3698c2ecf20Sopenharmony_ci ppsc->inactiveps = false; 3708c2ecf20Sopenharmony_ci ppsc->leisure_ps = false; 3718c2ecf20Sopenharmony_ci ppsc->fwctrl_lps = false; 3728c2ecf20Sopenharmony_ci ppsc->reg_fwctrl_lps = 3; 3738c2ecf20Sopenharmony_ci ppsc->reg_max_lps_awakeintvl = 5; 3748c2ecf20Sopenharmony_ci ppsc->fwctrl_psmode = FW_PS_DTIM_MODE; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* IBSS */ 3778c2ecf20Sopenharmony_ci mac->beacon_interval = 100; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* AMPDU */ 3808c2ecf20Sopenharmony_ci mac->min_space_cfg = 0; 3818c2ecf20Sopenharmony_ci mac->max_mss_density = 0; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* set sane AMPDU defaults */ 3848c2ecf20Sopenharmony_ci mac->current_ampdu_density = 7; 3858c2ecf20Sopenharmony_ci mac->current_ampdu_factor = 3; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* QOS */ 3888c2ecf20Sopenharmony_ci rtlusb->acm_method = EACMWAY2_SW; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* IRQ */ 3918c2ecf20Sopenharmony_ci /* HIMR - turn all on */ 3928c2ecf20Sopenharmony_ci rtlusb->irq_mask[0] = 0xFFFFFFFF; 3938c2ecf20Sopenharmony_ci /* HIMR_EX - turn all on */ 3948c2ecf20Sopenharmony_ci rtlusb->irq_mask[1] = 0xFFFFFFFF; 3958c2ecf20Sopenharmony_ci rtlusb->disablehwsm = true; 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic void _rtl_rx_completed(struct urb *urb); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int _rtl_prep_rx_urb(struct ieee80211_hw *hw, struct rtl_usb *rtlusb, 4018c2ecf20Sopenharmony_ci struct urb *urb, gfp_t gfp_mask) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci void *buf; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci buf = usb_alloc_coherent(rtlusb->udev, rtlusb->rx_max_size, gfp_mask, 4068c2ecf20Sopenharmony_ci &urb->transfer_dma); 4078c2ecf20Sopenharmony_ci if (!buf) { 4088c2ecf20Sopenharmony_ci pr_err("Failed to usb_alloc_coherent!!\n"); 4098c2ecf20Sopenharmony_ci return -ENOMEM; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci usb_fill_bulk_urb(urb, rtlusb->udev, 4138c2ecf20Sopenharmony_ci usb_rcvbulkpipe(rtlusb->udev, rtlusb->in_ep), 4148c2ecf20Sopenharmony_ci buf, rtlusb->rx_max_size, _rtl_rx_completed, rtlusb); 4158c2ecf20Sopenharmony_ci urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci return 0; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw, 4218c2ecf20Sopenharmony_ci struct sk_buff *skb) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 4248c2ecf20Sopenharmony_ci u8 *rxdesc = skb->data; 4258c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 4268c2ecf20Sopenharmony_ci bool unicast = false; 4278c2ecf20Sopenharmony_ci __le16 fc; 4288c2ecf20Sopenharmony_ci struct ieee80211_rx_status rx_status = {0}; 4298c2ecf20Sopenharmony_ci struct rtl_stats stats = { 4308c2ecf20Sopenharmony_ci .signal = 0, 4318c2ecf20Sopenharmony_ci .rate = 0, 4328c2ecf20Sopenharmony_ci }; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci skb_pull(skb, RTL_RX_DESC_SIZE); 4358c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, rxdesc, skb); 4368c2ecf20Sopenharmony_ci skb_pull(skb, (stats.rx_drvinfo_size + stats.rx_bufshift)); 4378c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)(skb->data); 4388c2ecf20Sopenharmony_ci fc = hdr->frame_control; 4398c2ecf20Sopenharmony_ci if (!stats.crc) { 4408c2ecf20Sopenharmony_ci memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (is_broadcast_ether_addr(hdr->addr1)) { 4438c2ecf20Sopenharmony_ci /*TODO*/; 4448c2ecf20Sopenharmony_ci } else if (is_multicast_ether_addr(hdr->addr1)) { 4458c2ecf20Sopenharmony_ci /*TODO*/ 4468c2ecf20Sopenharmony_ci } else { 4478c2ecf20Sopenharmony_ci unicast = true; 4488c2ecf20Sopenharmony_ci rtlpriv->stats.rxbytesunicast += skb->len; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (ieee80211_is_data(fc)) { 4528c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (unicast) 4558c2ecf20Sopenharmony_ci rtlpriv->link_info.num_rx_inperiod++; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci /* static bcn for roaming */ 4588c2ecf20Sopenharmony_ci rtl_beacon_statistic(hw, skb); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw, 4638c2ecf20Sopenharmony_ci struct sk_buff *skb) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 4668c2ecf20Sopenharmony_ci u8 *rxdesc = skb->data; 4678c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 4688c2ecf20Sopenharmony_ci bool unicast = false; 4698c2ecf20Sopenharmony_ci __le16 fc; 4708c2ecf20Sopenharmony_ci struct ieee80211_rx_status rx_status = {0}; 4718c2ecf20Sopenharmony_ci struct rtl_stats stats = { 4728c2ecf20Sopenharmony_ci .signal = 0, 4738c2ecf20Sopenharmony_ci .rate = 0, 4748c2ecf20Sopenharmony_ci }; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci skb_pull(skb, RTL_RX_DESC_SIZE); 4778c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, rxdesc, skb); 4788c2ecf20Sopenharmony_ci skb_pull(skb, (stats.rx_drvinfo_size + stats.rx_bufshift)); 4798c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)(skb->data); 4808c2ecf20Sopenharmony_ci fc = hdr->frame_control; 4818c2ecf20Sopenharmony_ci if (!stats.crc) { 4828c2ecf20Sopenharmony_ci memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (is_broadcast_ether_addr(hdr->addr1)) { 4858c2ecf20Sopenharmony_ci /*TODO*/; 4868c2ecf20Sopenharmony_ci } else if (is_multicast_ether_addr(hdr->addr1)) { 4878c2ecf20Sopenharmony_ci /*TODO*/ 4888c2ecf20Sopenharmony_ci } else { 4898c2ecf20Sopenharmony_ci unicast = true; 4908c2ecf20Sopenharmony_ci rtlpriv->stats.rxbytesunicast += skb->len; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (ieee80211_is_data(fc)) { 4948c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (unicast) 4978c2ecf20Sopenharmony_ci rtlpriv->link_info.num_rx_inperiod++; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* static bcn for roaming */ 5018c2ecf20Sopenharmony_ci rtl_beacon_statistic(hw, skb); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (likely(rtl_action_proc(hw, skb, false))) 5048c2ecf20Sopenharmony_ci ieee80211_rx(hw, skb); 5058c2ecf20Sopenharmony_ci else 5068c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 5078c2ecf20Sopenharmony_ci } else { 5088c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci struct sk_buff *_skb; 5158c2ecf20Sopenharmony_ci struct sk_buff_head rx_queue; 5168c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci skb_queue_head_init(&rx_queue); 5198c2ecf20Sopenharmony_ci if (rtlusb->usb_rx_segregate_hdl) 5208c2ecf20Sopenharmony_ci rtlusb->usb_rx_segregate_hdl(hw, skb, &rx_queue); 5218c2ecf20Sopenharmony_ci WARN_ON(skb_queue_empty(&rx_queue)); 5228c2ecf20Sopenharmony_ci while (!skb_queue_empty(&rx_queue)) { 5238c2ecf20Sopenharmony_ci _skb = skb_dequeue(&rx_queue); 5248c2ecf20Sopenharmony_ci _rtl_usb_rx_process_agg(hw, _skb); 5258c2ecf20Sopenharmony_ci ieee80211_rx(hw, _skb); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci#define __RX_SKB_MAX_QUEUED 64 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic void _rtl_rx_work(struct tasklet_struct *t) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = from_tasklet(rtlusb, t, rx_work_tasklet); 5348c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); 5358c2ecf20Sopenharmony_ci struct sk_buff *skb; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci while ((skb = skb_dequeue(&rtlusb->rx_queue))) { 5388c2ecf20Sopenharmony_ci if (unlikely(IS_USB_STOP(rtlusb))) { 5398c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 5408c2ecf20Sopenharmony_ci continue; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (likely(!rtlusb->usb_rx_segregate_hdl)) { 5448c2ecf20Sopenharmony_ci _rtl_usb_rx_process_noagg(hw, skb); 5458c2ecf20Sopenharmony_ci } else { 5468c2ecf20Sopenharmony_ci /* TO DO */ 5478c2ecf20Sopenharmony_ci _rtl_rx_pre_process(hw, skb); 5488c2ecf20Sopenharmony_ci pr_err("rx agg not supported\n"); 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic unsigned int _rtl_rx_get_padding(struct ieee80211_hdr *hdr, 5548c2ecf20Sopenharmony_ci unsigned int len) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci#if NET_IP_ALIGN != 0 5578c2ecf20Sopenharmony_ci unsigned int padding = 0; 5588c2ecf20Sopenharmony_ci#endif 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* make function no-op when possible */ 5618c2ecf20Sopenharmony_ci if (NET_IP_ALIGN == 0 || len < sizeof(*hdr)) 5628c2ecf20Sopenharmony_ci return 0; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci#if NET_IP_ALIGN != 0 5658c2ecf20Sopenharmony_ci /* alignment calculation as in lbtf_rx() / carl9170_rx_copy_data() */ 5668c2ecf20Sopenharmony_ci /* TODO: deduplicate common code, define helper function instead? */ 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) { 5698c2ecf20Sopenharmony_ci u8 *qc = ieee80211_get_qos_ctl(hdr); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci padding ^= NET_IP_ALIGN; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* Input might be invalid, avoid accessing memory outside 5748c2ecf20Sopenharmony_ci * the buffer. 5758c2ecf20Sopenharmony_ci */ 5768c2ecf20Sopenharmony_ci if ((unsigned long)qc - (unsigned long)hdr < len && 5778c2ecf20Sopenharmony_ci *qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) 5788c2ecf20Sopenharmony_ci padding ^= NET_IP_ALIGN; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (ieee80211_has_a4(hdr->frame_control)) 5828c2ecf20Sopenharmony_ci padding ^= NET_IP_ALIGN; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return padding; 5858c2ecf20Sopenharmony_ci#endif 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci#define __RADIO_TAP_SIZE_RSV 32 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic void _rtl_rx_completed(struct urb *_urb) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = (struct rtl_usb *)_urb->context; 5938c2ecf20Sopenharmony_ci int err = 0; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (unlikely(IS_USB_STOP(rtlusb))) 5968c2ecf20Sopenharmony_ci goto free; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (likely(0 == _urb->status)) { 5998c2ecf20Sopenharmony_ci unsigned int padding; 6008c2ecf20Sopenharmony_ci struct sk_buff *skb; 6018c2ecf20Sopenharmony_ci unsigned int qlen; 6028c2ecf20Sopenharmony_ci unsigned int size = _urb->actual_length; 6038c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (size < RTL_RX_DESC_SIZE + sizeof(struct ieee80211_hdr)) { 6068c2ecf20Sopenharmony_ci pr_err("Too short packet from bulk IN! (len: %d)\n", 6078c2ecf20Sopenharmony_ci size); 6088c2ecf20Sopenharmony_ci goto resubmit; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci qlen = skb_queue_len(&rtlusb->rx_queue); 6128c2ecf20Sopenharmony_ci if (qlen >= __RX_SKB_MAX_QUEUED) { 6138c2ecf20Sopenharmony_ci pr_err("Pending RX skbuff queue full! (qlen: %d)\n", 6148c2ecf20Sopenharmony_ci qlen); 6158c2ecf20Sopenharmony_ci goto resubmit; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci hdr = (void *)(_urb->transfer_buffer + RTL_RX_DESC_SIZE); 6198c2ecf20Sopenharmony_ci padding = _rtl_rx_get_padding(hdr, size - RTL_RX_DESC_SIZE); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci skb = dev_alloc_skb(size + __RADIO_TAP_SIZE_RSV + padding); 6228c2ecf20Sopenharmony_ci if (!skb) { 6238c2ecf20Sopenharmony_ci pr_err("Can't allocate skb for bulk IN!\n"); 6248c2ecf20Sopenharmony_ci goto resubmit; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci _rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* Make sure the payload data is 4 byte aligned. */ 6308c2ecf20Sopenharmony_ci skb_reserve(skb, padding); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* reserve some space for mac80211's radiotap */ 6338c2ecf20Sopenharmony_ci skb_reserve(skb, __RADIO_TAP_SIZE_RSV); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci skb_put_data(skb, _urb->transfer_buffer, size); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci skb_queue_tail(&rtlusb->rx_queue, skb); 6388c2ecf20Sopenharmony_ci tasklet_schedule(&rtlusb->rx_work_tasklet); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci goto resubmit; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci switch (_urb->status) { 6448c2ecf20Sopenharmony_ci /* disconnect */ 6458c2ecf20Sopenharmony_ci case -ENOENT: 6468c2ecf20Sopenharmony_ci case -ECONNRESET: 6478c2ecf20Sopenharmony_ci case -ENODEV: 6488c2ecf20Sopenharmony_ci case -ESHUTDOWN: 6498c2ecf20Sopenharmony_ci goto free; 6508c2ecf20Sopenharmony_ci default: 6518c2ecf20Sopenharmony_ci break; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ciresubmit: 6558c2ecf20Sopenharmony_ci usb_anchor_urb(_urb, &rtlusb->rx_submitted); 6568c2ecf20Sopenharmony_ci err = usb_submit_urb(_urb, GFP_ATOMIC); 6578c2ecf20Sopenharmony_ci if (unlikely(err)) { 6588c2ecf20Sopenharmony_ci usb_unanchor_urb(_urb); 6598c2ecf20Sopenharmony_ci goto free; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci return; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cifree: 6648c2ecf20Sopenharmony_ci /* On some architectures, usb_free_coherent must not be called from 6658c2ecf20Sopenharmony_ci * hardirq context. Queue urb to cleanup list. 6668c2ecf20Sopenharmony_ci */ 6678c2ecf20Sopenharmony_ci usb_anchor_urb(_urb, &rtlusb->rx_cleanup_urbs); 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci#undef __RADIO_TAP_SIZE_RSV 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic void _rtl_usb_cleanup_rx(struct ieee80211_hw *hw) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 6758c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 6768c2ecf20Sopenharmony_ci struct urb *urb; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci usb_kill_anchored_urbs(&rtlusb->rx_submitted); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci tasklet_kill(&rtlusb->rx_work_tasklet); 6818c2ecf20Sopenharmony_ci cancel_work_sync(&rtlpriv->works.lps_change_work); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (rtlpriv->works.rtl_wq) { 6848c2ecf20Sopenharmony_ci destroy_workqueue(rtlpriv->works.rtl_wq); 6858c2ecf20Sopenharmony_ci rtlpriv->works.rtl_wq = NULL; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci skb_queue_purge(&rtlusb->rx_queue); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) { 6918c2ecf20Sopenharmony_ci usb_free_coherent(urb->dev, urb->transfer_buffer_length, 6928c2ecf20Sopenharmony_ci urb->transfer_buffer, urb->transfer_dma); 6938c2ecf20Sopenharmony_ci usb_free_urb(urb); 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cistatic int _rtl_usb_receive(struct ieee80211_hw *hw) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci struct urb *urb; 7008c2ecf20Sopenharmony_ci int err; 7018c2ecf20Sopenharmony_ci int i; 7028c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci WARN_ON(0 == rtlusb->rx_urb_num); 7058c2ecf20Sopenharmony_ci /* 1600 == 1514 + max WLAN header + rtk info */ 7068c2ecf20Sopenharmony_ci WARN_ON(rtlusb->rx_max_size < 1600); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci for (i = 0; i < rtlusb->rx_urb_num; i++) { 7098c2ecf20Sopenharmony_ci err = -ENOMEM; 7108c2ecf20Sopenharmony_ci urb = usb_alloc_urb(0, GFP_KERNEL); 7118c2ecf20Sopenharmony_ci if (!urb) 7128c2ecf20Sopenharmony_ci goto err_out; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci err = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL); 7158c2ecf20Sopenharmony_ci if (err < 0) { 7168c2ecf20Sopenharmony_ci pr_err("Failed to prep_rx_urb!!\n"); 7178c2ecf20Sopenharmony_ci usb_free_urb(urb); 7188c2ecf20Sopenharmony_ci goto err_out; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci usb_anchor_urb(urb, &rtlusb->rx_submitted); 7228c2ecf20Sopenharmony_ci err = usb_submit_urb(urb, GFP_KERNEL); 7238c2ecf20Sopenharmony_ci if (err) { 7248c2ecf20Sopenharmony_ci usb_unanchor_urb(urb); 7258c2ecf20Sopenharmony_ci usb_free_urb(urb); 7268c2ecf20Sopenharmony_ci goto err_out; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci usb_free_urb(urb); 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci return 0; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cierr_out: 7338c2ecf20Sopenharmony_ci usb_kill_anchored_urbs(&rtlusb->rx_submitted); 7348c2ecf20Sopenharmony_ci _rtl_usb_cleanup_rx(hw); 7358c2ecf20Sopenharmony_ci return err; 7368c2ecf20Sopenharmony_ci} 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_cistatic int rtl_usb_start(struct ieee80211_hw *hw) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci int err; 7418c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 7428c2ecf20Sopenharmony_ci struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 7438c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci err = rtlpriv->cfg->ops->hw_init(hw); 7468c2ecf20Sopenharmony_ci if (!err) { 7478c2ecf20Sopenharmony_ci rtl_init_rx_config(hw); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* Enable software */ 7508c2ecf20Sopenharmony_ci SET_USB_START(rtlusb); 7518c2ecf20Sopenharmony_ci /* should after adapter start and interrupt enable. */ 7528c2ecf20Sopenharmony_ci set_hal_start(rtlhal); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* Start bulk IN */ 7558c2ecf20Sopenharmony_ci err = _rtl_usb_receive(hw); 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci return err; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci/*======================= tx =========================================*/ 7628c2ecf20Sopenharmony_cistatic void rtl_usb_cleanup(struct ieee80211_hw *hw) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci u32 i; 7658c2ecf20Sopenharmony_ci struct sk_buff *_skb; 7668c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 7678c2ecf20Sopenharmony_ci struct ieee80211_tx_info *txinfo; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* clean up rx stuff. */ 7708c2ecf20Sopenharmony_ci _rtl_usb_cleanup_rx(hw); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* clean up tx stuff */ 7738c2ecf20Sopenharmony_ci for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) { 7748c2ecf20Sopenharmony_ci while ((_skb = skb_dequeue(&rtlusb->tx_skb_queue[i]))) { 7758c2ecf20Sopenharmony_ci rtlusb->usb_tx_cleanup(hw, _skb); 7768c2ecf20Sopenharmony_ci txinfo = IEEE80211_SKB_CB(_skb); 7778c2ecf20Sopenharmony_ci ieee80211_tx_info_clear_status(txinfo); 7788c2ecf20Sopenharmony_ci txinfo->flags |= IEEE80211_TX_STAT_ACK; 7798c2ecf20Sopenharmony_ci ieee80211_tx_status_irqsafe(hw, _skb); 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci usb_kill_anchored_urbs(&rtlusb->tx_pending[i]); 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci usb_kill_anchored_urbs(&rtlusb->tx_submitted); 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci/* We may add some struct into struct rtl_usb later. Do deinit here. */ 7878c2ecf20Sopenharmony_cistatic void rtl_usb_deinit(struct ieee80211_hw *hw) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci rtl_usb_cleanup(hw); 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic void rtl_usb_stop(struct ieee80211_hw *hw) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 7958c2ecf20Sopenharmony_ci struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 7968c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 7978c2ecf20Sopenharmony_ci struct urb *urb; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* should after adapter start and interrupt enable. */ 8008c2ecf20Sopenharmony_ci set_hal_stop(rtlhal); 8018c2ecf20Sopenharmony_ci cancel_work_sync(&rtlpriv->works.fill_h2c_cmd); 8028c2ecf20Sopenharmony_ci /* Enable software */ 8038c2ecf20Sopenharmony_ci SET_USB_STOP(rtlusb); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* free pre-allocated URBs from rtl_usb_start() */ 8068c2ecf20Sopenharmony_ci usb_kill_anchored_urbs(&rtlusb->rx_submitted); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci tasklet_kill(&rtlusb->rx_work_tasklet); 8098c2ecf20Sopenharmony_ci cancel_work_sync(&rtlpriv->works.lps_change_work); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci flush_workqueue(rtlpriv->works.rtl_wq); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci skb_queue_purge(&rtlusb->rx_queue); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) { 8168c2ecf20Sopenharmony_ci usb_free_coherent(urb->dev, urb->transfer_buffer_length, 8178c2ecf20Sopenharmony_ci urb->transfer_buffer, urb->transfer_dma); 8188c2ecf20Sopenharmony_ci usb_free_urb(urb); 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->hw_disable(hw); 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic void _rtl_submit_tx_urb(struct ieee80211_hw *hw, struct urb *_urb) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci int err; 8278c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci usb_anchor_urb(_urb, &rtlusb->tx_submitted); 8308c2ecf20Sopenharmony_ci err = usb_submit_urb(_urb, GFP_ATOMIC); 8318c2ecf20Sopenharmony_ci if (err < 0) { 8328c2ecf20Sopenharmony_ci struct sk_buff *skb; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci pr_err("Failed to submit urb\n"); 8358c2ecf20Sopenharmony_ci usb_unanchor_urb(_urb); 8368c2ecf20Sopenharmony_ci skb = (struct sk_buff *)_urb->context; 8378c2ecf20Sopenharmony_ci kfree_skb(skb); 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci usb_free_urb(_urb); 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic int _usb_tx_post(struct ieee80211_hw *hw, struct urb *urb, 8438c2ecf20Sopenharmony_ci struct sk_buff *skb) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 8468c2ecf20Sopenharmony_ci struct ieee80211_tx_info *txinfo; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci rtlusb->usb_tx_post_hdl(hw, urb, skb); 8498c2ecf20Sopenharmony_ci skb_pull(skb, RTL_TX_HEADER_SIZE); 8508c2ecf20Sopenharmony_ci txinfo = IEEE80211_SKB_CB(skb); 8518c2ecf20Sopenharmony_ci ieee80211_tx_info_clear_status(txinfo); 8528c2ecf20Sopenharmony_ci txinfo->flags |= IEEE80211_TX_STAT_ACK; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci if (urb->status) { 8558c2ecf20Sopenharmony_ci pr_err("Urb has error status 0x%X\n", urb->status); 8568c2ecf20Sopenharmony_ci goto out; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci /* TODO: statistics */ 8598c2ecf20Sopenharmony_ciout: 8608c2ecf20Sopenharmony_ci ieee80211_tx_status_irqsafe(hw, skb); 8618c2ecf20Sopenharmony_ci return urb->status; 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic void _rtl_tx_complete(struct urb *urb) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci struct sk_buff *skb = (struct sk_buff *)urb->context; 8678c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 8688c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = (struct rtl_usb *)info->rate_driver_data[0]; 8698c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); 8708c2ecf20Sopenharmony_ci int err; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (unlikely(IS_USB_STOP(rtlusb))) 8738c2ecf20Sopenharmony_ci return; 8748c2ecf20Sopenharmony_ci err = _usb_tx_post(hw, urb, skb); 8758c2ecf20Sopenharmony_ci if (err) { 8768c2ecf20Sopenharmony_ci /* Ignore error and keep issuiing other urbs */ 8778c2ecf20Sopenharmony_ci return; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic struct urb *_rtl_usb_tx_urb_setup(struct ieee80211_hw *hw, 8828c2ecf20Sopenharmony_ci struct sk_buff *skb, u32 ep_num) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 8858c2ecf20Sopenharmony_ci struct urb *_urb; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci WARN_ON(NULL == skb); 8888c2ecf20Sopenharmony_ci _urb = usb_alloc_urb(0, GFP_ATOMIC); 8898c2ecf20Sopenharmony_ci if (!_urb) 8908c2ecf20Sopenharmony_ci return NULL; 8918c2ecf20Sopenharmony_ci _rtl_install_trx_info(rtlusb, skb, ep_num); 8928c2ecf20Sopenharmony_ci usb_fill_bulk_urb(_urb, rtlusb->udev, usb_sndbulkpipe(rtlusb->udev, 8938c2ecf20Sopenharmony_ci ep_num), skb->data, skb->len, _rtl_tx_complete, skb); 8948c2ecf20Sopenharmony_ci _urb->transfer_flags |= URB_ZERO_PACKET; 8958c2ecf20Sopenharmony_ci return _urb; 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, 8998c2ecf20Sopenharmony_ci enum rtl_txq qnum) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 9028c2ecf20Sopenharmony_ci u32 ep_num; 9038c2ecf20Sopenharmony_ci struct urb *_urb = NULL; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci WARN_ON(NULL == rtlusb->usb_tx_aggregate_hdl); 9068c2ecf20Sopenharmony_ci if (unlikely(IS_USB_STOP(rtlusb))) { 9078c2ecf20Sopenharmony_ci pr_err("USB device is stopping...\n"); 9088c2ecf20Sopenharmony_ci kfree_skb(skb); 9098c2ecf20Sopenharmony_ci return; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci ep_num = rtlusb->ep_map.ep_mapping[qnum]; 9128c2ecf20Sopenharmony_ci _urb = _rtl_usb_tx_urb_setup(hw, skb, ep_num); 9138c2ecf20Sopenharmony_ci if (unlikely(!_urb)) { 9148c2ecf20Sopenharmony_ci pr_err("Can't allocate urb. Drop skb!\n"); 9158c2ecf20Sopenharmony_ci kfree_skb(skb); 9168c2ecf20Sopenharmony_ci return; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci _rtl_submit_tx_urb(hw, _urb); 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, 9228c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 9238c2ecf20Sopenharmony_ci struct sk_buff *skb, 9248c2ecf20Sopenharmony_ci u16 hw_queue) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 9278c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 9288c2ecf20Sopenharmony_ci struct rtl_tx_desc *pdesc = NULL; 9298c2ecf20Sopenharmony_ci struct rtl_tcb_desc tcb_desc; 9308c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); 9318c2ecf20Sopenharmony_ci __le16 fc = hdr->frame_control; 9328c2ecf20Sopenharmony_ci u8 *pda_addr = hdr->addr1; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); 9358c2ecf20Sopenharmony_ci if (ieee80211_is_auth(fc)) { 9368c2ecf20Sopenharmony_ci rtl_dbg(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n"); 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (rtlpriv->psc.sw_ps_enabled) { 9408c2ecf20Sopenharmony_ci if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && 9418c2ecf20Sopenharmony_ci !ieee80211_has_pm(fc)) 9428c2ecf20Sopenharmony_ci hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci rtl_action_proc(hw, skb, true); 9468c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(pda_addr)) 9478c2ecf20Sopenharmony_ci rtlpriv->stats.txbytesmulticast += skb->len; 9488c2ecf20Sopenharmony_ci else if (is_broadcast_ether_addr(pda_addr)) 9498c2ecf20Sopenharmony_ci rtlpriv->stats.txbytesbroadcast += skb->len; 9508c2ecf20Sopenharmony_ci else 9518c2ecf20Sopenharmony_ci rtlpriv->stats.txbytesunicast += skb->len; 9528c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, NULL, info, sta, skb, 9538c2ecf20Sopenharmony_ci hw_queue, &tcb_desc); 9548c2ecf20Sopenharmony_ci if (ieee80211_is_data(fc)) 9558c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic int rtl_usb_tx(struct ieee80211_hw *hw, 9598c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 9608c2ecf20Sopenharmony_ci struct sk_buff *skb, 9618c2ecf20Sopenharmony_ci struct rtl_tcb_desc *dummy) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 9648c2ecf20Sopenharmony_ci struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 9658c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); 9668c2ecf20Sopenharmony_ci __le16 fc = hdr->frame_control; 9678c2ecf20Sopenharmony_ci u16 hw_queue; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (unlikely(is_hal_stop(rtlhal))) 9708c2ecf20Sopenharmony_ci goto err_free; 9718c2ecf20Sopenharmony_ci hw_queue = rtlusb->usb_mq_to_hwq(fc, skb_get_queue_mapping(skb)); 9728c2ecf20Sopenharmony_ci _rtl_usb_tx_preprocess(hw, sta, skb, hw_queue); 9738c2ecf20Sopenharmony_ci _rtl_usb_transmit(hw, skb, hw_queue); 9748c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cierr_free: 9778c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 9788c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_cistatic bool rtl_usb_tx_chk_waitq_insert(struct ieee80211_hw *hw, 9828c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 9838c2ecf20Sopenharmony_ci struct sk_buff *skb) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci return false; 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic void rtl_fill_h2c_cmd_work_callback(struct work_struct *work) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct rtl_works *rtlworks = 9918c2ecf20Sopenharmony_ci container_of(work, struct rtl_works, fill_h2c_cmd); 9928c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = rtlworks->hw; 9938c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->fill_h2c_cmd(hw, H2C_RA_MASK, 5, rtlpriv->rate_mask); 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic const struct rtl_intf_ops rtl_usb_ops = { 9998c2ecf20Sopenharmony_ci .adapter_start = rtl_usb_start, 10008c2ecf20Sopenharmony_ci .adapter_stop = rtl_usb_stop, 10018c2ecf20Sopenharmony_ci .adapter_tx = rtl_usb_tx, 10028c2ecf20Sopenharmony_ci .waitq_insert = rtl_usb_tx_chk_waitq_insert, 10038c2ecf20Sopenharmony_ci}; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ciint rtl_usb_probe(struct usb_interface *intf, 10068c2ecf20Sopenharmony_ci const struct usb_device_id *id, 10078c2ecf20Sopenharmony_ci struct rtl_hal_cfg *rtl_hal_cfg) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci int err; 10108c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = NULL; 10118c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = NULL; 10128c2ecf20Sopenharmony_ci struct usb_device *udev; 10138c2ecf20Sopenharmony_ci struct rtl_usb_priv *usb_priv; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci hw = ieee80211_alloc_hw(sizeof(struct rtl_priv) + 10168c2ecf20Sopenharmony_ci sizeof(struct rtl_usb_priv), &rtl_ops); 10178c2ecf20Sopenharmony_ci if (!hw) { 10188c2ecf20Sopenharmony_ci pr_warn("rtl_usb: ieee80211 alloc failed\n"); 10198c2ecf20Sopenharmony_ci return -ENOMEM; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci rtlpriv = hw->priv; 10228c2ecf20Sopenharmony_ci rtlpriv->hw = hw; 10238c2ecf20Sopenharmony_ci rtlpriv->usb_data = kcalloc(RTL_USB_MAX_RX_COUNT, sizeof(u32), 10248c2ecf20Sopenharmony_ci GFP_KERNEL); 10258c2ecf20Sopenharmony_ci if (!rtlpriv->usb_data) { 10268c2ecf20Sopenharmony_ci ieee80211_free_hw(hw); 10278c2ecf20Sopenharmony_ci return -ENOMEM; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* this spin lock must be initialized early */ 10318c2ecf20Sopenharmony_ci spin_lock_init(&rtlpriv->locks.usb_lock); 10328c2ecf20Sopenharmony_ci INIT_WORK(&rtlpriv->works.fill_h2c_cmd, 10338c2ecf20Sopenharmony_ci rtl_fill_h2c_cmd_work_callback); 10348c2ecf20Sopenharmony_ci INIT_WORK(&rtlpriv->works.lps_change_work, 10358c2ecf20Sopenharmony_ci rtl_lps_change_work_callback); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci rtlpriv->usb_data_index = 0; 10388c2ecf20Sopenharmony_ci init_completion(&rtlpriv->firmware_loading_complete); 10398c2ecf20Sopenharmony_ci SET_IEEE80211_DEV(hw, &intf->dev); 10408c2ecf20Sopenharmony_ci udev = interface_to_usbdev(intf); 10418c2ecf20Sopenharmony_ci usb_get_dev(udev); 10428c2ecf20Sopenharmony_ci usb_priv = rtl_usbpriv(hw); 10438c2ecf20Sopenharmony_ci memset(usb_priv, 0, sizeof(*usb_priv)); 10448c2ecf20Sopenharmony_ci usb_priv->dev.intf = intf; 10458c2ecf20Sopenharmony_ci usb_priv->dev.udev = udev; 10468c2ecf20Sopenharmony_ci usb_set_intfdata(intf, hw); 10478c2ecf20Sopenharmony_ci /* init cfg & intf_ops */ 10488c2ecf20Sopenharmony_ci rtlpriv->rtlhal.interface = INTF_USB; 10498c2ecf20Sopenharmony_ci rtlpriv->cfg = rtl_hal_cfg; 10508c2ecf20Sopenharmony_ci rtlpriv->intf_ops = &rtl_usb_ops; 10518c2ecf20Sopenharmony_ci /* Init IO handler */ 10528c2ecf20Sopenharmony_ci _rtl_usb_io_handler_init(&udev->dev, hw); 10538c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->read_chip_version(hw); 10548c2ecf20Sopenharmony_ci /*like read eeprom and so on */ 10558c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->read_eeprom_info(hw); 10568c2ecf20Sopenharmony_ci err = _rtl_usb_init(hw); 10578c2ecf20Sopenharmony_ci if (err) 10588c2ecf20Sopenharmony_ci goto error_out2; 10598c2ecf20Sopenharmony_ci rtl_usb_init_sw(hw); 10608c2ecf20Sopenharmony_ci /* Init mac80211 sw */ 10618c2ecf20Sopenharmony_ci err = rtl_init_core(hw); 10628c2ecf20Sopenharmony_ci if (err) { 10638c2ecf20Sopenharmony_ci pr_err("Can't allocate sw for mac80211\n"); 10648c2ecf20Sopenharmony_ci goto error_out2; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci if (rtlpriv->cfg->ops->init_sw_vars(hw)) { 10678c2ecf20Sopenharmony_ci pr_err("Can't init_sw_vars\n"); 10688c2ecf20Sopenharmony_ci goto error_out; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->init_sw_leds(hw); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci err = ieee80211_register_hw(hw); 10738c2ecf20Sopenharmony_ci if (err) { 10748c2ecf20Sopenharmony_ci pr_err("Can't register mac80211 hw.\n"); 10758c2ecf20Sopenharmony_ci err = -ENODEV; 10768c2ecf20Sopenharmony_ci goto error_out; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci rtlpriv->mac80211.mac80211_registered = 1; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); 10818c2ecf20Sopenharmony_ci return 0; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cierror_out: 10848c2ecf20Sopenharmony_ci rtl_deinit_core(hw); 10858c2ecf20Sopenharmony_cierror_out2: 10868c2ecf20Sopenharmony_ci _rtl_usb_io_handler_release(hw); 10878c2ecf20Sopenharmony_ci usb_put_dev(udev); 10888c2ecf20Sopenharmony_ci complete(&rtlpriv->firmware_loading_complete); 10898c2ecf20Sopenharmony_ci kfree(rtlpriv->usb_data); 10908c2ecf20Sopenharmony_ci ieee80211_free_hw(hw); 10918c2ecf20Sopenharmony_ci return -ENODEV; 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rtl_usb_probe); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_civoid rtl_usb_disconnect(struct usb_interface *intf) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = usb_get_intfdata(intf); 10988c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 10998c2ecf20Sopenharmony_ci struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); 11008c2ecf20Sopenharmony_ci struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci if (unlikely(!rtlpriv)) 11038c2ecf20Sopenharmony_ci return; 11048c2ecf20Sopenharmony_ci /* just in case driver is removed before firmware callback */ 11058c2ecf20Sopenharmony_ci wait_for_completion(&rtlpriv->firmware_loading_complete); 11068c2ecf20Sopenharmony_ci clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); 11078c2ecf20Sopenharmony_ci /*ieee80211_unregister_hw will call ops_stop */ 11088c2ecf20Sopenharmony_ci if (rtlmac->mac80211_registered == 1) { 11098c2ecf20Sopenharmony_ci ieee80211_unregister_hw(hw); 11108c2ecf20Sopenharmony_ci rtlmac->mac80211_registered = 0; 11118c2ecf20Sopenharmony_ci } else { 11128c2ecf20Sopenharmony_ci rtl_deinit_deferred_work(hw, false); 11138c2ecf20Sopenharmony_ci rtlpriv->intf_ops->adapter_stop(hw); 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci /*deinit rfkill */ 11168c2ecf20Sopenharmony_ci /* rtl_deinit_rfkill(hw); */ 11178c2ecf20Sopenharmony_ci rtl_usb_deinit(hw); 11188c2ecf20Sopenharmony_ci rtl_deinit_core(hw); 11198c2ecf20Sopenharmony_ci kfree(rtlpriv->usb_data); 11208c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->deinit_sw_leds(hw); 11218c2ecf20Sopenharmony_ci rtlpriv->cfg->ops->deinit_sw_vars(hw); 11228c2ecf20Sopenharmony_ci _rtl_usb_io_handler_release(hw); 11238c2ecf20Sopenharmony_ci usb_put_dev(rtlusb->udev); 11248c2ecf20Sopenharmony_ci usb_set_intfdata(intf, NULL); 11258c2ecf20Sopenharmony_ci ieee80211_free_hw(hw); 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rtl_usb_disconnect); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ciint rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci return 0; 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rtl_usb_suspend); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ciint rtl_usb_resume(struct usb_interface *pusb_intf) 11368c2ecf20Sopenharmony_ci{ 11378c2ecf20Sopenharmony_ci return 0; 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rtl_usb_resume); 1140