These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / net / wireless / mwifiex / usb.c
index fd8027f..e43aff9 100644 (file)
@@ -42,9 +42,9 @@ static struct usb_device_id mwifiex_usb_table[] = {
        {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8801_PID_2,
                                       USB_CLASS_VENDOR_SPEC,
                                       USB_SUBCLASS_VENDOR_SPEC, 0xff)},
-       /* 8897 */
-       {USB_DEVICE(USB8XXX_VID, USB8897_PID_1)},
-       {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8897_PID_2,
+       /* 8997 */
+       {USB_DEVICE(USB8XXX_VID, USB8997_PID_1)},
+       {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8997_PID_2,
                                       USB_CLASS_VENDOR_SPEC,
                                       USB_SUBCLASS_VENDOR_SPEC, 0xff)},
        { }     /* Terminating entry */
@@ -60,7 +60,6 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size);
 static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
                            struct sk_buff *skb, u8 ep)
 {
-       struct device *dev = adapter->dev;
        u32 recv_type;
        __le32 tmp;
        int ret;
@@ -69,13 +68,15 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
                mwifiex_process_hs_config(adapter);
 
        if (skb->len < INTF_HEADER_LEN) {
-               dev_err(dev, "%s: invalid skb->len\n", __func__);
+               mwifiex_dbg(adapter, ERROR,
+                           "%s: invalid skb->len\n", __func__);
                return -1;
        }
 
        switch (ep) {
        case MWIFIEX_USB_EP_CMD_EVENT:
-               dev_dbg(dev, "%s: EP_CMD_EVENT\n", __func__);
+               mwifiex_dbg(adapter, EVENT,
+                           "%s: EP_CMD_EVENT\n", __func__);
                skb_copy_from_linear_data(skb, &tmp, INTF_HEADER_LEN);
                recv_type = le32_to_cpu(tmp);
                skb_pull(skb, INTF_HEADER_LEN);
@@ -83,11 +84,12 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
                switch (recv_type) {
                case MWIFIEX_USB_TYPE_CMD:
                        if (skb->len > MWIFIEX_SIZE_OF_CMD_BUFFER) {
-                               dev_err(dev, "CMD: skb->len too large\n");
+                               mwifiex_dbg(adapter, ERROR,
+                                           "CMD: skb->len too large\n");
                                ret = -1;
                                goto exit_restore_skb;
                        } else if (!adapter->curr_cmd) {
-                               dev_dbg(dev, "CMD: no curr_cmd\n");
+                               mwifiex_dbg(adapter, WARN, "CMD: no curr_cmd\n");
                                if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
                                        mwifiex_process_sleep_confirm_resp(
                                                        adapter, skb->data,
@@ -104,16 +106,19 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
                        break;
                case MWIFIEX_USB_TYPE_EVENT:
                        if (skb->len < sizeof(u32)) {
-                               dev_err(dev, "EVENT: skb->len too small\n");
+                               mwifiex_dbg(adapter, ERROR,
+                                           "EVENT: skb->len too small\n");
                                ret = -1;
                                goto exit_restore_skb;
                        }
                        skb_copy_from_linear_data(skb, &tmp, sizeof(u32));
                        adapter->event_cause = le32_to_cpu(tmp);
-                       dev_dbg(dev, "event_cause %#x\n", adapter->event_cause);
+                       mwifiex_dbg(adapter, EVENT,
+                                   "event_cause %#x\n", adapter->event_cause);
 
                        if (skb->len > MAX_EVENT_SIZE) {
-                               dev_err(dev, "EVENT: event body too large\n");
+                               mwifiex_dbg(adapter, ERROR,
+                                           "EVENT: event body too large\n");
                                ret = -1;
                                goto exit_restore_skb;
                        }
@@ -125,14 +130,16 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
                        adapter->event_skb = skb;
                        break;
                default:
-                       dev_err(dev, "unknown recv_type %#x\n", recv_type);
+                       mwifiex_dbg(adapter, ERROR,
+                                   "unknown recv_type %#x\n", recv_type);
                        return -1;
                }
                break;
        case MWIFIEX_USB_EP_DATA:
-               dev_dbg(dev, "%s: EP_DATA\n", __func__);
+               mwifiex_dbg(adapter, DATA, "%s: EP_DATA\n", __func__);
                if (skb->len > MWIFIEX_RX_DATA_BUF_SIZE) {
-                       dev_err(dev, "DATA: skb->len too large\n");
+                       mwifiex_dbg(adapter, ERROR,
+                                   "DATA: skb->len too large\n");
                        return -1;
                }
 
@@ -141,7 +148,8 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
                atomic_inc(&adapter->rx_pending);
                break;
        default:
-               dev_err(dev, "%s: unknown endport %#x\n", __func__, ep);
+               mwifiex_dbg(adapter, ERROR,
+                           "%s: unknown endport %#x\n", __func__, ep);
                return -1;
        }
 
@@ -176,8 +184,8 @@ static void mwifiex_usb_rx_complete(struct urb *urb)
 
        if (recv_length) {
                if (urb->status || (adapter->surprise_removed)) {
-                       dev_err(adapter->dev,
-                               "URB status is failed: %d\n", urb->status);
+                       mwifiex_dbg(adapter, ERROR,
+                                   "URB status is failed: %d\n", urb->status);
                        /* Do not free skb in case of command ep */
                        if (card->rx_cmd_ep != context->ep)
                                dev_kfree_skb_any(skb);
@@ -190,8 +198,9 @@ static void mwifiex_usb_rx_complete(struct urb *urb)
 
                status = mwifiex_usb_recv(adapter, skb, context->ep);
 
-               dev_dbg(adapter->dev, "info: recv_length=%d, status=%d\n",
-                       recv_length, status);
+               mwifiex_dbg(adapter, INFO,
+                           "info: recv_length=%d, status=%d\n",
+                           recv_length, status);
                if (status == -EINPROGRESS) {
                        mwifiex_queue_main_work(adapter);
 
@@ -203,8 +212,8 @@ static void mwifiex_usb_rx_complete(struct urb *urb)
                                return;
                } else {
                        if (status == -1)
-                               dev_err(adapter->dev,
-                                       "received data processing failed!\n");
+                               mwifiex_dbg(adapter, ERROR,
+                                           "received data processing failed!\n");
 
                        /* Do not free skb in case of command ep */
                        if (card->rx_cmd_ep != context->ep)
@@ -212,8 +221,8 @@ static void mwifiex_usb_rx_complete(struct urb *urb)
                }
        } else if (urb->status) {
                if (!adapter->is_suspended) {
-                       dev_warn(adapter->dev,
-                                "Card is removed: %d\n", urb->status);
+                       mwifiex_dbg(adapter, FATAL,
+                                   "Card is removed: %d\n", urb->status);
                        adapter->surprise_removed = true;
                }
                dev_kfree_skb_any(skb);
@@ -235,9 +244,11 @@ setup_for_next:
        if (card->rx_cmd_ep == context->ep) {
                mwifiex_usb_submit_rx_urb(context, size);
        } else {
-               context->skb = NULL;
-               if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING)
+               if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING){
                        mwifiex_usb_submit_rx_urb(context, size);
+               }else{
+                       context->skb = NULL;
+               }
        }
 
        return;
@@ -248,20 +259,36 @@ static void mwifiex_usb_tx_complete(struct urb *urb)
        struct urb_context *context = (struct urb_context *)(urb->context);
        struct mwifiex_adapter *adapter = context->adapter;
        struct usb_card_rec *card = adapter->card;
+       struct usb_tx_data_port *port;
+       int i;
 
-       dev_dbg(adapter->dev, "%s: status: %d\n", __func__, urb->status);
+       mwifiex_dbg(adapter, INFO,
+                   "%s: status: %d\n", __func__, urb->status);
 
        if (context->ep == card->tx_cmd_ep) {
-               dev_dbg(adapter->dev, "%s: CMD\n", __func__);
+               mwifiex_dbg(adapter, CMD,
+                           "%s: CMD\n", __func__);
                atomic_dec(&card->tx_cmd_urb_pending);
                adapter->cmd_sent = false;
        } else {
-               dev_dbg(adapter->dev, "%s: DATA\n", __func__);
-               atomic_dec(&card->tx_data_urb_pending);
+               mwifiex_dbg(adapter, DATA,
+                           "%s: DATA\n", __func__);
+               for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
+                       port = &card->port[i];
+                       if (context->ep == port->tx_data_ep) {
+                               atomic_dec(&port->tx_data_urb_pending);
+                               port->block_status = false;
+                               break;
+                       }
+               }
+               adapter->data_sent = false;
                mwifiex_write_data_complete(adapter, context->skb, 0,
                                            urb->status ? -1 : 0);
        }
 
+       if (card->mc_resync_flag)
+               mwifiex_multi_chan_resync(adapter);
+
        mwifiex_queue_main_work(adapter);
 
        return;
@@ -275,8 +302,8 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size)
        if (card->rx_cmd_ep != ctx->ep) {
                ctx->skb = dev_alloc_skb(size);
                if (!ctx->skb) {
-                       dev_err(adapter->dev,
-                               "%s: dev_alloc_skb failed\n", __func__);
+                       mwifiex_dbg(adapter, ERROR,
+                                   "%s: dev_alloc_skb failed\n", __func__);
                        return -ENOMEM;
                }
        }
@@ -291,7 +318,7 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size)
                atomic_inc(&card->rx_data_urb_pending);
 
        if (usb_submit_urb(ctx->urb, GFP_ATOMIC)) {
-               dev_err(adapter->dev, "usb_submit_urb failed\n");
+               mwifiex_dbg(adapter, ERROR, "usb_submit_urb failed\n");
                dev_kfree_skb_any(ctx->skb);
                ctx->skb = NULL;
 
@@ -308,7 +335,8 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size)
 
 static void mwifiex_usb_free(struct usb_card_rec *card)
 {
-       int i;
+       struct usb_tx_data_port *port;
+       int i, j;
 
        if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb)
                usb_kill_urb(card->rx_cmd.urb);
