#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
+#include <linux/kthread.h>
#include <net/iw_handler.h>
#include <net/ieee80211.h>
#include "debugfs.h"
#include "assoc.h"
-#define DRIVER_RELEASE_VERSION "322.p0"
+#define DRIVER_RELEASE_VERSION "322.p1"
const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
#ifdef DEBUG
"-dbg"
};
/**
- * the rates supported
+ * the table to keep region code
*/
-u8 libertas_supported_rates[G_SUPPORTED_RATES] =
- { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0 };
+u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
+ { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
/**
- * the rates supported for ad-hoc G mode
+ * 802.11b/g supported bitrates (in 500Kb/s units)
*/
-u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] =
- { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0 };
+u8 libertas_bg_rates[MAX_RATES] =
+ { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0x00, 0x00 };
/**
- * the rates supported for ad-hoc B mode
+ * 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.
*/
-u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 };
+static u8 fw_data_rates[MAX_RATES] =
+ { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+ 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
+};
/**
- * the table to keep region code
+ * @brief use index to get the data rate
+ *
+ * @param idx The index of data rate
+ * @return data rate or 0
*/
-u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
- { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
+u32 libertas_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 libertas_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;
+}
/**
* Attributes exported through sysfs
*/
/**
- * @brief Get function for sysfs attribute libertas_mpp
+ * @brief Get function for sysfs attribute anycast_mask
*/
-static ssize_t libertas_mpp_get(struct device * dev,
- struct device_attribute *attr, char * buf) {
+static ssize_t libertas_anycast_get(struct device * dev,
+ struct device_attribute *attr, char * buf)
+{
struct cmd_ds_mesh_access mesh_access;
memset(&mesh_access, 0, sizeof(mesh_access));
libertas_prepare_and_send_command(to_net_dev(dev)->priv,
- cmd_mesh_access,
- cmd_act_mesh_get_mpp,
- cmd_option_waitforrsp, 0, (void *)&mesh_access);
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_GET_ANYCAST,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
- return snprintf(buf, 3, "%d\n", le32_to_cpu(mesh_access.data[0]));
+ return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
}
/**
- * @brief Set function for sysfs attribute libertas_mpp
+ * @brief Set function for sysfs attribute anycast_mask
*/
-static ssize_t libertas_mpp_set(struct device * dev,
- struct device_attribute *attr, const char * buf, size_t count) {
+static ssize_t libertas_anycast_set(struct device * dev,
+ struct device_attribute *attr, const char * buf, size_t count)
+{
struct cmd_ds_mesh_access mesh_access;
uint32_t datum;
memset(&mesh_access, 0, sizeof(mesh_access));
- sscanf(buf, "%d", &datum);
+ sscanf(buf, "%x", &datum);
mesh_access.data[0] = cpu_to_le32(datum);
libertas_prepare_and_send_command((to_net_dev(dev))->priv,
- cmd_mesh_access,
- cmd_act_mesh_set_mpp,
- cmd_option_waitforrsp, 0, (void *)&mesh_access);
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_SET_ANYCAST,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
return strlen(buf);
}
/**
- * libertas_mpp attribute to be exported per mshX interface
- * through sysfs (/sys/class/net/mshX/libertas-mpp)
+ * anycast_mask attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/anycast_mask)
*/
-static DEVICE_ATTR(libertas_mpp, 0644, libertas_mpp_get, libertas_mpp_set );
+static DEVICE_ATTR(anycast_mask, 0644, libertas_anycast_get, libertas_anycast_set);
+
+static ssize_t libertas_autostart_enabled_get(struct device * dev,
+ struct device_attribute *attr, char * buf)
+{
+ struct cmd_ds_mesh_access mesh_access;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ libertas_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);
+
+ return sprintf(buf, "%d\n", le32_to_cpu(mesh_access.data[0]));
+}
+
+static ssize_t libertas_autostart_enabled_set(struct device * dev,
+ struct device_attribute *attr, const char * buf, size_t count)
+{
+ struct cmd_ds_mesh_access mesh_access;
+ uint32_t datum;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ sscanf(buf, "%d", &datum);
+ mesh_access.data[0] = cpu_to_le32(datum);
+
+ libertas_prepare_and_send_command((to_net_dev(dev))->priv,
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(autostart_enabled, 0644,
+ libertas_autostart_enabled_get, libertas_autostart_enabled_set);
+
+static struct attribute *libertas_mesh_sysfs_entries[] = {
+ &dev_attr_anycast_mask.attr,
+ &dev_attr_autostart_enabled.attr,
+ NULL,
+};
+
+static struct attribute_group libertas_mesh_attr_group = {
+ .attrs = libertas_mesh_sysfs_entries,
+};
/**
* @brief Check if the device can be open and wait if necessary.
* @param dev A pointer to net_device structure
* @return 0
*/
-static int wlan_dev_open(struct net_device *dev)
+static int libertas_dev_open(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv;
wlan_adapter *adapter = priv->adapter;
priv->open = 1;
- if (adapter->connect_status == libertas_connected) {
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
netif_carrier_on(priv->dev);
- netif_carrier_on(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_carrier_on(priv->mesh_dev);
} else {
netif_carrier_off(priv->dev);
- netif_carrier_off(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_carrier_off(priv->mesh_dev);
}
lbs_deb_leave(LBS_DEB_NET);
* @param dev A pointer to net_device structure
* @return 0
*/
-static int mesh_open(struct net_device *dev)
+static int libertas_mesh_open(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv ;
priv->mesh_open = 1 ;
netif_wake_queue(priv->mesh_dev);
if (priv->infra_open == 0)
- return wlan_dev_open(priv->dev) ;
+ return libertas_dev_open(priv->dev) ;
return 0;
}
* @param dev A pointer to net_device structure
* @return 0
*/
-static int wlan_open(struct net_device *dev)
+static int libertas_open(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv ;
priv->infra_open = 1 ;
netif_wake_queue(priv->dev);
if (priv->open == 0)
- return wlan_dev_open(priv->dev) ;
+ return libertas_dev_open(priv->dev) ;
return 0;
}
-static int wlan_dev_close(struct net_device *dev)
+static int libertas_dev_close(struct net_device *dev)
{
wlan_private *priv = dev->priv;
* @param dev A pointer to net_device structure
* @return 0
*/
-static int mesh_close(struct net_device *dev)
+static int libertas_mesh_close(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) (dev->priv);
priv->mesh_open = 0;
netif_stop_queue(priv->mesh_dev);
if (priv->infra_open == 0)
- return wlan_dev_close(dev);
+ return libertas_dev_close(dev);
else
return 0;
}
* @param dev A pointer to net_device structure
* @return 0
*/
-static int wlan_close(struct net_device *dev)
+static int libertas_close(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv;
netif_stop_queue(dev);
priv->infra_open = 0;
if (priv->mesh_open == 0)
- return wlan_dev_close(dev);
+ return libertas_dev_close(dev);
else
return 0;
}
-static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int libertas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
int ret = 0;
wlan_private *priv = dev->priv;
}
netif_stop_queue(priv->dev);
- netif_stop_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_stop_queue(priv->mesh_dev);
if (libertas_process_tx(priv, skb) == 0)
dev->trans_start = jiffies;
}
/**
- * @brief Mark mesh packets and handover them to wlan_hard_start_xmit
+ * @brief Mark mesh packets and handover them to libertas_hard_start_xmit
*
*/
-static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int libertas_mesh_pre_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
wlan_private *priv = dev->priv;
int ret;
SET_MESH_FRAME(skb);
- ret = wlan_hard_start_xmit(skb, priv->dev);
+ ret = libertas_hard_start_xmit(skb, priv->dev);
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
return ret;
}
/**
- * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit
+ * @brief Mark non-mesh packets and handover them to libertas_hard_start_xmit
*
*/
-static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
int ret;
UNSET_MESH_FRAME(skb);
- ret = wlan_hard_start_xmit(skb, dev);
+ ret = libertas_hard_start_xmit(skb, dev);
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
return ret;
}
-static void wlan_tx_timeout(struct net_device *dev)
+static void libertas_tx_timeout(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv;
priv->adapter->eventcause = 0x01000000;
libertas_send_tx_feedback(priv);
} else
- wake_up_interruptible(&priv->mainthread.waitq);
- } else if (priv->adapter->connect_status == libertas_connected) {
+ wake_up_interruptible(&priv->waitq);
+ } else if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
netif_wake_queue(priv->dev);
- netif_wake_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_wake_queue(priv->mesh_dev);
}
lbs_deb_leave(LBS_DEB_TX);
* @param dev A pointer to wlan_private structure
* @return A pointer to net_device_stats structure
*/
-static struct net_device_stats *wlan_get_stats(struct net_device *dev)
+static struct net_device_stats *libertas_get_stats(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv;
return &priv->stats;
}
-static int wlan_set_mac_address(struct net_device *dev, void *addr)
+static int libertas_set_mac_address(struct net_device *dev, void *addr)
{
int ret = 0;
wlan_private *priv = (wlan_private *) dev->priv;
memset(adapter->current_addr, 0, ETH_ALEN);
/* dev->dev_addr is 8 bytes */
- lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+ lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN);
- lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN);
+ lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN);
memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address,
- cmd_act_set,
- cmd_option_waitforrsp, 0, NULL);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
if (ret) {
lbs_deb_net("set MAC address failed\n");
goto done;
}
- lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN);
+ lbs_deb_hex(LBS_DEB_NET, "adapter->macaddr", adapter->current_addr, ETH_ALEN);
memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
if (priv->mesh_dev)
memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
return ret;
}
-static int wlan_copy_multicast_address(wlan_adapter * adapter,
+static int libertas_copy_multicast_address(wlan_adapter * adapter,
struct net_device *dev)
{
int i = 0;
}
-static void wlan_set_multicast_list(struct net_device *dev)
+static void libertas_set_multicast_list(struct net_device *dev)
{
wlan_private *priv = dev->priv;
wlan_adapter *adapter = priv->adapter;
if (dev->flags & IFF_PROMISC) {
lbs_deb_net("enable promiscuous mode\n");
adapter->currentpacketfilter |=
- cmd_act_mac_promiscuous_enable;
+ CMD_ACT_MAC_PROMISCUOUS_ENABLE;
adapter->currentpacketfilter &=
- ~(cmd_act_mac_all_multicast_enable |
- cmd_act_mac_multicast_enable);
+ ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
+ CMD_ACT_MAC_MULTICAST_ENABLE);
} else {
/* Multicast */
adapter->currentpacketfilter &=
- ~cmd_act_mac_promiscuous_enable;
+ ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
if (dev->flags & IFF_ALLMULTI || dev->mc_count >
MRVDRV_MAX_MULTICAST_LIST_SIZE) {
lbs_deb_net( "enabling all multicast\n");
adapter->currentpacketfilter |=
- cmd_act_mac_all_multicast_enable;
+ CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
adapter->currentpacketfilter &=
- ~cmd_act_mac_multicast_enable;
+ ~CMD_ACT_MAC_MULTICAST_ENABLE;
} else {
adapter->currentpacketfilter &=
- ~cmd_act_mac_all_multicast_enable;
+ ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
if (!dev->mc_count) {
lbs_deb_net("no multicast addresses, "
"disabling multicast\n");
adapter->currentpacketfilter &=
- ~cmd_act_mac_multicast_enable;
+ ~CMD_ACT_MAC_MULTICAST_ENABLE;
} else {
int i;
adapter->currentpacketfilter |=
- cmd_act_mac_multicast_enable;
+ CMD_ACT_MAC_MULTICAST_ENABLE;
adapter->nr_of_multicastmacaddr =
- wlan_copy_multicast_address(adapter, dev);
+ libertas_copy_multicast_address(adapter, dev);
lbs_deb_net("multicast addresses: %d\n",
dev->mc_count);
}
/* send multicast addresses to firmware */
libertas_prepare_and_send_command(priv,
- cmd_mac_multicast_adr,
- cmd_act_set, 0, 0,
+ CMD_MAC_MULTICAST_ADR,
+ CMD_ACT_SET, 0, 0,
NULL);
}
}
* @param data A pointer to wlan_thread structure
* @return 0
*/
-static int wlan_service_main_thread(void *data)
+static int libertas_thread(void *data)
{
- struct wlan_thread *thread = data;
- wlan_private *priv = thread->priv;
+ struct net_device *dev = data;
+ wlan_private *priv = dev->priv;
wlan_adapter *adapter = priv->adapter;
wait_queue_t wait;
u8 ireg = 0;
lbs_deb_enter(LBS_DEB_THREAD);
- wlan_activate_thread(thread);
-
init_waitqueue_entry(&wait, current);
for (;;) {
adapter->intcounter,
adapter->currenttxskb, priv->dnld_sent);
- add_wait_queue(&thread->waitq, &wait);
+ add_wait_queue(&priv->waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irq(&adapter->driver_lock);
if ((adapter->psstate == PS_STATE_SLEEP) ||
adapter->currenttxskb, priv->dnld_sent);
set_current_state(TASK_RUNNING);
- remove_wait_queue(&thread->waitq, &wait);
+ remove_wait_queue(&priv->waitq, &wait);
try_to_freeze();
lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p "
adapter->currenttxskb, priv->dnld_sent);
/* command response? */
- if (adapter->hisregcpy & his_cmdupldrdy) {
+ if (adapter->hisregcpy & MRVDRV_CMD_UPLD_RDY) {
lbs_deb_thread("main-thread: cmd response ready\n");
- adapter->hisregcpy &= ~his_cmdupldrdy;
+ adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
spin_unlock_irq(&adapter->driver_lock);
libertas_process_rx_command(priv);
spin_lock_irq(&adapter->driver_lock);
}
/* Any Card Event */
- if (adapter->hisregcpy & his_cardevent) {
+ if (adapter->hisregcpy & MRVDRV_CARDEVENT) {
lbs_deb_thread("main-thread: Card Event Activity\n");
- adapter->hisregcpy &= ~his_cardevent;
+ adapter->hisregcpy &= ~MRVDRV_CARDEVENT;
if (priv->hw_read_event_cause(priv)) {
lbs_pr_alert(
if (adapter->psstate == PS_STATE_PRE_SLEEP) {
if (!priv->dnld_sent && !adapter->cur_cmd) {
if (adapter->connect_status ==
- libertas_connected) {
+ LIBERTAS_CONNECTED) {
lbs_deb_thread(
"main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
"dnld_sent=%d cur_cmd=%p, confirm now\n",
del_timer(&adapter->command_timer);
adapter->nr_cmd_pending = 0;
wake_up_all(&adapter->cmd_pending);
- wlan_deactivate_thread(thread);
lbs_deb_leave(LBS_DEB_THREAD);
return 0;
}
/**
+ * @brief This function downloads firmware image, gets
+ * HW spec from firmware and set basic parameters to
+ * firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 or -1
+ */
+static int wlan_setup_station_hw(wlan_private * priv)
+{
+ int ret = -1;
+ wlan_adapter *adapter = priv->adapter;
+
+ lbs_deb_enter(LBS_DEB_FW);
+
+ ret = priv->hw_prog_firmware(priv);
+
+ if (ret) {
+ lbs_deb_fw("bootloader in invalid state\n");
+ ret = -1;
+ goto done;
+ }
+
+ /*
+ * Read MAC address from HW
+ */
+ memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+ ret = libertas_prepare_and_send_command(priv, CMD_GET_HW_SPEC,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+
+ libertas_set_mac_packet_filter(priv);
+
+ /* Get the supported Data rates */
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE,
+ CMD_ACT_GET_TX_RATE,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+
+ ret = 0;
+done:
+ lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+ return ret;
+}
+
+static void command_timer_fn(unsigned long data);
+
+/**
+ * This function handles the timeout of command sending.
+ * It will re-send the same command again.
+ */
+static void command_timer_fn(unsigned long data)
+{
+ wlan_private *priv = (wlan_private *)data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *ptempnode;
+ struct cmd_ds_command *cmd;
+ unsigned long flags;
+
+ ptempnode = adapter->cur_cmd;
+ if (ptempnode == NULL) {
+ lbs_deb_fw("ptempnode empty\n");
+ return;
+ }
+
+ cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
+ if (!cmd) {
+ lbs_deb_fw("cmd is NULL\n");
+ return;
+ }
+
+ lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command);
+
+ if (!adapter->fw_ready)
+ return;
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ lbs_deb_fw("re-sending same command because of timeout\n");
+ libertas_queue_cmd(adapter, ptempnode, 0);
+
+ wake_up_interruptible(&priv->waitq);
+
+ return;
+}
+
+static void libertas_free_adapter(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ if (!adapter) {
+ lbs_deb_fw("why double free adapter?\n");
+ return;
+ }
+
+ lbs_deb_fw("free command buffer\n");
+ libertas_free_cmd_buffer(priv);
+
+ lbs_deb_fw("free command_timer\n");
+ del_timer(&adapter->command_timer);
+
+ lbs_deb_fw("free scan results table\n");
+ kfree(adapter->networks);
+ adapter->networks = NULL;
+
+ /* Free the adapter object itself */
+ lbs_deb_fw("free adapter\n");
+ kfree(adapter);
+ priv->adapter = NULL;
+}
+
+static int wlan_allocate_adapter(wlan_private * priv)
+{
+ size_t bufsize;
+ wlan_adapter *adapter = priv->adapter;
+
+ /* Allocate buffer to store the BSSID list */
+ bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
+ adapter->networks = kzalloc(bufsize, GFP_KERNEL);
+ if (!adapter->networks) {
+ lbs_pr_err("Out of memory allocating beacons\n");
+ libertas_free_adapter(priv);
+ return -ENOMEM;
+ }
+
+ /* Allocate the command buffers */
+ libertas_allocate_cmd_buffer(priv);
+
+ memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep));
+ adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
+ adapter->libertas_ps_confirm_sleep.command =
+ cpu_to_le16(CMD_802_11_PS_MODE);
+ adapter->libertas_ps_confirm_sleep.size =
+ cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
+ adapter->libertas_ps_confirm_sleep.result = 0;
+ adapter->libertas_ps_confirm_sleep.action =
+ cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED);
+
+ return 0;
+}
+
+static void wlan_init_adapter(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int i;
+
+ adapter->connect_status = LIBERTAS_DISCONNECTED;
+ memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+ /* scan type */
+ adapter->scantype = CMD_SCAN_TYPE_ACTIVE;
+
+ /* scan mode */
+ adapter->scanmode = CMD_BSS_TYPE_ANY;
+
+ /* 802.11 specific */
+ adapter->secinfo.wep_enabled = 0;
+ for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
+ i++)
+ memset(&adapter->wep_keys[i], 0, sizeof(struct enc_key));
+ adapter->wep_tx_keyidx = 0;
+ adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
+ adapter->mode = IW_MODE_INFRA;
+
+ adapter->pending_assoc_req = NULL;
+ adapter->in_progress_assoc_req = NULL;
+
+ /* Initialize scan result lists */
+ INIT_LIST_HEAD(&adapter->network_free_list);
+ INIT_LIST_HEAD(&adapter->network_list);
+ for (i = 0; i < MAX_NETWORK_COUNT; i++) {
+ list_add_tail(&adapter->networks[i].list,
+ &adapter->network_free_list);
+ }
+
+ mutex_init(&adapter->lock);
+
+ memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
+ adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
+
+ /* PnP and power profile */
+ adapter->surpriseremoved = 0;
+
+ adapter->currentpacketfilter =
+ CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
+
+ adapter->radioon = RADIO_ON;
+
+ adapter->auto_rate = 1;
+ adapter->cur_rate = 0;
+ adapter->adhoc_grate_enabled = 0;
+
+ adapter->beaconperiod = MRVDRV_BEACON_INTERVAL;
+
+ // set default capabilities
+ adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
+
+ adapter->psmode = WLAN802_11POWERMODECAM;
+
+ adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
+
+ adapter->psstate = PS_STATE_FULL_POWER;
+ adapter->needtowakeup = 0;
+
+ adapter->intcounter = 0;
+
+ adapter->currenttxskb = NULL;
+
+ memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
+ adapter->tx_queue_idx = 0;
+ spin_lock_init(&adapter->txqueue_lock);
+
+ return;
+}
+
+static int libertas_init_fw(wlan_private * priv)
+{
+ int ret = -1;
+ wlan_adapter *adapter = priv->adapter;
+
+ lbs_deb_enter(LBS_DEB_FW);
+
+ /* Allocate adapter structure */
+ if ((ret = wlan_allocate_adapter(priv)) != 0)
+ goto done;
+
+ /* init adapter structure */
+ wlan_init_adapter(priv);
+
+ /* init timer etc. */
+ setup_timer(&adapter->command_timer, command_timer_fn,
+ (unsigned long)priv);
+
+ /* download fimrware etc. */
+ if ((ret = wlan_setup_station_hw(priv)) != 0) {
+ del_timer_sync(&adapter->command_timer);
+ goto done;
+ }
+
+ /* init 802.11d */
+ libertas_init_11d(priv);
+
+ ret = 0;
+done:
+ lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+ return ret;
+}
+
+/**
* @brief This function adds the card. it will probe the
* card, allocate the wlan_priv and initialize the device.
*
SET_MODULE_OWNER(dev);
/* Setup the OS Interface to our functions */
- dev->open = wlan_open;
- dev->hard_start_xmit = wlan_pre_start_xmit;
- dev->stop = wlan_close;
- dev->do_ioctl = libertas_do_ioctl;
- dev->set_mac_address = wlan_set_mac_address;
- dev->tx_timeout = wlan_tx_timeout;
- dev->get_stats = wlan_get_stats;
+ dev->open = libertas_open;
+ dev->hard_start_xmit = libertas_pre_start_xmit;
+ dev->stop = libertas_close;
+ dev->set_mac_address = libertas_set_mac_address;
+ dev->tx_timeout = libertas_tx_timeout;
+ dev->get_stats = libertas_get_stats;
dev->watchdog_timeo = 5 * HZ;
dev->ethtool_ops = &libertas_ethtool_ops;
#ifdef WIRELESS_EXT
#define NETIF_F_DYNALLOC 16
dev->features |= NETIF_F_DYNALLOC;
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
- dev->set_multicast_list = wlan_set_multicast_list;
+ dev->set_multicast_list = libertas_set_multicast_list;
SET_NETDEV_DEV(dev, dmdev);
}
EXPORT_SYMBOL_GPL(libertas_add_card);
-int libertas_activate_card(wlan_private *priv, char *fw_name)
+int libertas_activate_card(wlan_private *priv)
{
struct net_device *dev = priv->dev;
int ret = -1;
lbs_deb_enter(LBS_DEB_MAIN);
- lbs_deb_thread("Starting kthread...\n");
- priv->mainthread.priv = priv;
- wlan_create_thread(wlan_service_main_thread,
- &priv->mainthread, "wlan_main_service");
+ lbs_deb_thread("Starting main thread...\n");
+ init_waitqueue_head(&priv->waitq);
+ priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main");
+ if (IS_ERR(priv->main_thread)) {
+ lbs_deb_thread("Error creating main thread.\n");
+ goto done;
+ }
priv->assoc_thread =
create_singlethread_workqueue("libertas_assoc");
INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
+ INIT_WORK(&priv->sync_channel, libertas_sync_channel);
/*
* Register the device. Fillup the private data structure with
}
/* init FW and HW */
- if (fw_name && libertas_init_fw(priv, fw_name)) {
+ if (libertas_init_fw(priv)) {
lbs_pr_err("firmware init failed\n");
goto err_registerdev;
}
err_registerdev:
destroy_workqueue(priv->assoc_thread);
/* Stop the thread servicing the interrupts */
- wake_up_interruptible(&priv->mainthread.waitq);
- wlan_terminate_thread(&priv->mainthread);
+ wake_up_interruptible(&priv->waitq);
+ kthread_stop(priv->main_thread);
done:
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
return ret;
SET_MODULE_OWNER(mesh_dev);
- mesh_dev->open = mesh_open;
- mesh_dev->hard_start_xmit = mesh_pre_start_xmit;
- mesh_dev->stop = mesh_close;
- mesh_dev->do_ioctl = libertas_do_ioctl;
- mesh_dev->get_stats = wlan_get_stats;
- mesh_dev->set_mac_address = wlan_set_mac_address;
+ mesh_dev->open = libertas_mesh_open;
+ mesh_dev->hard_start_xmit = libertas_mesh_pre_start_xmit;
+ mesh_dev->stop = libertas_mesh_close;
+ mesh_dev->get_stats = libertas_get_stats;
+ mesh_dev->set_mac_address = libertas_set_mac_address;
mesh_dev->ethtool_ops = &libertas_ethtool_ops;
memcpy(mesh_dev->dev_addr, priv->dev->dev_addr,
sizeof(priv->dev->dev_addr));
goto err_free;
}
- ret = device_create_file(&(mesh_dev->dev), &dev_attr_libertas_mpp);
+ ret = sysfs_create_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group);
if (ret)
goto err_unregister;
ret = 0;
goto done;
-
err_unregister:
unregister_netdev(mesh_dev);
struct cmd_ctrl_node *cmdnode;
unsigned long flags;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
spin_lock_irqsave(&priv->adapter->driver_lock, flags);
list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
cancel_delayed_work(&priv->assoc_work);
destroy_workqueue(priv->assoc_thread);
- if (adapter->psmode == wlan802_11powermodemax_psp) {
- adapter->psmode = wlan802_11powermodecam;
- libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+ if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
+ adapter->psmode = WLAN802_11POWERMODECAM;
+ libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
}
memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
adapter->surpriseremoved = 1;
/* Stop the thread servicing the interrupts */
- wlan_terminate_thread(&priv->mainthread);
+ kthread_stop(priv->main_thread);
libertas_debugfs_remove_one(priv);
netif_stop_queue(mesh_dev);
netif_carrier_off(priv->mesh_dev);
- device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp);
+ sysfs_remove_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group);
unregister_netdev(mesh_dev);
priv->mesh_dev = NULL ;
if (priv->adapter->psstate == PS_STATE_SLEEP) {
priv->adapter->psstate = PS_STATE_AWAKE;
netif_wake_queue(dev);
- netif_wake_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_wake_queue(priv->mesh_dev);
}
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
lbs_deb_leave(LBS_DEB_THREAD);
}
EXPORT_SYMBOL_GPL(libertas_interrupt);
+int libertas_reset_device(wlan_private *priv)
+{
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET,
+ CMD_ACT_HALT, 0, 0, NULL);
+ msleep_interruptible(10);
+
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(libertas_reset_device);
+
static int libertas_init_module(void)
{
lbs_deb_enter(LBS_DEB_MAIN);