mwifiex/mxm_wifiex/wlan_src/mlinux/moal_usb.c

2118 lines
59 KiB
C

/** @file moal_usb.c
*
* @brief This file contains the interfaceing to USB bus
* driver.
*
*
* Copyright 2008-2021 NXP
*
* NXP CONFIDENTIAL
* The source code contained or described herein and all documents related to
* the source code (Materials) are owned by NXP, its
* suppliers and/or its licensors. Title to the Materials remains with NXP,
* its suppliers and/or its licensors. The Materials contain
* trade secrets and proprietary and confidential information of NXP, its
* suppliers and/or its licensors. The Materials are protected by worldwide
* copyright and trade secret laws and treaty provisions. No part of the
* Materials may be used, copied, reproduced, modified, published, uploaded,
* posted, transmitted, distributed, or disclosed in any way without NXP's prior
* express written permission.
*
* No license under any patent, copyright, trade secret or other intellectual
* property right is granted to or conferred upon you by disclosure or delivery
* of the Materials, either expressly, by implication, inducement, estoppel or
* otherwise. Any license under such intellectual property rights must be
* express and approved by NXP in writing.
*
* Alternatively, this software may be distributed under the terms of GPL v2.
* SPDX-License-Identifier: GPL-2.0
*
*/
/********************************************************
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) || defined(USBNW62X)
/** 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 */
static const char usbdriver_name[] = "usbxxx";
/** This structure contains the device signature */
static struct usb_device_id woal_usb_table[] = {
/* Enter the device signature inside */
#ifdef USB8801
{NXP_USB_DEVICE(USB8801_VID_1, USB8801_PID_1, "NXP WLAN USB Adapter")},
{NXP_USB_DEVICE(USB8801_VID_1, USB8801_PID_2, "NXP WLAN USB Adapter")},
#endif
#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
#ifdef USBNW62X
{NXP_USB_DEVICE(USBNW62X_VID_1, USBNW62X_PID_1,
"NXP WLAN USB Adapter")},
{NXP_USB_DEVICE(USBNW62X_VID_1, USBNW62X_PID_2,
"NXP WLAN USB Adapter")},
#endif
/* Terminating entry */
{},
};
/** This structure contains the device signature */
static struct usb_device_id woal_usb_table_skip_fwdnld[] = {
/* Enter the device signature inside */
#ifdef USB8801
{NXP_USB_DEVICE(USB8801_VID_1, USB8801_PID_2, "NXP WLAN USB Adapter")},
#endif
#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
#ifdef USBNW62X
{NXP_USB_DEVICE(USBNW62X_VID_1, USBNW62X_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
********************************************************/
/********************************************************
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
* USB_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) >=
USB_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) || defined(USBNW62X)
/**
* @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
*/
static 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 = NULL;
t_u8 *recv_buff = NULL;
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 USB8801
if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)USB8801_PID_1 ||
woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)USB8801_PID_2) {
card_type = CARD_TYPE_USB8801;
moal_memcpy_ext(NULL, driver_version, CARD_USB8801,
strlen(CARD_USB8801), strlen(driver_version));
moal_memcpy_ext(NULL,
driver_version + strlen(INTF_CARDTYPE) +
strlen(KERN_VERSION),
V14, strlen(V14),
strlen(driver_version) - strlen(INTF_CARDTYPE) -
strlen(KERN_VERSION));
}
#endif
#ifdef USB8897
if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)USB8897_PID_1 ||
woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)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) ==
(__force __le16)USB8997_PID_1 ||
woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)USB8997_PID_2 ||
woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)USB8997_PID_3 ||
woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)USB8997_PID_4 ||
woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)USB8997_PID_5 ||
woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)USB8997_PID_6 ||
woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)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) ==
(__force __le16)USB8978_PID_1 ||
woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)USB8978_PID_2) {
card_type = CARD_TYPE_USB8978;
moal_memcpy_ext(NULL, driver_version, "USBIW416",
strlen("USBIW416"), 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) ==
(__force __le16)USB9098_PID_1 ||
woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)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) ==
(__force __le16)USB9097_PID_1 ||
woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)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
#ifdef USBNW62X
if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)USBNW62X_PID_1 ||
woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
(__force __le16)USBNW62X_PID_2) {
card_type = CARD_TYPE_USBNW62X;
moal_memcpy_ext(NULL, driver_version, CARD_USBNW62X,
strlen(CARD_USBNW62X), 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) ==
(__force __le16)woal_usb_table[i].idVendor &&
woal_cpu_to_le16(udev->descriptor.idProduct) ==
(__force __le16)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 USB8801
case (__force __le16)USB8801_PID_1:
#endif /* USB8801 */
#ifdef USB8897
case (__force __le16)USB8897_PID_1:
#endif /* USB8897 */
#ifdef USB8997
case (__force __le16)USB8997_PID_1:
case (__force __le16)USB8997V2_PID_1:
#endif /* USB8997 */
#ifdef USB8978
case (__force __le16)USB8978_PID_1:
case (__force __le16)USB8978_PID_1_BT:
#endif /* USB8978 */
#ifdef USB9098
case (__force __le16)USB9098_PID_1:
#endif /* USB9098 */
#ifdef USB9097
case (__force __le16)USB9097_PID_1:
#endif /* USB9097 */
#ifdef USBNW62X
case (__force __le16)USBNW62X_PID_1:
#endif /* USBNW62X */
/* 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 USB8801
case (__force __le16)USB8801_PID_2:
#endif /* USB8801 */
#ifdef USB8897
case (__force __le16)USB8897_PID_2:
#endif /* USB8897 */
#ifdef USB8997
case (__force __le16)USB8997_PID_2:
#endif /* USB8997 */
#ifdef USB8978
case (__force __le16)USB8978_PID_2:
case (__force __le16)USB8978_PID_2_BT:
#endif /* USB8978 */
#ifdef USB9098
case (__force __le16)USB9098_PID_2:
#endif /* USB9098 */
#ifdef USB9097
case (__force __le16)USB9097_PID_2:
#endif /* USB9097 */
#ifdef USBNW62X
case (__force __le16)USBNW62X_PID_2:
#endif /* USBNW62X */
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 =
(__force int)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 =
(__force int)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;
ENTER();
PRINTM(MCMND, "<--- Enter woal_usb_resume --->\n");
if (!cardp || !cardp->phandle) {
PRINTM(MERROR, "Card or adapter structure is not valid\n");
goto done;
}
handle = cardp->phandle;
if (handle->is_suspended == MFALSE) {
PRINTM(MWARN, "Device already resumed\n");
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
*/
static 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_usb_dump_fw_info: 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_usb_dump_fw_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);
phandle->is_fw_dump_timer_set = MTRUE;
woal_mod_timer(&phandle->fw_dump_timer, MOAL_TIMER_5S);
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) || defined(USBNW62X)
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;
#ifdef USB8801
if (IS_USB8801(handle->card_type))
goto done;
#endif
#if defined(USB8997) || defined(USB9098) || defined(USB9097) || \
defined(USB8978) || defined(USBNW62X)
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
#ifdef USBNW62X
if (IS_USBNW62X(handle->card_type)) {
if (strap == CARD_TYPE_USB_UART)
strcpy(handle->card_info->fw_name,
USBUARTNW62X_COMBO_FW_NAME);
else
strcpy(handle->card_info->fw_name,
USBUSBNW62X_COMBO_FW_NAME);
}
#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,
};