@@ -326,9 +354,12 @@ static void mwifiex_usb_free(struct usb_card_rec *card)
                card->rx_data_list[i].urb = NULL;
        }
 
-       for (i = 0; i < MWIFIEX_TX_DATA_URB; i++) {
-               usb_free_urb(card->tx_data_list[i].urb);
-               card->tx_data_list[i].urb = NULL;
+       for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
+               port = &card->port[i];
+               for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) {
+                       usb_free_urb(port->tx_data_list[j].urb);
+                       port->tx_data_list[j].urb = NULL;
+               }
        }
 
        usb_free_urb(card->tx_cmd.urb);
@@ -367,13 +398,13 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
        case USB8766_PID_1:
        case USB8797_PID_1:
        case USB8801_PID_1:
-       case USB8897_PID_1:
+       case USB8997_PID_1:
                card->usb_boot_state = USB8XXX_FW_DNLD;
                break;
        case USB8766_PID_2:
        case USB8797_PID_2:
        case USB8801_PID_2:
-       case USB8897_PID_2:
+       case USB8997_PID_2:
                card->usb_boot_state = USB8XXX_FW_READY;
                break;
        default:
@@ -416,8 +447,18 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
                        pr_debug("info: bulk OUT: max pkt size: %d, addr: %d\n",
                                 le16_to_cpu(epd->wMaxPacketSize),
                                 epd->bEndpointAddress);
