/**
* This file contains the major functions in WLAN
* driver. It includes init, exit, open, close and main
* thread etc..
*/
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/kthread.h>
#include <linux/kfifo.h>
#include <linux/slab.h>
#include <net/cfg80211.h>
#include "host.h"
#include "decl.h"
#include "dev.h"
#include "cfg.h"
#include "debugfs.h"
#include "cmd.h"
#define DRIVER_RELEASE_VERSION "323.p0"
const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
#ifdef DEBUG
"-dbg"
#endif
"";
/* Module parameters */
unsigned int lbs_debug;
EXPORT_SYMBOL_GPL(lbs_debug);
module_param_named(libertas_debug, lbs_debug, int, 0644);
/* This global structure is used to send the confirm_sleep command as
* fast as possible down to the firmware. */
struct cmd_confirm_sleep confirm_sleep;
/**
* the table to keep region code
*/
u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
{ 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
/**
* FW rate table. FW refers to rates by their index in this table, not by the
* rate value itself. Values of 0x00 are
* reserved positions.
*/
static u8 fw_data_rates[MAX_RATES] =
{ 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
};
/**
* @brief use index to get the data rate
*
* @param idx The index of data rate
* @return data rate or 0
*/
u32 lbs_fw_index_to_data_rate(u8 idx)
{
if (idx >= sizeof(fw_data_rates))
idx = 0;
return fw_data_rates[idx];
}
/**
* @brief use rate to get the index
*
* @param rate data rate
* @return index or 0
*/
u8 lbs_data_rate_to_fw_index(u32 rate)
{
u8 i;
if (!rate)
return 0;
for (i = 0; i < sizeof(fw_data_rates); i++) {
if (rate == fw_data_rates[i])
return i;
}
return 0;
}
/**
* @brief This function opens the ethX interface
*
* @param dev A pointer to net_device structure
* @return 0 or -EBUSY if monitor mode active
*/
static int lbs_dev_open(struct net_device *dev)
{
struct lbs_private *priv = dev->ml_priv;
int ret = 0;
lbs_deb_enter(LBS_DEB_NET);
spin_lock_irq(&priv->driver_lock);
if (priv->connect_status == LBS_CONNECTED)
netif_carrier_on(dev);
else
netif_carrier_off(dev);
if (!priv->tx_pending_len)
netif_wake_queue(dev);
spin_unlock_irq(&priv->driver_lock);
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
return ret;
}
/**
* @brief This function closes the ethX interface
*
* @param dev A pointer to net_device structure
* @return 0
*/
static int lbs_eth_stop(struct net_device *dev)
{
struct lbs_private *priv = dev->ml_priv;
lbs_deb_enter(LBS_DEB_NET);
spin_lock_irq(&priv->driver_lock);
netif_stop_queue(dev);
spin_unlock_irq(&priv->driver_lock);
schedule_work(&priv->mcast_work);
lbs_deb_leave(LBS_DEB_NET);
return 0;
}
static void lbs_tx_timeout(struct net_device *dev)
{
struct lbs_private *priv = dev->ml_priv;
lbs_deb_enter(LBS_DEB_TX);
lbs_pr_err("tx watch dog timeout\n");
dev->trans_start = jiffies; /* prevent tx timeout */
if (priv->currenttxskb)
lbs_send_tx_feedback(priv, 0);
/* XX: Shouldn't we also call into the hw-specific driver
to kick it somehow? */
lbs_host_to_card_done(priv);
/* FIXME: reset the card */
lbs_deb_leave(LBS_DEB_TX);
}
void lbs_host_to_card_done(struct lbs_private *priv)
{
unsigned long flags;
lbs_deb_enter(LBS_DEB_THREAD);
spin_lock_irqsave(&priv->driver_lock, flags);
priv->dnld_sent = DNLD_RES_RECEIVED;
/* Wake main thread if commands are pending */
if (!priv->cur_cmd || priv->tx_pending_len > 0) {
if (!priv->wakeup_dev_required)
wake_up_interruptible(&priv->waitq);
}
spin_unlock_irqrestore(&priv