summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.c')
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.c2028
1 files changed, 2028 insertions, 0 deletions
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.c
new file mode 100644
index 000000000000..155003f086af
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.c
@@ -0,0 +1,2028 @@
+/** @file moal_usb.c
+ *
+ * @brief This file contains the interfaceing to USB bus
+ * driver.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#include "moal_usb.h"
+extern struct semaphore AddRemoveCardSem;
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+#if defined(USB8997) || defined(USB9098) || defined(USB9097) || defined(USB8978)
+/** Card-type detection frame response */
+typedef struct {
+ /** 32-bit ACK+WINNER field */
+ t_u32 ack_winner;
+ /** 32-bit Sequence number */
+ t_u32 seq;
+ /** 32-bit extend */
+ t_u32 extend;
+ /** 32-bit chip-revision code */
+ t_u32 chip_rev;
+ /** 32-bit strap setting */
+ t_u32 strap;
+} usb_ack_pkt;
+#endif
+
+/** NXP USB device */
+#define NXP_USB_DEVICE(vid, pid, name) \
+ USB_DEVICE(vid, pid), .driver_info = (t_ptr)name
+
+/** Name of the USB driver */
+const char usbdriver_name[] = "usbxxx";
+
+/** This structure contains the device signature */
+struct usb_device_id woal_usb_table[] = {
+/* Enter the device signature inside */
+#ifdef USB8897
+ {NXP_USB_DEVICE(USB8897_VID_1, USB8897_PID_1, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8897_VID_1, USB8897_PID_2, "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB8997
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_1, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997V2_PID_1,
+ "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_2, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_3, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_4, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_5, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_6, "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB8978
+ {NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_1, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_1_BT,
+ "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_2, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_2_BT,
+ "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB9098
+ {NXP_USB_DEVICE(USB9098_VID_1, USB9098_PID_1, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB9098_VID_1, USB9098_PID_2, "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB9097
+ {NXP_USB_DEVICE(USB9097_VID_1, USB9097_PID_1, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB9097_VID_1, USB9097_PID_2, "NXP WLAN USB Adapter")},
+#endif
+ /* Terminating entry */
+ {},
+};
+
+/** This structure contains the device signature */
+struct usb_device_id woal_usb_table_skip_fwdnld[] = {
+/* Enter the device signature inside */
+#ifdef USB8897
+ {NXP_USB_DEVICE(USB8897_VID_1, USB8897_PID_2, "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB8997
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_2, "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB8978
+ {NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_2, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_2_BT,
+ "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB9098
+ {NXP_USB_DEVICE(USB9098_VID_1, USB9098_PID_2, "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB9097
+ {NXP_USB_DEVICE(USB9097_VID_1, USB9097_PID_2, "NXP WLAN USB Adapter")},
+#endif
+ /* Terminating entry */
+ {},
+};
+
+static mlan_status woal_usb_submit_rx_urb(urb_context *ctx, int size);
+static int woal_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id);
+static void woal_usb_disconnect(struct usb_interface *intf);
+static mlan_status woal_usb_write_data_sync(moal_handle *handle,
+ mlan_buffer *pmbuf, t_u32 endpoint,
+ t_u32 timeout);
+static mlan_status woal_usb_read_data_sync(moal_handle *handle,
+ mlan_buffer *pmbuf, t_u32 endpoint,
+ t_u32 timeout);
+#ifdef CONFIG_PM
+static int woal_usb_suspend(struct usb_interface *intf, pm_message_t message);
+static int woal_usb_resume(struct usb_interface *intf);
+#endif /* CONFIG_PM */
+
+/** woal_usb_driver */
+static struct usb_driver REFDATA woal_usb_driver = {
+ /* Driver name */
+ .name = usbdriver_name,
+
+ /* Probe function name */
+ .probe = woal_usb_probe,
+
+ /* Disconnect function name */
+ .disconnect = woal_usb_disconnect,
+
+ /* Device signature table */
+ .id_table = woal_usb_table,
+#ifdef CONFIG_PM
+ /* Suspend function name */
+ .suspend = woal_usb_suspend,
+
+ /* Resume function name */
+ .resume = woal_usb_resume,
+
+ /* Reset resume function name */
+ .reset_resume = woal_usb_resume,
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+ /* Driver supports autosuspend */
+ .supports_autosuspend = 1,
+#endif
+#endif /* CONFIG_PM */
+};
+
+MODULE_DEVICE_TABLE(usb, woal_usb_table);
+MODULE_DEVICE_TABLE(usb, woal_usb_table_skip_fwdnld);
+
+/* moal interface ops */
+static moal_if_ops usb_ops;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+extern int skip_fwdnld;
+extern int max_tx_buf;
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+/**
+ * @brief This function receive packet of the data/cmd/event packet
+ * and pass to MLAN
+ *
+ * @param urb Pointer to struct urb
+ * @param regs Registers
+ *
+ * @return N/A
+ */
+static void woal_usb_receive(struct urb *urb, struct pt_regs *regs)
+#else
+/**
+ * @brief This function receive packet of the data/cmd/event packet
+ * and pass to MLAN
+ *
+ * @param urb Pointer to struct urb
+ *
+ * @return N/A
+ */
+static void woal_usb_receive(struct urb *urb)
+#endif
+{
+ urb_context *context = NULL;
+ moal_handle *handle = NULL;
+ mlan_buffer *pmbuf = NULL;
+ struct usb_card_rec *cardp = NULL;
+ int recv_length;
+ int size;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!urb || !urb->context) {
+ PRINTM(MERROR, "URB or URB context is not valid in USB Rx\n");
+ LEAVE();
+ return;
+ }
+ context = (urb_context *)urb->context;
+ handle = context->handle;
+ pmbuf = context->pmbuf;
+ recv_length = urb->actual_length;
+
+ if (!handle || !handle->card || !pmbuf) {
+ PRINTM(MERROR,
+ "moal handle, card structure or mlan_buffer is not valid in USB Rx\n");
+ LEAVE();
+ return;
+ }
+ cardp = (struct usb_card_rec *)handle->card;
+ if (cardp->rx_cmd_ep == context->ep)
+ atomic_dec(&cardp->rx_cmd_urb_pending);
+ else
+ atomic_dec(&cardp->rx_data_urb_pending);
+
+ if (recv_length) {
+ if (urb->status || (handle->surprise_removed == MTRUE)) {
+ if (handle->surprise_removed || handle->is_suspended) {
+ woal_free_mlan_buffer(handle, pmbuf);
+ context->pmbuf = NULL;
+ goto rx_exit;
+ } else {
+ PRINTM(MERROR,
+ "EP %d Rx URB status failure: %d\n",
+ context->ep, urb->status);
+ /* Do not free mlan_buffer in case of command ep
+ */
+ if (cardp->rx_cmd_ep != context->ep)
+ woal_free_mlan_buffer(handle, pmbuf);
+ goto setup_for_next;
+ }
+ }
+ pmbuf->data_len = recv_length;
+ pmbuf->flags |= MLAN_BUF_FLAG_RX_DEAGGR;
+ /* Send packet to MLAN */
+ atomic_inc(&handle->rx_pending);
+ status = mlan_recv(handle->pmlan_adapter, pmbuf, context->ep);
+ PRINTM(MINFO, "Receive length = 0x%x, status=%d\n", recv_length,
+ status);
+ if (status == MLAN_STATUS_PENDING) {
+ queue_work(handle->workqueue, &handle->main_work);
+ /* urb for data_ep is re-submitted now, unless we reach
+ * HIGH_RX_PENDING */
+ /* urb for cmd_ep will be re-submitted in callback
+ * moal_recv_complete */
+ if (cardp->rx_cmd_ep == context->ep)
+ goto rx_exit;
+ else if (atomic_read(&handle->rx_pending) >=
+ HIGH_RX_PENDING) {
+ context->pmbuf = NULL;
+ goto rx_exit;
+ }
+ } else {
+ atomic_dec(&handle->rx_pending);
+ if (status == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR,
+ "MLAN fail to process the receive data\n");
+ } else if ((status == MLAN_STATUS_SUCCESS) &&
+ (pmbuf->flags &
+ MLAN_BUF_FLAG_SLEEPCFM_RESP)) {
+ pmbuf->flags &= ~MLAN_BUF_FLAG_SLEEPCFM_RESP;
+ queue_work(handle->workqueue,
+ &handle->main_work);
+ }
+ /* Do not free mlan_buffer in case of command ep */
+ if (cardp->rx_cmd_ep != context->ep)
+ woal_free_mlan_buffer(handle, pmbuf);
+ }
+ } else if (urb->status) {
+ if (!((cardp->rx_data_ep == context->ep) &&
+ (cardp->resubmit_urbs == 1))) {
+ if (!handle->is_suspended) {
+ PRINTM(MMSG, "Card is removed: %d\n",
+ urb->status);
+ handle->surprise_removed = MTRUE;
+ }
+ }
+ woal_free_mlan_buffer(handle, pmbuf);
+ context->pmbuf = NULL;
+ goto rx_exit;
+ } else {
+ /* Do not free mlan_buffer in case of command ep */
+ if (cardp->rx_cmd_ep != context->ep)
+ woal_free_mlan_buffer(handle, pmbuf);
+ goto setup_for_next;
+ }
+
+setup_for_next:
+ if (cardp->rx_cmd_ep == context->ep) {
+ size = MLAN_RX_CMD_BUF_SIZE;
+ } else {
+ if (cardp->rx_deaggr_ctrl.enable) {
+ size = cardp->rx_deaggr_ctrl.aggr_max;
+ if (cardp->rx_deaggr_ctrl.aggr_mode ==
+ MLAN_USB_AGGR_MODE_NUM) {
+ size *= MAX(MLAN_USB_MAX_PKT_SIZE,
+ cardp->rx_deaggr_ctrl.aggr_align);
+ size = MAX(size, MLAN_RX_DATA_BUF_SIZE);
+ }
+ } else
+ size = MLAN_RX_DATA_BUF_SIZE;
+ }
+ woal_usb_submit_rx_urb(context, size);
+
+rx_exit:
+ LEAVE();
+ return;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+/**
+ * @brief Call back function to handle the status of the Tx data URB
+ *
+ * @param urb Pointer to urb structure
+ * @param regs Registers
+ *
+ * @return N/A
+ */
+static void woal_usb_tx_complete(struct urb *urb, struct pt_regs *regs)
+#else
+/**
+ * @brief Call back function to handle the status of the Tx data URB
+ *
+ * @param urb Pointer to urb structure
+ *
+ * @return N/A
+ */
+static void woal_usb_tx_complete(struct urb *urb)
+#endif
+{
+ urb_context *context = NULL;
+ moal_handle *handle = NULL;
+ struct usb_card_rec *cardp = NULL;
+
+ ENTER();
+
+ if (!urb || !urb->context) {
+ PRINTM(MERROR,
+ "URB or URB context is not valid in USB Tx complete\n");
+ LEAVE();
+ return;
+ }
+ context = (urb_context *)urb->context;
+ handle = context->handle;
+
+ if (!handle || !handle->card || !context->pmbuf) {
+ PRINTM(MERROR,
+ "moal handle, card structure or mlan_buffer is not valid in USB Tx complete\n");
+ LEAVE();
+ return;
+ }
+ cardp = handle->card;
+
+ /* Handle the transmission complete validations */
+ if (urb->status) {
+ PRINTM(MERROR, "EP %d Tx URB status failure: %d\n", context->ep,
+ urb->status);
+ mlan_write_data_async_complete(handle->pmlan_adapter,
+ context->pmbuf, context->ep,
+ MLAN_STATUS_FAILURE);
+ } else {
+ mlan_write_data_async_complete(handle->pmlan_adapter,
+ context->pmbuf, context->ep,
+ MLAN_STATUS_SUCCESS);
+ }
+
+ /* Decrease pending URB counter */
+ if (context->ep == cardp->tx_cmd_ep)
+ atomic_dec(&cardp->tx_cmd_urb_pending);
+ else if (context->ep == cardp->tx_data_ep)
+ atomic_dec(&cardp->tx_data_urb_pending);
+
+ queue_work(handle->workqueue, &handle->main_work);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function sets up the data to receive
+ *
+ * @param ctx Pointer to urb_context structure
+ * @param size Skb size
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_usb_submit_rx_urb(urb_context *ctx, int size)
+{
+ moal_handle *handle = ctx->handle;
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *data = NULL;
+
+ ENTER();
+
+ if (handle->surprise_removed || handle->is_suspended) {
+ if ((cardp->rx_cmd_ep == ctx->ep) && ctx->pmbuf) {
+ woal_free_mlan_buffer(handle, ctx->pmbuf);
+ ctx->pmbuf = NULL;
+ }
+ PRINTM(MERROR,
+ "Card removed/suspended, EP %d Rx URB submit skipped\n",
+ ctx->ep);
+ goto rx_ret;
+ }
+
+ if (cardp->rx_cmd_ep != ctx->ep) {
+ ctx->pmbuf = woal_alloc_mlan_buffer(handle, size);
+ if (!ctx->pmbuf) {
+ PRINTM(MERROR,
+ "Fail to submit Rx URB due to no memory/skb\n");
+ goto rx_ret;
+ }
+ ctx->pmbuf->data_offset = MLAN_RX_HEADER_LEN;
+ data = ctx->pmbuf->pbuf + ctx->pmbuf->data_offset;
+ } else {
+ ctx->pmbuf->data_offset = 0;
+ data = ctx->pmbuf->pbuf + ctx->pmbuf->data_offset;
+ }
+
+ if (cardp->rx_cmd_ep == ctx->ep &&
+ cardp->rx_cmd_ep_type == USB_ENDPOINT_XFER_INT)
+ usb_fill_int_urb(ctx->urb, cardp->udev,
+ usb_rcvintpipe(cardp->udev, ctx->ep), data,
+ size - ctx->pmbuf->data_offset,
+ woal_usb_receive, (void *)ctx,
+ cardp->rx_cmd_interval);
+ else
+ usb_fill_bulk_urb(ctx->urb, cardp->udev,
+ usb_rcvbulkpipe(cardp->udev, ctx->ep), data,
+ size - ctx->pmbuf->data_offset,
+ woal_usb_receive, (void *)ctx);
+ if (cardp->rx_cmd_ep == ctx->ep)
+ atomic_inc(&cardp->rx_cmd_urb_pending);
+ else
+ atomic_inc(&cardp->rx_data_urb_pending);
+ if (usb_submit_urb(ctx->urb, GFP_ATOMIC)) {
+ /* Submit URB failure */
+ PRINTM(MERROR, "Submit EP %d Rx URB failed: %d\n", ctx->ep,
+ ret);
+ woal_free_mlan_buffer(handle, ctx->pmbuf);
+ if (cardp->rx_cmd_ep == ctx->ep)
+ atomic_dec(&cardp->rx_cmd_urb_pending);
+ else
+ atomic_dec(&cardp->rx_data_urb_pending);
+ ctx->pmbuf = NULL;
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ ret = MLAN_STATUS_SUCCESS;
+ }
+rx_ret:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+#if defined(USB8997) || defined(USB9098) || defined(USB9097) || defined(USB8978)
+/**
+ * @brief Check chip revision
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param usb_chip_rev A pointer to usb_chip_rev variable
+ * @param usb_strap A pointer to usb_strap
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_check_chip_revision(moal_handle *handle, t_u32 *usb_chip_rev,
+ t_u32 *usb_strap)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_buffer mbuf;
+ t_u8 *tx_buff = 0;
+ t_u8 *recv_buff = 0;
+ usb_ack_pkt ack_pkt;
+ t_u32 extend_ver;
+ t_u8 tx_size = CHIP_REV_TX_BUF_SIZE;
+ struct usb_card_rec *cardp = handle->card;
+
+ ENTER();
+
+ /* Allocate memory for transmit */
+ tx_buff = kzalloc(tx_size, GFP_ATOMIC | GFP_DMA);
+ if (tx_buff == NULL) {
+ PRINTM(MERROR,
+ "Could not allocate buffer for chip revision check frame transmission\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto cleanup;
+ }
+
+ /* Allocate memory for receive */
+ recv_buff = kzalloc(CHIP_REV_RX_BUF_SIZE, GFP_ATOMIC | GFP_DMA);
+ if (recv_buff == NULL) {
+ PRINTM(MERROR,
+ "Could not allocate buffer for chip revision check frame response\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto cleanup;
+ }
+
+ /* The struct is initialised to all zero */
+ memset(&ack_pkt, 0, sizeof(usb_ack_pkt));
+
+ /* Send pseudo data to check winner status first */
+ memset(&mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = (t_u8 *)tx_buff;
+ mbuf.data_len = tx_size;
+
+ /* Send the chip revision check frame */
+ ret = woal_usb_write_data_sync(handle, &mbuf, cardp->tx_cmd_ep,
+ MLAN_USB_BULK_MSG_TIMEOUT);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Chip revision check frame dnld: write_data failed, ret %d\n",
+ ret);
+ ret = MLAN_STATUS_FAILURE;
+ goto cleanup;
+ }
+
+ memset(&mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = (t_u8 *)recv_buff;
+ mbuf.data_len = CHIP_REV_RX_BUF_SIZE;
+
+ /* Receive the chip revision check frame response */
+ ret = woal_usb_read_data_sync(handle, &mbuf, cardp->rx_cmd_ep,
+ MLAN_USB_BULK_MSG_TIMEOUT);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Chip revision check frame response: read_data failed, ret %d\n",
+ ret);
+ ret = MLAN_STATUS_FAILURE;
+ goto cleanup;
+ }
+ moal_memcpy_ext(handle, &ack_pkt, recv_buff, sizeof(usb_ack_pkt),
+ sizeof(ack_pkt));
+ ack_pkt.ack_winner = woal_le32_to_cpu(ack_pkt.ack_winner);
+ ack_pkt.seq = woal_le32_to_cpu(ack_pkt.seq);
+ ack_pkt.extend = woal_le32_to_cpu(ack_pkt.extend);
+ ack_pkt.chip_rev = woal_le32_to_cpu(ack_pkt.chip_rev);
+ ack_pkt.strap = woal_le32_to_cpu(ack_pkt.strap);
+
+ if ((ack_pkt.extend & 0xffff0000) == EXTEND_HDR) {
+ extend_ver = ack_pkt.extend & 0x0000ffff;
+ *usb_chip_rev = ack_pkt.chip_rev & 0x000000ff;
+ if (extend_ver >= EXTEND_V2) {
+ PRINTM(MINFO, "chip_rev=0x%x, strap=0x%x\n",
+ *usb_chip_rev, ack_pkt.strap);
+ *usb_strap = ack_pkt.strap & 0x7;
+ } else
+ PRINTM(MINFO, "chip_rev=0x%x\n", *usb_chip_rev);
+ }
+cleanup:
+ kfree(recv_buff);
+ kfree(tx_buff);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief This function unlink urb
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return N/A
+ */
+static void woal_usb_unlink_urb(void *card_desc)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)card_desc;
+ int i;
+ ENTER();
+ if (cardp) {
+ /* Unlink Rx cmd URB */
+ if (atomic_read(&cardp->rx_cmd_urb_pending) &&
+ cardp->rx_cmd.urb) {
+ usb_kill_urb(cardp->rx_cmd.urb);
+ }
+ /* Unlink Rx data URBs */
+ if (atomic_read(&cardp->rx_data_urb_pending)) {
+ for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
+ if (cardp->rx_data_list[i].urb)
+ usb_kill_urb(
+ cardp->rx_data_list[i].urb);
+ }
+ }
+ /* Unlink Tx cmd URB */
+ if (atomic_read(&cardp->tx_cmd_urb_pending) &&
+ cardp->tx_cmd.urb) {
+ usb_kill_urb(cardp->tx_cmd.urb);
+ }
+ /* Unlink Tx data URBs */
+ if (atomic_read(&cardp->tx_data_urb_pending)) {
+ for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) {
+ if (cardp->tx_data_list[i].urb) {
+ usb_kill_urb(
+ cardp->tx_data_list[i].urb);
+ }
+ }
+ }
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Free Tx/Rx urb, skb and Rx buffer
+ *
+ * @param cardp Pointer usb_card_rec
+ *
+ * @return N/A
+ */
+void woal_usb_free(struct usb_card_rec *cardp)
+{
+ int i;
+
+ ENTER();
+
+ woal_usb_unlink_urb(cardp);
+ /* Free Rx data URBs */
+ for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
+ if (cardp->rx_data_list[i].urb) {
+ usb_free_urb(cardp->rx_data_list[i].urb);
+ cardp->rx_data_list[i].urb = NULL;
+ }
+ }
+ /* Free Rx cmd URB */
+ if (cardp->rx_cmd.urb) {
+ usb_free_urb(cardp->rx_cmd.urb);
+ cardp->rx_cmd.urb = NULL;
+ }
+
+ /* Free Tx data URBs */
+ for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) {
+ if (cardp->tx_data_list[i].urb) {
+ usb_free_urb(cardp->tx_data_list[i].urb);
+ cardp->tx_data_list[i].urb = NULL;
+ }
+ }
+ /* Free Tx cmd URB */
+ if (cardp->tx_cmd.urb) {
+ usb_free_urb(cardp->tx_cmd.urb);
+ cardp->tx_cmd.urb = NULL;
+ }
+
+ LEAVE();
+ return;
+}
+
+static t_u16 woal_update_card_type(t_void *card)
+{
+ struct usb_card_rec *cardp_usb = (struct usb_card_rec *)card;
+ t_u16 card_type = 0;
+
+ /* Update card type */
+#ifdef USB8897
+ if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8897_PID_1 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8897_PID_2) {
+ card_type = CARD_TYPE_USB8897;
+ moal_memcpy_ext(NULL, driver_version, CARD_USB8897,
+ strlen(CARD_USB8897), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V15, strlen(V15),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+#ifdef USB8997
+ if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997_PID_1 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997_PID_2 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997_PID_3 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997_PID_4 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997_PID_5 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997_PID_6 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997V2_PID_1) {
+ card_type = CARD_TYPE_USB8997;
+ moal_memcpy_ext(NULL, driver_version, CARD_USB8997,
+ strlen(CARD_USB8997), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V16, strlen(V16),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+#ifdef USB8978
+ if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8978_PID_1 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8978_PID_2) {
+ card_type = CARD_TYPE_USB8978;
+ moal_memcpy_ext(NULL, driver_version, CARD_USB8978,
+ strlen(CARD_USB8978), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V16, strlen(V16),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+#ifdef USB9098
+ if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB9098_PID_1 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB9098_PID_2) {
+ card_type = CARD_TYPE_USB9098;
+ moal_memcpy_ext(NULL, driver_version, CARD_USB9098,
+ strlen(CARD_USB9098), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V17, strlen(V17),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+#ifdef USB9097
+ if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB9097_PID_1 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB9097_PID_2) {
+ card_type = CARD_TYPE_USB9097;
+ moal_memcpy_ext(NULL, driver_version, CARD_USB9097,
+ strlen(CARD_USB9097), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V17, strlen(V17),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+ return card_type;
+}
+
+/**
+ * @brief Sets the configuration values
+ *
+ * @param intf Pointer to usb_interface
+ * @param id Pointer to usb_device_id
+ *
+ * @return Address of variable usb_cardp, error code otherwise
+ */
+static int woal_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
+ struct usb_card_rec *usb_cardp = NULL;
+ t_u16 card_type = 0;
+
+ ENTER();
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ PRINTM(MMSG,
+ "USB probe: idVendor=%x idProduct=%x bInterfaceNumber=%d\n",
+ id->idVendor, id->idProduct, id->bInterfaceNumber);
+#endif
+
+ udev = interface_to_usbdev(intf);
+ usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL);
+ if (!usb_cardp) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ /* Check probe is for our device */
+ for (i = 0; woal_usb_table[i].idVendor; i++) {
+ if (woal_cpu_to_le16(udev->descriptor.idVendor) ==
+ woal_usb_table[i].idVendor &&
+ woal_cpu_to_le16(udev->descriptor.idProduct) ==
+ woal_usb_table[i].idProduct) {
+ PRINTM(MMSG, "VID/PID = %X/%X, Boot2 version = %X\n",
+ woal_cpu_to_le16(udev->descriptor.idVendor),
+ woal_cpu_to_le16(udev->descriptor.idProduct),
+ woal_cpu_to_le16(udev->descriptor.bcdDevice));
+ switch (woal_cpu_to_le16(udev->descriptor.idProduct)) {
+#ifdef USB8897
+ case USB8897_PID_1:
+#endif /* USB8897 */
+#ifdef USB8997
+ case USB8997_PID_1:
+ case USB8997V2_PID_1:
+#endif /* USB8997 */
+#ifdef USB8978
+ case USB8978_PID_1:
+ case USB8978_PID_1_BT:
+#endif /* USB8978 */
+#ifdef USB9098
+ case USB9098_PID_1:
+#endif /* USB9098 */
+#ifdef USB9097
+ case USB9097_PID_1:
+#endif /* USB9097 */
+ /* If skip FW is set, we must return error so
+ * the next driver can download the FW */
+ if (skip_fwdnld)
+ goto error;
+ else
+ usb_cardp->boot_state = USB_FW_DNLD;
+ break;
+#ifdef USB8897
+ case USB8897_PID_2:
+#endif /* USB8897 */
+#ifdef USB8997
+ case USB8997_PID_2:
+#endif /* USB8997 */
+#ifdef USB8978
+ case USB8978_PID_2:
+ case USB8978_PID_2_BT:
+#endif /* USB8978 */
+#ifdef USB9098
+ case USB9098_PID_2:
+#endif /* USB9098 */
+#ifdef USB9097
+ case USB9097_PID_2:
+#endif /* USB9097 */
+ usb_cardp->boot_state = USB_FW_READY;
+ break;
+ }
+ /*To do, get card type*/
+ /* if
+ (woal_cpu_to_le16(udev->descriptor.idProduct) ==
+ USB8897_PID_2) usb_cardp->card_type =
+ CARD_TYPE_USB8897; else if
+ (woal_cpu_to_le16(udev->descriptor.idProduct) ==
+ USB8997_PID_2) usb_cardp->card_type =
+ CARD_TYPE_USB997;
+ */
+ break;
+ }
+ }
+
+ if (woal_usb_table[i].idVendor) {
+ usb_cardp->udev = udev;
+ iface_desc = intf->cur_altsetting;
+ usb_cardp->intf = intf;
+
+ PRINTM(MINFO,
+ "bcdUSB = 0x%X bDeviceClass = 0x%X"
+ " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
+ woal_cpu_to_le16(udev->descriptor.bcdUSB),
+ udev->descriptor.bDeviceClass,
+ udev->descriptor.bDeviceSubClass,
+ udev->descriptor.bDeviceProtocol);
+
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if ((usb_endpoint_is_bulk_in(endpoint) ||
+ usb_endpoint_is_int_in(endpoint)) &&
+ (usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_CMD_EVENT ||
+ usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_CMD_EVENT_IF2)) {
+ usb_cardp->rx_cmd_ep_type =
+ usb_endpoint_type(endpoint);
+ usb_cardp->rx_cmd_interval =
+ endpoint->bInterval;
+ /* We found a bulk in command/event endpoint */
+ PRINTM(MCMND,
+ "Rx CMD/EVT: max packet size = %d, address = %d ep_type=%d\n",
+ woal_le16_to_cpu(
+ endpoint->wMaxPacketSize),
+ endpoint->bEndpointAddress,
+ usb_cardp->rx_cmd_ep_type);
+ usb_cardp->rx_cmd_ep =
+ (endpoint->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK);
+
+ atomic_set(&usb_cardp->rx_cmd_urb_pending, 0);
+ if (usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_CMD_EVENT_IF2)
+ usb_cardp->second_mac = MTRUE;
+ }
+ if (usb_endpoint_is_bulk_in(endpoint) &&
+ (usb_endpoint_num(endpoint) == MLAN_USB_EP_DATA ||
+ usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_DATA_IF2)) {
+ /* We found a bulk in data endpoint */
+ PRINTM(MINFO,
+ "Bulk IN: max packet size = %d, address = %d\n",
+ woal_le16_to_cpu(
+ endpoint->wMaxPacketSize),
+ endpoint->bEndpointAddress);
+ usb_cardp->rx_data_ep =
+ (endpoint->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK);
+ atomic_set(&usb_cardp->rx_data_urb_pending, 0);
+ }
+ if (usb_endpoint_is_bulk_out(endpoint) &&
+ (usb_endpoint_num(endpoint) == MLAN_USB_EP_DATA ||
+ usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_DATA_IF2)) {
+ /* We found a bulk out data endpoint */
+ PRINTM(MCMND,
+ "Bulk OUT: max packet size = %d, address = %d\n",
+ woal_le16_to_cpu(
+ endpoint->wMaxPacketSize),
+ endpoint->bEndpointAddress);
+ usb_cardp->tx_data_ep =
+ endpoint->bEndpointAddress;
+ atomic_set(&usb_cardp->tx_data_urb_pending, 0);
+ usb_cardp->tx_data_maxpktsize =
+ woal_le16_to_cpu(
+ endpoint->wMaxPacketSize);
+ }
+
+ if ((usb_endpoint_is_bulk_out(endpoint) ||
+ usb_endpoint_is_int_out(endpoint)) &&
+ (usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_CMD_EVENT ||
+ usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_CMD_EVENT_IF2)) {
+ usb_cardp->tx_cmd_ep_type =
+ usb_endpoint_type(endpoint);
+ usb_cardp->tx_cmd_interval =
+ endpoint->bInterval;
+ /* We found a bulk out command/event endpoint */
+ PRINTM(MCMND,
+ "Tx CMD: max packet size = %d, address = %d ep_type=%d\n",
+ woal_le16_to_cpu(
+ endpoint->wMaxPacketSize),
+ endpoint->bEndpointAddress,
+ usb_cardp->tx_cmd_ep_type);
+ usb_cardp->tx_cmd_ep =
+ endpoint->bEndpointAddress;
+ atomic_set(&usb_cardp->tx_cmd_urb_pending, 0);
+ usb_cardp->tx_cmd_maxpktsize = woal_le16_to_cpu(
+ endpoint->wMaxPacketSize);
+ }
+ }
+
+ if (usb_cardp->boot_state == USB_FW_DNLD) {
+ if (!usb_cardp->tx_cmd_ep || !usb_cardp->rx_cmd_ep)
+ goto error;
+ } else if (usb_cardp->boot_state == USB_FW_READY) {
+ if (!usb_cardp->tx_cmd_ep || !usb_cardp->tx_data_ep ||
+ !usb_cardp->rx_cmd_ep || !usb_cardp->rx_data_ep) {
+ PRINTM(MERROR,
+ "%s: invalid endpoint assignment\n",
+ __FUNCTION__);
+ goto error;
+ }
+ }
+
+ usb_cardp->tx_aggr_ctrl.enable = MFALSE;
+ usb_cardp->tx_aggr_ctrl.aggr_mode = MLAN_USB_AGGR_MODE_NUM;
+ usb_cardp->tx_aggr_ctrl.aggr_align =
+ MAX(max_tx_buf, MLAN_USB_TX_AGGR_ALIGN);
+ usb_cardp->tx_aggr_ctrl.aggr_max = MLAN_USB_TX_MAX_AGGR_NUM;
+ usb_cardp->tx_aggr_ctrl.aggr_tmo =
+ MLAN_USB_TX_AGGR_TIMEOUT_MSEC * 1000;
+ usb_cardp->rx_deaggr_ctrl.enable = MFALSE;
+ usb_cardp->rx_deaggr_ctrl.aggr_mode = MLAN_USB_AGGR_MODE_NUM;
+ usb_cardp->rx_deaggr_ctrl.aggr_align = MLAN_USB_RX_ALIGN_SIZE;
+ usb_cardp->rx_deaggr_ctrl.aggr_max = MLAN_USB_RX_MAX_AGGR_NUM;
+ usb_cardp->rx_deaggr_ctrl.aggr_tmo =
+ MLAN_USB_RX_DEAGGR_TIMEOUT_USEC;
+ usb_set_intfdata(intf, usb_cardp);
+
+ card_type = woal_update_card_type(usb_cardp);
+ if (!card_type) {
+ PRINTM(MERROR,
+ "usb probe: woal_update_card_type() failed\n");
+ goto error;
+ }
+
+ /* At this point wlan_add_card() will be called */
+ if (!(woal_add_card(usb_cardp, &usb_cardp->udev->dev, &usb_ops,
+ card_type))) {
+ PRINTM(MERROR, "%s: woal_add_card failed\n",
+ __FUNCTION__);
+ goto error;
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+ /* Note: From 2.6.34.2 onwards, remote wakeup is NOT enabled by
+ * default. So drivers wanting remote wakeup will have to enable
+ * this using -
+ * device_set_wakeup_enable(&udev->dev, 1);
+ * It has been observed that some cards having device attr =
+ * 0xa0 do not support remote wakeup. These cards come
+ * immediately out of the suspend when power/wakeup file is set
+ * to 'enabled'. To support all types of cards i.e. with/without
+ * remote wakeup, we are NOT setting the 'power/wakeup' file
+ * from here. Also in principle, we are not supposed to change
+ * the wakeup policy, which is purely a userspace decision.
+ */
+ /* if (udev->actconfig->desc.bmAttributes &
+ USB_CONFIG_ATT_WAKEUP) intf->needs_remote_wakeup = 1; */
+#endif
+ usb_get_dev(udev);
+ LEAVE();
+ return 0;
+ } else {
+ PRINTM(MINFO, "Discard the Probe request\n");
+ PRINTM(MINFO, "VID = 0x%X PID = 0x%X\n",
+ woal_cpu_to_le16(udev->descriptor.idVendor),
+ woal_cpu_to_le16(udev->descriptor.idProduct));
+ }
+error:
+ kfree(usb_cardp);
+ usb_cardp = NULL;
+ LEAVE();
+ return -ENXIO;
+}
+
+/**
+ * @brief Free resource and cleanup
+ *
+ * @param intf Pointer to usb_interface
+ *
+ * @return N/A
+ */
+static void woal_usb_disconnect(struct usb_interface *intf)
+{
+ struct usb_card_rec *cardp = usb_get_intfdata(intf);
+ moal_handle *phandle = NULL;
+ ENTER();
+ if (!cardp || !cardp->phandle) {
+ PRINTM(MERROR, "Card or phandle is not valid\n");
+ LEAVE();
+ return;
+ }
+ phandle = (moal_handle *)cardp->phandle;
+
+ /*
+ * Update Surprise removed to TRUE
+ * Free all the URB's allocated
+ */
+ phandle->surprise_removed = MTRUE;
+
+ /* Card is removed and we can call wlan_remove_card */
+ PRINTM(MINFO, "Call remove card\n");
+ woal_remove_card(cardp);
+
+ usb_set_intfdata(intf, NULL);
+ usb_put_dev(interface_to_usbdev(intf));
+ kfree(cardp);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief killall pending urbs
+ *
+ * @param handle Pointer to moal_handle
+ *
+ *
+ * @return N/A
+ */
+void woal_kill_urbs(moal_handle *handle)
+{
+ ENTER();
+ handle->is_suspended = MTRUE;
+ woal_usb_unlink_urb(handle->card);
+ LEAVE();
+}
+
+/**
+ * @brief resubmit urbs
+ *
+ * @param handle Pointer to moal_handle
+ *
+ *
+ * @return N/A
+ */
+void woal_resubmit_urbs(moal_handle *handle)
+{
+ struct usb_card_rec *cardp = handle->card;
+
+ ENTER();
+ handle->is_suspended = MFALSE;
+
+ if (!atomic_read(&cardp->rx_data_urb_pending)) {
+ /* Submit multiple Rx data URBs */
+ woal_usb_submit_rx_data_urbs(handle);
+ }
+ if (!atomic_read(&cardp->rx_cmd_urb_pending)) {
+ cardp->rx_cmd.pmbuf =
+ woal_alloc_mlan_buffer(handle, MLAN_RX_CMD_BUF_SIZE);
+ if (cardp->rx_cmd.pmbuf)
+ woal_usb_submit_rx_urb(&cardp->rx_cmd,
+ MLAN_RX_CMD_BUF_SIZE);
+ }
+ LEAVE();
+}
+
+#ifdef CONFIG_PM
+/**
+ * @brief Handle suspend
+ *
+ * @param intf Pointer to usb_interface
+ * @param message Pointer to pm_message_t structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int woal_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct usb_card_rec *cardp = usb_get_intfdata(intf);
+ moal_handle *handle = NULL;
+ int i;
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MCMND, "<--- Enter woal_usb_suspend --->\n");
+ if (!cardp || !cardp->phandle) {
+ PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
+ ret = 0;
+ goto done;
+ }
+ handle = cardp->phandle;
+ if (handle->is_suspended == MTRUE) {
+ PRINTM(MWARN, "Device already suspended\n");
+ ret = 0;
+ goto done;
+ }
+#ifdef STA_SUPPORT
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i] &&
+ (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA))
+ woal_cancel_scan(handle->priv[i], MOAL_IOCTL_WAIT);
+ }
+#endif
+ /* Enable Host Sleep */
+ woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY));
+
+ /* Indicate device suspended */
+ /* The flag must be set here before the usb_kill_urb() calls.
+ * Reason: In the complete handlers, urb->status(= -ENOENT) and
+ * 'is_suspended' flag is used in combination to distinguish
+ * between a suspended state and a 'disconnect' one.
+ */
+ handle->is_suspended = MTRUE;
+ for (i = 0; i < handle->priv_num; i++)
+ netif_carrier_off(handle->priv[i]->netdev);
+
+ /* Unlink Rx cmd URB */
+ if (atomic_read(&cardp->rx_cmd_urb_pending) && cardp->rx_cmd.urb) {
+ usb_kill_urb(cardp->rx_cmd.urb);
+ }
+ /* Unlink Rx data URBs */
+ if (atomic_read(&cardp->rx_data_urb_pending)) {
+ for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
+ if (cardp->rx_data_list[i].urb) {
+ usb_kill_urb(cardp->rx_data_list[i].urb);
+ usb_init_urb(cardp->rx_data_list[i].urb);
+ }
+ }
+ }
+
+ /* Unlink Tx data URBs */
+ for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) {
+ if (cardp->tx_data_list[i].urb) {
+ usb_kill_urb(cardp->tx_data_list[i].urb);
+ }
+ }
+ /* Unlink Tx cmd URB */
+ if (cardp->tx_cmd.urb) {
+ usb_kill_urb(cardp->tx_cmd.urb);
+ }
+
+ handle->suspend_wait_q_woken = MTRUE;
+ wake_up_interruptible(&handle->suspend_wait_q);
+
+done:
+ PRINTM(MCMND, "<--- Leave woal_usb_suspend --->\n");
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle resume
+ *
+ * @param intf Pointer to usb_interface
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int woal_usb_resume(struct usb_interface *intf)
+{
+ struct usb_card_rec *cardp = usb_get_intfdata(intf);
+ moal_handle *handle = NULL;
+ int i;
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MCMND, "<--- Enter woal_usb_resume --->\n");
+ if (!cardp || !cardp->phandle) {
+ PRINTM(MERROR, "Card or adapter structure is not valid\n");
+ ret = 0;
+ goto done;
+ }
+ handle = cardp->phandle;
+
+ if (handle->is_suspended == MFALSE) {
+ PRINTM(MWARN, "Device already resumed\n");
+ ret = 0;
+ goto done;
+ }
+
+ /* Indicate device resumed.
+ * The netdev queue will be resumed only after the urbs
+ * have been resubmitted */
+ handle->is_suspended = MFALSE;
+
+ if (!atomic_read(&cardp->rx_data_urb_pending)) {
+ /* Submit multiple Rx data URBs */
+ woal_usb_submit_rx_data_urbs(handle);
+ }
+ if (!atomic_read(&cardp->rx_cmd_urb_pending)) {
+ cardp->rx_cmd.pmbuf =
+ woal_alloc_mlan_buffer(handle, MLAN_RX_CMD_BUF_SIZE);
+ if (cardp->rx_cmd.pmbuf)
+ woal_usb_submit_rx_urb(&cardp->rx_cmd,
+ MLAN_RX_CMD_BUF_SIZE);
+ }
+
+ for (i = 0; i < handle->priv_num; i++)
+ if (handle->priv[i]->media_connected == MTRUE)
+ netif_carrier_on(handle->priv[i]->netdev);
+
+ /* Disable Host Sleep */
+ if (handle->hs_activated)
+ woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
+ MOAL_NO_WAIT);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+ /* Resume handler may be called due to remote wakeup,
+ force to exit suspend anyway */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+ cardp->udev->autosuspend_disabled = 1;
+#else
+#ifdef CONFIG_PM_RUNTIME
+ cardp->udev->dev.power.runtime_auto = 0;
+#endif
+#endif /* < 2.6.35 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
+ cardp->udev->autoresume_disabled = 0;
+#endif /* < 2.6.33 */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+#ifdef CONFIG_PM_RUNTIME
+ atomic_inc(&(cardp->udev)->dev.power.usage_count);
+#endif
+#endif /* >= 2.6.34 */
+#endif /* >= 2.6.24 */
+
+done:
+ PRINTM(MCMND, "<--- Leave woal_usb_resume --->\n");
+ LEAVE();
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+/**
+ * @brief This function initialize the tx URBs
+ *
+ * @param handle Pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_usb_tx_init(moal_handle *handle)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ int i;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ cardp->tx_cmd.handle = handle;
+ cardp->tx_cmd.ep = cardp->tx_cmd_ep;
+ /* Allocate URB for command */
+ cardp->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!cardp->tx_cmd.urb) {
+ PRINTM(MERROR, "Tx command URB allocation failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto init_exit;
+ }
+
+ cardp->tx_data_ix = 0;
+ for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) {
+ cardp->tx_data_list[i].handle = handle;
+ cardp->tx_data_list[i].ep = cardp->tx_data_ep;
+ /* Allocate URB for data */
+ cardp->tx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!cardp->tx_data_list[i].urb) {
+ PRINTM(MERROR, "Tx data URB allocation failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto init_exit;
+ }
+ }
+
+init_exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function submits the rx data URBs
+ *
+ * @param handle Pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_usb_submit_rx_data_urbs(moal_handle *handle)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ int i;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u32 buffer_len = MLAN_RX_DATA_BUF_SIZE;
+
+ ENTER();
+
+ if (cardp->rx_deaggr_ctrl.enable) {
+ buffer_len = cardp->rx_deaggr_ctrl.aggr_max;
+ if (cardp->rx_deaggr_ctrl.aggr_mode == MLAN_USB_AGGR_MODE_NUM) {
+ buffer_len *= MAX(MLAN_USB_MAX_PKT_SIZE,
+ cardp->rx_deaggr_ctrl.aggr_align);
+ buffer_len = MAX(buffer_len, MLAN_RX_DATA_BUF_SIZE);
+ }
+ }
+
+ for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
+ /* Submit Rx data URB */
+ if (!cardp->rx_data_list[i].pmbuf) {
+ if (woal_usb_submit_rx_urb(&cardp->rx_data_list[i],
+ buffer_len))
+ continue;
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initialize the rx URBs and submit them
+ *
+ * @param handle Pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_usb_rx_init(moal_handle *handle)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ int i;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ cardp->rx_cmd.handle = handle;
+ cardp->rx_cmd.ep = cardp->rx_cmd_ep;
+ /* Allocate URB for command/event */
+ cardp->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!cardp->rx_cmd.urb) {
+ PRINTM(MERROR, "Rx command URB allocation failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto init_exit;
+ }
+
+ cardp->rx_cmd.pmbuf =
+ woal_alloc_mlan_buffer(handle, MLAN_RX_CMD_BUF_SIZE);
+ if (cardp->rx_cmd.pmbuf) {
+ /* Submit Rx command URB */
+ if (woal_usb_submit_rx_urb(&cardp->rx_cmd,
+ MLAN_RX_CMD_BUF_SIZE)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto init_exit;
+ }
+ }
+ for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
+ cardp->rx_data_list[i].handle = handle;
+ cardp->rx_data_list[i].ep = cardp->rx_data_ep;
+ /* Allocate URB for data */
+ cardp->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!cardp->rx_data_list[i].urb) {
+ PRINTM(MERROR, "Rx data URB allocation failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto init_exit;
+ }
+ }
+ ret = woal_usb_submit_rx_data_urbs(handle);
+ if (ret) {
+ PRINTM(MERROR, "Rx data URB submission failed\n");
+ goto init_exit;
+ }
+
+init_exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads data blocks to device
+ *
+ * @param handle Pointer to moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param ep Endpoint to send
+ * @param timeout Timeout value in milliseconds (if 0 the wait is forever)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_usb_write_data_sync(moal_handle *handle,
+ mlan_buffer *pmbuf, t_u32 endpoint,
+ t_u32 timeout)
+{
+ struct usb_card_rec *cardp = handle->card;
+ t_u8 *data = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 ep = endpoint;
+ t_u32 length = pmbuf->data_len;
+ int actual_length;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int bulk_out_maxpktsize = 512;
+
+ if (ep == cardp->tx_cmd_ep)
+ bulk_out_maxpktsize = cardp->tx_cmd_maxpktsize;
+ else if (ep == cardp->tx_data_ep)
+ bulk_out_maxpktsize = cardp->tx_data_maxpktsize;
+
+ if (length % bulk_out_maxpktsize == 0)
+ length++;
+
+ /* Send the data block */
+ ret = usb_bulk_msg(cardp->udev, usb_sndbulkpipe(cardp->udev, ep),
+ (t_u8 *)data, length, &actual_length, timeout);
+ if (ret) {
+ PRINTM(MERROR, "usb_blk_msg for send failed, ret %d\n", ret);
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ pmbuf->data_len = actual_length;
+ DBG_HEXDUMP(MIF_D, "write sync", data, actual_length);
+
+ return ret;
+}
+
+/**
+ * @brief This function read data blocks to device
+ *
+ * @param handle Pointer to moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param ep Endpoint to receive
+ * @param timeout Timeout value in milliseconds (if 0 the wait is forever)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_usb_read_data_sync(moal_handle *handle,
+ mlan_buffer *pmbuf, t_u32 endpoint,
+ t_u32 timeout)
+{
+ struct usb_card_rec *cardp = handle->card;
+ t_u8 *data = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 ep = endpoint;
+ t_u32 buf_len = pmbuf->data_len;
+ int actual_length;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ /* Receive the data response */
+ ret = usb_bulk_msg(cardp->udev, usb_rcvbulkpipe(cardp->udev, ep), data,
+ buf_len, &actual_length, timeout);
+ if (ret) {
+ PRINTM(MERROR, "usb_bulk_msg failed: %d\n", ret);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ pmbuf->data_len = actual_length;
+ DBG_HEXDUMP(MIF_D, "read sync", data, actual_length);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads data/command packet to device
+ *
+ * @param handle Pointer to moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param ep Endpoint to send
+ *
+ * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE or
+ * MLAN_STATUS_RESOURCE
+ */
+mlan_status woal_write_data_async(moal_handle *handle, mlan_buffer *pmbuf,
+ t_u8 ep)
+{
+ struct usb_card_rec *cardp = handle->card;
+ urb_context *context = NULL;
+ t_u8 *data = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
+ struct urb *tx_urb = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 data_len = pmbuf->data_len;
+ int bulk_out_maxpktsize = 512;
+
+ ENTER();
+
+ /* Check if device is removed */
+ if (handle->surprise_removed) {
+ PRINTM(MERROR, "Device removed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto tx_ret;
+ }
+
+ if ((ep == cardp->tx_data_ep) &&
+ (atomic_read(&cardp->tx_data_urb_pending) >= MVUSB_TX_HIGH_WMARK)) {
+ ret = MLAN_STATUS_RESOURCE;
+ goto tx_ret;
+ }
+ PRINTM(MINFO, "woal_write_data_async: ep=%d\n", ep);
+
+ if (ep == cardp->tx_cmd_ep) {
+ context = &cardp->tx_cmd;
+ bulk_out_maxpktsize = cardp->tx_cmd_maxpktsize;
+ } else {
+ if (ep == cardp->tx_data_ep) {
+ bulk_out_maxpktsize = cardp->tx_data_maxpktsize;
+ if (cardp->tx_data_ix >= MVUSB_TX_HIGH_WMARK)
+ cardp->tx_data_ix = 0;
+ context = &cardp->tx_data_list[cardp->tx_data_ix++];
+ }
+ }
+
+ if (!context) {
+ PRINTM(MERROR, "Cannot allocate Tx urb_context\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto tx_ret;
+ }
+ context->handle = handle;
+ context->ep = ep;
+ context->pmbuf = pmbuf;
+
+ tx_urb = context->urb;
+
+ if (data_len % bulk_out_maxpktsize == 0)
+ data_len++;
+
+ /*
+ * Use USB API usb_fill_bulk_urb() to set the
+ * configuration information of the Tx bulk URB
+ * and initialize the Tx callback
+ */
+
+ if (ep == cardp->tx_cmd_ep &&
+ cardp->tx_cmd_ep_type == USB_ENDPOINT_XFER_INT) {
+ usb_fill_int_urb(tx_urb, cardp->udev,
+ usb_sndintpipe(cardp->udev, ep), data,
+ data_len, woal_usb_tx_complete,
+ (void *)context, cardp->tx_cmd_interval);
+ } else
+ usb_fill_bulk_urb(tx_urb, cardp->udev,
+ usb_sndbulkpipe(cardp->udev, ep), data,
+ data_len, woal_usb_tx_complete,
+ (void *)context);
+ /* We find on Ubuntu 12.10 this flag does not work */
+ // tx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+ if (ep == cardp->tx_cmd_ep)
+ atomic_inc(&cardp->tx_cmd_urb_pending);
+ else if (ep == cardp->tx_data_ep)
+ atomic_inc(&cardp->tx_data_urb_pending);
+ if (usb_submit_urb(tx_urb, GFP_ATOMIC)) {
+ /* Submit URB failure */
+ PRINTM(MERROR, "Submit EP %d Tx URB failed: %d\n", ep, ret);
+ if (ep == cardp->tx_cmd_ep)
+ atomic_dec(&cardp->tx_cmd_urb_pending);
+ else {
+ if (ep == cardp->tx_data_ep) {
+ atomic_dec(&cardp->tx_data_urb_pending);
+ if (cardp->tx_data_ix)
+ cardp->tx_data_ix--;
+ else
+ cardp->tx_data_ix = MVUSB_TX_HIGH_WMARK;
+ }
+ }
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ if (ep == cardp->tx_data_ep &&
+ (atomic_read(&cardp->tx_data_urb_pending) ==
+ MVUSB_TX_HIGH_WMARK))
+ ret = MLAN_STATUS_PRESOURCE;
+ else
+ ret = MLAN_STATUS_SUCCESS;
+ }
+
+tx_ret:
+
+ if (!ret)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function register usb device and initialize parameter
+ *
+ * @param handle Pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_usb_register_dev(moal_handle *handle)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ cardp->phandle = handle;
+ LEAVE();
+ return ret;
+}
+
+static void woal_usb_unregister_dev(moal_handle *handle)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ PRINTM(MMSG, "USB: unregister device\n");
+ woal_usb_free(cardp);
+ cardp->phandle = NULL;
+ return;
+}
+
+/**
+ * @brief This function registers driver.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_usb_bus_register(void)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ if (skip_fwdnld) {
+ woal_usb_driver.id_table = woal_usb_table_skip_fwdnld;
+ }
+ /*
+ * API registers the NXP USB driver
+ * to the USB system
+ */
+ if (usb_register(&woal_usb_driver)) {
+ PRINTM(MFATAL, "USB Driver Registration Failed \n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function removes usb driver.
+ *
+ * @return N/A
+ */
+void woal_usb_bus_unregister(void)
+{
+ ENTER();
+ /* API unregisters the driver from USB subsystem */
+ usb_deregister(&woal_usb_driver);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function check if this is second mac
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MTRUE/MFALSE
+ *
+ */
+static t_u8 woal_usb_is_second_mac(moal_handle *handle)
+{
+ return ((struct usb_card_rec *)(handle->card))->second_mac;
+}
+
+#ifdef CONFIG_USB_SUSPEND
+/**
+ * @brief This function makes USB device to suspend.
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_enter_usb_suspend(moal_handle *handle)
+{
+ struct usb_device *udev = ((struct usb_card_rec *)(handle->card))->udev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+ struct usb_interface *intf =
+ ((struct usb_card_rec *)(handle->card))->intf;
+#endif /* < 2.6.34 */
+#endif /* >= 2.6.24 */
+
+ ENTER();
+
+ PRINTM(MIOCTL, "USB suspend ioctl (state %d)\n", udev->state);
+
+ if (handle->is_suspended == MTRUE) {
+ PRINTM(MERROR, "Device already suspended\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ handle->suspend_wait_q_woken = MFALSE;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+ /* Enter into USB suspend */
+ usb_lock_device(udev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
+ udev->autosuspend_delay = 0; /* Autosuspend delay in jiffies */
+#else
+ pm_runtime_set_autosuspend_delay(&udev->dev, 0); /* Autosuspend delay in
+ jiffies */
+#endif /* < 2.6.38 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+ udev->autosuspend_disabled = 0; /* /sys/bus/usb/devices/.../power/level
+ < auto */
+#endif /* < 2.6.34 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
+ udev->autoresume_disabled = 0;
+#endif /* < 2.6.33 */
+ usb_unlock_device(udev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
+ intf->pm_usage_cnt = 1;
+#else
+ atomic_set(&intf->pm_usage_cnt, 1);
+#endif /* < 2.6.32 */
+ usb_autopm_put_interface(intf);
+#else
+ usb_lock_device(udev);
+ atomic_set(&udev->dev.power.usage_count, 1);
+ usb_enable_autosuspend(udev);
+ usb_unlock_device(udev);
+#endif /* < 2.6.34 */
+#endif /* >= 2.6.24 */
+
+ /* Wait for suspend to complete */
+ wait_event_interruptible(handle->suspend_wait_q,
+ handle->suspend_wait_q_woken);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function makes USB device to resume.
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_exit_usb_suspend(moal_handle *handle)
+{
+ struct usb_device *udev = ((struct usb_card_rec *)(handle->card))->udev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+ struct usb_interface *intf =
+ ((struct usb_card_rec *)(handle->card))->intf;
+#endif /* < 2.6.34 */
+#endif /* >= 2.6.24 */
+
+ ENTER();
+
+ PRINTM(MIOCTL, "USB resume ioctl (state %d)\n", udev->state);
+
+ if (handle->is_suspended == MFALSE ||
+ udev->state != USB_STATE_SUSPENDED) {
+ PRINTM(MERROR, "Device already resumed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+ /* Exit from USB suspend */
+ usb_lock_device(udev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+ udev->autosuspend_disabled = 1; /* /sys/bus/usb/devices/.../power/level
+ < on */
+#endif /* < 2.6.34 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
+ udev->autoresume_disabled = 0;
+#endif /* < 2.6.33 */
+ usb_unlock_device(udev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
+ intf->pm_usage_cnt = 0;
+#else
+ atomic_set(&intf->pm_usage_cnt, 0);
+#endif /* < 2.6.32 */
+ usb_autopm_get_interface(intf);
+#else
+ usb_lock_device(udev);
+ atomic_set(&udev->dev.power.usage_count, 0);
+ usb_disable_autosuspend(udev);
+ usb_unlock_device(udev);
+#endif /* < 2.6.34 */
+#endif /* >= 2.6.24 */
+
+ LEAVE();
+ return 0;
+}
+#endif /* CONFIG_USB_SUSPEND */
+
+/**
+ * @brief This function will submit rx urb.
+ *
+ * @param handle Pointer to moal_handle
+ * @param ep Endpoint to re-submit urb
+ *
+ * @return N/A
+ */
+void woal_submit_rx_urb(moal_handle *handle, t_u8 ep)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+
+ ENTER();
+
+ if ((ep == cardp->rx_cmd_ep) &&
+ (!atomic_read(&cardp->rx_cmd_urb_pending))) {
+ woal_usb_submit_rx_urb(&cardp->rx_cmd, MLAN_RX_CMD_BUF_SIZE);
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function dump firmware memory to file
+ *
+ * @param phandle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+void woal_usb_dump_fw_info(moal_handle *phandle)
+{
+ moal_private *priv = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *pcfg_misc = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ priv = woal_get_priv(phandle, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ PRINTM(MERROR, "woal_dump_firmware_info get priv is NULL!\n");
+ goto done;
+ }
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ PRINTM(MERROR, "woal_dump_firmware_info alloc req fail!\n");
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
+ pcfg_misc->sub_command = MLAN_OID_MISC_FW_DUMP_EVENT;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+done:
+ LEAVE();
+ return;
+}
+
+static mlan_status woal_usb_get_fw_name(moal_handle *handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#if defined(USB8997) || defined(USB9098) || defined(USB9097) || defined(USB8978)
+ t_u32 revision_id = 0;
+ t_u32 strap = 0;
+#endif
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+#if defined(USB9098)
+ moal_handle *ref_handle = NULL;
+#endif
+
+ ENTER();
+ if (handle->params.fw_name)
+ goto done;
+ if (cardp->boot_state == USB_FW_READY)
+ goto done;
+#if defined(USB8997) || defined(USB9098) || defined(USB9097) || defined(USB8978)
+ ret = woal_check_chip_revision(handle, &revision_id, &strap);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL, "Chip revision check failure!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MCMND, "revision=0x%x, strap=0x%x\n", revision_id, strap);
+#endif
+
+#ifdef USB8997
+ if (IS_USB8997(handle->card_type)) {
+ if (strap == CARD_TYPE_USB_UART)
+ strcpy(handle->card_info->fw_name,
+ USBUART8997_DEFAULT_COMBO_FW_NAME);
+ else if (strap != 0)
+ strcpy(handle->card_info->fw_name,
+ USBUSB8997_DEFAULT_COMBO_FW_NAME);
+ }
+#endif
+
+#ifdef USB8978
+ if (IS_USB8978(handle->card_type)) {
+ if (strap == CARD_TYPE_USB_UART)
+ strcpy(handle->card_info->fw_name,
+ USBUART8978_DEFAULT_COMBO_FW_NAME);
+ else if (strap != 0)
+ strcpy(handle->card_info->fw_name,
+ USBUSB8978_DEFAULT_COMBO_FW_NAME);
+ }
+#endif
+
+#ifdef USB9098
+ if (IS_USB9098(handle->card_type)) {
+ if (cardp->second_mac) {
+ ref_handle = (moal_handle *)handle->pref_mac;
+ if (ref_handle) {
+ strcpy(handle->card_info->fw_name,
+ ref_handle->card_info->fw_name);
+ strcpy(handle->card_info->fw_name_wlan,
+ ref_handle->card_info->fw_name_wlan);
+ }
+ goto done;
+ }
+ switch (revision_id) {
+ case USB9098_Z1Z2:
+ if (strap != 0) {
+ if (strap == CARD_TYPE_USB_UART)
+ strcpy(handle->card_info->fw_name,
+ USBUART9098_DEFAULT_COMBO_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ USBUSB9098_DEFAULT_COMBO_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ USB9098_DEFAULT_WLAN_FW_NAME);
+ break;
+ case USB9098_A0:
+ case USB9098_A1:
+ case USB9098_A2:
+ if (strap != 0) {
+ if (strap == CARD_TYPE_USB_UART)
+ strcpy(handle->card_info->fw_name,
+ USBUART9098_COMBO_V1_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ USBUSB9098_COMBO_V1_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ USB9098_WLAN_V1_FW_NAME);
+ break;
+ }
+ }
+#endif
+#ifdef USB9097
+ if (IS_USB9097(handle->card_type)) {
+ switch (revision_id) {
+ case USB9097_B0:
+ case USB9097_B1:
+ if (strap != 0) {
+ if (strap == CARD_TYPE_USB_UART)
+ strcpy(handle->card_info->fw_name,
+ USBUART9097_COMBO_V1_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ USBUSB9097_COMBO_V1_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ USB9097_WLAN_V1_FW_NAME);
+ break;
+ }
+ }
+#endif
+done:
+ PRINTM(MCMND, "combo fw:%s wlan fw:%s \n", handle->card_info->fw_name,
+ handle->card_info->fw_name_wlan);
+ LEAVE();
+ return ret;
+}
+
+static moal_if_ops usb_ops = {
+ .register_dev = woal_usb_register_dev,
+ .unregister_dev = woal_usb_unregister_dev,
+ .read_data_sync = woal_usb_read_data_sync,
+ .write_data_sync = woal_usb_write_data_sync,
+ .get_fw_name = woal_usb_get_fw_name,
+ .dump_fw_info = woal_usb_dump_fw_info,
+ .is_second_mac = woal_usb_is_second_mac,
+};