-                       card->tx_data_ep = usb_endpoint_num(epd);
-                       atomic_set(&card->tx_data_urb_pending, 0);
+                       card->port[0].tx_data_ep = usb_endpoint_num(epd);
+                       atomic_set(&card->port[0].tx_data_urb_pending, 0);
+               }
+               if (usb_endpoint_dir_out(epd) &&
+                   usb_endpoint_num(epd) == MWIFIEX_USB_EP_DATA_CH2 &&
+                   usb_endpoint_xfer_bulk(epd)) {
+                       pr_debug("info: bulk OUT chan2:\t"
+                                "max pkt size: %d, addr: %d\n",
+                                le16_to_cpu(epd->wMaxPacketSize),
+                                epd->bEndpointAddress);
+                       card->port[1].tx_data_ep = usb_endpoint_num(epd);
+                       atomic_set(&card->port[1].tx_data_urb_pending, 0);
                }
                if (usb_endpoint_dir_out(epd) &&
                    usb_endpoint_num(epd) == MWIFIEX_USB_EP_CMD_EVENT &&
@@ -459,7 +500,8 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct usb_card_rec *card = usb_get_intfdata(intf);
        struct mwifiex_adapter *adapter;
-       int i;
+       struct usb_tx_data_port *port;
+       int i, j;
 
        if (!card || !card->adapter) {
                pr_err("%s: card or card->adapter is NULL\n", __func__);
@@ -468,7 +510,8 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
        adapter = card->adapter;
 
        if (unlikely(adapter->is_suspended))
-               dev_warn(adapter->dev, "Device already suspended\n");
+               mwifiex_dbg(adapter, WARN,
+                           "Device already suspended\n");
 
        mwifiex_enable_hs(adapter);
 
@@ -489,9 +532,13 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
                        if (card->rx_data_list[i].urb)
                                usb_kill_urb(card->rx_data_list[i].urb);
 
-       for (i = 0; i < MWIFIEX_TX_DATA_URB; i++)
-               if (card->tx_data_list[i].urb)
-                       usb_kill_urb(card->tx_data_list[i].urb);
+       for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
+               port = &card->port[i];
+               for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) {
+                       if (port->tx_data_list[j].urb)
+                               usb_kill_urb(port->tx_data_list[j].urb);
+               }
+       }
 
        if (card->tx_cmd.urb)
                usb_kill_urb(card->tx_cmd.urb);
