/*
* Marvell Wireless LAN device driver: major functions
*
* Copyright (C) 2011, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this 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.
*/
#include "main.h"
#include "wmm.h"
#include "cfg80211.h"
#include "11n.h"
#define VERSION "1.0"
const char driver_version[] = "mwifiex " VERSION " (%s) ";
static char *cal_data_cfg;
module_param(cal_data_cfg, charp, 0);
static void scan_delay_timer_fn(unsigned long data)
{
struct mwifiex_private *priv = (struct mwifiex_private *)data;
struct mwifiex_adapter *adapter = priv->adapter;
struct cmd_ctrl_node *cmd_node, *tmp_node;
unsigned long flags;
if (adapter->surprise_removed)
return;
if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
/*
* Abort scan operation by cancelling all pending scan
* commands
*/
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
list_for_each_entry_safe(cmd_node, tmp_node,
&adapter->scan_pending_q, list) {
list_del(&cmd_node->list);
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
}
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->scan_processing = false;
adapter->scan_delay_cnt = 0;
adapter->empty_tx_q_cnt = 0;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
if (priv->scan_request) {
dev_dbg(adapter->dev, "info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
priv->scan_request = NULL;
} else {
priv->scan_aborting = false;
dev_dbg(adapter->dev, "info: scan already aborted\n");
}
goto done;
}
if (!atomic_read(&priv->adapter->is_tx_received)) {
adapter->empty_tx_q_cnt++;
if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) {
/*
* No Tx traffic for 200msec. Get scan command from
* scan pending queue and put to cmd pending queue to
* resume scan operation
*/
adapter->scan_delay_cnt = 0;
adapter->empty_tx_q_cnt = 0;
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
cmd_node = list_first_entry(&adapter->scan_pending_q,
struct cmd_ctrl_node, list);
list_del(&cmd_node->list);
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
flags);
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
true);
queue_work(adapter->workqueue, &adapter->main_work);
goto done;
}
} else {
adapter->empty_tx_q_cnt = 0;
}
/* Delay scan operation further by 20msec */
mod_timer(&priv->scan_delay_timer, jiffies +
msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
adapter->scan_delay_cnt++;
done:
if (atomic_read(&priv->adapter->is_tx_received))
atomic_set(&priv->adapter->is_tx_received, false);
return;
}
/*
* This function registers the device and performs all the necessary
* initializations.
*
* The following initialization operations are performed -
* - Allocate adapter structure
* - Save interface specific operations table in adapter
* - Call interface specific initialization routine
* - Allocate private structures
* - Set default adapter structure parameters
* - Initialize locks
*
* In case of any errors during inittialization, this function also ensures
* proper cleanup before exiting.
*/
static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
void **padapter)
{
struct mwifiex_adapter *adapter;
int i;
adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL);
if (!adapter)
return -ENOMEM;
*padapter = adapter;
adapter->card = card;
/* Save interface specific operations in adapter */
memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops));
/* card specific initialization has been deferred until now .. */
if (adapter->if_ops.init_if)
if (adapter->if_ops.init_if(adapter))