linux/drivers/staging/rtl8723au/hal/usb_ops_linux.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of version 2 of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12 * more details.
  13 *
  14 ******************************************************************************/
  15#define _HCI_OPS_OS_C_
  16
  17#include <osdep_service.h>
  18#include <drv_types.h>
  19#include <osdep_intf.h>
  20#include <usb_ops.h>
  21#include <recv_osdep.h>
  22#include <rtl8723a_hal.h>
  23#include <rtl8723a_recv.h>
  24
  25u8 rtl8723au_read8(struct rtw_adapter *padapter, u16 addr)
  26{
  27        struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
  28        struct usb_device *udev = pdvobjpriv->pusbdev;
  29        int len;
  30        u8 data;
  31
  32        mutex_lock(&pdvobjpriv->usb_vendor_req_mutex);
  33        len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
  34                              REALTEK_USB_VENQT_CMD_REQ, REALTEK_USB_VENQT_READ,
  35                              addr, 0, &pdvobjpriv->usb_buf.val8, sizeof(data),
  36                              RTW_USB_CONTROL_MSG_TIMEOUT);
  37
  38        data = pdvobjpriv->usb_buf.val8;
  39        mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex);
  40
  41        return data;
  42}
  43
  44u16 rtl8723au_read16(struct rtw_adapter *padapter, u16 addr)
  45{
  46        struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
  47        struct usb_device *udev = pdvobjpriv->pusbdev;
  48        int len;
  49        u16 data;
  50
  51        mutex_lock(&pdvobjpriv->usb_vendor_req_mutex);
  52        len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
  53                              REALTEK_USB_VENQT_CMD_REQ, REALTEK_USB_VENQT_READ,
  54                              addr, 0, &pdvobjpriv->usb_buf.val16, sizeof(data),
  55                              RTW_USB_CONTROL_MSG_TIMEOUT);
  56
  57        data = le16_to_cpu(pdvobjpriv->usb_buf.val16);
  58        mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex);
  59
  60        return data;
  61}
  62
  63u32 rtl8723au_read32(struct rtw_adapter *padapter, u16 addr)
  64{
  65        struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
  66        struct usb_device *udev = pdvobjpriv->pusbdev;
  67        int len;
  68        u32 data;
  69
  70        mutex_lock(&pdvobjpriv->usb_vendor_req_mutex);
  71        len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
  72                              REALTEK_USB_VENQT_CMD_REQ, REALTEK_USB_VENQT_READ,
  73                              addr, 0, &pdvobjpriv->usb_buf.val32, sizeof(data),
  74                              RTW_USB_CONTROL_MSG_TIMEOUT);
  75
  76        data = le32_to_cpu(pdvobjpriv->usb_buf.val32);
  77        mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex);
  78
  79        return data;
  80}
  81
  82int rtl8723au_write8(struct rtw_adapter *padapter, u16 addr, u8 val)
  83{
  84        struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
  85        struct usb_device *udev = pdvobjpriv->pusbdev;
  86        int ret;
  87
  88        mutex_lock(&pdvobjpriv->usb_vendor_req_mutex);
  89        pdvobjpriv->usb_buf.val8 = val;
  90
  91        ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
  92                              REALTEK_USB_VENQT_CMD_REQ,
  93                              REALTEK_USB_VENQT_WRITE,
  94                              addr, 0, &pdvobjpriv->usb_buf.val8, sizeof(val),
  95                              RTW_USB_CONTROL_MSG_TIMEOUT);
  96
  97        if (ret != sizeof(val))
  98                ret = _FAIL;
  99        else
 100                ret = _SUCCESS;
 101
 102        mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex);
 103        return ret;
 104}
 105
 106int rtl8723au_write16(struct rtw_adapter *padapter, u16 addr, u16 val)
 107{
 108        struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
 109        struct usb_device *udev = pdvobjpriv->pusbdev;
 110        int ret;
 111
 112        mutex_lock(&pdvobjpriv->usb_vendor_req_mutex);
 113        pdvobjpriv->usb_buf.val16 = cpu_to_le16(val);
 114
 115        ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 116                              REALTEK_USB_VENQT_CMD_REQ,
 117                              REALTEK_USB_VENQT_WRITE,
 118                              addr, 0, &pdvobjpriv->usb_buf.val16, sizeof(val),
 119                              RTW_USB_CONTROL_MSG_TIMEOUT);
 120
 121        if (ret != sizeof(val))
 122                ret = _FAIL;
 123        else
 124                ret = _SUCCESS;
 125
 126        mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex);
 127        return ret;
 128}
 129
 130int rtl8723au_write32(struct rtw_adapter *padapter, u16 addr, u32 val)
 131{
 132        struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
 133        struct usb_device *udev = pdvobjpriv->pusbdev;
 134        int ret;
 135
 136        mutex_lock(&pdvobjpriv->usb_vendor_req_mutex);
 137        pdvobjpriv->usb_buf.val32 = cpu_to_le32(val);
 138
 139        ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 140                              REALTEK_USB_VENQT_CMD_REQ,
 141                              REALTEK_USB_VENQT_WRITE,
 142                              addr, 0, &pdvobjpriv->usb_buf.val32, sizeof(val),
 143                              RTW_USB_CONTROL_MSG_TIMEOUT);
 144
 145        if (ret != sizeof(val))
 146                ret = _FAIL;
 147        else
 148                ret = _SUCCESS;
 149
 150        mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex);
 151        return ret;
 152}
 153
 154int rtl8723au_writeN(struct rtw_adapter *padapter, u16 addr, u16 len, u8 *buf)
 155{
 156        struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
 157        struct usb_device *udev = pdvobjpriv->pusbdev;
 158        int ret;
 159
 160        ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 161                              REALTEK_USB_VENQT_CMD_REQ,
 162                              REALTEK_USB_VENQT_WRITE,
 163                              addr, 0, buf, len, RTW_USB_CONTROL_MSG_TIMEOUT);
 164
 165        if (ret != len)
 166                return _FAIL;
 167        return _SUCCESS;
 168}
 169
 170/*
 171 * Description:
 172 *      Recognize the interrupt content by reading the interrupt
 173 *      register or content and masking interrupt mask (IMR)
 174 *      if it is our NIC's interrupt. After recognizing, we may clear
 175 *      the all interrupts (ISR).
 176 * Arguments:
 177 *      [in] Adapter -
 178 *              The adapter context.
 179 *      [in] pContent -
 180 *              Under PCI interface, this field is ignord.
 181 *              Under USB interface, the content is the interrupt
 182 *              content pointer.
 183 *              Under SDIO interface, this is the interrupt type which
 184 *              is Local interrupt or system interrupt.
 185 *      [in] ContentLen -
 186 *              The length in byte of pContent.
 187 * Return:
 188 *      If any interrupt matches the mask (IMR), return true, and
 189 *      return false otherwise.
 190 */
 191static bool
 192InterruptRecognized8723AU(struct rtw_adapter *Adapter, void *pContent,
 193                          u32 ContentLen)
 194{
 195        struct hal_data_8723a   *pHalData = GET_HAL_DATA(Adapter);
 196        u8 *buffer = (u8 *)pContent;
 197        struct reportpwrstate_parm report;
 198
 199        memcpy(&pHalData->IntArray[0], &buffer[USB_INTR_CONTENT_HISR_OFFSET],
 200               4);
 201        pHalData->IntArray[0] &= pHalData->IntrMask[0];
 202
 203        /* For HISR extension. Added by tynli. 2009.10.07. */
 204        memcpy(&pHalData->IntArray[1],
 205               &buffer[USB_INTR_CONTENT_HISRE_OFFSET], 4);
 206        pHalData->IntArray[1] &= pHalData->IntrMask[1];
 207
 208        /* We sholud remove this function later because DDK suggest
 209         * not to executing too many operations in MPISR  */
 210
 211        memcpy(&report.state, &buffer[USB_INTR_CPWM_OFFSET], 1);
 212
 213        return (pHalData->IntArray[0] & pHalData->IntrMask[0]) != 0 ||
 214                (pHalData->IntArray[1] & pHalData->IntrMask[1]) != 0;
 215}
 216
 217static void usb_read_interrupt_complete(struct urb *purb)
 218{
 219        int err;
 220        struct rtw_adapter *padapter = (struct rtw_adapter *)purb->context;
 221
 222        if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
 223            padapter->bReadPortCancel) {
 224                DBG_8723A("%s() RX Warning! bDriverStopped(%d) OR "
 225                          "bSurpriseRemoved(%d) bReadPortCancel(%d)\n",
 226                          __func__, padapter->bDriverStopped,
 227                          padapter->bSurpriseRemoved,
 228                          padapter->bReadPortCancel);
 229                return;
 230        }
 231
 232        if (purb->status == 0) {
 233                struct c2h_evt_hdr *c2h_evt;
 234
 235                c2h_evt = (struct c2h_evt_hdr *)purb->transfer_buffer;
 236
 237                if (purb->actual_length > USB_INTR_CONTENT_LENGTH) {
 238                        DBG_8723A("usb_read_interrupt_complete: purb->actual_"
 239                                  "length > USB_INTR_CONTENT_LENGTH\n");
 240                        goto urb_submit;
 241                }
 242
 243                InterruptRecognized8723AU(padapter, purb->transfer_buffer,
 244                                          purb->actual_length);
 245
 246                if (c2h_evt_exist(c2h_evt)) {
 247                        if (c2h_id_filter_ccx_8723a(c2h_evt->id)) {
 248                                /* Handle CCX report here */
 249                                handle_txrpt_ccx_8723a(padapter, (void *)
 250                                                       c2h_evt->payload);
 251                                schedule_work(&padapter->evtpriv.irq_wk);
 252                        } else {
 253                                struct evt_work *c2w;
 254                                int res;
 255
 256                                c2w = kmalloc(sizeof(struct evt_work),
 257                                                GFP_ATOMIC);
 258
 259                                if (!c2w)
 260                                        goto urb_submit;
 261
 262                                c2w->adapter = padapter;
 263                                INIT_WORK(&c2w->work, rtw_evt_work);
 264                                memcpy(c2w->u.buf, purb->transfer_buffer, 16);
 265
 266                                res = queue_work(padapter->evtpriv.wq,
 267                                                 &c2w->work);
 268
 269                                if (!res) {
 270                                        printk(KERN_ERR "%s: Call to "
 271                                               "queue_work() failed\n",
 272                                               __func__);
 273                                        kfree(c2w);
 274                                        goto urb_submit;
 275                                }
 276                        }
 277                }
 278
 279urb_submit:
 280                err = usb_submit_urb(purb, GFP_ATOMIC);
 281                if (err && (err != -EPERM)) {
 282                        DBG_8723A("cannot submit interrupt in-token(err = "
 283                                  "0x%08x), urb_status = %d\n",
 284                                  err, purb->status);
 285                }
 286        } else {
 287                DBG_8723A("###=> usb_read_interrupt_complete => urb "
 288                          "status(%d)\n", purb->status);
 289
 290                switch (purb->status) {
 291                case -EINVAL:
 292                case -EPIPE:
 293                case -ENODEV:
 294                case -ESHUTDOWN:
 295                        RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
 296                                 "usb_read_port_complete:bSurpriseRemoved =true\n");
 297                        /* Fall Through here */
 298                case -ENOENT:
 299                        padapter->bDriverStopped = true;
 300                        RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
 301                                 "usb_read_port_complete:bDriverStopped =true\n");
 302                        break;
 303                case -EPROTO:
 304                        break;
 305                case -EINPROGRESS:
 306                        DBG_8723A("ERROR: URB IS IN PROGRESS!\n");
 307                        break;
 308                default:
 309                        break;
 310                }
 311        }
 312}
 313
 314int rtl8723au_read_interrupt(struct rtw_adapter *adapter)
 315{
 316        int err;
 317        unsigned int pipe;
 318        int ret = _SUCCESS;
 319        struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);
 320        struct recv_priv *precvpriv = &adapter->recvpriv;
 321        struct usb_device *pusbd = pdvobj->pusbdev;
 322
 323        /* translate DMA FIFO addr to pipehandle */
 324        pipe = usb_rcvintpipe(pusbd, pdvobj->RtInPipe[1]);
 325
 326        usb_fill_int_urb(precvpriv->int_in_urb, pusbd, pipe,
 327                         precvpriv->int_in_buf, USB_INTR_CONTENT_LENGTH,
 328                         usb_read_interrupt_complete, adapter, 1);
 329
 330        err = usb_submit_urb(precvpriv->int_in_urb, GFP_ATOMIC);
 331        if (err && (err != -EPERM)) {
 332                DBG_8723A("cannot submit interrupt in-token(err = 0x%08x),"
 333                          "urb_status = %d\n", err,
 334                          precvpriv->int_in_urb->status);
 335                ret = _FAIL;
 336        }
 337
 338        return ret;
 339}
 340
 341static int recvbuf2recvframe(struct rtw_adapter *padapter, struct sk_buff *pskb)
 342{
 343        u8      *pbuf;
 344        u8      shift_sz = 0;
 345        u16     pkt_cnt;
 346        u32     pkt_offset, skb_len, alloc_sz;
 347        int     transfer_len;
 348        struct recv_stat *prxstat;
 349        struct phy_stat *pphy_info;
 350        struct sk_buff *pkt_copy;
 351        struct recv_frame *precvframe;
 352        struct rx_pkt_attrib *pattrib;
 353        struct recv_priv *precvpriv = &padapter->recvpriv;
 354        struct rtw_queue *pfree_recv_queue = &precvpriv->free_recv_queue;
 355
 356        transfer_len = (int)pskb->len;
 357        pbuf = pskb->data;
 358
 359        prxstat = (struct recv_stat *)pbuf;
 360        pkt_cnt = (le32_to_cpu(prxstat->rxdw2) >> 16) & 0xff;
 361
 362        do {
 363                RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
 364                         "recvbuf2recvframe: rxdesc = offsset 0:0x%08x, 4:0x%08x, 8:0x%08x, C:0x%08x\n",
 365                         prxstat->rxdw0, prxstat->rxdw1,
 366                         prxstat->rxdw2, prxstat->rxdw4);
 367
 368                prxstat = (struct recv_stat *)pbuf;
 369
 370                precvframe = rtw_alloc_recvframe23a(pfree_recv_queue);
 371                if (!precvframe) {
 372                        RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
 373                                 "recvbuf2recvframe: precvframe == NULL\n");
 374                        DBG_8723A("%s()-%d: rtw_alloc_recvframe23a() failed! RX "
 375                                  "Drop!\n", __func__, __LINE__);
 376                        goto _exit_recvbuf2recvframe;
 377                }
 378
 379                INIT_LIST_HEAD(&precvframe->list);
 380
 381                update_recvframe_attrib(precvframe, prxstat);
 382
 383                pattrib = &precvframe->attrib;
 384
 385                if (pattrib->crc_err) {
 386                        DBG_8723A("%s()-%d: RX Warning! rx CRC ERROR !!\n",
 387                                  __func__, __LINE__);
 388                        rtw_free_recvframe23a(precvframe);
 389                        goto _exit_recvbuf2recvframe;
 390                }
 391
 392                pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz +
 393                        pattrib->shift_sz + pattrib->pkt_len;
 394
 395                if (pattrib->pkt_len <= 0 || pkt_offset > transfer_len) {
 396                        RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
 397                                 "recvbuf2recvframe: pkt_len<= 0\n");
 398                        DBG_8723A("%s()-%d: RX Warning!\n",
 399                                  __func__, __LINE__);
 400                        rtw_free_recvframe23a(precvframe);
 401                        goto _exit_recvbuf2recvframe;
 402                }
 403
 404                /*      Modified by Albert 20101213 */
 405                /*      For 8 bytes IP header alignment. */
 406                /*      Qos data, wireless lan header length is 26 */
 407                if (pattrib->qos)
 408                        shift_sz = 6;
 409                else
 410                        shift_sz = 0;
 411
 412                skb_len = pattrib->pkt_len;
 413
 414                /* for first fragment packet, driver need allocate
 415                 * 1536+drvinfo_sz+RXDESC_SIZE to defrag packet.
 416                 * modify alloc_sz for recvive crc error packet
 417                 * by thomas 2011-06-02 */
 418                if (pattrib->mfrag == 1 && pattrib->frag_num == 0) {
 419                        /* alloc_sz = 1664;     1664 is 128 alignment. */
 420                        if (skb_len <= 1650)
 421                                alloc_sz = 1664;
 422                        else
 423                                alloc_sz = skb_len + 14;
 424                } else {
 425                        alloc_sz = skb_len;
 426                /*  6 is for IP header 8 bytes alignment in QoS packet case. */
 427                /*  8 is for skb->data 4 bytes alignment. */
 428                        alloc_sz += 14;
 429                }
 430
 431                pkt_copy = netdev_alloc_skb(padapter->pnetdev, alloc_sz);
 432                if (pkt_copy) {
 433                        pkt_copy->dev = padapter->pnetdev;
 434                        precvframe->pkt = pkt_copy;
 435                        /* force pkt_copy->data at 8-byte alignment address */
 436                        skb_reserve(pkt_copy, 8 -
 437                                    ((unsigned long)(pkt_copy->data) & 7));
 438                        /*force ip_hdr at 8-byte alignment address
 439                          according to shift_sz. */
 440                        skb_reserve(pkt_copy, shift_sz);
 441                        memcpy(pkt_copy->data, pbuf + pattrib->shift_sz +
 442                               pattrib->drvinfo_sz + RXDESC_SIZE, skb_len);
 443                        skb_put(pkt_copy, skb_len);
 444                } else {
 445                        if (pattrib->mfrag == 1 && pattrib->frag_num == 0) {
 446                                DBG_8723A("recvbuf2recvframe: alloc_skb fail, "
 447                                          "drop frag frame \n");
 448                                rtw_free_recvframe23a(precvframe);
 449                                goto _exit_recvbuf2recvframe;
 450                        }
 451
 452                        precvframe->pkt = skb_clone(pskb, GFP_ATOMIC);
 453                        if (!precvframe->pkt) {
 454                                DBG_8723A("recvbuf2recvframe: skb_clone "
 455                                          "fail\n");
 456                                rtw_free_recvframe23a(precvframe);
 457                                goto _exit_recvbuf2recvframe;
 458                        }
 459                }
 460
 461                if (pattrib->physt) {
 462                        pphy_info = (struct phy_stat *)(pbuf + RXDESC_OFFSET);
 463                        update_recvframe_phyinfo(precvframe, pphy_info);
 464                }
 465
 466                if (rtw_recv_entry23a(precvframe) != _SUCCESS)
 467                        RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
 468                                 "recvbuf2recvframe: rtw_recv_entry23a(precvframe) != _SUCCESS\n");
 469
 470                pkt_cnt--;
 471                transfer_len -= pkt_offset;
 472                pbuf += pkt_offset;
 473                precvframe = NULL;
 474                pkt_copy = NULL;
 475
 476                if (transfer_len > 0 && pkt_cnt == 0)
 477                        pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16) & 0xff;
 478
 479        } while (transfer_len > 0 && pkt_cnt > 0);
 480
 481_exit_recvbuf2recvframe:
 482
 483        return _SUCCESS;
 484}
 485
 486void rtl8723au_recv_tasklet(void *priv)
 487{
 488        struct sk_buff *pskb;
 489        struct rtw_adapter *padapter = (struct rtw_adapter *)priv;
 490        struct recv_priv *precvpriv = &padapter->recvpriv;
 491
 492        while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) {
 493                if (padapter->bDriverStopped || padapter->bSurpriseRemoved) {
 494                        DBG_8723A("recv_tasklet => bDriverStopped or "
 495                                  "bSurpriseRemoved \n");
 496                        dev_kfree_skb_any(pskb);
 497                        break;
 498                }
 499
 500                recvbuf2recvframe(padapter, pskb);
 501                skb_reset_tail_pointer(pskb);
 502
 503                pskb->len = 0;
 504
 505                skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
 506        }
 507}
 508
 509static void usb_read_port_complete(struct urb *purb)
 510{
 511        struct recv_buf *precvbuf = (struct recv_buf *)purb->context;
 512        struct rtw_adapter *padapter = (struct rtw_adapter *)precvbuf->adapter;
 513        struct recv_priv *precvpriv = &padapter->recvpriv;
 514
 515        RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
 516                 "usb_read_port_complete!!!\n");
 517
 518        precvpriv->rx_pending_cnt--;
 519
 520        if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
 521            padapter->bReadPortCancel) {
 522                RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
 523                         "usb_read_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)\n",
 524                         padapter->bDriverStopped, padapter->bSurpriseRemoved);
 525
 526                DBG_8723A("%s()-%d: RX Warning! bDriverStopped(%d) OR "
 527                          "bSurpriseRemoved(%d) bReadPortCancel(%d)\n",
 528                          __func__, __LINE__, padapter->bDriverStopped,
 529                          padapter->bSurpriseRemoved, padapter->bReadPortCancel);
 530                return;
 531        }
 532
 533        if (purb->status == 0) {
 534                if (purb->actual_length > MAX_RECVBUF_SZ ||
 535                    purb->actual_length < RXDESC_SIZE) {
 536                        RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
 537                                 "usb_read_port_complete: (purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)\n");
 538                        rtl8723au_read_port(padapter, 0, precvbuf);
 539                        DBG_8723A("%s()-%d: RX Warning!\n",
 540                                  __func__, __LINE__);
 541                } else {
 542                        rtw_reset_continual_urb_error(
 543                                adapter_to_dvobj(padapter));
 544
 545                        skb_put(precvbuf->pskb, purb->actual_length);
 546                        skb_queue_tail(&precvpriv->rx_skb_queue,
 547                                       precvbuf->pskb);
 548
 549                        if (skb_queue_len(&precvpriv->rx_skb_queue) <= 1)
 550                                tasklet_schedule(&precvpriv->recv_tasklet);
 551
 552                        precvbuf->pskb = NULL;
 553                        rtl8723au_read_port(padapter, 0, precvbuf);
 554                }
 555        } else {
 556                RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
 557                         "usb_read_port_complete : purb->status(%d) != 0\n",
 558                         purb->status);
 559                skb_put(precvbuf->pskb, purb->actual_length);
 560                precvbuf->pskb = NULL;
 561
 562                DBG_8723A("###=> usb_read_port_complete => urb status(%d)\n",
 563                          purb->status);
 564
 565                if (rtw_inc_and_chk_continual_urb_error(
 566                            adapter_to_dvobj(padapter))) {
 567                        padapter->bSurpriseRemoved = true;
 568                }
 569
 570                switch (purb->status) {
 571                case -EINVAL:
 572                case -EPIPE:
 573                case -ENODEV:
 574                case -ESHUTDOWN:
 575                        RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
 576                                 "usb_read_port_complete:bSurpriseRemoved = true\n");
 577                        /* Intentional fall through here */
 578                case -ENOENT:
 579                        padapter->bDriverStopped = true;
 580                        RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
 581                                 "usb_read_port_complete:bDriverStopped = true\n");
 582                        break;
 583                case -EPROTO:
 584                case -EOVERFLOW:
 585                        rtl8723au_read_port(padapter, 0, precvbuf);
 586                        break;
 587                case -EINPROGRESS:
 588                        DBG_8723A("ERROR: URB IS IN PROGRESS!\n");
 589                        break;
 590                default:
 591                        break;
 592                }
 593        }
 594}
 595
 596int rtl8723au_read_port(struct rtw_adapter *adapter, u32 cnt,
 597                        struct recv_buf *precvbuf)
 598{
 599        struct urb *purb;
 600        struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);
 601        struct recv_priv *precvpriv = &adapter->recvpriv;
 602        struct usb_device *pusbd = pdvobj->pusbdev;
 603        int err;
 604        unsigned int pipe;
 605        unsigned long tmpaddr;
 606        unsigned long alignment;
 607        int ret = _SUCCESS;
 608
 609        if (adapter->bDriverStopped || adapter->bSurpriseRemoved) {
 610                RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
 611                         "usb_read_port:(padapter->bDriverStopped ||padapter->bSurpriseRemoved)!!!\n");
 612                return _FAIL;
 613        }
 614
 615        if (!precvbuf) {
 616                RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
 617                         "usb_read_port:precvbuf == NULL\n");
 618                return _FAIL;
 619        }
 620
 621        if (!precvbuf->pskb)
 622                precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue);
 623
 624        /* re-assign for linux based on skb */
 625        if (!precvbuf->pskb) {
 626                precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
 627                if (precvbuf->pskb == NULL) {
 628                        RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
 629                                 "init_recvbuf(): alloc_skb fail!\n");
 630                        return _FAIL;
 631                }
 632
 633                tmpaddr = (unsigned long)precvbuf->pskb->data;
 634                alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
 635                skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
 636        }
 637
 638        precvpriv->rx_pending_cnt++;
 639
 640        purb = precvbuf->purb;
 641
 642        /* translate DMA FIFO addr to pipehandle */
 643        pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]);
 644
 645        usb_fill_bulk_urb(purb, pusbd, pipe, precvbuf->pskb->data,
 646                          MAX_RECVBUF_SZ, usb_read_port_complete,
 647                          precvbuf);/* context is precvbuf */
 648
 649        err = usb_submit_urb(purb, GFP_ATOMIC);
 650        if ((err) && (err != -EPERM)) {
 651                RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
 652                         "cannot submit rx in-token(err = 0x%.8x), URB_STATUS = 0x%.8x\n",
 653                         err, purb->status);
 654                DBG_8723A("cannot submit rx in-token(err = 0x%08x), urb_status "
 655                          "= %d\n", err, purb->status);
 656                ret = _FAIL;
 657        }
 658        return ret;
 659}
 660
 661void rtl8723au_xmit_tasklet(void *priv)
 662{
 663        int ret;
 664        struct rtw_adapter *padapter = (struct rtw_adapter *)priv;
 665        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
 666
 667        if (check_fwstate(&padapter->mlmepriv, _FW_UNDER_SURVEY))
 668                return;
 669
 670        while (1) {
 671                if (padapter->bDriverStopped || padapter->bSurpriseRemoved ||
 672                    padapter->bWritePortCancel) {
 673                        DBG_8723A("xmit_tasklet => bDriverStopped or "
 674                                  "bSurpriseRemoved or bWritePortCancel\n");
 675                        break;
 676                }
 677
 678                ret = rtl8723au_xmitframe_complete(padapter, pxmitpriv, NULL);
 679
 680                if (!ret)
 681                        break;
 682        }
 683}
 684
 685void rtl8723au_set_hw_type(struct rtw_adapter *padapter)
 686{
 687        padapter->chip_type = RTL8723A;
 688        padapter->HardwareType = HARDWARE_TYPE_RTL8723AU;
 689        DBG_8723A("CHIP TYPE: RTL8723A\n");
 690}
 691