@@ -519,7 +566,8 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
        adapter = card->adapter;
 
        if (unlikely(!adapter->is_suspended)) {
-               dev_warn(adapter->dev, "Device already resumed\n");
+               mwifiex_dbg(adapter, WARN,
+                           "Device already resumed\n");
                return 0;
        }
 
@@ -578,7 +626,8 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
 
        mwifiex_usb_free(card);
 
-       dev_dbg(adapter->dev, "%s: removing card\n", __func__);
+       mwifiex_dbg(adapter, FATAL,
+                   "%s: removing card\n", __func__);
        mwifiex_remove_card(adapter, &add_remove_card_sem);
 
        usb_set_intfdata(intf, NULL);
@@ -601,28 +650,38 @@ static struct usb_driver mwifiex_usb_driver = {
 static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
 {
        struct usb_card_rec *card = (struct usb_card_rec *)adapter->card;
-       int i;
+       struct usb_tx_data_port *port;
+       int i, j;
 
        card->tx_cmd.adapter = adapter;
        card->tx_cmd.ep = card->tx_cmd_ep;
 
        card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!card->tx_cmd.urb) {
-               dev_err(adapter->dev, "tx_cmd.urb allocation failed\n");
+               mwifiex_dbg(adapter, ERROR,
+                           "tx_cmd.urb allocation failed\n");
                return -ENOMEM;
        }
 
-       card->tx_data_ix = 0;
-
-       for (i = 0; i < MWIFIEX_TX_DATA_URB; i++) {
-               card->tx_data_list[i].adapter = adapter;
-               card->tx_data_list[i].ep = card->tx_data_ep;
-
-               card->tx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!card->tx_data_list[i].urb) {
-                       dev_err(adapter->dev,
-                               "tx_data_list[] urb allocation failed\n");
-                       return -ENOMEM;
+       for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
+               port = &card->port[i];
+               if (!port->tx_data_ep)
+                       continue;
+               port->tx_data_ix = 0;
+               if (port->tx_data_ep == MWIFIEX_USB_EP_DATA)
+                       port->block_status = false;
+               else
+                       port->block_status = true;
+               for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) {
+                       port->tx_data_list[j].adapter = adapter;
+                       port->tx_data_list[j].ep = port->tx_data_ep;
+                       port->tx_data_list[j].urb =
+                                       usb_alloc_urb(0, GFP_KERNEL);
+                       if (!port->tx_data_list[j].urb) {
+                               mwifiex_dbg(adapter, ERROR,
+                                           "urb allocation failed\n");
+                               return -ENOMEM;
+                       }
                }
        }
 
@@ -639,15 +698,13 @@ static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter)
 
        card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!card->rx_cmd.urb) {
-               dev_err(adapter->dev, "rx_cmd.urb allocation failed\n");
+               mwifiex_dbg(adapter, ERROR, "rx_cmd.urb allocation failed\n");
                return -ENOMEM;
        }
 
        card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE);
-       if (!card->rx_cmd.skb) {
-               dev_err(adapter->dev, "rx_cmd.skb allocation failed\n");
+       if (!card->rx_cmd.skb)
                return -ENOMEM;
-       }
 
        if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE))
                return -1;
@@ -658,8 +715,8 @@ static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter)
 
                card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
                if (!card->rx_data_list[i].urb) {
-                       dev_err(adapter->dev,
-                               "rx_data_list[] urb allocation failed\n");
+                       mwifiex_dbg(adapter, ERROR,
+                                   "rx_data_list[] urb allocation failed\n");
                        return -1;
                }
                if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i],
