1*90aac0d8SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2*90aac0d8SBjoern A. Zeeb /* Copyright(c) 2018-2019 Realtek Corporation 3*90aac0d8SBjoern A. Zeeb */ 4*90aac0d8SBjoern A. Zeeb 5*90aac0d8SBjoern A. Zeeb #include <linux/module.h> 6*90aac0d8SBjoern A. Zeeb #include <linux/usb.h> 7*90aac0d8SBjoern A. Zeeb #include <linux/mutex.h> 8*90aac0d8SBjoern A. Zeeb #include "main.h" 9*90aac0d8SBjoern A. Zeeb #include "debug.h" 10*90aac0d8SBjoern A. Zeeb #include "reg.h" 11*90aac0d8SBjoern A. Zeeb #include "tx.h" 12*90aac0d8SBjoern A. Zeeb #include "rx.h" 13*90aac0d8SBjoern A. Zeeb #include "fw.h" 14*90aac0d8SBjoern A. Zeeb #include "ps.h" 15*90aac0d8SBjoern A. Zeeb #include "usb.h" 16*90aac0d8SBjoern A. Zeeb 17*90aac0d8SBjoern A. Zeeb #define RTW_USB_MAX_RXQ_LEN 512 18*90aac0d8SBjoern A. Zeeb 19*90aac0d8SBjoern A. Zeeb struct rtw_usb_txcb { 20*90aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev; 21*90aac0d8SBjoern A. Zeeb struct sk_buff_head tx_ack_queue; 22*90aac0d8SBjoern A. Zeeb }; 23*90aac0d8SBjoern A. Zeeb 24*90aac0d8SBjoern A. Zeeb static void rtw_usb_fill_tx_checksum(struct rtw_usb *rtwusb, 25*90aac0d8SBjoern A. Zeeb struct sk_buff *skb, int agg_num) 26*90aac0d8SBjoern A. Zeeb { 27*90aac0d8SBjoern A. Zeeb struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data; 28*90aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = rtwusb->rtwdev; 29*90aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info pkt_info; 30*90aac0d8SBjoern A. Zeeb 31*90aac0d8SBjoern A. Zeeb le32p_replace_bits(&tx_desc->w7, agg_num, RTW_TX_DESC_W7_DMA_TXAGG_NUM); 32*90aac0d8SBjoern A. Zeeb pkt_info.pkt_offset = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_PKT_OFFSET); 33*90aac0d8SBjoern A. Zeeb rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, skb->data); 34*90aac0d8SBjoern A. Zeeb } 35*90aac0d8SBjoern A. Zeeb 36*90aac0d8SBjoern A. Zeeb static u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len) 37*90aac0d8SBjoern A. Zeeb { 38*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 39*90aac0d8SBjoern A. Zeeb struct usb_device *udev = rtwusb->udev; 40*90aac0d8SBjoern A. Zeeb __le32 *data; 41*90aac0d8SBjoern A. Zeeb unsigned long flags; 42*90aac0d8SBjoern A. Zeeb int idx, ret; 43*90aac0d8SBjoern A. Zeeb static int count; 44*90aac0d8SBjoern A. Zeeb 45*90aac0d8SBjoern A. Zeeb spin_lock_irqsave(&rtwusb->usb_lock, flags); 46*90aac0d8SBjoern A. Zeeb 47*90aac0d8SBjoern A. Zeeb idx = rtwusb->usb_data_index; 48*90aac0d8SBjoern A. Zeeb rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1); 49*90aac0d8SBjoern A. Zeeb 50*90aac0d8SBjoern A. Zeeb spin_unlock_irqrestore(&rtwusb->usb_lock, flags); 51*90aac0d8SBjoern A. Zeeb 52*90aac0d8SBjoern A. Zeeb data = &rtwusb->usb_data[idx]; 53*90aac0d8SBjoern A. Zeeb 54*90aac0d8SBjoern A. Zeeb ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 55*90aac0d8SBjoern A. Zeeb RTW_USB_CMD_REQ, RTW_USB_CMD_READ, addr, 56*90aac0d8SBjoern A. Zeeb RTW_USB_VENQT_CMD_IDX, data, len, 1000); 57*90aac0d8SBjoern A. Zeeb if (ret < 0 && ret != -ENODEV && count++ < 4) 58*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "read register 0x%x failed with %d\n", 59*90aac0d8SBjoern A. Zeeb addr, ret); 60*90aac0d8SBjoern A. Zeeb 61*90aac0d8SBjoern A. Zeeb return le32_to_cpu(*data); 62*90aac0d8SBjoern A. Zeeb } 63*90aac0d8SBjoern A. Zeeb 64*90aac0d8SBjoern A. Zeeb static u8 rtw_usb_read8(struct rtw_dev *rtwdev, u32 addr) 65*90aac0d8SBjoern A. Zeeb { 66*90aac0d8SBjoern A. Zeeb return (u8)rtw_usb_read(rtwdev, addr, 1); 67*90aac0d8SBjoern A. Zeeb } 68*90aac0d8SBjoern A. Zeeb 69*90aac0d8SBjoern A. Zeeb static u16 rtw_usb_read16(struct rtw_dev *rtwdev, u32 addr) 70*90aac0d8SBjoern A. Zeeb { 71*90aac0d8SBjoern A. Zeeb return (u16)rtw_usb_read(rtwdev, addr, 2); 72*90aac0d8SBjoern A. Zeeb } 73*90aac0d8SBjoern A. Zeeb 74*90aac0d8SBjoern A. Zeeb static u32 rtw_usb_read32(struct rtw_dev *rtwdev, u32 addr) 75*90aac0d8SBjoern A. Zeeb { 76*90aac0d8SBjoern A. Zeeb return (u32)rtw_usb_read(rtwdev, addr, 4); 77*90aac0d8SBjoern A. Zeeb } 78*90aac0d8SBjoern A. Zeeb 79*90aac0d8SBjoern A. Zeeb static void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len) 80*90aac0d8SBjoern A. Zeeb { 81*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = (struct rtw_usb *)rtwdev->priv; 82*90aac0d8SBjoern A. Zeeb struct usb_device *udev = rtwusb->udev; 83*90aac0d8SBjoern A. Zeeb unsigned long flags; 84*90aac0d8SBjoern A. Zeeb __le32 *data; 85*90aac0d8SBjoern A. Zeeb int idx, ret; 86*90aac0d8SBjoern A. Zeeb static int count; 87*90aac0d8SBjoern A. Zeeb 88*90aac0d8SBjoern A. Zeeb spin_lock_irqsave(&rtwusb->usb_lock, flags); 89*90aac0d8SBjoern A. Zeeb 90*90aac0d8SBjoern A. Zeeb idx = rtwusb->usb_data_index; 91*90aac0d8SBjoern A. Zeeb rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1); 92*90aac0d8SBjoern A. Zeeb 93*90aac0d8SBjoern A. Zeeb spin_unlock_irqrestore(&rtwusb->usb_lock, flags); 94*90aac0d8SBjoern A. Zeeb 95*90aac0d8SBjoern A. Zeeb data = &rtwusb->usb_data[idx]; 96*90aac0d8SBjoern A. Zeeb 97*90aac0d8SBjoern A. Zeeb *data = cpu_to_le32(val); 98*90aac0d8SBjoern A. Zeeb 99*90aac0d8SBjoern A. Zeeb ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 100*90aac0d8SBjoern A. Zeeb RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE, 101*90aac0d8SBjoern A. Zeeb addr, 0, data, len, 30000); 102*90aac0d8SBjoern A. Zeeb if (ret < 0 && ret != -ENODEV && count++ < 4) 103*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "write register 0x%x failed with %d\n", 104*90aac0d8SBjoern A. Zeeb addr, ret); 105*90aac0d8SBjoern A. Zeeb } 106*90aac0d8SBjoern A. Zeeb 107*90aac0d8SBjoern A. Zeeb static void rtw_usb_write8(struct rtw_dev *rtwdev, u32 addr, u8 val) 108*90aac0d8SBjoern A. Zeeb { 109*90aac0d8SBjoern A. Zeeb rtw_usb_write(rtwdev, addr, val, 1); 110*90aac0d8SBjoern A. Zeeb } 111*90aac0d8SBjoern A. Zeeb 112*90aac0d8SBjoern A. Zeeb static void rtw_usb_write16(struct rtw_dev *rtwdev, u32 addr, u16 val) 113*90aac0d8SBjoern A. Zeeb { 114*90aac0d8SBjoern A. Zeeb rtw_usb_write(rtwdev, addr, val, 2); 115*90aac0d8SBjoern A. Zeeb } 116*90aac0d8SBjoern A. Zeeb 117*90aac0d8SBjoern A. Zeeb static void rtw_usb_write32(struct rtw_dev *rtwdev, u32 addr, u32 val) 118*90aac0d8SBjoern A. Zeeb { 119*90aac0d8SBjoern A. Zeeb rtw_usb_write(rtwdev, addr, val, 4); 120*90aac0d8SBjoern A. Zeeb } 121*90aac0d8SBjoern A. Zeeb 122*90aac0d8SBjoern A. Zeeb static int dma_mapping_to_ep(enum rtw_dma_mapping dma_mapping) 123*90aac0d8SBjoern A. Zeeb { 124*90aac0d8SBjoern A. Zeeb switch (dma_mapping) { 125*90aac0d8SBjoern A. Zeeb case RTW_DMA_MAPPING_HIGH: 126*90aac0d8SBjoern A. Zeeb return 0; 127*90aac0d8SBjoern A. Zeeb case RTW_DMA_MAPPING_NORMAL: 128*90aac0d8SBjoern A. Zeeb return 1; 129*90aac0d8SBjoern A. Zeeb case RTW_DMA_MAPPING_LOW: 130*90aac0d8SBjoern A. Zeeb return 2; 131*90aac0d8SBjoern A. Zeeb case RTW_DMA_MAPPING_EXTRA: 132*90aac0d8SBjoern A. Zeeb return 3; 133*90aac0d8SBjoern A. Zeeb default: 134*90aac0d8SBjoern A. Zeeb return -EINVAL; 135*90aac0d8SBjoern A. Zeeb } 136*90aac0d8SBjoern A. Zeeb } 137*90aac0d8SBjoern A. Zeeb 138*90aac0d8SBjoern A. Zeeb static int rtw_usb_parse(struct rtw_dev *rtwdev, 139*90aac0d8SBjoern A. Zeeb struct usb_interface *interface) 140*90aac0d8SBjoern A. Zeeb { 141*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 142*90aac0d8SBjoern A. Zeeb struct usb_host_interface *host_interface = &interface->altsetting[0]; 143*90aac0d8SBjoern A. Zeeb struct usb_interface_descriptor *interface_desc = &host_interface->desc; 144*90aac0d8SBjoern A. Zeeb struct usb_endpoint_descriptor *endpoint; 145*90aac0d8SBjoern A. Zeeb int num_out_pipes = 0; 146*90aac0d8SBjoern A. Zeeb int i; 147*90aac0d8SBjoern A. Zeeb u8 num; 148*90aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 149*90aac0d8SBjoern A. Zeeb const struct rtw_rqpn *rqpn; 150*90aac0d8SBjoern A. Zeeb 151*90aac0d8SBjoern A. Zeeb for (i = 0; i < interface_desc->bNumEndpoints; i++) { 152*90aac0d8SBjoern A. Zeeb endpoint = &host_interface->endpoint[i].desc; 153*90aac0d8SBjoern A. Zeeb num = usb_endpoint_num(endpoint); 154*90aac0d8SBjoern A. Zeeb 155*90aac0d8SBjoern A. Zeeb if (usb_endpoint_dir_in(endpoint) && 156*90aac0d8SBjoern A. Zeeb usb_endpoint_xfer_bulk(endpoint)) { 157*90aac0d8SBjoern A. Zeeb if (rtwusb->pipe_in) { 158*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "IN pipes overflow\n"); 159*90aac0d8SBjoern A. Zeeb return -EINVAL; 160*90aac0d8SBjoern A. Zeeb } 161*90aac0d8SBjoern A. Zeeb 162*90aac0d8SBjoern A. Zeeb rtwusb->pipe_in = num; 163*90aac0d8SBjoern A. Zeeb } 164*90aac0d8SBjoern A. Zeeb 165*90aac0d8SBjoern A. Zeeb if (usb_endpoint_dir_in(endpoint) && 166*90aac0d8SBjoern A. Zeeb usb_endpoint_xfer_int(endpoint)) { 167*90aac0d8SBjoern A. Zeeb if (rtwusb->pipe_interrupt) { 168*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "INT pipes overflow\n"); 169*90aac0d8SBjoern A. Zeeb return -EINVAL; 170*90aac0d8SBjoern A. Zeeb } 171*90aac0d8SBjoern A. Zeeb 172*90aac0d8SBjoern A. Zeeb rtwusb->pipe_interrupt = num; 173*90aac0d8SBjoern A. Zeeb } 174*90aac0d8SBjoern A. Zeeb 175*90aac0d8SBjoern A. Zeeb if (usb_endpoint_dir_out(endpoint) && 176*90aac0d8SBjoern A. Zeeb usb_endpoint_xfer_bulk(endpoint)) { 177*90aac0d8SBjoern A. Zeeb if (num_out_pipes >= ARRAY_SIZE(rtwusb->out_ep)) { 178*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "OUT pipes overflow\n"); 179*90aac0d8SBjoern A. Zeeb return -EINVAL; 180*90aac0d8SBjoern A. Zeeb } 181*90aac0d8SBjoern A. Zeeb 182*90aac0d8SBjoern A. Zeeb rtwusb->out_ep[num_out_pipes++] = num; 183*90aac0d8SBjoern A. Zeeb } 184*90aac0d8SBjoern A. Zeeb } 185*90aac0d8SBjoern A. Zeeb 186*90aac0d8SBjoern A. Zeeb rtwdev->hci.bulkout_num = num_out_pipes; 187*90aac0d8SBjoern A. Zeeb 188*90aac0d8SBjoern A. Zeeb if (num_out_pipes < 1 || num_out_pipes > 4) { 189*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "invalid number of endpoints %d\n", num_out_pipes); 190*90aac0d8SBjoern A. Zeeb return -EINVAL; 191*90aac0d8SBjoern A. Zeeb } 192*90aac0d8SBjoern A. Zeeb 193*90aac0d8SBjoern A. Zeeb rqpn = &chip->rqpn_table[num_out_pipes]; 194*90aac0d8SBjoern A. Zeeb 195*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID0] = dma_mapping_to_ep(rqpn->dma_map_be); 196*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID1] = dma_mapping_to_ep(rqpn->dma_map_bk); 197*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID2] = dma_mapping_to_ep(rqpn->dma_map_bk); 198*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID3] = dma_mapping_to_ep(rqpn->dma_map_be); 199*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID4] = dma_mapping_to_ep(rqpn->dma_map_vi); 200*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID5] = dma_mapping_to_ep(rqpn->dma_map_vi); 201*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID6] = dma_mapping_to_ep(rqpn->dma_map_vo); 202*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID7] = dma_mapping_to_ep(rqpn->dma_map_vo); 203*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID8] = -EINVAL; 204*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID9] = -EINVAL; 205*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID10] = -EINVAL; 206*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID11] = -EINVAL; 207*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID12] = -EINVAL; 208*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID13] = -EINVAL; 209*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID14] = -EINVAL; 210*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID15] = -EINVAL; 211*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_BEACON] = dma_mapping_to_ep(rqpn->dma_map_hi); 212*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_HIGH] = dma_mapping_to_ep(rqpn->dma_map_hi); 213*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_MGMT] = dma_mapping_to_ep(rqpn->dma_map_mg); 214*90aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_H2C] = dma_mapping_to_ep(rqpn->dma_map_hi); 215*90aac0d8SBjoern A. Zeeb 216*90aac0d8SBjoern A. Zeeb return 0; 217*90aac0d8SBjoern A. Zeeb } 218*90aac0d8SBjoern A. Zeeb 219*90aac0d8SBjoern A. Zeeb static void rtw_usb_write_port_tx_complete(struct urb *urb) 220*90aac0d8SBjoern A. Zeeb { 221*90aac0d8SBjoern A. Zeeb struct rtw_usb_txcb *txcb = urb->context; 222*90aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = txcb->rtwdev; 223*90aac0d8SBjoern A. Zeeb struct ieee80211_hw *hw = rtwdev->hw; 224*90aac0d8SBjoern A. Zeeb 225*90aac0d8SBjoern A. Zeeb while (true) { 226*90aac0d8SBjoern A. Zeeb struct sk_buff *skb = skb_dequeue(&txcb->tx_ack_queue); 227*90aac0d8SBjoern A. Zeeb struct ieee80211_tx_info *info; 228*90aac0d8SBjoern A. Zeeb struct rtw_usb_tx_data *tx_data; 229*90aac0d8SBjoern A. Zeeb 230*90aac0d8SBjoern A. Zeeb if (!skb) 231*90aac0d8SBjoern A. Zeeb break; 232*90aac0d8SBjoern A. Zeeb 233*90aac0d8SBjoern A. Zeeb info = IEEE80211_SKB_CB(skb); 234*90aac0d8SBjoern A. Zeeb tx_data = rtw_usb_get_tx_data(skb); 235*90aac0d8SBjoern A. Zeeb 236*90aac0d8SBjoern A. Zeeb /* enqueue to wait for tx report */ 237*90aac0d8SBjoern A. Zeeb if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { 238*90aac0d8SBjoern A. Zeeb rtw_tx_report_enqueue(rtwdev, skb, tx_data->sn); 239*90aac0d8SBjoern A. Zeeb continue; 240*90aac0d8SBjoern A. Zeeb } 241*90aac0d8SBjoern A. Zeeb 242*90aac0d8SBjoern A. Zeeb /* always ACK for others, then they won't be marked as drop */ 243*90aac0d8SBjoern A. Zeeb ieee80211_tx_info_clear_status(info); 244*90aac0d8SBjoern A. Zeeb if (info->flags & IEEE80211_TX_CTL_NO_ACK) 245*90aac0d8SBjoern A. Zeeb info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 246*90aac0d8SBjoern A. Zeeb else 247*90aac0d8SBjoern A. Zeeb info->flags |= IEEE80211_TX_STAT_ACK; 248*90aac0d8SBjoern A. Zeeb 249*90aac0d8SBjoern A. Zeeb ieee80211_tx_status_irqsafe(hw, skb); 250*90aac0d8SBjoern A. Zeeb } 251*90aac0d8SBjoern A. Zeeb 252*90aac0d8SBjoern A. Zeeb kfree(txcb); 253*90aac0d8SBjoern A. Zeeb } 254*90aac0d8SBjoern A. Zeeb 255*90aac0d8SBjoern A. Zeeb static int qsel_to_ep(struct rtw_usb *rtwusb, unsigned int qsel) 256*90aac0d8SBjoern A. Zeeb { 257*90aac0d8SBjoern A. Zeeb if (qsel >= ARRAY_SIZE(rtwusb->qsel_to_ep)) 258*90aac0d8SBjoern A. Zeeb return -EINVAL; 259*90aac0d8SBjoern A. Zeeb 260*90aac0d8SBjoern A. Zeeb return rtwusb->qsel_to_ep[qsel]; 261*90aac0d8SBjoern A. Zeeb } 262*90aac0d8SBjoern A. Zeeb 263*90aac0d8SBjoern A. Zeeb static int rtw_usb_write_port(struct rtw_dev *rtwdev, u8 qsel, struct sk_buff *skb, 264*90aac0d8SBjoern A. Zeeb usb_complete_t cb, void *context) 265*90aac0d8SBjoern A. Zeeb { 266*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 267*90aac0d8SBjoern A. Zeeb struct usb_device *usbd = rtwusb->udev; 268*90aac0d8SBjoern A. Zeeb struct urb *urb; 269*90aac0d8SBjoern A. Zeeb unsigned int pipe; 270*90aac0d8SBjoern A. Zeeb int ret; 271*90aac0d8SBjoern A. Zeeb int ep = qsel_to_ep(rtwusb, qsel); 272*90aac0d8SBjoern A. Zeeb 273*90aac0d8SBjoern A. Zeeb if (ep < 0) 274*90aac0d8SBjoern A. Zeeb return ep; 275*90aac0d8SBjoern A. Zeeb 276*90aac0d8SBjoern A. Zeeb pipe = usb_sndbulkpipe(usbd, rtwusb->out_ep[ep]); 277*90aac0d8SBjoern A. Zeeb urb = usb_alloc_urb(0, GFP_ATOMIC); 278*90aac0d8SBjoern A. Zeeb if (!urb) 279*90aac0d8SBjoern A. Zeeb return -ENOMEM; 280*90aac0d8SBjoern A. Zeeb 281*90aac0d8SBjoern A. Zeeb usb_fill_bulk_urb(urb, usbd, pipe, skb->data, skb->len, cb, context); 282*90aac0d8SBjoern A. Zeeb urb->transfer_flags |= URB_ZERO_PACKET; 283*90aac0d8SBjoern A. Zeeb ret = usb_submit_urb(urb, GFP_ATOMIC); 284*90aac0d8SBjoern A. Zeeb 285*90aac0d8SBjoern A. Zeeb usb_free_urb(urb); 286*90aac0d8SBjoern A. Zeeb 287*90aac0d8SBjoern A. Zeeb return ret; 288*90aac0d8SBjoern A. Zeeb } 289*90aac0d8SBjoern A. Zeeb 290*90aac0d8SBjoern A. Zeeb static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list) 291*90aac0d8SBjoern A. Zeeb { 292*90aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = rtwusb->rtwdev; 293*90aac0d8SBjoern A. Zeeb struct rtw_tx_desc *tx_desc; 294*90aac0d8SBjoern A. Zeeb struct rtw_usb_txcb *txcb; 295*90aac0d8SBjoern A. Zeeb struct sk_buff *skb_head; 296*90aac0d8SBjoern A. Zeeb struct sk_buff *skb_iter; 297*90aac0d8SBjoern A. Zeeb int agg_num = 0; 298*90aac0d8SBjoern A. Zeeb unsigned int align_next = 0; 299*90aac0d8SBjoern A. Zeeb u8 qsel; 300*90aac0d8SBjoern A. Zeeb 301*90aac0d8SBjoern A. Zeeb if (skb_queue_empty(list)) 302*90aac0d8SBjoern A. Zeeb return false; 303*90aac0d8SBjoern A. Zeeb 304*90aac0d8SBjoern A. Zeeb txcb = kmalloc(sizeof(*txcb), GFP_ATOMIC); 305*90aac0d8SBjoern A. Zeeb if (!txcb) 306*90aac0d8SBjoern A. Zeeb return false; 307*90aac0d8SBjoern A. Zeeb 308*90aac0d8SBjoern A. Zeeb txcb->rtwdev = rtwdev; 309*90aac0d8SBjoern A. Zeeb skb_queue_head_init(&txcb->tx_ack_queue); 310*90aac0d8SBjoern A. Zeeb 311*90aac0d8SBjoern A. Zeeb skb_iter = skb_dequeue(list); 312*90aac0d8SBjoern A. Zeeb 313*90aac0d8SBjoern A. Zeeb if (skb_queue_empty(list)) { 314*90aac0d8SBjoern A. Zeeb skb_head = skb_iter; 315*90aac0d8SBjoern A. Zeeb goto queue; 316*90aac0d8SBjoern A. Zeeb } 317*90aac0d8SBjoern A. Zeeb 318*90aac0d8SBjoern A. Zeeb skb_head = dev_alloc_skb(RTW_USB_MAX_XMITBUF_SZ); 319*90aac0d8SBjoern A. Zeeb if (!skb_head) { 320*90aac0d8SBjoern A. Zeeb skb_head = skb_iter; 321*90aac0d8SBjoern A. Zeeb goto queue; 322*90aac0d8SBjoern A. Zeeb } 323*90aac0d8SBjoern A. Zeeb 324*90aac0d8SBjoern A. Zeeb while (skb_iter) { 325*90aac0d8SBjoern A. Zeeb unsigned long flags; 326*90aac0d8SBjoern A. Zeeb 327*90aac0d8SBjoern A. Zeeb skb_put(skb_head, align_next); 328*90aac0d8SBjoern A. Zeeb skb_put_data(skb_head, skb_iter->data, skb_iter->len); 329*90aac0d8SBjoern A. Zeeb 330*90aac0d8SBjoern A. Zeeb align_next = ALIGN(skb_iter->len, 8) - skb_iter->len; 331*90aac0d8SBjoern A. Zeeb 332*90aac0d8SBjoern A. Zeeb agg_num++; 333*90aac0d8SBjoern A. Zeeb 334*90aac0d8SBjoern A. Zeeb skb_queue_tail(&txcb->tx_ack_queue, skb_iter); 335*90aac0d8SBjoern A. Zeeb 336*90aac0d8SBjoern A. Zeeb spin_lock_irqsave(&list->lock, flags); 337*90aac0d8SBjoern A. Zeeb 338*90aac0d8SBjoern A. Zeeb skb_iter = skb_peek(list); 339*90aac0d8SBjoern A. Zeeb 340*90aac0d8SBjoern A. Zeeb if (skb_iter && skb_iter->len + skb_head->len <= RTW_USB_MAX_XMITBUF_SZ) 341*90aac0d8SBjoern A. Zeeb __skb_unlink(skb_iter, list); 342*90aac0d8SBjoern A. Zeeb else 343*90aac0d8SBjoern A. Zeeb skb_iter = NULL; 344*90aac0d8SBjoern A. Zeeb spin_unlock_irqrestore(&list->lock, flags); 345*90aac0d8SBjoern A. Zeeb } 346*90aac0d8SBjoern A. Zeeb 347*90aac0d8SBjoern A. Zeeb if (agg_num > 1) 348*90aac0d8SBjoern A. Zeeb rtw_usb_fill_tx_checksum(rtwusb, skb_head, agg_num); 349*90aac0d8SBjoern A. Zeeb 350*90aac0d8SBjoern A. Zeeb queue: 351*90aac0d8SBjoern A. Zeeb skb_queue_tail(&txcb->tx_ack_queue, skb_head); 352*90aac0d8SBjoern A. Zeeb tx_desc = (struct rtw_tx_desc *)skb_head->data; 353*90aac0d8SBjoern A. Zeeb qsel = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_QSEL); 354*90aac0d8SBjoern A. Zeeb 355*90aac0d8SBjoern A. Zeeb rtw_usb_write_port(rtwdev, qsel, skb_head, rtw_usb_write_port_tx_complete, txcb); 356*90aac0d8SBjoern A. Zeeb 357*90aac0d8SBjoern A. Zeeb return true; 358*90aac0d8SBjoern A. Zeeb } 359*90aac0d8SBjoern A. Zeeb 360*90aac0d8SBjoern A. Zeeb static void rtw_usb_tx_handler(struct work_struct *work) 361*90aac0d8SBjoern A. Zeeb { 362*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, tx_work); 363*90aac0d8SBjoern A. Zeeb int i, limit; 364*90aac0d8SBjoern A. Zeeb 365*90aac0d8SBjoern A. Zeeb for (i = ARRAY_SIZE(rtwusb->tx_queue) - 1; i >= 0; i--) { 366*90aac0d8SBjoern A. Zeeb for (limit = 0; limit < 200; limit++) { 367*90aac0d8SBjoern A. Zeeb struct sk_buff_head *list = &rtwusb->tx_queue[i]; 368*90aac0d8SBjoern A. Zeeb 369*90aac0d8SBjoern A. Zeeb if (!rtw_usb_tx_agg_skb(rtwusb, list)) 370*90aac0d8SBjoern A. Zeeb break; 371*90aac0d8SBjoern A. Zeeb } 372*90aac0d8SBjoern A. Zeeb } 373*90aac0d8SBjoern A. Zeeb } 374*90aac0d8SBjoern A. Zeeb 375*90aac0d8SBjoern A. Zeeb static void rtw_usb_tx_queue_purge(struct rtw_usb *rtwusb) 376*90aac0d8SBjoern A. Zeeb { 377*90aac0d8SBjoern A. Zeeb int i; 378*90aac0d8SBjoern A. Zeeb 379*90aac0d8SBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) 380*90aac0d8SBjoern A. Zeeb skb_queue_purge(&rtwusb->tx_queue[i]); 381*90aac0d8SBjoern A. Zeeb } 382*90aac0d8SBjoern A. Zeeb 383*90aac0d8SBjoern A. Zeeb static void rtw_usb_write_port_complete(struct urb *urb) 384*90aac0d8SBjoern A. Zeeb { 385*90aac0d8SBjoern A. Zeeb struct sk_buff *skb = urb->context; 386*90aac0d8SBjoern A. Zeeb 387*90aac0d8SBjoern A. Zeeb dev_kfree_skb_any(skb); 388*90aac0d8SBjoern A. Zeeb } 389*90aac0d8SBjoern A. Zeeb 390*90aac0d8SBjoern A. Zeeb static int rtw_usb_write_data(struct rtw_dev *rtwdev, 391*90aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info *pkt_info, 392*90aac0d8SBjoern A. Zeeb u8 *buf) 393*90aac0d8SBjoern A. Zeeb { 394*90aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 395*90aac0d8SBjoern A. Zeeb struct sk_buff *skb; 396*90aac0d8SBjoern A. Zeeb unsigned int desclen, headsize, size; 397*90aac0d8SBjoern A. Zeeb u8 qsel; 398*90aac0d8SBjoern A. Zeeb int ret = 0; 399*90aac0d8SBjoern A. Zeeb 400*90aac0d8SBjoern A. Zeeb size = pkt_info->tx_pkt_size; 401*90aac0d8SBjoern A. Zeeb qsel = pkt_info->qsel; 402*90aac0d8SBjoern A. Zeeb desclen = chip->tx_pkt_desc_sz; 403*90aac0d8SBjoern A. Zeeb headsize = pkt_info->offset ? pkt_info->offset : desclen; 404*90aac0d8SBjoern A. Zeeb 405*90aac0d8SBjoern A. Zeeb skb = dev_alloc_skb(headsize + size); 406*90aac0d8SBjoern A. Zeeb if (unlikely(!skb)) 407*90aac0d8SBjoern A. Zeeb return -ENOMEM; 408*90aac0d8SBjoern A. Zeeb 409*90aac0d8SBjoern A. Zeeb skb_reserve(skb, headsize); 410*90aac0d8SBjoern A. Zeeb skb_put_data(skb, buf, size); 411*90aac0d8SBjoern A. Zeeb skb_push(skb, headsize); 412*90aac0d8SBjoern A. Zeeb memset(skb->data, 0, headsize); 413*90aac0d8SBjoern A. Zeeb rtw_tx_fill_tx_desc(pkt_info, skb); 414*90aac0d8SBjoern A. Zeeb rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); 415*90aac0d8SBjoern A. Zeeb 416*90aac0d8SBjoern A. Zeeb ret = rtw_usb_write_port(rtwdev, qsel, skb, 417*90aac0d8SBjoern A. Zeeb rtw_usb_write_port_complete, skb); 418*90aac0d8SBjoern A. Zeeb if (unlikely(ret)) 419*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to do USB write, ret=%d\n", ret); 420*90aac0d8SBjoern A. Zeeb 421*90aac0d8SBjoern A. Zeeb return ret; 422*90aac0d8SBjoern A. Zeeb } 423*90aac0d8SBjoern A. Zeeb 424*90aac0d8SBjoern A. Zeeb static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, 425*90aac0d8SBjoern A. Zeeb u32 size) 426*90aac0d8SBjoern A. Zeeb { 427*90aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 428*90aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info pkt_info = {0}; 429*90aac0d8SBjoern A. Zeeb 430*90aac0d8SBjoern A. Zeeb pkt_info.tx_pkt_size = size; 431*90aac0d8SBjoern A. Zeeb pkt_info.qsel = TX_DESC_QSEL_BEACON; 432*90aac0d8SBjoern A. Zeeb pkt_info.offset = chip->tx_pkt_desc_sz; 433*90aac0d8SBjoern A. Zeeb 434*90aac0d8SBjoern A. Zeeb return rtw_usb_write_data(rtwdev, &pkt_info, buf); 435*90aac0d8SBjoern A. Zeeb } 436*90aac0d8SBjoern A. Zeeb 437*90aac0d8SBjoern A. Zeeb static int rtw_usb_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size) 438*90aac0d8SBjoern A. Zeeb { 439*90aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info pkt_info = {0}; 440*90aac0d8SBjoern A. Zeeb 441*90aac0d8SBjoern A. Zeeb pkt_info.tx_pkt_size = size; 442*90aac0d8SBjoern A. Zeeb pkt_info.qsel = TX_DESC_QSEL_H2C; 443*90aac0d8SBjoern A. Zeeb 444*90aac0d8SBjoern A. Zeeb return rtw_usb_write_data(rtwdev, &pkt_info, buf); 445*90aac0d8SBjoern A. Zeeb } 446*90aac0d8SBjoern A. Zeeb 447*90aac0d8SBjoern A. Zeeb static u8 rtw_usb_tx_queue_mapping_to_qsel(struct sk_buff *skb) 448*90aac0d8SBjoern A. Zeeb { 449*90aac0d8SBjoern A. Zeeb struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 450*90aac0d8SBjoern A. Zeeb __le16 fc = hdr->frame_control; 451*90aac0d8SBjoern A. Zeeb u8 qsel; 452*90aac0d8SBjoern A. Zeeb 453*90aac0d8SBjoern A. Zeeb if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))) 454*90aac0d8SBjoern A. Zeeb qsel = TX_DESC_QSEL_MGMT; 455*90aac0d8SBjoern A. Zeeb else if (is_broadcast_ether_addr(hdr->addr1) || 456*90aac0d8SBjoern A. Zeeb is_multicast_ether_addr(hdr->addr1)) 457*90aac0d8SBjoern A. Zeeb qsel = TX_DESC_QSEL_HIGH; 458*90aac0d8SBjoern A. Zeeb else if (skb_get_queue_mapping(skb) <= IEEE80211_AC_BK) 459*90aac0d8SBjoern A. Zeeb qsel = skb->priority; 460*90aac0d8SBjoern A. Zeeb else 461*90aac0d8SBjoern A. Zeeb qsel = TX_DESC_QSEL_BEACON; 462*90aac0d8SBjoern A. Zeeb 463*90aac0d8SBjoern A. Zeeb return qsel; 464*90aac0d8SBjoern A. Zeeb } 465*90aac0d8SBjoern A. Zeeb 466*90aac0d8SBjoern A. Zeeb static int rtw_usb_tx_write(struct rtw_dev *rtwdev, 467*90aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info *pkt_info, 468*90aac0d8SBjoern A. Zeeb struct sk_buff *skb) 469*90aac0d8SBjoern A. Zeeb { 470*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 471*90aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 472*90aac0d8SBjoern A. Zeeb struct rtw_usb_tx_data *tx_data; 473*90aac0d8SBjoern A. Zeeb u8 *pkt_desc; 474*90aac0d8SBjoern A. Zeeb int ep; 475*90aac0d8SBjoern A. Zeeb 476*90aac0d8SBjoern A. Zeeb pkt_info->qsel = rtw_usb_tx_queue_mapping_to_qsel(skb); 477*90aac0d8SBjoern A. Zeeb pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); 478*90aac0d8SBjoern A. Zeeb memset(pkt_desc, 0, chip->tx_pkt_desc_sz); 479*90aac0d8SBjoern A. Zeeb ep = qsel_to_ep(rtwusb, pkt_info->qsel); 480*90aac0d8SBjoern A. Zeeb rtw_tx_fill_tx_desc(pkt_info, skb); 481*90aac0d8SBjoern A. Zeeb rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); 482*90aac0d8SBjoern A. Zeeb tx_data = rtw_usb_get_tx_data(skb); 483*90aac0d8SBjoern A. Zeeb tx_data->sn = pkt_info->sn; 484*90aac0d8SBjoern A. Zeeb 485*90aac0d8SBjoern A. Zeeb skb_queue_tail(&rtwusb->tx_queue[ep], skb); 486*90aac0d8SBjoern A. Zeeb 487*90aac0d8SBjoern A. Zeeb return 0; 488*90aac0d8SBjoern A. Zeeb } 489*90aac0d8SBjoern A. Zeeb 490*90aac0d8SBjoern A. Zeeb static void rtw_usb_tx_kick_off(struct rtw_dev *rtwdev) 491*90aac0d8SBjoern A. Zeeb { 492*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 493*90aac0d8SBjoern A. Zeeb 494*90aac0d8SBjoern A. Zeeb queue_work(rtwusb->txwq, &rtwusb->tx_work); 495*90aac0d8SBjoern A. Zeeb } 496*90aac0d8SBjoern A. Zeeb 497*90aac0d8SBjoern A. Zeeb static void rtw_usb_rx_handler(struct work_struct *work) 498*90aac0d8SBjoern A. Zeeb { 499*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, rx_work); 500*90aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = rtwusb->rtwdev; 501*90aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 502*90aac0d8SBjoern A. Zeeb struct rtw_rx_pkt_stat pkt_stat; 503*90aac0d8SBjoern A. Zeeb struct ieee80211_rx_status rx_status; 504*90aac0d8SBjoern A. Zeeb struct sk_buff *skb; 505*90aac0d8SBjoern A. Zeeb u32 pkt_desc_sz = chip->rx_pkt_desc_sz; 506*90aac0d8SBjoern A. Zeeb u32 pkt_offset; 507*90aac0d8SBjoern A. Zeeb u8 *rx_desc; 508*90aac0d8SBjoern A. Zeeb int limit; 509*90aac0d8SBjoern A. Zeeb 510*90aac0d8SBjoern A. Zeeb for (limit = 0; limit < 200; limit++) { 511*90aac0d8SBjoern A. Zeeb skb = skb_dequeue(&rtwusb->rx_queue); 512*90aac0d8SBjoern A. Zeeb if (!skb) 513*90aac0d8SBjoern A. Zeeb break; 514*90aac0d8SBjoern A. Zeeb 515*90aac0d8SBjoern A. Zeeb rx_desc = skb->data; 516*90aac0d8SBjoern A. Zeeb chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, 517*90aac0d8SBjoern A. Zeeb &rx_status); 518*90aac0d8SBjoern A. Zeeb pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + 519*90aac0d8SBjoern A. Zeeb pkt_stat.shift; 520*90aac0d8SBjoern A. Zeeb 521*90aac0d8SBjoern A. Zeeb if (pkt_stat.is_c2h) { 522*90aac0d8SBjoern A. Zeeb skb_put(skb, pkt_stat.pkt_len + pkt_offset); 523*90aac0d8SBjoern A. Zeeb rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, skb); 524*90aac0d8SBjoern A. Zeeb continue; 525*90aac0d8SBjoern A. Zeeb } 526*90aac0d8SBjoern A. Zeeb 527*90aac0d8SBjoern A. Zeeb if (skb_queue_len(&rtwusb->rx_queue) >= RTW_USB_MAX_RXQ_LEN) { 528*90aac0d8SBjoern A. Zeeb dev_dbg_ratelimited(rtwdev->dev, "failed to get rx_queue, overflow\n"); 529*90aac0d8SBjoern A. Zeeb dev_kfree_skb_any(skb); 530*90aac0d8SBjoern A. Zeeb continue; 531*90aac0d8SBjoern A. Zeeb } 532*90aac0d8SBjoern A. Zeeb 533*90aac0d8SBjoern A. Zeeb skb_put(skb, pkt_stat.pkt_len); 534*90aac0d8SBjoern A. Zeeb skb_reserve(skb, pkt_offset); 535*90aac0d8SBjoern A. Zeeb memcpy(skb->cb, &rx_status, sizeof(rx_status)); 536*90aac0d8SBjoern A. Zeeb ieee80211_rx_irqsafe(rtwdev->hw, skb); 537*90aac0d8SBjoern A. Zeeb } 538*90aac0d8SBjoern A. Zeeb } 539*90aac0d8SBjoern A. Zeeb 540*90aac0d8SBjoern A. Zeeb static void rtw_usb_read_port_complete(struct urb *urb); 541*90aac0d8SBjoern A. Zeeb 542*90aac0d8SBjoern A. Zeeb static void rtw_usb_rx_resubmit(struct rtw_usb *rtwusb, struct rx_usb_ctrl_block *rxcb) 543*90aac0d8SBjoern A. Zeeb { 544*90aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = rtwusb->rtwdev; 545*90aac0d8SBjoern A. Zeeb int error; 546*90aac0d8SBjoern A. Zeeb 547*90aac0d8SBjoern A. Zeeb rxcb->rx_skb = alloc_skb(RTW_USB_MAX_RECVBUF_SZ, GFP_ATOMIC); 548*90aac0d8SBjoern A. Zeeb if (!rxcb->rx_skb) 549*90aac0d8SBjoern A. Zeeb return; 550*90aac0d8SBjoern A. Zeeb 551*90aac0d8SBjoern A. Zeeb usb_fill_bulk_urb(rxcb->rx_urb, rtwusb->udev, 552*90aac0d8SBjoern A. Zeeb usb_rcvbulkpipe(rtwusb->udev, rtwusb->pipe_in), 553*90aac0d8SBjoern A. Zeeb rxcb->rx_skb->data, RTW_USB_MAX_RECVBUF_SZ, 554*90aac0d8SBjoern A. Zeeb rtw_usb_read_port_complete, rxcb); 555*90aac0d8SBjoern A. Zeeb 556*90aac0d8SBjoern A. Zeeb error = usb_submit_urb(rxcb->rx_urb, GFP_ATOMIC); 557*90aac0d8SBjoern A. Zeeb if (error) { 558*90aac0d8SBjoern A. Zeeb kfree_skb(rxcb->rx_skb); 559*90aac0d8SBjoern A. Zeeb if (error != -ENODEV) 560*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "Err sending rx data urb %d\n", 561*90aac0d8SBjoern A. Zeeb error); 562*90aac0d8SBjoern A. Zeeb } 563*90aac0d8SBjoern A. Zeeb } 564*90aac0d8SBjoern A. Zeeb 565*90aac0d8SBjoern A. Zeeb static void rtw_usb_read_port_complete(struct urb *urb) 566*90aac0d8SBjoern A. Zeeb { 567*90aac0d8SBjoern A. Zeeb struct rx_usb_ctrl_block *rxcb = urb->context; 568*90aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = rxcb->rtwdev; 569*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 570*90aac0d8SBjoern A. Zeeb struct sk_buff *skb = rxcb->rx_skb; 571*90aac0d8SBjoern A. Zeeb 572*90aac0d8SBjoern A. Zeeb if (urb->status == 0) { 573*90aac0d8SBjoern A. Zeeb if (urb->actual_length >= RTW_USB_MAX_RECVBUF_SZ || 574*90aac0d8SBjoern A. Zeeb urb->actual_length < 24) { 575*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to get urb length:%d\n", 576*90aac0d8SBjoern A. Zeeb urb->actual_length); 577*90aac0d8SBjoern A. Zeeb if (skb) 578*90aac0d8SBjoern A. Zeeb dev_kfree_skb_any(skb); 579*90aac0d8SBjoern A. Zeeb } else { 580*90aac0d8SBjoern A. Zeeb skb_queue_tail(&rtwusb->rx_queue, skb); 581*90aac0d8SBjoern A. Zeeb queue_work(rtwusb->rxwq, &rtwusb->rx_work); 582*90aac0d8SBjoern A. Zeeb } 583*90aac0d8SBjoern A. Zeeb rtw_usb_rx_resubmit(rtwusb, rxcb); 584*90aac0d8SBjoern A. Zeeb } else { 585*90aac0d8SBjoern A. Zeeb switch (urb->status) { 586*90aac0d8SBjoern A. Zeeb case -EINVAL: 587*90aac0d8SBjoern A. Zeeb case -EPIPE: 588*90aac0d8SBjoern A. Zeeb case -ENODEV: 589*90aac0d8SBjoern A. Zeeb case -ESHUTDOWN: 590*90aac0d8SBjoern A. Zeeb case -ENOENT: 591*90aac0d8SBjoern A. Zeeb case -EPROTO: 592*90aac0d8SBjoern A. Zeeb case -EILSEQ: 593*90aac0d8SBjoern A. Zeeb case -ETIME: 594*90aac0d8SBjoern A. Zeeb case -ECOMM: 595*90aac0d8SBjoern A. Zeeb case -EOVERFLOW: 596*90aac0d8SBjoern A. Zeeb case -EINPROGRESS: 597*90aac0d8SBjoern A. Zeeb break; 598*90aac0d8SBjoern A. Zeeb default: 599*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "status %d\n", urb->status); 600*90aac0d8SBjoern A. Zeeb break; 601*90aac0d8SBjoern A. Zeeb } 602*90aac0d8SBjoern A. Zeeb if (skb) 603*90aac0d8SBjoern A. Zeeb dev_kfree_skb_any(skb); 604*90aac0d8SBjoern A. Zeeb } 605*90aac0d8SBjoern A. Zeeb } 606*90aac0d8SBjoern A. Zeeb 607*90aac0d8SBjoern A. Zeeb static void rtw_usb_cancel_rx_bufs(struct rtw_usb *rtwusb) 608*90aac0d8SBjoern A. Zeeb { 609*90aac0d8SBjoern A. Zeeb struct rx_usb_ctrl_block *rxcb; 610*90aac0d8SBjoern A. Zeeb int i; 611*90aac0d8SBjoern A. Zeeb 612*90aac0d8SBjoern A. Zeeb for (i = 0; i < RTW_USB_RXCB_NUM; i++) { 613*90aac0d8SBjoern A. Zeeb rxcb = &rtwusb->rx_cb[i]; 614*90aac0d8SBjoern A. Zeeb if (rxcb->rx_urb) 615*90aac0d8SBjoern A. Zeeb usb_kill_urb(rxcb->rx_urb); 616*90aac0d8SBjoern A. Zeeb } 617*90aac0d8SBjoern A. Zeeb } 618*90aac0d8SBjoern A. Zeeb 619*90aac0d8SBjoern A. Zeeb static void rtw_usb_free_rx_bufs(struct rtw_usb *rtwusb) 620*90aac0d8SBjoern A. Zeeb { 621*90aac0d8SBjoern A. Zeeb struct rx_usb_ctrl_block *rxcb; 622*90aac0d8SBjoern A. Zeeb int i; 623*90aac0d8SBjoern A. Zeeb 624*90aac0d8SBjoern A. Zeeb for (i = 0; i < RTW_USB_RXCB_NUM; i++) { 625*90aac0d8SBjoern A. Zeeb rxcb = &rtwusb->rx_cb[i]; 626*90aac0d8SBjoern A. Zeeb if (rxcb->rx_urb) { 627*90aac0d8SBjoern A. Zeeb usb_kill_urb(rxcb->rx_urb); 628*90aac0d8SBjoern A. Zeeb usb_free_urb(rxcb->rx_urb); 629*90aac0d8SBjoern A. Zeeb } 630*90aac0d8SBjoern A. Zeeb } 631*90aac0d8SBjoern A. Zeeb } 632*90aac0d8SBjoern A. Zeeb 633*90aac0d8SBjoern A. Zeeb static int rtw_usb_alloc_rx_bufs(struct rtw_usb *rtwusb) 634*90aac0d8SBjoern A. Zeeb { 635*90aac0d8SBjoern A. Zeeb int i; 636*90aac0d8SBjoern A. Zeeb 637*90aac0d8SBjoern A. Zeeb for (i = 0; i < RTW_USB_RXCB_NUM; i++) { 638*90aac0d8SBjoern A. Zeeb struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i]; 639*90aac0d8SBjoern A. Zeeb 640*90aac0d8SBjoern A. Zeeb rxcb->rtwdev = rtwusb->rtwdev; 641*90aac0d8SBjoern A. Zeeb rxcb->rx_urb = usb_alloc_urb(0, GFP_KERNEL); 642*90aac0d8SBjoern A. Zeeb if (!rxcb->rx_urb) 643*90aac0d8SBjoern A. Zeeb goto err; 644*90aac0d8SBjoern A. Zeeb } 645*90aac0d8SBjoern A. Zeeb 646*90aac0d8SBjoern A. Zeeb return 0; 647*90aac0d8SBjoern A. Zeeb err: 648*90aac0d8SBjoern A. Zeeb rtw_usb_free_rx_bufs(rtwusb); 649*90aac0d8SBjoern A. Zeeb return -ENOMEM; 650*90aac0d8SBjoern A. Zeeb } 651*90aac0d8SBjoern A. Zeeb 652*90aac0d8SBjoern A. Zeeb static int rtw_usb_setup(struct rtw_dev *rtwdev) 653*90aac0d8SBjoern A. Zeeb { 654*90aac0d8SBjoern A. Zeeb /* empty function for rtw_hci_ops */ 655*90aac0d8SBjoern A. Zeeb return 0; 656*90aac0d8SBjoern A. Zeeb } 657*90aac0d8SBjoern A. Zeeb 658*90aac0d8SBjoern A. Zeeb static int rtw_usb_start(struct rtw_dev *rtwdev) 659*90aac0d8SBjoern A. Zeeb { 660*90aac0d8SBjoern A. Zeeb return 0; 661*90aac0d8SBjoern A. Zeeb } 662*90aac0d8SBjoern A. Zeeb 663*90aac0d8SBjoern A. Zeeb static void rtw_usb_stop(struct rtw_dev *rtwdev) 664*90aac0d8SBjoern A. Zeeb { 665*90aac0d8SBjoern A. Zeeb } 666*90aac0d8SBjoern A. Zeeb 667*90aac0d8SBjoern A. Zeeb static void rtw_usb_deep_ps(struct rtw_dev *rtwdev, bool enter) 668*90aac0d8SBjoern A. Zeeb { 669*90aac0d8SBjoern A. Zeeb /* empty function for rtw_hci_ops */ 670*90aac0d8SBjoern A. Zeeb } 671*90aac0d8SBjoern A. Zeeb 672*90aac0d8SBjoern A. Zeeb static void rtw_usb_link_ps(struct rtw_dev *rtwdev, bool enter) 673*90aac0d8SBjoern A. Zeeb { 674*90aac0d8SBjoern A. Zeeb /* empty function for rtw_hci_ops */ 675*90aac0d8SBjoern A. Zeeb } 676*90aac0d8SBjoern A. Zeeb 677*90aac0d8SBjoern A. Zeeb static void rtw_usb_interface_cfg(struct rtw_dev *rtwdev) 678*90aac0d8SBjoern A. Zeeb { 679*90aac0d8SBjoern A. Zeeb /* empty function for rtw_hci_ops */ 680*90aac0d8SBjoern A. Zeeb } 681*90aac0d8SBjoern A. Zeeb 682*90aac0d8SBjoern A. Zeeb static struct rtw_hci_ops rtw_usb_ops = { 683*90aac0d8SBjoern A. Zeeb .tx_write = rtw_usb_tx_write, 684*90aac0d8SBjoern A. Zeeb .tx_kick_off = rtw_usb_tx_kick_off, 685*90aac0d8SBjoern A. Zeeb .setup = rtw_usb_setup, 686*90aac0d8SBjoern A. Zeeb .start = rtw_usb_start, 687*90aac0d8SBjoern A. Zeeb .stop = rtw_usb_stop, 688*90aac0d8SBjoern A. Zeeb .deep_ps = rtw_usb_deep_ps, 689*90aac0d8SBjoern A. Zeeb .link_ps = rtw_usb_link_ps, 690*90aac0d8SBjoern A. Zeeb .interface_cfg = rtw_usb_interface_cfg, 691*90aac0d8SBjoern A. Zeeb 692*90aac0d8SBjoern A. Zeeb .write8 = rtw_usb_write8, 693*90aac0d8SBjoern A. Zeeb .write16 = rtw_usb_write16, 694*90aac0d8SBjoern A. Zeeb .write32 = rtw_usb_write32, 695*90aac0d8SBjoern A. Zeeb .read8 = rtw_usb_read8, 696*90aac0d8SBjoern A. Zeeb .read16 = rtw_usb_read16, 697*90aac0d8SBjoern A. Zeeb .read32 = rtw_usb_read32, 698*90aac0d8SBjoern A. Zeeb 699*90aac0d8SBjoern A. Zeeb .write_data_rsvd_page = rtw_usb_write_data_rsvd_page, 700*90aac0d8SBjoern A. Zeeb .write_data_h2c = rtw_usb_write_data_h2c, 701*90aac0d8SBjoern A. Zeeb }; 702*90aac0d8SBjoern A. Zeeb 703*90aac0d8SBjoern A. Zeeb static int rtw_usb_init_rx(struct rtw_dev *rtwdev) 704*90aac0d8SBjoern A. Zeeb { 705*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 706*90aac0d8SBjoern A. Zeeb int i; 707*90aac0d8SBjoern A. Zeeb 708*90aac0d8SBjoern A. Zeeb rtwusb->rxwq = create_singlethread_workqueue("rtw88_usb: rx wq"); 709*90aac0d8SBjoern A. Zeeb if (!rtwusb->rxwq) { 710*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to create RX work queue\n"); 711*90aac0d8SBjoern A. Zeeb return -ENOMEM; 712*90aac0d8SBjoern A. Zeeb } 713*90aac0d8SBjoern A. Zeeb 714*90aac0d8SBjoern A. Zeeb skb_queue_head_init(&rtwusb->rx_queue); 715*90aac0d8SBjoern A. Zeeb 716*90aac0d8SBjoern A. Zeeb INIT_WORK(&rtwusb->rx_work, rtw_usb_rx_handler); 717*90aac0d8SBjoern A. Zeeb 718*90aac0d8SBjoern A. Zeeb for (i = 0; i < RTW_USB_RXCB_NUM; i++) { 719*90aac0d8SBjoern A. Zeeb struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i]; 720*90aac0d8SBjoern A. Zeeb 721*90aac0d8SBjoern A. Zeeb rtw_usb_rx_resubmit(rtwusb, rxcb); 722*90aac0d8SBjoern A. Zeeb } 723*90aac0d8SBjoern A. Zeeb 724*90aac0d8SBjoern A. Zeeb return 0; 725*90aac0d8SBjoern A. Zeeb } 726*90aac0d8SBjoern A. Zeeb 727*90aac0d8SBjoern A. Zeeb static void rtw_usb_deinit_rx(struct rtw_dev *rtwdev) 728*90aac0d8SBjoern A. Zeeb { 729*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 730*90aac0d8SBjoern A. Zeeb 731*90aac0d8SBjoern A. Zeeb skb_queue_purge(&rtwusb->rx_queue); 732*90aac0d8SBjoern A. Zeeb 733*90aac0d8SBjoern A. Zeeb flush_workqueue(rtwusb->rxwq); 734*90aac0d8SBjoern A. Zeeb destroy_workqueue(rtwusb->rxwq); 735*90aac0d8SBjoern A. Zeeb } 736*90aac0d8SBjoern A. Zeeb 737*90aac0d8SBjoern A. Zeeb static int rtw_usb_init_tx(struct rtw_dev *rtwdev) 738*90aac0d8SBjoern A. Zeeb { 739*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 740*90aac0d8SBjoern A. Zeeb int i; 741*90aac0d8SBjoern A. Zeeb 742*90aac0d8SBjoern A. Zeeb rtwusb->txwq = create_singlethread_workqueue("rtw88_usb: tx wq"); 743*90aac0d8SBjoern A. Zeeb if (!rtwusb->txwq) { 744*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to create TX work queue\n"); 745*90aac0d8SBjoern A. Zeeb return -ENOMEM; 746*90aac0d8SBjoern A. Zeeb } 747*90aac0d8SBjoern A. Zeeb 748*90aac0d8SBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) 749*90aac0d8SBjoern A. Zeeb skb_queue_head_init(&rtwusb->tx_queue[i]); 750*90aac0d8SBjoern A. Zeeb 751*90aac0d8SBjoern A. Zeeb INIT_WORK(&rtwusb->tx_work, rtw_usb_tx_handler); 752*90aac0d8SBjoern A. Zeeb 753*90aac0d8SBjoern A. Zeeb return 0; 754*90aac0d8SBjoern A. Zeeb } 755*90aac0d8SBjoern A. Zeeb 756*90aac0d8SBjoern A. Zeeb static void rtw_usb_deinit_tx(struct rtw_dev *rtwdev) 757*90aac0d8SBjoern A. Zeeb { 758*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 759*90aac0d8SBjoern A. Zeeb 760*90aac0d8SBjoern A. Zeeb rtw_usb_tx_queue_purge(rtwusb); 761*90aac0d8SBjoern A. Zeeb flush_workqueue(rtwusb->txwq); 762*90aac0d8SBjoern A. Zeeb destroy_workqueue(rtwusb->txwq); 763*90aac0d8SBjoern A. Zeeb } 764*90aac0d8SBjoern A. Zeeb 765*90aac0d8SBjoern A. Zeeb static int rtw_usb_intf_init(struct rtw_dev *rtwdev, 766*90aac0d8SBjoern A. Zeeb struct usb_interface *intf) 767*90aac0d8SBjoern A. Zeeb { 768*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 769*90aac0d8SBjoern A. Zeeb struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf)); 770*90aac0d8SBjoern A. Zeeb int ret; 771*90aac0d8SBjoern A. Zeeb 772*90aac0d8SBjoern A. Zeeb rtwusb->udev = udev; 773*90aac0d8SBjoern A. Zeeb ret = rtw_usb_parse(rtwdev, intf); 774*90aac0d8SBjoern A. Zeeb if (ret) 775*90aac0d8SBjoern A. Zeeb return ret; 776*90aac0d8SBjoern A. Zeeb 777*90aac0d8SBjoern A. Zeeb rtwusb->usb_data = kcalloc(RTW_USB_MAX_RXTX_COUNT, sizeof(u32), 778*90aac0d8SBjoern A. Zeeb GFP_KERNEL); 779*90aac0d8SBjoern A. Zeeb if (!rtwusb->usb_data) 780*90aac0d8SBjoern A. Zeeb return -ENOMEM; 781*90aac0d8SBjoern A. Zeeb 782*90aac0d8SBjoern A. Zeeb usb_set_intfdata(intf, rtwdev->hw); 783*90aac0d8SBjoern A. Zeeb 784*90aac0d8SBjoern A. Zeeb SET_IEEE80211_DEV(rtwdev->hw, &intf->dev); 785*90aac0d8SBjoern A. Zeeb spin_lock_init(&rtwusb->usb_lock); 786*90aac0d8SBjoern A. Zeeb 787*90aac0d8SBjoern A. Zeeb return 0; 788*90aac0d8SBjoern A. Zeeb } 789*90aac0d8SBjoern A. Zeeb 790*90aac0d8SBjoern A. Zeeb static void rtw_usb_intf_deinit(struct rtw_dev *rtwdev, 791*90aac0d8SBjoern A. Zeeb struct usb_interface *intf) 792*90aac0d8SBjoern A. Zeeb { 793*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 794*90aac0d8SBjoern A. Zeeb 795*90aac0d8SBjoern A. Zeeb usb_put_dev(rtwusb->udev); 796*90aac0d8SBjoern A. Zeeb kfree(rtwusb->usb_data); 797*90aac0d8SBjoern A. Zeeb usb_set_intfdata(intf, NULL); 798*90aac0d8SBjoern A. Zeeb } 799*90aac0d8SBjoern A. Zeeb 800*90aac0d8SBjoern A. Zeeb int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) 801*90aac0d8SBjoern A. Zeeb { 802*90aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev; 803*90aac0d8SBjoern A. Zeeb struct ieee80211_hw *hw; 804*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb; 805*90aac0d8SBjoern A. Zeeb int drv_data_size; 806*90aac0d8SBjoern A. Zeeb int ret; 807*90aac0d8SBjoern A. Zeeb 808*90aac0d8SBjoern A. Zeeb drv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_usb); 809*90aac0d8SBjoern A. Zeeb hw = ieee80211_alloc_hw(drv_data_size, &rtw_ops); 810*90aac0d8SBjoern A. Zeeb if (!hw) 811*90aac0d8SBjoern A. Zeeb return -ENOMEM; 812*90aac0d8SBjoern A. Zeeb 813*90aac0d8SBjoern A. Zeeb rtwdev = hw->priv; 814*90aac0d8SBjoern A. Zeeb rtwdev->hw = hw; 815*90aac0d8SBjoern A. Zeeb rtwdev->dev = &intf->dev; 816*90aac0d8SBjoern A. Zeeb rtwdev->chip = (struct rtw_chip_info *)id->driver_info; 817*90aac0d8SBjoern A. Zeeb rtwdev->hci.ops = &rtw_usb_ops; 818*90aac0d8SBjoern A. Zeeb rtwdev->hci.type = RTW_HCI_TYPE_USB; 819*90aac0d8SBjoern A. Zeeb 820*90aac0d8SBjoern A. Zeeb rtwusb = rtw_get_usb_priv(rtwdev); 821*90aac0d8SBjoern A. Zeeb rtwusb->rtwdev = rtwdev; 822*90aac0d8SBjoern A. Zeeb 823*90aac0d8SBjoern A. Zeeb ret = rtw_usb_alloc_rx_bufs(rtwusb); 824*90aac0d8SBjoern A. Zeeb if (ret) 825*90aac0d8SBjoern A. Zeeb goto err_release_hw; 826*90aac0d8SBjoern A. Zeeb 827*90aac0d8SBjoern A. Zeeb ret = rtw_core_init(rtwdev); 828*90aac0d8SBjoern A. Zeeb if (ret) 829*90aac0d8SBjoern A. Zeeb goto err_release_hw; 830*90aac0d8SBjoern A. Zeeb 831*90aac0d8SBjoern A. Zeeb ret = rtw_usb_intf_init(rtwdev, intf); 832*90aac0d8SBjoern A. Zeeb if (ret) { 833*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to init USB interface\n"); 834*90aac0d8SBjoern A. Zeeb goto err_deinit_core; 835*90aac0d8SBjoern A. Zeeb } 836*90aac0d8SBjoern A. Zeeb 837*90aac0d8SBjoern A. Zeeb ret = rtw_usb_init_tx(rtwdev); 838*90aac0d8SBjoern A. Zeeb if (ret) { 839*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to init USB TX\n"); 840*90aac0d8SBjoern A. Zeeb goto err_destroy_usb; 841*90aac0d8SBjoern A. Zeeb } 842*90aac0d8SBjoern A. Zeeb 843*90aac0d8SBjoern A. Zeeb ret = rtw_usb_init_rx(rtwdev); 844*90aac0d8SBjoern A. Zeeb if (ret) { 845*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to init USB RX\n"); 846*90aac0d8SBjoern A. Zeeb goto err_destroy_txwq; 847*90aac0d8SBjoern A. Zeeb } 848*90aac0d8SBjoern A. Zeeb 849*90aac0d8SBjoern A. Zeeb ret = rtw_chip_info_setup(rtwdev); 850*90aac0d8SBjoern A. Zeeb if (ret) { 851*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to setup chip information\n"); 852*90aac0d8SBjoern A. Zeeb goto err_destroy_rxwq; 853*90aac0d8SBjoern A. Zeeb } 854*90aac0d8SBjoern A. Zeeb 855*90aac0d8SBjoern A. Zeeb ret = rtw_register_hw(rtwdev, rtwdev->hw); 856*90aac0d8SBjoern A. Zeeb if (ret) { 857*90aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to register hw\n"); 858*90aac0d8SBjoern A. Zeeb goto err_destroy_rxwq; 859*90aac0d8SBjoern A. Zeeb } 860*90aac0d8SBjoern A. Zeeb 861*90aac0d8SBjoern A. Zeeb return 0; 862*90aac0d8SBjoern A. Zeeb 863*90aac0d8SBjoern A. Zeeb err_destroy_rxwq: 864*90aac0d8SBjoern A. Zeeb rtw_usb_deinit_rx(rtwdev); 865*90aac0d8SBjoern A. Zeeb 866*90aac0d8SBjoern A. Zeeb err_destroy_txwq: 867*90aac0d8SBjoern A. Zeeb rtw_usb_deinit_tx(rtwdev); 868*90aac0d8SBjoern A. Zeeb 869*90aac0d8SBjoern A. Zeeb err_destroy_usb: 870*90aac0d8SBjoern A. Zeeb rtw_usb_intf_deinit(rtwdev, intf); 871*90aac0d8SBjoern A. Zeeb 872*90aac0d8SBjoern A. Zeeb err_deinit_core: 873*90aac0d8SBjoern A. Zeeb rtw_core_deinit(rtwdev); 874*90aac0d8SBjoern A. Zeeb 875*90aac0d8SBjoern A. Zeeb err_release_hw: 876*90aac0d8SBjoern A. Zeeb ieee80211_free_hw(hw); 877*90aac0d8SBjoern A. Zeeb 878*90aac0d8SBjoern A. Zeeb return ret; 879*90aac0d8SBjoern A. Zeeb } 880*90aac0d8SBjoern A. Zeeb EXPORT_SYMBOL(rtw_usb_probe); 881*90aac0d8SBjoern A. Zeeb 882*90aac0d8SBjoern A. Zeeb void rtw_usb_disconnect(struct usb_interface *intf) 883*90aac0d8SBjoern A. Zeeb { 884*90aac0d8SBjoern A. Zeeb struct ieee80211_hw *hw = usb_get_intfdata(intf); 885*90aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev; 886*90aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb; 887*90aac0d8SBjoern A. Zeeb 888*90aac0d8SBjoern A. Zeeb if (!hw) 889*90aac0d8SBjoern A. Zeeb return; 890*90aac0d8SBjoern A. Zeeb 891*90aac0d8SBjoern A. Zeeb rtwdev = hw->priv; 892*90aac0d8SBjoern A. Zeeb rtwusb = rtw_get_usb_priv(rtwdev); 893*90aac0d8SBjoern A. Zeeb 894*90aac0d8SBjoern A. Zeeb rtw_usb_cancel_rx_bufs(rtwusb); 895*90aac0d8SBjoern A. Zeeb 896*90aac0d8SBjoern A. Zeeb rtw_unregister_hw(rtwdev, hw); 897*90aac0d8SBjoern A. Zeeb rtw_usb_deinit_tx(rtwdev); 898*90aac0d8SBjoern A. Zeeb rtw_usb_deinit_rx(rtwdev); 899*90aac0d8SBjoern A. Zeeb 900*90aac0d8SBjoern A. Zeeb if (rtwusb->udev->state != USB_STATE_NOTATTACHED) 901*90aac0d8SBjoern A. Zeeb usb_reset_device(rtwusb->udev); 902*90aac0d8SBjoern A. Zeeb 903*90aac0d8SBjoern A. Zeeb rtw_usb_free_rx_bufs(rtwusb); 904*90aac0d8SBjoern A. Zeeb 905*90aac0d8SBjoern A. Zeeb rtw_usb_intf_deinit(rtwdev, intf); 906*90aac0d8SBjoern A. Zeeb rtw_core_deinit(rtwdev); 907*90aac0d8SBjoern A. Zeeb ieee80211_free_hw(hw); 908*90aac0d8SBjoern A. Zeeb } 909*90aac0d8SBjoern A. Zeeb EXPORT_SYMBOL(rtw_usb_disconnect); 910*90aac0d8SBjoern A. Zeeb 911*90aac0d8SBjoern A. Zeeb MODULE_AUTHOR("Realtek Corporation"); 912*90aac0d8SBjoern A. Zeeb MODULE_DESCRIPTION("Realtek 802.11ac wireless USB driver"); 913*90aac0d8SBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL"); 914*90aac0d8SBjoern A. Zeeb #if defined(__FreeBSD__) 915*90aac0d8SBjoern A. Zeeb MODULE_VERSION(rtw88_usb, 1); 916*90aac0d8SBjoern A. Zeeb MODULE_DEPEND(rtw88_usb, rtw88_core, 1, 1, 1); 917*90aac0d8SBjoern A. Zeeb MODULE_DEPEND(rtw88_usb, linuxkpi, 1, 1, 1); 918*90aac0d8SBjoern A. Zeeb MODULE_DEPEND(rtw88_usb, linuxkpi_wlan, 1, 1, 1); 919*90aac0d8SBjoern A. Zeeb #endif 920