#include "debugfs.h"
#include "assoc.h"
#include "join.h"
+#include "cmd.h"
#define DRIVER_RELEASE_VERSION "323.p0"
const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
static ssize_t lbs_anycast_get(struct device *dev,
struct device_attribute *attr, char * buf)
{
+ struct lbs_private *priv = to_net_dev(dev)->priv;
struct cmd_ds_mesh_access mesh_access;
+ int ret;
memset(&mesh_access, 0, sizeof(mesh_access));
- lbs_prepare_and_send_command(to_net_dev(dev)->priv,
- CMD_MESH_ACCESS,
- CMD_ACT_MESH_GET_ANYCAST,
- CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+
+ ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
+ if (ret)
+ return ret;
return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
}
static ssize_t lbs_anycast_set(struct device *dev,
struct device_attribute *attr, const char * buf, size_t count)
{
+ struct lbs_private *priv = to_net_dev(dev)->priv;
struct cmd_ds_mesh_access mesh_access;
uint32_t datum;
+ int ret;
memset(&mesh_access, 0, sizeof(mesh_access));
sscanf(buf, "%x", &datum);
mesh_access.data[0] = cpu_to_le32(datum);
- lbs_prepare_and_send_command((to_net_dev(dev))->priv,
- CMD_MESH_ACCESS,
- CMD_ACT_MESH_SET_ANYCAST,
- CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
+ if (ret)
+ return ret;
+
return strlen(buf);
}
if(priv->monitormode == monitor_mode)
return strlen(buf);
if (priv->monitormode == LBS_MONITOR_OFF) {
+ if (priv->infra_open || priv->mesh_open)
+ return -EBUSY;
if (priv->mode == IW_MODE_INFRA)
lbs_send_deauthentication(priv);
else if (priv->mode == IW_MODE_ADHOC)
static ssize_t lbs_autostart_enabled_get(struct device *dev,
struct device_attribute *attr, char * buf)
{
+ struct lbs_private *priv = to_net_dev(dev)->priv;
struct cmd_ds_mesh_access mesh_access;
+ int ret;
memset(&mesh_access, 0, sizeof(mesh_access));
- lbs_prepare_and_send_command(to_net_dev(dev)->priv,
- CMD_MESH_ACCESS,
- CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
- CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_AUTOSTART_ENABLED, &mesh_access);
+ if (ret)
+ return ret;
return sprintf(buf, "%d\n", le32_to_cpu(mesh_access.data[0]));
}
sscanf(buf, "%d", &datum);
mesh_access.data[0] = cpu_to_le32(datum);
- ret = lbs_prepare_and_send_command(priv,
- CMD_MESH_ACCESS,
- CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
- CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_AUTOSTART_ENABLED, &mesh_access);
if (ret == 0)
priv->mesh_autostart_enabled = datum ? 1 : 0;
};
/**
- * @brief Check if the device can be open and wait if necessary.
+ * @brief This function opens the ethX or mshX interface
*
* @param dev A pointer to net_device structure
- * @return 0
- *
- * For USB adapter, on some systems the device open handler will be
- * called before FW ready. Use the following flag check and wait
- * function to work around the issue.
- *
- */
-static int pre_open_check(struct net_device *dev)
-{
- struct lbs_private *priv = (struct lbs_private *) dev->priv;
- int i = 0;
-
- while (!priv->fw_ready && i < 20) {
- i++;
- msleep_interruptible(100);
- }
- if (!priv->fw_ready) {
- lbs_pr_err("firmware not ready\n");
- return -1;
- }
-
- return 0;
-}
-
-/**
- * @brief This function opens the device
- *
- * @param dev A pointer to net_device structure
- * @return 0
+ * @return 0 or -EBUSY if monitor mode active
*/
static int lbs_dev_open(struct net_device *dev)
{
- struct lbs_private *priv = (struct lbs_private *) dev->priv;
-
- lbs_deb_enter(LBS_DEB_NET);
+ struct lbs_private *priv = (struct lbs_private *) dev->priv ;
+ int ret = 0;
- priv->open = 1;
+ spin_lock_irq(&priv->driver_lock);
- if (priv->connect_status == LBS_CONNECTED)
- netif_carrier_on(priv->dev);
- else
- netif_carrier_off(priv->dev);
+ if (priv->monitormode != LBS_MONITOR_OFF) {
+ ret = -EBUSY;
+ goto out;
+ }
- if (priv->mesh_dev) {
- if (priv->mesh_connect_status == LBS_CONNECTED)
- netif_carrier_on(priv->mesh_dev);
+ if (dev == priv->mesh_dev) {
+ priv->mesh_open = 1;
+ priv->mesh_connect_status = LBS_CONNECTED;
+ netif_carrier_on(dev);
+ } else {
+ priv->infra_open = 1;
+
+ if (priv->connect_status == LBS_CONNECTED)
+ netif_carrier_on(dev);
else
- netif_carrier_off(priv->mesh_dev);
+ netif_carrier_off(dev);
}
- lbs_deb_leave(LBS_DEB_NET);
- return 0;
-}
-/**
- * @brief This function opens the mshX interface
- *
- * @param dev A pointer to net_device structure
- * @return 0
- */
-static int lbs_mesh_open(struct net_device *dev)
-{
- struct lbs_private *priv = (struct lbs_private *) dev->priv ;
-
- if (pre_open_check(dev) == -1)
- return -1;
- priv->mesh_open = 1 ;
- netif_wake_queue(priv->mesh_dev);
-
- priv->mesh_connect_status = LBS_CONNECTED;
-
- netif_carrier_on(priv->mesh_dev);
- netif_wake_queue(priv->mesh_dev);
- if (priv->infra_open == 0)
- return lbs_dev_open(priv->dev) ;
- return 0;
-}
-
-/**
- * @brief This function opens the ethX interface
- *
- * @param dev A pointer to net_device structure
- * @return 0
- */
-static int lbs_open(struct net_device *dev)
-{
- struct lbs_private *priv = (struct lbs_private *) dev->priv ;
-
- if(pre_open_check(dev) == -1)
- return -1;
- priv->infra_open = 1 ;
- netif_wake_queue(priv->dev);
- if (priv->open == 0)
- return lbs_dev_open(priv->dev) ;
- return 0;
-}
-
-static int lbs_dev_close(struct net_device *dev)
-{
- struct lbs_private *priv = dev->priv;
-
- lbs_deb_enter(LBS_DEB_NET);
-
- netif_carrier_off(priv->dev);
- priv->open = 0;
+ if (!priv->tx_pending_len)
+ netif_wake_queue(dev);
+ out:
- lbs_deb_leave(LBS_DEB_NET);
- return 0;
+ spin_unlock_irq(&priv->driver_lock);
+ return ret;
}
/**
* @param dev A pointer to net_device structure
* @return 0
*/
-static int lbs_mesh_close(struct net_device *dev)
+static int lbs_mesh_stop(struct net_device *dev)
{
struct lbs_private *priv = (struct lbs_private *) (dev->priv);
+ spin_lock_irq(&priv->driver_lock);
+
priv->mesh_open = 0;
- netif_stop_queue(priv->mesh_dev);
- if (priv->infra_open == 0)
- return lbs_dev_close(dev);
- else
- return 0;
+ priv->mesh_connect_status = LBS_DISCONNECTED;
+
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+
+ spin_unlock_irq(&priv->driver_lock);
+ return 0;
}
/**
* @param dev A pointer to net_device structure
* @return 0
*/
-static int lbs_close(struct net_device *dev)
+static int lbs_eth_stop(struct net_device *dev)
{
struct lbs_private *priv = (struct lbs_private *) dev->priv;
- netif_stop_queue(dev);
+ spin_lock_irq(&priv->driver_lock);
+
priv->infra_open = 0;
- if (priv->mesh_open == 0)
- return lbs_dev_close(dev);
- else
- return 0;
+
+ netif_stop_queue(dev);
+
+ spin_unlock_irq(&priv->driver_lock);
+ return 0;
}
static void lbs_tx_timeout(struct net_device *dev)
set_freezable();
for (;;) {
+ int shouldsleep;
+
lbs_deb_thread( "main-thread 111: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
priv->intcounter, priv->currenttxskb, priv->dnld_sent);
set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irq(&priv->driver_lock);
- if ((priv->psstate == PS_STATE_SLEEP) ||
- (!priv->intcounter && (priv->dnld_sent || priv->cur_cmd || list_empty(&priv->cmdpendingq)))) {
+ if (priv->surpriseremoved)
+ shouldsleep = 0; /* Bye */
+ else if (priv->psstate == PS_STATE_SLEEP)
+ shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */
+ else if (priv->intcounter)
+ shouldsleep = 0; /* Interrupt pending. Deal with it now */
+ else if (!priv->fw_ready)
+ shouldsleep = 1; /* Firmware not ready. We're waiting for it */
+ else if (priv->dnld_sent)
+ shouldsleep = 1; /* Something is en route to the device already */
+ else if (priv->tx_pending_len > 0)
+ shouldsleep = 0; /* We've a packet to send */
+ else if (priv->cur_cmd)
+ shouldsleep = 1; /* Can't send a command; one already running */
+ else if (!list_empty(&priv->cmdpendingq))
+ shouldsleep = 0; /* We have a command to send */
+ else
+ shouldsleep = 1; /* No command */
+
+ if (shouldsleep) {
lbs_deb_thread("main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
priv->connect_status, priv->intcounter,
priv->psmode, priv->psstate);
} else
spin_unlock_irq(&priv->driver_lock);
+ if (!priv->fw_ready)
+ continue;
+
/* Check if we need to confirm Sleep Request received previously */
if (priv->psstate == PS_STATE_PRE_SLEEP &&
!priv->dnld_sent && !priv->cur_cmd) {
*/
if (!list_empty(&priv->cmdpendingq))
wake_up_all(&priv->cmd_pending);
+
+ spin_lock_irq(&priv->driver_lock);
+ if (!priv->dnld_sent && priv->tx_pending_len > 0) {
+ int ret = priv->hw_host_to_card(priv, MVMS_DAT,
+ priv->tx_pending_buf,
+ priv->tx_pending_len);
+ if (ret) {
+ lbs_deb_tx("host_to_card failed %d\n", ret);
+ priv->dnld_sent = DNLD_RES_RECEIVED;
+ }
+ priv->tx_pending_len = 0;
+ if (!priv->currenttxskb) {
+ /* We can wake the queues immediately if we aren't
+ waiting for TX feedback */
+ if (priv->connect_status == LBS_CONNECTED)
+ netif_wake_queue(priv->dev);
+ if (priv->mesh_dev &&
+ priv->mesh_connect_status == LBS_CONNECTED)
+ netif_wake_queue(priv->mesh_dev);
+ }
+ }
+ spin_unlock_irq(&priv->driver_lock);
}
del_timer(&priv->command_timer);
* Read MAC address from HW
*/
memset(priv->current_addr, 0xff, ETH_ALEN);
-
- ret = lbs_prepare_and_send_command(priv, CMD_GET_HW_SPEC,
- 0, CMD_OPTION_WAITFORRSP, 0, NULL);
-
+ ret = lbs_update_hw_spec(priv);
if (ret) {
ret = -1;
goto done;
lbs_set_mac_packet_filter(priv);
- /* Get the supported Data rates */
- ret = lbs_prepare_and_send_command(priv, CMD_802_11_DATA_RATE,
- CMD_ACT_GET_TX_RATE,
- CMD_OPTION_WAITFORRSP, 0, NULL);
-
- if (ret) {
+ ret = lbs_get_data_rate(priv);
+ if (ret < 0) {
ret = -1;
goto done;
}
if (priv->mesh_dev) {
memset(&mesh_access, 0, sizeof(mesh_access));
mesh_access.data[0] = cpu_to_le32(0);
- ret = lbs_prepare_and_send_command(priv,
- CMD_MESH_ACCESS,
- CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
- CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+ &mesh_access);
if (ret) {
ret = -1;
goto done;
static void command_timer_fn(unsigned long data)
{
struct lbs_private *priv = (struct lbs_private *)data;
- struct cmd_ctrl_node *ptempnode;
- struct cmd_ds_command *cmd;
+ struct cmd_ctrl_node *node;
unsigned long flags;
- ptempnode = priv->cur_cmd;
- if (ptempnode == NULL) {
+ node = priv->cur_cmd;
+ if (node == NULL) {
lbs_deb_fw("ptempnode empty\n");
return;
}
- cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
- if (!cmd) {
+ if (!node->cmdbuf) {
lbs_deb_fw("cmd is NULL\n");
return;
}
- lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command);
+ lbs_deb_fw("command_timer_fn fired, cmd %x\n", node->cmdbuf->command);
if (!priv->fw_ready)
return;
spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_fw("re-sending same command because of timeout\n");
- lbs_queue_cmd(priv, ptempnode, 0);
+ lbs_queue_cmd(priv, node, 0);
wake_up_interruptible(&priv->waitq);
priv->infra_open = 0;
/* Setup the OS Interface to our functions */
- dev->open = lbs_open;
+ dev->open = lbs_dev_open;
dev->hard_start_xmit = lbs_hard_start_xmit;
- dev->stop = lbs_close;
+ dev->stop = lbs_eth_stop;
dev->set_mac_address = lbs_set_mac_address;
dev->tx_timeout = lbs_tx_timeout;
dev->get_stats = lbs_get_stats;
lbs_remove_rtap(priv);
dev = priv->dev;
- device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
cancel_delayed_work(&priv->scan_work);
cancel_delayed_work(&priv->assoc_work);
netif_carrier_off(priv->dev);
lbs_debugfs_remove_one(priv);
+ device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
/* Flush pending command nodes */
spin_lock_irqsave(&priv->driver_lock, flags);
mesh_dev->priv = priv;
priv->mesh_dev = mesh_dev;
- mesh_dev->open = lbs_mesh_open;
+ mesh_dev->open = lbs_dev_open;
mesh_dev->hard_start_xmit = lbs_hard_start_xmit;
- mesh_dev->stop = lbs_mesh_close;
+ mesh_dev->stop = lbs_mesh_stop;
mesh_dev->get_stats = lbs_get_stats;
mesh_dev->set_mac_address = lbs_set_mac_address;
mesh_dev->ethtool_ops = &lbs_ethtool_ops;
* @param dev A pointer to net_device structure
* @return n/a
*/
-void lbs_interrupt(struct net_device *dev)
+void lbs_interrupt(struct lbs_private *priv)
{
- struct lbs_private *priv = dev->priv;
-
lbs_deb_enter(LBS_DEB_THREAD);
- lbs_deb_thread("lbs_interrupt: intcounter=%d\n",
- priv->intcounter);
+ lbs_deb_thread("lbs_interrupt: intcounter=%d\n", priv->intcounter);
+
+ if (spin_trylock(&priv->driver_lock)) {
+ spin_unlock(&priv->driver_lock);
+ printk(KERN_CRIT "%s called without driver_lock held\n", __func__);
+ WARN_ON(1);
+ }
priv->intcounter++;
- if (priv->psstate == PS_STATE_SLEEP) {
+ if (priv->psstate == PS_STATE_SLEEP)
priv->psstate = PS_STATE_AWAKE;
- netif_wake_queue(dev);
- if (priv->mesh_dev)
- netif_wake_queue(priv->mesh_dev);
- }
wake_up_interruptible(&priv->waitq);
static int lbs_rtap_open(struct net_device *dev)
{
+ /* Yes, _stop_ the queue. Because we don't support injection */
netif_carrier_off(dev);
netif_stop_queue(dev);
return 0;
static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
netif_stop_queue(dev);
- return -EOPNOTSUPP;
+ return NETDEV_TX_BUSY;
}
static struct net_device_stats *lbs_rtap_get_stats(struct net_device *dev)