@@ -683,7 +740,8 @@ static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf,
        ret = usb_bulk_msg(card->udev, usb_sndbulkpipe(card->udev, ep), pbuf,
                           *len, &actual_length, timeout);
        if (ret) {
-               dev_err(adapter->dev, "usb_bulk_msg for tx failed: %d\n", ret);
+               mwifiex_dbg(adapter, ERROR,
+                           "usb_bulk_msg for tx failed: %d\n", ret);
                return ret;
        }
 
@@ -702,7 +760,8 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf,
        ret = usb_bulk_msg(card->udev, usb_rcvbulkpipe(card->udev, ep), pbuf,
                           *len, &actual_length, timeout);
        if (ret) {
-               dev_err(adapter->dev, "usb_bulk_msg for rx failed: %d\n", ret);
+               mwifiex_dbg(adapter, ERROR,
+                           "usb_bulk_msg for rx failed: %d\n", ret);
                return ret;
        }
 
@@ -711,40 +770,126 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf,
        return ret;
 }
 
+static void mwifiex_usb_port_resync(struct mwifiex_adapter *adapter)
+{
+       struct usb_card_rec *card = adapter->card;
+       u8 active_port = MWIFIEX_USB_EP_DATA;
+       struct mwifiex_private *priv = NULL;
+       int i;
+
+       if (adapter->usb_mc_status) {
+               for (i = 0; i < adapter->priv_num; i++) {
+                       priv = adapter->priv[i];
+                       if (!priv)
+                               continue;
+                       if ((priv->bss_role == MWIFIEX_BSS_ROLE_UAP &&
+                            !priv->bss_started) ||
+                           (priv->bss_role == MWIFIEX_BSS_ROLE_STA &&
+                            !priv->media_connected))
+                               priv->usb_port = MWIFIEX_USB_EP_DATA;
+               }
+               for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++)
+                       card->port[i].block_status = false;
+       } else {
+               for (i = 0; i < adapter->priv_num; i++) {
+                       priv = adapter->priv[i];
+                       if (!priv)
+                               continue;
+                       if ((priv->bss_role == MWIFIEX_BSS_ROLE_UAP &&
+                            priv->bss_started) ||
+                           (priv->bss_role == MWIFIEX_BSS_ROLE_STA &&
+                            priv->media_connected)) {
+                               active_port = priv->usb_port;
+                               break;
+                       }
+               }
+               for (i = 0; i < adapter->priv_num; i++) {
+                       priv = adapter->priv[i];
+                       if (priv)
+                               priv->usb_port = active_port;
+               }
+               for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
+                       if (active_port == card->port[i].tx_data_ep)
+                               card->port[i].block_status = false;
+                       else
+                               card->port[i].block_status = true;
+               }
+       }
+}
+
+static bool mwifiex_usb_is_port_ready(struct mwifiex_private *priv)
+{
+       struct usb_card_rec *card = priv->adapter->card;
+       int idx;
+
+       for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) {
+               if (priv->usb_port == card->port[idx].tx_data_ep)
+                       return !card->port[idx].block_status;
+       }
+
+       return false;
+}
+
+static inline u8 mwifiex_usb_data_sent(struct mwifiex_adapter *adapter)
+{
+       struct usb_card_rec *card = adapter->card;
+       int i;
+
+       for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++)
+               if (!card->port[i].block_status)
+                       return false;
+
+       return true;
+}
+
 /* This function write a command/data packet to card. */
 static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
                                    struct sk_buff *skb,
                                    struct mwifiex_tx_param *tx_param)
 {
        struct usb_card_rec *card = adapter->card;
-       struct urb_context *context;
+       struct urb_context *context = NULL;
+       struct usb_tx_data_port *port = NULL;
        u8 *data = (u8 *)skb->data;
        struct urb *tx_urb;
+       int idx, ret;
 
        if (adapter->is_suspended) {
-               dev_err(adapter->dev,
-                       "%s: not allowed while suspended\n", __func__);
+               mwifiex_dbg(adapter, ERROR,
+                           "%s: not allowed while suspended\n", __func__);
                return -1;
        }
 
        if (adapter->surprise_removed) {
-               dev_err(adapter->dev, "%s: device removed\n", __func__);
+               mwifiex_dbg(adapter, ERROR, "%s: device removed\n", __func__);
                return -1;
        }
 
-       if (ep == card->tx_data_ep &&
-           atomic_read(&card->tx_data_urb_pending) >= MWIFIEX_TX_DATA_URB) {
-               return -EBUSY;
-       }
-
-       dev_dbg(adapter->dev, "%s: ep=%d\n", __func__, ep);
+       mwifiex_dbg(adapter, INFO, "%s: ep=%d\n", __func__, ep);
 
        if (ep == card->tx_cmd_ep) {
                context = &card->tx_cmd;
        } else {
-               if (card->tx_data_ix >= MWIFIEX_TX_DATA_URB)
-                       card->tx_data_ix = 0;
-               context = &card->tx_data_list[card->tx_data_ix++];
+               for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) {
+                       if (ep == card->port[idx].tx_data_ep) {
+                               port = &card->port[idx];
+                               if (atomic_read(&port->tx_data_urb_pending)
+                                   >= MWIFIEX_TX_DATA_URB) {
+                                       port->block_status = true;
+                                       ret = -EBUSY;
+                                       goto done;
+                               }
+                               if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB)
+                                       port->tx_data_ix = 0;
+                               context =
+                                       &port->tx_data_list[port->tx_data_ix++];
+                               break;
+                       }
+               }
+               if (!port) {
+                       mwifiex_dbg(adapter, ERROR, "Wrong usb tx data port\n");
+                       return -1;
+               }
        }
 
        context->adapter = adapter;
@@ -761,29 +906,40 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
        if (ep == card->tx_cmd_ep)
                atomic_inc(&card->tx_cmd_urb_pending);
        else
-               atomic_inc(&card->tx_data_urb_pending);
+               atomic_inc(&port->tx_data_urb_pending);
 
        if (usb_submit_urb(tx_urb, GFP_ATOMIC)) {
-               dev_err(adapter->dev, "%s: usb_submit_urb failed\n", __func__);
+               mwifiex_dbg(adapter, ERROR,
+                           "%s: usb_submit_urb failed\n", __func__);
                if (ep == card->tx_cmd_ep) {
                        atomic_dec(&card->tx_cmd_urb_pending);
                } else {
-                       atomic_dec(&card->tx_data_urb_pending);
-                       if (card->tx_data_ix)
-                               card->tx_data_ix--;
+                       atomic_dec(&port->tx_data_urb_pending);
+                       port->block_status = false;
+                       if (port->tx_data_ix)
+                               port->tx_data_ix--;
                        else
-                               card->tx_data_ix = MWIFIEX_TX_DATA_URB;
+                               port->tx_data_ix = MWIFIEX_TX_DATA_URB;
                }
 
                return -1;
        } else {
-               if (ep == card->tx_data_ep &&
-                   atomic_read(&card->tx_data_urb_pending) ==
-                                                       MWIFIEX_TX_DATA_URB)
-                       return -ENOSR;
+               if (ep != card->tx_cmd_ep &&
+                   atomic_read(&port->tx_data_urb_pending) ==
+                                                       MWIFIEX_TX_DATA_URB) {
+                       port->block_status = true;
+                       ret = -ENOSR;
+                       goto done;
+               }
        }
 
        return -EINPROGRESS;
+
+done:
+       if (ep != card->tx_cmd_ep)
+               adapter->data_sent = mwifiex_usb_data_sent(adapter);
+
+       return ret;
 }
 
 /* This function register usb device and initialize parameter. */
@@ -795,10 +951,10 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
        adapter->dev = &card->udev->dev;
 
        switch (le16_to_cpu(card->udev->descriptor.idProduct)) {
-       case USB8897_PID_1:
-       case USB8897_PID_2:
+       case USB8997_PID_1:
+       case USB8997_PID_2:
                adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
-               strcpy(adapter->fw_name, USB8897_DEFAULT_FW_NAME);
+               strcpy(adapter->fw_name, USB8997_DEFAULT_FW_NAME);
                adapter->ext_scan = true;
                break;
        case USB8766_PID_1:
@@ -821,6 +977,9 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
                break;
        }
 
+       adapter->usb_mc_status = false;
+       adapter->usb_mc_setup = false;
+
        return 0;
 }
 
@@ -843,16 +1002,18 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
        u8 check_winner = 1;
 
        if (!firmware) {
-               dev_err(adapter->dev,
-                       "No firmware image found! Terminating download\n");
+               mwifiex_dbg(adapter, ERROR,
+                           "No firmware image found! Terminating download\n");
                ret = -1;
                goto fw_exit;
        }
 
        /* Allocate memory for transmit */
        fwdata = kzalloc(FW_DNLD_TX_BUF_SIZE, GFP_KERNEL);
-       if (!fwdata)
+       if (!fwdata) {
+               ret = -ENOMEM;
                goto fw_exit;
+       }
 
        /* Allocate memory for receive */
        recv_buff = kzalloc(FW_DNLD_RX_BUF_SIZE, GFP_KERNEL);
@@ -889,8 +1050,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
                                                MWIFIEX_USB_EP_CMD_EVENT,
                                                MWIFIEX_USB_TIMEOUT);
                        if (ret) {
-                               dev_err(adapter->dev,
-                                       "write_data_sync: failed: %d\n", ret);
+                               mwifiex_dbg(adapter, ERROR,
+                                           "write_data_sync: failed: %d\n",
+                                           ret);
                                continue;
                        }
 
@@ -902,8 +1064,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
                                                MWIFIEX_USB_EP_CMD_EVENT,
                                                MWIFIEX_USB_TIMEOUT);
                        if (ret) {
-                               dev_err(adapter->dev,
-                                       "read_data_sync: failed: %d\n", ret);
+                               mwifiex_dbg(adapter, ERROR,
+                                           "read_data_sync: failed: %d\n",
+                                           ret);
                                continue;
                        }
 
@@ -913,17 +1076,17 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
                        /* check 1st firmware block resp for highest bit set */
                        if (check_winner) {
                                if (le32_to_cpu(sync_fw.cmd) & 0x80000000) {
-                                       dev_warn(adapter->dev,
-                                                "USB is not the winner %#x\n",
-                                                sync_fw.cmd);
+                                       mwifiex_dbg(adapter, WARN,
+                                                   "USB is not the winner %#x\n",
+                                                   sync_fw.cmd);
 
                                        /* returning success */
                                        ret = 0;
                                        goto cleanup;
                                }
 
-                               dev_dbg(adapter->dev,
-                                       "USB is the winner, start to download FW\n");
+                               mwifiex_dbg(adapter, MSG,
+                                           "start to download FW...\n");
 
                                check_winner = 0;
                                break;
@@ -931,9 +1094,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
 
                        /* check the firmware block response for CRC errors */
                        if (sync_fw.cmd) {
-                               dev_err(adapter->dev,
-                                       "FW received block with CRC %#x\n",
-                                       sync_fw.cmd);
+                               mwifiex_dbg(adapter, ERROR,
+                                           "FW received block with CRC %#x\n",
+                                           sync_fw.cmd);
                                ret = -1;
                                continue;
                        }
@@ -945,8 +1108,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
        } while ((dnld_cmd != FW_HAS_LAST_BLOCK) && retries);
 
 cleanup:
-       dev_notice(adapter->dev,
-                  "info: FW download over, size %d bytes\n", tlen);
+       mwifiex_dbg(adapter, MSG,
+                   "info: FW download over, size %d bytes\n", tlen);
 
        kfree(recv_buff);
        kfree(fwdata);
@@ -1046,6 +1209,8 @@ static struct mwifiex_if_ops usb_ops = {
        .event_complete =       mwifiex_usb_cmd_event_complete,
        .host_to_card =         mwifiex_usb_host_to_card,
        .submit_rem_rx_urbs =   mwifiex_usb_submit_rem_rx_urbs,
+       .multi_port_resync =    mwifiex_usb_port_resync,
+       .is_port_ready =        mwifiex_usb_is_port_ready,
 };
 
 /* This function initializes the USB driver module.
@@ -1099,4 +1264,4 @@ MODULE_LICENSE("GPL v2");
 MODULE_FIRMWARE(USB8766_DEFAULT_FW_NAME);
 MODULE_FIRMWARE(USB8797_DEFAULT_FW_NAME);
 MODULE_FIRMWARE(USB8801_DEFAULT_FW_NAME);
-MODULE_FIRMWARE(USB8897_DEFAULT_FW_NAME);
+MODULE_FIRMWARE(USB8997_DEFAULT_FW_NAME);