Updating libertas wireless driver to latest version.

SVN-Revision: 10235
This commit is contained in:
Jens Muecke 2008-01-24 03:03:04 +00:00
parent 8ee2e7a4a3
commit 3829f7b3f1
24 changed files with 1205 additions and 1233 deletions

View File

@ -1,5 +1,5 @@
# #
# Copyright (C) 2007 OpenWrt.org # Copyright (C) 2007 - 2008 OpenWrt.org
# #
# This is free software, licensed under the GNU General Public License v2. # This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information. # See /LICENSE for more information.
@ -33,6 +33,8 @@ endef
define Build/Prepare define Build/Prepare
mkdir -p $(PKG_BUILD_DIR) mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/ $(CP) ./src/* $(PKG_BUILD_DIR)/
$(Build/Patch)
$(if $(QUILT),touch $(PKG_BUILD_DIR)/.quilt_used)
endef endef
define Build/Compile define Build/Compile
@ -42,7 +44,7 @@ define Build/Compile
SUBDIRS="$(PKG_BUILD_DIR)" \ SUBDIRS="$(PKG_BUILD_DIR)" \
CONFIG_LIBERTAS=m \ CONFIG_LIBERTAS=m \
CONFIG_LIBERTAS_USB=m \ CONFIG_LIBERTAS_USB=m \
EXTRA_CFLAGS="-I$(PKG_BUILD_DIR) -include compat.h -I$(STAGING_DIR)/usr/include/mac80211" \ EXTRA_CFLAGS="-I$(PKG_BUILD_DIR) -DCONFIG_LIBERTAS_DEBUG -include compat.h -I$(STAGING_DIR)/usr/include/mac80211" \
modules modules
endef endef

View File

@ -0,0 +1,50 @@
Index: kmod-libertas/ethtool.c
===================================================================
--- kmod-libertas.orig/ethtool.c 2008-01-14 22:14:06.000000000 +0000
+++ kmod-libertas/ethtool.c 2008-01-14 22:14:14.000000000 +0000
@@ -144,16 +144,6 @@
lbs_deb_enter(LBS_DEB_ETHTOOL);
}
-static int lbs_ethtool_get_sset_count(struct net_device * dev, int sset)
-{
- switch (sset) {
- case ETH_SS_STATS:
- return MESH_STATS_NUM;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static void lbs_ethtool_get_strings(struct net_device *dev,
u32 stringset,
u8 * s)
@@ -221,7 +211,6 @@
.get_drvinfo = lbs_ethtool_get_drvinfo,
.get_eeprom = lbs_ethtool_get_eeprom,
.get_eeprom_len = lbs_ethtool_get_eeprom_len,
- .get_sset_count = lbs_ethtool_get_sset_count,
.get_ethtool_stats = lbs_ethtool_get_stats,
.get_strings = lbs_ethtool_get_strings,
.get_wol = lbs_ethtool_get_wol,
Index: kmod-libertas/if_usb.c
===================================================================
--- kmod-libertas.orig/if_usb.c 2008-01-14 22:14:57.000000000 +0000
+++ kmod-libertas/if_usb.c 2008-01-14 22:17:09.000000000 +0000
@@ -188,14 +188,14 @@
endpoint = &iface_desc->endpoint[i].desc;
if (usb_endpoint_is_bulk_in(endpoint)) {
cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
- cardp->ep_in = usb_endpoint_num(endpoint);
+ cardp->ep_in = endpoint->bEndpointAddress;
lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
} else if (usb_endpoint_is_bulk_out(endpoint)) {
cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
- cardp->ep_out = usb_endpoint_num(endpoint);
+ cardp->ep_out = endpoint->bEndpointAddress;
lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);

View File

@ -46,11 +46,13 @@ static struct chan_freq_power channel_freq_power_UN_BG[] = {
static u8 lbs_region_2_code(u8 *region) static u8 lbs_region_2_code(u8 *region)
{ {
u8 i; u8 i;
u8 size = sizeof(region_code_mapping)/
sizeof(struct region_code_mapping);
for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++) for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
region[i] = toupper(region[i]); region[i] = toupper(region[i]);
for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) { for (i = 0; i < size; i++) {
if (!memcmp(region, region_code_mapping[i].region, if (!memcmp(region, region_code_mapping[i].region,
COUNTRY_CODE_LEN)) COUNTRY_CODE_LEN))
return (region_code_mapping[i].code); return (region_code_mapping[i].code);
@ -63,8 +65,9 @@ static u8 lbs_region_2_code(u8 *region)
static u8 *lbs_code_2_region(u8 code) static u8 *lbs_code_2_region(u8 code)
{ {
u8 i; u8 i;
u8 size = sizeof(region_code_mapping)
for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) { / sizeof(struct region_code_mapping);
for (i = 0; i < size; i++) {
if (region_code_mapping[i].code == code) if (region_code_mapping[i].code == code)
return (region_code_mapping[i].region); return (region_code_mapping[i].region);
} }
@ -87,7 +90,8 @@ static u8 lbs_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 *chan)
u8 cfp_no; u8 cfp_no;
cfp = channel_freq_power_UN_BG; cfp = channel_freq_power_UN_BG;
cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG); cfp_no = sizeof(channel_freq_power_UN_BG) /
sizeof(struct chan_freq_power);
for (i = 0; i < cfp_no; i++) { for (i = 0; i < cfp_no; i++) {
if ((cfp + i)->channel == firstchan) { if ((cfp + i)->channel == firstchan) {
@ -137,12 +141,16 @@ static u8 lbs_channel_known_11d(u8 chan,
u32 lbs_chan_2_freq(u8 chan, u8 band) u32 lbs_chan_2_freq(u8 chan, u8 band)
{ {
struct chan_freq_power *cf; struct chan_freq_power *cf;
u16 cnt;
u16 i; u16 i;
u32 freq = 0; u32 freq = 0;
cf = channel_freq_power_UN_BG; cf = channel_freq_power_UN_BG;
cnt =
sizeof(channel_freq_power_UN_BG) /
sizeof(struct chan_freq_power);
for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) { for (i = 0; i < cnt; i++) {
if (chan == cf[i].channel) if (chan == cf[i].channel)
freq = cf[i].freq; freq = cf[i].freq;
} }

View File

@ -1,62 +0,0 @@
#
# Copyright (C) 2007 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# $Id: Makefile 8694 2007-09-08 19:55:42Z nbd $
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=kmod-libertas
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define KernelPackage/libertas
SUBMENU:=Other modules
DEPENDS:=@TARGET_olpc +kmod-mac80211
TITLE:=Marvell 88W8015 Wireless Driver
FILES:= \
$(PKG_BUILD_DIR)/libertas.$(LINUX_KMOD_SUFFIX) \
$(PKG_BUILD_DIR)/usb8xxx.$(LINUX_KMOD_SUFFIX)
# AUTOLOAD:=$(call AutoLoad,20,switch-core switch-robo switch-adm)
endef
define Download/firmware
URL:=http://dev.laptop.org/pub/firmware/libertas
FILE:=usb8388-5.220.11.p5.bin
MD5SUM=123
endef
define Download/firmware_license
URL:=http://dev.laptop.org/pub/firmware/libertas
FILE:=LICENSE
MD5SUM=123
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C "$(LINUX_DIR)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
ARCH="$(LINUX_KARCH)" \
SUBDIRS="$(PKG_BUILD_DIR)" \
CONFIG_LIBERTAS=m \
CONFIG_LIBERTAS_USB=m \
EXTRA_CFLAGS="-I$(PKG_BUILD_DIR) -include compat.h -I$(STAGING_DIR)/usr/include/mac80211" \
modules
endef
define KernelPackage/libertas/install
$(INSTALL_DIR) $(1)/lib/firmware
$(INSTALL_BIN) $(DL_DIR)/usb8388-5.220.11.p5.bin $(1)/lib/firmware/usb8388.bin
$(INSTALL_BIN) $(DL_DIR)/LICENSE $(1)/lib/firmware/
endef
$(eval $(call KernelPackage,libertas))
$(eval $(call Download,firmware))

View File

@ -163,17 +163,18 @@ done:
} }
static int update_channel(struct lbs_private *priv) int lbs_update_channel(struct lbs_private *priv)
{ {
int ret; int ret;
/* the channel in f/w could be out of sync, get the current channel */ /* the channel in f/w could be out of sync; get the current channel */
lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_enter(LBS_DEB_ASSOC);
ret = lbs_get_channel(priv); ret = lbs_get_channel(priv);
if (ret > 0) if (ret > 0) {
priv->curbssparams.channel = (u8) ret; priv->curbssparams.channel = ret;
ret = 0;
}
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret; return ret;
} }
@ -184,7 +185,7 @@ void lbs_sync_channel(struct work_struct *work)
sync_channel); sync_channel);
lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_enter(LBS_DEB_ASSOC);
if (update_channel(priv) != 0) if (lbs_update_channel(priv))
lbs_pr_info("Channel synchronization failed."); lbs_pr_info("Channel synchronization failed.");
lbs_deb_leave(LBS_DEB_ASSOC); lbs_deb_leave(LBS_DEB_ASSOC);
} }
@ -196,33 +197,37 @@ static int assoc_helper_channel(struct lbs_private *priv,
lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_enter(LBS_DEB_ASSOC);
ret = update_channel(priv); ret = lbs_update_channel(priv);
if (ret < 0) { if (ret) {
lbs_deb_assoc("ASSOC: channel: error getting channel."); lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
goto done;
} }
if (assoc_req->channel == priv->curbssparams.channel) if (assoc_req->channel == priv->curbssparams.channel)
goto done; goto done;
if (priv->mesh_dev) { if (priv->mesh_dev) {
/* Disconnect mesh while associating -- otherwise it /* Change mesh channel first; 21.p21 firmware won't let
won't let us change channels */ you change channel otherwise (even though it'll return
lbs_mesh_config(priv, 0); an error to this */
lbs_mesh_config(priv, 0, assoc_req->channel);
} }
lbs_deb_assoc("ASSOC: channel: %d -> %d\n", lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
priv->curbssparams.channel, assoc_req->channel); priv->curbssparams.channel, assoc_req->channel);
ret = lbs_set_channel(priv, assoc_req->channel); ret = lbs_set_channel(priv, assoc_req->channel);
if (ret < 0) if (ret < 0)
lbs_deb_assoc("ASSOC: channel: error setting channel."); lbs_deb_assoc("ASSOC: channel: error setting channel.\n");
/* FIXME: shouldn't need to grab the channel _again_ after setting /* FIXME: shouldn't need to grab the channel _again_ after setting
* it since the firmware is supposed to return the new channel, but * it since the firmware is supposed to return the new channel, but
* whatever... */ * whatever... */
ret = update_channel(priv); ret = lbs_update_channel(priv);
if (ret < 0) if (ret) {
lbs_deb_assoc("ASSOC: channel: error getting channel."); lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
goto done;
}
if (assoc_req->channel != priv->curbssparams.channel) { if (assoc_req->channel != priv->curbssparams.channel) {
lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n", lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
@ -240,11 +245,11 @@ static int assoc_helper_channel(struct lbs_private *priv,
} }
/* Must restart/rejoin adhoc networks after channel change */ /* Must restart/rejoin adhoc networks after channel change */
set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
restore_mesh: restore_mesh:
if (priv->mesh_dev) if (priv->mesh_dev)
lbs_mesh_config(priv, 1); lbs_mesh_config(priv, 1, priv->curbssparams.channel);
done: done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@ -253,7 +258,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
static int assoc_helper_wep_keys(struct lbs_private *priv, static int assoc_helper_wep_keys(struct lbs_private *priv,
struct assoc_request * assoc_req) struct assoc_request *assoc_req)
{ {
int i; int i;
int ret = 0; int ret = 0;
@ -261,22 +266,11 @@ static int assoc_helper_wep_keys(struct lbs_private *priv,
lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_enter(LBS_DEB_ASSOC);
/* Set or remove WEP keys */ /* Set or remove WEP keys */
if ( assoc_req->wep_keys[0].len if (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
|| assoc_req->wep_keys[1].len assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)
|| assoc_req->wep_keys[2].len ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_ADD, assoc_req);
|| assoc_req->wep_keys[3].len) { else
ret = lbs_prepare_and_send_command(priv, ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, assoc_req);
CMD_802_11_SET_WEP,
CMD_ACT_ADD,
CMD_OPTION_WAITFORRSP,
0, assoc_req);
} else {
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_SET_WEP,
CMD_ACT_REMOVE,
CMD_OPTION_WAITFORRSP,
0, NULL);
}
if (ret) if (ret)
goto out; goto out;
@ -286,6 +280,7 @@ static int assoc_helper_wep_keys(struct lbs_private *priv,
priv->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE; priv->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE;
else else
priv->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE; priv->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE;
ret = lbs_set_mac_packet_filter(priv); ret = lbs_set_mac_packet_filter(priv);
if (ret) if (ret)
goto out; goto out;
@ -295,7 +290,7 @@ static int assoc_helper_wep_keys(struct lbs_private *priv,
/* Copy WEP keys into priv wep key fields */ /* Copy WEP keys into priv wep key fields */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i], memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i],
sizeof(struct enc_key)); sizeof(struct enc_key));
} }
priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx; priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
@ -310,8 +305,8 @@ static int assoc_helper_secinfo(struct lbs_private *priv,
struct assoc_request * assoc_req) struct assoc_request * assoc_req)
{ {
int ret = 0; int ret = 0;
u32 do_wpa; uint16_t do_wpa;
u32 rsn = 0; uint16_t rsn = 0;
lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_enter(LBS_DEB_ASSOC);
@ -328,28 +323,19 @@ static int assoc_helper_secinfo(struct lbs_private *priv,
*/ */
/* Get RSN enabled/disabled */ /* Get RSN enabled/disabled */
ret = lbs_prepare_and_send_command(priv, ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn);
CMD_802_11_ENABLE_RSN,
CMD_ACT_GET,
CMD_OPTION_WAITFORRSP,
0, &rsn);
if (ret) { if (ret) {
lbs_deb_assoc("Failed to get RSN status: %d", ret); lbs_deb_assoc("Failed to get RSN status: %d\n", ret);
goto out; goto out;
} }
/* Don't re-enable RSN if it's already enabled */ /* Don't re-enable RSN if it's already enabled */
do_wpa = (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled); do_wpa = assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled;
if (do_wpa == rsn) if (do_wpa == rsn)
goto out; goto out;
/* Set RSN enabled/disabled */ /* Set RSN enabled/disabled */
rsn = do_wpa; ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &do_wpa);
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_ENABLE_RSN,
CMD_ACT_SET,
CMD_OPTION_WAITFORRSP,
0, &rsn);
out: out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);

File diff suppressed because it is too large Load Diff

View File

@ -6,14 +6,24 @@
#include "hostcmd.h" #include "hostcmd.h"
#include "dev.h" #include "dev.h"
#define lbs_cmd(priv, cmdnr, cmd, callback, callback_arg) \ /* lbs_cmd() infers the size of the buffer to copy data back into, from
__lbs_cmd(priv, cmdnr, &(cmd).hdr, sizeof(cmd), \ the size of the target of the pointer. Since the command to be sent
callback, callback_arg) may often be smaller, that size is set in cmd->size by the caller.*/
#define lbs_cmd(priv, cmdnr, cmd, cb, cb_arg) ({ \
uint16_t __sz = le16_to_cpu((cmd)->hdr.size); \
(cmd)->hdr.size = cpu_to_le16(sizeof(*(cmd))); \
__lbs_cmd(priv, cmdnr, &(cmd)->hdr, __sz, cb, cb_arg); \
})
#define lbs_cmd_with_response(priv, cmdnr, cmd) \ #define lbs_cmd_with_response(priv, cmdnr, cmd) \
__lbs_cmd(priv, cmdnr, &(cmd).hdr, sizeof(cmd), \ lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd))
lbs_cmd_copyback, (unsigned long) &cmd)
/* __lbs_cmd() will free the cmdnode and return success/failure.
__lbs_cmd_async() requires that the callback free the cmdnode */
struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command,
struct cmd_header *in_cmd, int in_cmd_size,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
unsigned long callback_arg);
int __lbs_cmd(struct lbs_private *priv, uint16_t command, int __lbs_cmd(struct lbs_private *priv, uint16_t command,
struct cmd_header *in_cmd, int in_cmd_size, struct cmd_header *in_cmd, int in_cmd_size,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
@ -33,6 +43,19 @@ int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
int lbs_get_channel(struct lbs_private *priv); int lbs_get_channel(struct lbs_private *priv);
int lbs_set_channel(struct lbs_private *priv, u8 channel); int lbs_set_channel(struct lbs_private *priv, u8 channel);
int lbs_mesh_config(struct lbs_private *priv, int enable); int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria);
int lbs_suspend(struct lbs_private *priv);
int lbs_resume(struct lbs_private *priv);
int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
uint16_t cmd_action, uint16_t *timeout);
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
struct sleep_params *sp);
int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc);
int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
uint16_t *enable);
#endif /* _LBS_CMD_H */ #endif /* _LBS_CMD_H */

View File

@ -43,14 +43,15 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
msleep_interruptible(1000); msleep_interruptible(1000);
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
/* Free Tx and Rx packets */
kfree_skb(priv->currenttxskb);
priv->currenttxskb = NULL;
/* report disconnect to upper layer */ /* report disconnect to upper layer */
netif_stop_queue(priv->dev); netif_stop_queue(priv->dev);
netif_carrier_off(priv->dev); netif_carrier_off(priv->dev);
/* Free Tx and Rx packets */
kfree_skb(priv->currenttxskb);
priv->currenttxskb = NULL;
priv->tx_pending_len = 0;
/* reset SNR/NF/RSSI values */ /* reset SNR/NF/RSSI values */
memset(priv->SNR, 0x00, sizeof(priv->SNR)); memset(priv->SNR, 0x00, sizeof(priv->SNR));
memset(priv->NF, 0x00, sizeof(priv->NF)); memset(priv->NF, 0x00, sizeof(priv->NF));
@ -145,29 +146,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
return ret; return ret;
} }
static int lbs_ret_802_11_sleep_params(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
lbs_deb_enter(LBS_DEB_CMD);
lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x "
"extsleepclk 0x%x\n", le16_to_cpu(sp->error),
le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime),
sp->calcontrol, sp->externalsleepclk);
priv->sp.sp_error = le16_to_cpu(sp->error);
priv->sp.sp_offset = le16_to_cpu(sp->offset);
priv->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
priv->sp.sp_calcontrol = sp->calcontrol;
priv->sp.sp_extsleepclk = sp->externalsleepclk;
priv->sp.sp_reserved = le16_to_cpu(sp->reserved);
lbs_deb_enter(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_stat(struct lbs_private *priv, static int lbs_ret_802_11_stat(struct lbs_private *priv,
struct cmd_ds_command *resp) struct cmd_ds_command *resp)
{ {
@ -394,23 +372,6 @@ static int lbs_ret_get_log(struct lbs_private *priv,
return 0; return 0;
} }
static int lbs_ret_802_11_enable_rsn(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_enable_rsn *enable_rsn = &resp->params.enbrsn;
u32 * pdata_buf = priv->cur_cmd->pdata_buf;
lbs_deb_enter(LBS_DEB_CMD);
if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) {
if (pdata_buf)
*pdata_buf = (u32) le16_to_cpu(enable_rsn->enable);
}
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv, static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
struct cmd_ds_command *resp) struct cmd_ds_command *resp)
{ {
@ -428,25 +389,6 @@ static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
return 0; return 0;
} }
static int lbs_ret_802_11_subscribe_event(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_subscribe_event *cmd_event =
&resp->params.subscribe_event;
struct cmd_ds_802_11_subscribe_event *dst_event =
priv->cur_cmd->pdata_buf;
lbs_deb_enter(LBS_DEB_CMD);
if (dst_event->action == cpu_to_le16(CMD_ACT_GET)) {
dst_event->events = cmd_event->events;
memcpy(dst_event->tlv, cmd_event->tlv, sizeof(dst_event->tlv));
}
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static inline int handle_cmd_response(struct lbs_private *priv, static inline int handle_cmd_response(struct lbs_private *priv,
unsigned long dummy, unsigned long dummy,
struct cmd_header *cmd_response) struct cmd_header *cmd_response)
@ -504,7 +446,7 @@ static inline int handle_cmd_response(struct lbs_private *priv,
case CMD_RET(CMD_802_11_SET_AFC): case CMD_RET(CMD_802_11_SET_AFC):
case CMD_RET(CMD_802_11_GET_AFC): case CMD_RET(CMD_802_11_GET_AFC):
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
memmove(priv->cur_cmd->pdata_buf, &resp->params.afc, memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
sizeof(struct cmd_ds_802_11_afc)); sizeof(struct cmd_ds_802_11_afc));
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
@ -512,17 +454,11 @@ static inline int handle_cmd_response(struct lbs_private *priv,
case CMD_RET(CMD_MAC_MULTICAST_ADR): case CMD_RET(CMD_MAC_MULTICAST_ADR):
case CMD_RET(CMD_MAC_CONTROL): case CMD_RET(CMD_MAC_CONTROL):
case CMD_RET(CMD_802_11_SET_WEP):
case CMD_RET(CMD_802_11_RESET): case CMD_RET(CMD_802_11_RESET):
case CMD_RET(CMD_802_11_AUTHENTICATE): case CMD_RET(CMD_802_11_AUTHENTICATE):
case CMD_RET(CMD_802_11_RADIO_CONTROL):
case CMD_RET(CMD_802_11_BEACON_STOP): case CMD_RET(CMD_802_11_BEACON_STOP):
break; break;
case CMD_RET(CMD_802_11_ENABLE_RSN):
ret = lbs_ret_802_11_enable_rsn(priv, resp);
break;
case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET): case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp); ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
break; break;
@ -551,35 +487,22 @@ static inline int handle_cmd_response(struct lbs_private *priv,
ret = lbs_ret_802_11d_domain_info(priv, resp); ret = lbs_ret_802_11d_domain_info(priv, resp);
break; break;
case CMD_RET(CMD_802_11_SLEEP_PARAMS):
ret = lbs_ret_802_11_sleep_params(priv, resp);
break;
case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT):
spin_lock_irqsave(&priv->driver_lock, flags);
*((u16 *) priv->cur_cmd->pdata_buf) =
le16_to_cpu(resp->params.inactivity_timeout.timeout);
spin_unlock_irqrestore(&priv->driver_lock, flags);
break;
case CMD_RET(CMD_802_11_TPC_CFG): case CMD_RET(CMD_802_11_TPC_CFG):
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
memmove(priv->cur_cmd->pdata_buf, &resp->params.tpccfg, memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
sizeof(struct cmd_ds_802_11_tpc_cfg)); sizeof(struct cmd_ds_802_11_tpc_cfg));
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
break; break;
case CMD_RET(CMD_802_11_LED_GPIO_CTRL): case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
memmove(priv->cur_cmd->pdata_buf, &resp->params.ledgpio, memmove((void *)priv->cur_cmd->callback_arg, &resp->params.ledgpio,
sizeof(struct cmd_ds_802_11_led_ctrl)); sizeof(struct cmd_ds_802_11_led_ctrl));
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
break; break;
case CMD_RET(CMD_802_11_SUBSCRIBE_EVENT):
ret = lbs_ret_802_11_subscribe_event(priv, resp);
break;
case CMD_RET(CMD_802_11_PWR_CFG): case CMD_RET(CMD_802_11_PWR_CFG):
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
memmove(priv->cur_cmd->pdata_buf, &resp->params.pwrcfg, memmove((void *)priv->cur_cmd->callback_arg, &resp->params.pwrcfg,
sizeof(struct cmd_ds_802_11_pwr_cfg)); sizeof(struct cmd_ds_802_11_pwr_cfg));
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
@ -587,21 +510,21 @@ static inline int handle_cmd_response(struct lbs_private *priv,
case CMD_RET(CMD_GET_TSF): case CMD_RET(CMD_GET_TSF):
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
memcpy(priv->cur_cmd->pdata_buf, memcpy((void *)priv->cur_cmd->callback_arg,
&resp->params.gettsf.tsfvalue, sizeof(u64)); &resp->params.gettsf.tsfvalue, sizeof(u64));
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
break; break;
case CMD_RET(CMD_BT_ACCESS): case CMD_RET(CMD_BT_ACCESS):
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->cur_cmd->pdata_buf) if (priv->cur_cmd->callback_arg)
memcpy(priv->cur_cmd->pdata_buf, memcpy((void *)priv->cur_cmd->callback_arg,
&resp->params.bt.addr1, 2 * ETH_ALEN); &resp->params.bt.addr1, 2 * ETH_ALEN);
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
break; break;
case CMD_RET(CMD_FWT_ACCESS): case CMD_RET(CMD_FWT_ACCESS):
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->cur_cmd->pdata_buf) if (priv->cur_cmd->callback_arg)
memcpy(priv->cur_cmd->pdata_buf, &resp->params.fwt, memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
sizeof(resp->params.fwt)); sizeof(resp->params.fwt));
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
break; break;
@ -611,7 +534,7 @@ static inline int handle_cmd_response(struct lbs_private *priv,
default: default:
lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
resp->command); le16_to_cpu(resp->command));
break; break;
} }
lbs_deb_leave(LBS_DEB_HOST); lbs_deb_leave(LBS_DEB_HOST);
@ -620,17 +543,14 @@ static inline int handle_cmd_response(struct lbs_private *priv,
int lbs_process_rx_command(struct lbs_private *priv) int lbs_process_rx_command(struct lbs_private *priv)
{ {
u16 respcmd; uint16_t respcmd, curcmd;
struct cmd_header *resp; struct cmd_header *resp;
int ret = 0; int ret = 0;
ulong flags; unsigned long flags;
u16 result; uint16_t result;
lbs_deb_enter(LBS_DEB_HOST); lbs_deb_enter(LBS_DEB_HOST);
/* Now we got response from FW, cancel the command timer */
del_timer(&priv->command_timer);
mutex_lock(&priv->lock); mutex_lock(&priv->lock);
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
@ -640,30 +560,57 @@ int lbs_process_rx_command(struct lbs_private *priv)
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
goto done; goto done;
} }
resp = priv->cur_cmd->cmdbuf;
resp = (void *)priv->upld_buf;
curcmd = le16_to_cpu(resp->command);
respcmd = le16_to_cpu(resp->command); respcmd = le16_to_cpu(resp->command);
result = le16_to_cpu(resp->result); result = le16_to_cpu(resp->result);
lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n", lbs_deb_host("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n",
respcmd, priv->upld_len, jiffies); respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies);
lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len); lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len);
if (!(respcmd & 0x8000)) { if (resp->seqnum != resp->seqnum) {
lbs_deb_host("invalid response!\n"); lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
priv->cur_cmd_retcode = -1; le16_to_cpu(resp->seqnum), le16_to_cpu(resp->seqnum));
__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
priv->cur_cmd = NULL;
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1; ret = -1;
goto done; goto done;
} }
if (respcmd != CMD_RET(curcmd) &&
respcmd != CMD_802_11_ASSOCIATE && curcmd != CMD_RET_802_11_ASSOCIATE) {
lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
}
if (resp->result == cpu_to_le16(0x0004)) {
/* 0x0004 means -EAGAIN. Drop the response, let it time out
and be resubmitted */
lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
le16_to_cpu(resp->command));
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
}
/* Now we got response from FW, cancel the command timer */
del_timer(&priv->command_timer);
priv->cmd_timed_out = 0;
if (priv->nr_retries) {
lbs_pr_info("Received result %x to command %x after %d retries\n",
result, curcmd, priv->nr_retries);
priv->nr_retries = 0;
}
/* Store the response code to cur_cmd_retcode. */ /* Store the response code to cur_cmd_retcode. */
priv->cur_cmd_retcode = result; priv->cur_cmd_retcode = result;
if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) { if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
struct cmd_ds_802_11_ps_mode *psmode = (void *) resp; struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
u16 action = le16_to_cpu(psmode->action); u16 action = le16_to_cpu(psmode->action);
lbs_deb_host( lbs_deb_host(
@ -708,8 +655,7 @@ int lbs_process_rx_command(struct lbs_private *priv)
lbs_deb_host("CMD_RESP: PS action 0x%X\n", action); lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
} }
__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd); lbs_complete_command(priv, priv->cur_cmd, result);
priv->cur_cmd = NULL;
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = 0; ret = 0;
@ -730,9 +676,7 @@ int lbs_process_rx_command(struct lbs_private *priv)
break; break;
} }
lbs_complete_command(priv, priv->cur_cmd, result);
__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
priv->cur_cmd = NULL;
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1; ret = -1;
@ -751,8 +695,7 @@ int lbs_process_rx_command(struct lbs_private *priv)
if (priv->cur_cmd) { if (priv->cur_cmd) {
/* Clean up and Put current command back to cmdfreeq */ /* Clean up and Put current command back to cmdfreeq */
__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd); lbs_complete_command(priv, priv->cur_cmd, result);
priv->cur_cmd = NULL;
} }
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
@ -762,6 +705,30 @@ done:
return ret; return ret;
} }
static int lbs_send_confirmwake(struct lbs_private *priv)
{
struct cmd_header *cmd = &priv->lbs_ps_confirm_wake;
int ret = 0;
lbs_deb_enter(LBS_DEB_HOST);
cmd->command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM);
cmd->size = cpu_to_le16(sizeof(*cmd));
cmd->seqnum = cpu_to_le16(++priv->seqnum);
cmd->result = 0;
lbs_deb_host("SEND_WAKEC_CMD: before download\n");
lbs_deb_hex(LBS_DEB_HOST, "wake confirm command", (void *)cmd, sizeof(*cmd));
ret = priv->hw_host_to_card(priv, MVMS_CMD, (void *)cmd, sizeof(*cmd));
if (ret)
lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n");
lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
int lbs_process_event(struct lbs_private *priv) int lbs_process_event(struct lbs_private *priv)
{ {
int ret = 0; int ret = 0;
@ -810,9 +777,13 @@ int lbs_process_event(struct lbs_private *priv)
break; break;
case MACREG_INT_CODE_HOST_AWAKE:
lbs_deb_cmd("EVENT: HOST_AWAKE\n");
lbs_send_confirmwake(priv);
break;
case MACREG_INT_CODE_PS_AWAKE: case MACREG_INT_CODE_PS_AWAKE:
lbs_deb_cmd("EVENT: awake\n"); lbs_deb_cmd("EVENT: awake\n");
/* handle unexpected PS AWAKE event */ /* handle unexpected PS AWAKE event */
if (priv->psstate == PS_STATE_FULL_POWER) { if (priv->psstate == PS_STATE_FULL_POWER) {
lbs_deb_cmd( lbs_deb_cmd(
@ -875,9 +846,10 @@ int lbs_process_event(struct lbs_private *priv)
} }
lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
priv->mesh_connect_status = LBS_CONNECTED; priv->mesh_connect_status = LBS_CONNECTED;
if (priv->mesh_open == 1) { if (priv->mesh_open) {
netif_wake_queue(priv->mesh_dev);
netif_carrier_on(priv->mesh_dev); netif_carrier_on(priv->mesh_dev);
if (!priv->tx_pending_len)
netif_wake_queue(priv->mesh_dev);
} }
priv->mode = IW_MODE_ADHOC; priv->mode = IW_MODE_ADHOC;
schedule_work(&priv->sync_channel); schedule_work(&priv->sync_channel);

View File

@ -10,6 +10,7 @@
#include "decl.h" #include "decl.h"
#include "host.h" #include "host.h"
#include "debugfs.h" #include "debugfs.h"
#include "cmd.h"
static struct dentry *lbs_dir; static struct dentry *lbs_dir;
static char *szStates[] = { static char *szStates[] = {
@ -103,71 +104,64 @@ static ssize_t lbs_sleepparams_write(struct file *file,
loff_t *ppos) loff_t *ppos)
{ {
struct lbs_private *priv = file->private_data; struct lbs_private *priv = file->private_data;
ssize_t buf_size, res; ssize_t buf_size, ret;
struct sleep_params sp;
int p1, p2, p3, p4, p5, p6; int p1, p2, p3, p4, p5, p6;
unsigned long addr = get_zeroed_page(GFP_KERNEL); unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr; char *buf = (char *)addr;
buf_size = min(count, len - 1); buf_size = min(count, len - 1);
if (copy_from_user(buf, user_buf, buf_size)) { if (copy_from_user(buf, user_buf, buf_size)) {
res = -EFAULT; ret = -EFAULT;
goto out_unlock; goto out_unlock;
} }
res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6); ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
if (res != 6) { if (ret != 6) {
res = -EFAULT; ret = -EINVAL;
goto out_unlock; goto out_unlock;
} }
priv->sp.sp_error = p1; sp.sp_error = p1;
priv->sp.sp_offset = p2; sp.sp_offset = p2;
priv->sp.sp_stabletime = p3; sp.sp_stabletime = p3;
priv->sp.sp_calcontrol = p4; sp.sp_calcontrol = p4;
priv->sp.sp_extsleepclk = p5; sp.sp_extsleepclk = p5;
priv->sp.sp_reserved = p6; sp.sp_reserved = p6;
res = lbs_prepare_and_send_command(priv, ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
CMD_802_11_SLEEP_PARAMS, if (!ret)
CMD_ACT_SET, ret = count;
CMD_OPTION_WAITFORRSP, 0, NULL); else if (ret > 0)
ret = -EINVAL;
if (!res)
res = count;
else
res = -EINVAL;
out_unlock: out_unlock:
free_page(addr); free_page(addr);
return res; return ret;
} }
static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf, static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct lbs_private *priv = file->private_data; struct lbs_private *priv = file->private_data;
ssize_t res; ssize_t ret;
size_t pos = 0; size_t pos = 0;
struct sleep_params sp;
unsigned long addr = get_zeroed_page(GFP_KERNEL); unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr; char *buf = (char *)addr;
res = lbs_prepare_and_send_command(priv, ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
CMD_802_11_SLEEP_PARAMS, if (ret)
CMD_ACT_GET,
CMD_OPTION_WAITFORRSP, 0, NULL);
if (res) {
res = -EFAULT;
goto out_unlock; goto out_unlock;
}
pos += snprintf(buf, len, "%d %d %d %d %d %d\n", priv->sp.sp_error, pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
priv->sp.sp_offset, priv->sp.sp_stabletime, sp.sp_offset, sp.sp_stabletime,
priv->sp.sp_calcontrol, priv->sp.sp_extsleepclk, sp.sp_calcontrol, sp.sp_extsleepclk,
priv->sp.sp_reserved); sp.sp_reserved);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
out_unlock: out_unlock:
free_page(addr); free_page(addr);
return res; return ret;
} }
static ssize_t lbs_extscan(struct file *file, const char __user *userbuf, static ssize_t lbs_extscan(struct file *file, const char __user *userbuf,
@ -352,20 +346,19 @@ static ssize_t lbs_setuserscan(struct file *file,
* and returns a pointer to the first data byte of the TLV, or to NULL * and returns a pointer to the first data byte of the TLV, or to NULL
* if the TLV hasn't been found. * if the TLV hasn't been found.
*/ */
static void *lbs_tlv_find(u16 tlv_type, const u8 *tlv, u16 size) static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
{ {
__le16 le_type = cpu_to_le16(tlv_type);
ssize_t pos = 0;
struct mrvlietypesheader *tlv_h; struct mrvlietypesheader *tlv_h;
uint16_t length;
ssize_t pos = 0;
while (pos < size) { while (pos < size) {
u16 length;
tlv_h = (struct mrvlietypesheader *) tlv; tlv_h = (struct mrvlietypesheader *) tlv;
if (tlv_h->type == le_type) if (!tlv_h->len)
return tlv_h;
if (tlv_h->len == 0)
return NULL; return NULL;
length = le16_to_cpu(tlv_h->len) + if (tlv_h->type == cpu_to_le16(tlv_type))
sizeof(struct mrvlietypesheader); return tlv_h;
length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h);
pos += length; pos += length;
tlv += length; tlv += length;
} }
@ -373,100 +366,100 @@ static void *lbs_tlv_find(u16 tlv_type, const u8 *tlv, u16 size)
} }
/* static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
* This just gets the bitmap of currently subscribed events. Used when struct file *file, char __user *userbuf,
* adding an additonal event subscription. size_t count, loff_t *ppos)
*/
static u16 lbs_get_events_bitmap(struct lbs_private *priv)
{
ssize_t res;
struct cmd_ds_802_11_subscribe_event *events = kzalloc(
sizeof(struct cmd_ds_802_11_subscribe_event),
GFP_KERNEL);
res = lbs_prepare_and_send_command(priv,
CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
CMD_OPTION_WAITFORRSP, 0, events);
if (res) {
kfree(events);
return 0;
}
return le16_to_cpu(events->events);
}
static ssize_t lbs_threshold_read(
u16 tlv_type, u16 event_mask,
struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{ {
struct cmd_ds_802_11_subscribe_event *subscribed;
struct mrvlietypes_thresholds *got;
struct lbs_private *priv = file->private_data; struct lbs_private *priv = file->private_data;
ssize_t res = 0; ssize_t ret = 0;
size_t pos = 0; size_t pos = 0;
unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf;
char *buf = (char *)addr;
u8 value; u8 value;
u8 freq; u8 freq;
int events = 0; int events = 0;
struct cmd_ds_802_11_subscribe_event *subscribed = kzalloc( buf = (char *)get_zeroed_page(GFP_KERNEL);
sizeof(struct cmd_ds_802_11_subscribe_event), if (!buf)
GFP_KERNEL); return -ENOMEM;
struct mrvlietypes_thresholds *got;
res = lbs_prepare_and_send_command(priv, subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL);
CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET, if (!subscribed) {
CMD_OPTION_WAITFORRSP, 0, subscribed); ret = -ENOMEM;
if (res) { goto out_page;
kfree(subscribed);
return res;
} }
subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed));
subscribed->action = cpu_to_le16(CMD_ACT_GET);
ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed);
if (ret)
goto out_cmd;
got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv)); got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
if (got) { if (got) {
value = got->value; value = got->value;
freq = got->freq; freq = got->freq;
events = le16_to_cpu(subscribed->events); events = le16_to_cpu(subscribed->events);
pos += snprintf(buf, len, "%d %d %d\n", value, freq,
!!(events & event_mask));
} }
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
out_cmd:
kfree(subscribed); kfree(subscribed);
if (got) out_page:
pos += snprintf(buf, len, "%d %d %d\n", value, freq, free_page((unsigned long)buf);
!!(events & event_mask)); return ret;
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
free_page(addr);
return res;
} }
static ssize_t lbs_threshold_write( static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
u16 tlv_type, u16 event_mask, struct file *file,
struct file *file, const char __user *userbuf, size_t count,
const char __user *userbuf, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
struct lbs_private *priv = file->private_data;
ssize_t res, buf_size;
int value, freq, curr_mask, new_mask;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
struct cmd_ds_802_11_subscribe_event *events; struct cmd_ds_802_11_subscribe_event *events;
struct mrvlietypes_thresholds *tlv;
struct lbs_private *priv = file->private_data;
ssize_t buf_size;
int value, freq, new_mask;
uint16_t curr_mask;
char *buf;
int ret;
buf = (char *)get_zeroed_page(GFP_KERNEL);
if (!buf)
return -ENOMEM;
buf_size = min(count, len - 1); buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) { if (copy_from_user(buf, userbuf, buf_size)) {
res = -EFAULT; ret = -EFAULT;
goto out_unlock; goto out_page;
} }
res = sscanf(buf, "%d %d %d", &value, &freq, &new_mask); ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
if (res != 3) { if (ret != 3) {
res = -EFAULT; ret = -EINVAL;
goto out_unlock; goto out_page;
} }
curr_mask = lbs_get_events_bitmap(priv); events = kzalloc(sizeof(*events), GFP_KERNEL);
if (!events) {
ret = -ENOMEM;
goto out_page;
}
events->hdr.size = cpu_to_le16(sizeof(*events));
events->action = cpu_to_le16(CMD_ACT_GET);
ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
if (ret)
goto out_events;
curr_mask = le16_to_cpu(events->events);
if (new_mask) if (new_mask)
new_mask = curr_mask | event_mask; new_mask = curr_mask | event_mask;
@ -474,147 +467,128 @@ static ssize_t lbs_threshold_write(
new_mask = curr_mask & ~event_mask; new_mask = curr_mask & ~event_mask;
/* Now everything is set and we can send stuff down to the firmware */ /* Now everything is set and we can send stuff down to the firmware */
events = kzalloc(
sizeof(struct cmd_ds_802_11_subscribe_event),
GFP_KERNEL);
if (events) {
struct mrvlietypes_thresholds *tlv =
(struct mrvlietypes_thresholds *) events->tlv;
events->action = cpu_to_le16(CMD_ACT_SET);
events->events = cpu_to_le16(new_mask);
tlv->header.type = cpu_to_le16(tlv_type);
tlv->header.len = cpu_to_le16(
sizeof(struct mrvlietypes_thresholds) -
sizeof(struct mrvlietypesheader));
tlv->value = value;
if (tlv_type != TLV_TYPE_BCNMISS)
tlv->freq = freq;
lbs_prepare_and_send_command(priv,
CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_SET,
CMD_OPTION_WAITFORRSP, 0, events);
kfree(events);
}
res = count; tlv = (void *)events->tlv;
out_unlock:
free_page(addr); events->action = cpu_to_le16(CMD_ACT_SET);
return res; events->events = cpu_to_le16(new_mask);
tlv->header.type = cpu_to_le16(tlv_type);
tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header));
tlv->value = value;
if (tlv_type != TLV_TYPE_BCNMISS)
tlv->freq = freq;
/* The command header, the event mask, and the one TLV */
events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 2 + sizeof(*tlv));
ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
if (!ret)
ret = count;
out_events:
kfree(events);
out_page:
free_page((unsigned long)buf);
return ret;
} }
static ssize_t lbs_lowrssi_read( static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
struct file *file, char __user *userbuf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW, return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
file, userbuf, count, ppos); file, userbuf, count, ppos);
} }
static ssize_t lbs_lowrssi_write( static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf,
struct file *file, const char __user *userbuf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW, return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
file, userbuf, count, ppos); file, userbuf, count, ppos);
} }
static ssize_t lbs_lowsnr_read( static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
struct file *file, char __user *userbuf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW, return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
file, userbuf, count, ppos); file, userbuf, count, ppos);
} }
static ssize_t lbs_lowsnr_write( static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf,
struct file *file, const char __user *userbuf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW, return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
file, userbuf, count, ppos); file, userbuf, count, ppos);
} }
static ssize_t lbs_failcount_read( static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
struct file *file, char __user *userbuf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT, return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
file, userbuf, count, ppos); file, userbuf, count, ppos);
} }
static ssize_t lbs_failcount_write( static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf,
struct file *file, const char __user *userbuf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT, return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
file, userbuf, count, ppos); file, userbuf, count, ppos);
} }
static ssize_t lbs_highrssi_read( static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
struct file *file, char __user *userbuf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH, return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
file, userbuf, count, ppos); file, userbuf, count, ppos);
} }
static ssize_t lbs_highrssi_write( static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf,
struct file *file, const char __user *userbuf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH, return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
file, userbuf, count, ppos); file, userbuf, count, ppos);
} }
static ssize_t lbs_highsnr_read( static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
struct file *file, char __user *userbuf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH, return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
file, userbuf, count, ppos); file, userbuf, count, ppos);
} }
static ssize_t lbs_highsnr_write( static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf,
struct file *file, const char __user *userbuf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH, return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
file, userbuf, count, ppos); file, userbuf, count, ppos);
} }
static ssize_t lbs_bcnmiss_read( static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
struct file *file, char __user *userbuf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS, return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
file, userbuf, count, ppos); file, userbuf, count, ppos);
} }
static ssize_t lbs_bcnmiss_write( static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
struct file *file, const char __user *userbuf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS, return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
file, userbuf, count, ppos); file, userbuf, count, ppos);
} }
static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {

View File

@ -28,10 +28,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
u16 cmd_action, u16 cmd_action,
u16 wait_option, u32 cmd_oid, void *pdata_buf); u16 wait_option, u32 cmd_oid, void *pdata_buf);
void lbs_queue_cmd(struct lbs_private *priv,
struct cmd_ctrl_node *cmdnode,
u8 addtail);
int lbs_allocate_cmd_buffer(struct lbs_private *priv); int lbs_allocate_cmd_buffer(struct lbs_private *priv);
int lbs_execute_next_command(struct lbs_private *priv); int lbs_execute_next_command(struct lbs_private *priv);
int lbs_process_event(struct lbs_private *priv); int lbs_process_event(struct lbs_private *priv);
@ -45,9 +41,8 @@ void lbs_get_fwversion(struct lbs_private *priv,
/** The proc fs interface */ /** The proc fs interface */
int lbs_process_rx_command(struct lbs_private *priv); int lbs_process_rx_command(struct lbs_private *priv);
void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv, void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
struct cmd_ctrl_node *ptempcmd); int result);
int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band); int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
@ -77,4 +72,5 @@ int lbs_stop_card(struct lbs_private *priv);
int lbs_reset_device(struct lbs_private *priv); int lbs_reset_device(struct lbs_private *priv);
void lbs_host_to_card_done(struct lbs_private *priv); void lbs_host_to_card_done(struct lbs_private *priv);
int lbs_update_channel(struct lbs_private *priv);
#endif #endif

View File

@ -141,6 +141,13 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define LBS_UPLD_SIZE 2312 #define LBS_UPLD_SIZE 2312
#define DEV_NAME_LEN 32 #define DEV_NAME_LEN 32
/* Wake criteria for HOST_SLEEP_CFG command */
#define EHS_WAKE_ON_BROADCAST_DATA 0x0001
#define EHS_WAKE_ON_UNICAST_DATA 0x0002
#define EHS_WAKE_ON_MAC_EVENT 0x0004
#define EHS_WAKE_ON_MULTICAST_DATA 0x0008
#define EHS_REMOVE_WAKEUP 0xFFFFFFFF
/** Misc constants */ /** Misc constants */
/* This section defines 802.11 specific contants */ /* This section defines 802.11 specific contants */

View File

@ -77,12 +77,12 @@ struct current_bss_params {
/** sleep_params */ /** sleep_params */
struct sleep_params { struct sleep_params {
u16 sp_error; uint16_t sp_error;
u16 sp_offset; uint16_t sp_offset;
u16 sp_stabletime; uint16_t sp_stabletime;
u8 sp_calcontrol; uint8_t sp_calcontrol;
u8 sp_extsleepclk; uint8_t sp_extsleepclk;
u16 sp_reserved; uint16_t sp_reserved;
}; };
/* Mesh statistics */ /* Mesh statistics */
@ -153,6 +153,11 @@ struct lbs_private {
int (*hw_get_int_status) (struct lbs_private *priv, u8 *); int (*hw_get_int_status) (struct lbs_private *priv, u8 *);
int (*hw_read_event_cause) (struct lbs_private *); int (*hw_read_event_cause) (struct lbs_private *);
/* Wake On LAN */
uint32_t wol_criteria;
uint8_t wol_gpio;
uint8_t wol_gap;
/* was struct lbs_adapter from here... */ /* was struct lbs_adapter from here... */
/** Wlan adapter data structure*/ /** Wlan adapter data structure*/
@ -196,11 +201,15 @@ struct lbs_private {
/** Timers */ /** Timers */
struct timer_list command_timer; struct timer_list command_timer;
int nr_retries;
int cmd_timed_out;
u8 hisregcpy; u8 hisregcpy;
/** current ssid/bssid related parameters*/ /** current ssid/bssid related parameters*/
struct current_bss_params curbssparams; struct current_bss_params curbssparams;
uint16_t mesh_tlv;
u8 mesh_ssid[IW_ESSID_MAX_SIZE + 1]; u8 mesh_ssid[IW_ESSID_MAX_SIZE + 1];
u8 mesh_ssid_len; u8 mesh_ssid_len;
@ -251,9 +260,11 @@ struct lbs_private {
u16 psmode; /* Wlan802_11PowermodeCAM=disable u16 psmode; /* Wlan802_11PowermodeCAM=disable
Wlan802_11PowermodeMAX_PSP=enable */ Wlan802_11PowermodeMAX_PSP=enable */
u32 psstate; u32 psstate;
char ps_supported;
u8 needtowakeup; u8 needtowakeup;
struct PS_CMD_ConfirmSleep lbs_ps_confirm_sleep; struct PS_CMD_ConfirmSleep lbs_ps_confirm_sleep;
struct cmd_header lbs_ps_confirm_wake;
struct assoc_request * pending_assoc_req; struct assoc_request * pending_assoc_req;
struct assoc_request * in_progress_assoc_req; struct assoc_request * in_progress_assoc_req;
@ -289,9 +300,6 @@ struct lbs_private {
u8 cur_rate; u8 cur_rate;
u8 auto_rate; u8 auto_rate;
/** sleep_params */
struct sleep_params sp;
/** RF calibration data */ /** RF calibration data */
#define MAX_REGION_CHANNEL_NUM 2 #define MAX_REGION_CHANNEL_NUM 2

View File

@ -8,6 +8,8 @@
#include "dev.h" #include "dev.h"
#include "join.h" #include "join.h"
#include "wext.h" #include "wext.h"
#include "cmd.h"
static const char * mesh_stat_strings[]= { static const char * mesh_stat_strings[]= {
"drop_duplicate_bcast", "drop_duplicate_bcast",
"drop_ttl_zero", "drop_ttl_zero",
@ -142,6 +144,16 @@ static void lbs_ethtool_get_stats(struct net_device * dev,
lbs_deb_enter(LBS_DEB_ETHTOOL); lbs_deb_enter(LBS_DEB_ETHTOOL);
} }
static int lbs_ethtool_get_sset_count(struct net_device * dev, int sset)
{
switch (sset) {
case ETH_SS_STATS:
return MESH_STATS_NUM;
default:
return -EOPNOTSUPP;
}
}
static void lbs_ethtool_get_strings(struct net_device *dev, static void lbs_ethtool_get_strings(struct net_device *dev,
u32 stringset, u32 stringset,
u8 * s) u8 * s)
@ -162,11 +174,57 @@ static void lbs_ethtool_get_strings(struct net_device *dev,
lbs_deb_enter(LBS_DEB_ETHTOOL); lbs_deb_enter(LBS_DEB_ETHTOOL);
} }
static void lbs_ethtool_get_wol(struct net_device *dev,
struct ethtool_wolinfo *wol)
{
struct lbs_private *priv = dev->priv;
if (priv->wol_criteria == 0xffffffff) {
/* Interface driver didn't configure wake */
wol->supported = wol->wolopts = 0;
return;
}
wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY;
if (priv->wol_criteria & EHS_WAKE_ON_UNICAST_DATA)
wol->wolopts |= WAKE_UCAST;
if (priv->wol_criteria & EHS_WAKE_ON_MULTICAST_DATA)
wol->wolopts |= WAKE_MCAST;
if (priv->wol_criteria & EHS_WAKE_ON_BROADCAST_DATA)
wol->wolopts |= WAKE_BCAST;
if (priv->wol_criteria & EHS_WAKE_ON_MAC_EVENT)
wol->wolopts |= WAKE_PHY;
}
static int lbs_ethtool_set_wol(struct net_device *dev,
struct ethtool_wolinfo *wol)
{
struct lbs_private *priv = dev->priv;
uint32_t criteria = 0;
if (priv->wol_criteria == 0xffffffff && wol->wolopts)
return -EOPNOTSUPP;
if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY))
return -EOPNOTSUPP;
if (wol->wolopts & WAKE_UCAST) criteria |= EHS_WAKE_ON_UNICAST_DATA;
if (wol->wolopts & WAKE_MCAST) criteria |= EHS_WAKE_ON_MULTICAST_DATA;
if (wol->wolopts & WAKE_BCAST) criteria |= EHS_WAKE_ON_BROADCAST_DATA;
if (wol->wolopts & WAKE_PHY) criteria |= EHS_WAKE_ON_MAC_EVENT;
return lbs_host_sleep_cfg(priv, criteria);
}
struct ethtool_ops lbs_ethtool_ops = { struct ethtool_ops lbs_ethtool_ops = {
.get_drvinfo = lbs_ethtool_get_drvinfo, .get_drvinfo = lbs_ethtool_get_drvinfo,
.get_eeprom = lbs_ethtool_get_eeprom, .get_eeprom = lbs_ethtool_get_eeprom,
.get_eeprom_len = lbs_ethtool_get_eeprom_len, .get_eeprom_len = lbs_ethtool_get_eeprom_len,
.get_sset_count = lbs_ethtool_get_sset_count,
.get_ethtool_stats = lbs_ethtool_get_stats, .get_ethtool_stats = lbs_ethtool_get_stats,
.get_strings = lbs_ethtool_get_strings, .get_strings = lbs_ethtool_get_strings,
.get_wol = lbs_ethtool_get_wol,
.set_wol = lbs_ethtool_set_wol,
}; };

View File

@ -73,6 +73,9 @@
#define CMD_802_11_SET_AFC 0x003c #define CMD_802_11_SET_AFC 0x003c
#define CMD_802_11_GET_AFC 0x003d #define CMD_802_11_GET_AFC 0x003d
#define CMD_802_11_AD_HOC_STOP 0x0040 #define CMD_802_11_AD_HOC_STOP 0x0040
#define CMD_802_11_HOST_SLEEP_CFG 0x0043
#define CMD_802_11_WAKEUP_CONFIRM 0x0044
#define CMD_802_11_HOST_SLEEP_ACTIVATE 0x0045
#define CMD_802_11_BEACON_STOP 0x0049 #define CMD_802_11_BEACON_STOP 0x0049
#define CMD_802_11_MAC_ADDRESS 0x004d #define CMD_802_11_MAC_ADDRESS 0x004d
#define CMD_802_11_LED_GPIO_CTRL 0x004e #define CMD_802_11_LED_GPIO_CTRL 0x004e
@ -82,8 +85,10 @@
#define CMD_802_11_KEY_MATERIAL 0x005e #define CMD_802_11_KEY_MATERIAL 0x005e
#define CMD_802_11_SLEEP_PARAMS 0x0066 #define CMD_802_11_SLEEP_PARAMS 0x0066
#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 #define CMD_802_11_INACTIVITY_TIMEOUT 0x0067
#define CMD_802_11_SLEEP_PERIOD 0x0068
#define CMD_802_11_TPC_CFG 0x0072 #define CMD_802_11_TPC_CFG 0x0072
#define CMD_802_11_PWR_CFG 0x0073 #define CMD_802_11_PWR_CFG 0x0073
#define CMD_802_11_FW_WAKE_METHOD 0x0074
#define CMD_802_11_SUBSCRIBE_EVENT 0x0075 #define CMD_802_11_SUBSCRIBE_EVENT 0x0075
#define CMD_802_11_RATE_ADAPT_RATESET 0x0076 #define CMD_802_11_RATE_ADAPT_RATESET 0x0076
#define CMD_802_11_TX_RATE_QUERY 0x007f #define CMD_802_11_TX_RATE_QUERY 0x007f
@ -204,6 +209,11 @@
#define CMD_TYPE_MAX_PSP 0x0001 #define CMD_TYPE_MAX_PSP 0x0001
#define CMD_TYPE_FAST_PSP 0x0002 #define CMD_TYPE_FAST_PSP 0x0002
/* Options for CMD_802_11_FW_WAKE_METHOD */
#define CMD_WAKE_METHOD_UNCHANGED 0x0000
#define CMD_WAKE_METHOD_COMMAND_INT 0x0001
#define CMD_WAKE_METHOD_GPIO 0x0002
/* Define action or option for CMD_BT_ACCESS */ /* Define action or option for CMD_BT_ACCESS */
enum cmd_bt_access_opts { enum cmd_bt_access_opts {
/* The bt commands start at 5 instead of 1 because the old dft commands /* The bt commands start at 5 instead of 1 because the old dft commands

View File

@ -74,10 +74,8 @@ struct cmd_header {
struct cmd_ctrl_node { struct cmd_ctrl_node {
struct list_head list; struct list_head list;
/* wait for finish or not */ int result;
u16 wait_option;
/* command response */ /* command response */
void *pdata_buf;
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *); int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *);
unsigned long callback_arg; unsigned long callback_arg;
/* command data */ /* command data */
@ -158,6 +156,8 @@ struct cmd_ds_802_11_reset {
}; };
struct cmd_ds_802_11_subscribe_event { struct cmd_ds_802_11_subscribe_event {
struct cmd_header hdr;
__le16 action; __le16 action;
__le16 events; __le16 events;
@ -166,7 +166,7 @@ struct cmd_ds_802_11_subscribe_event {
* 40 bytes. However, future firmware might add additional TLVs, so I * 40 bytes. However, future firmware might add additional TLVs, so I
* bump this up a bit. * bump this up a bit.
*/ */
u8 tlv[128]; uint8_t tlv[128];
}; };
/* /*
@ -258,6 +258,8 @@ struct cmd_ds_802_11_ad_hoc_result {
}; };
struct cmd_ds_802_11_set_wep { struct cmd_ds_802_11_set_wep {
struct cmd_header hdr;
/* ACT_ADD, ACT_REMOVE or ACT_ENABLE */ /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
__le16 action; __le16 action;
@ -265,8 +267,8 @@ struct cmd_ds_802_11_set_wep {
__le16 keyindex; __le16 keyindex;
/* 40, 128bit or TXWEP */ /* 40, 128bit or TXWEP */
u8 keytype[4]; uint8_t keytype[4];
u8 keymaterial[4][16]; uint8_t keymaterial[4][16];
}; };
struct cmd_ds_802_3_get_stat { struct cmd_ds_802_3_get_stat {
@ -344,6 +346,8 @@ struct cmd_ds_rf_reg_access {
}; };
struct cmd_ds_802_11_radio_control { struct cmd_ds_802_11_radio_control {
struct cmd_header hdr;
__le16 action; __le16 action;
__le16 control; __le16 control;
}; };
@ -355,6 +359,8 @@ struct cmd_ds_802_11_beacon_control {
}; };
struct cmd_ds_802_11_sleep_params { struct cmd_ds_802_11_sleep_params {
struct cmd_header hdr;
/* ACT_GET/ACT_SET */ /* ACT_GET/ACT_SET */
__le16 action; __le16 action;
@ -368,16 +374,18 @@ struct cmd_ds_802_11_sleep_params {
__le16 stabletime; __le16 stabletime;
/* control periodic calibration */ /* control periodic calibration */
u8 calcontrol; uint8_t calcontrol;
/* control the use of external sleep clock */ /* control the use of external sleep clock */
u8 externalsleepclk; uint8_t externalsleepclk;
/* reserved field, should be set to zero */ /* reserved field, should be set to zero */
__le16 reserved; __le16 reserved;
}; };
struct cmd_ds_802_11_inactivity_timeout { struct cmd_ds_802_11_inactivity_timeout {
struct cmd_header hdr;
/* ACT_GET/ACT_SET */ /* ACT_GET/ACT_SET */
__le16 action; __le16 action;
@ -441,6 +449,20 @@ struct cmd_ds_set_boot2_ver {
__le16 version; __le16 version;
}; };
struct cmd_ds_802_11_fw_wake_method {
struct cmd_header hdr;
__le16 action;
__le16 method;
};
struct cmd_ds_802_11_sleep_period {
struct cmd_header hdr;
__le16 action;
__le16 period;
};
struct cmd_ds_802_11_ps_mode { struct cmd_ds_802_11_ps_mode {
__le16 action; __le16 action;
__le16 nullpktinterval; __le16 nullpktinterval;
@ -516,6 +538,8 @@ struct cmd_ds_802_11_ad_hoc_join {
} __attribute__ ((packed)); } __attribute__ ((packed));
struct cmd_ds_802_11_enable_rsn { struct cmd_ds_802_11_enable_rsn {
struct cmd_header hdr;
__le16 action; __le16 action;
__le16 enable; __le16 enable;
} __attribute__ ((packed)); } __attribute__ ((packed));
@ -540,6 +564,13 @@ struct MrvlIEtype_keyParamSet {
u8 key[32]; u8 key[32];
}; };
struct cmd_ds_host_sleep {
struct cmd_header hdr;
__le32 criteria;
uint8_t gpio;
uint8_t gap;
} __attribute__ ((packed));
struct cmd_ds_802_11_key_material { struct cmd_ds_802_11_key_material {
__le16 action; __le16 action;
struct MrvlIEtype_keyParamSet keyParamSet[2]; struct MrvlIEtype_keyParamSet keyParamSet[2];
@ -663,7 +694,6 @@ struct cmd_ds_command {
struct cmd_ds_mac_control macctrl; struct cmd_ds_mac_control macctrl;
struct cmd_ds_802_11_associate associate; struct cmd_ds_802_11_associate associate;
struct cmd_ds_802_11_deauthenticate deauth; struct cmd_ds_802_11_deauthenticate deauth;
struct cmd_ds_802_11_set_wep wep;
struct cmd_ds_802_11_ad_hoc_start ads; struct cmd_ds_802_11_ad_hoc_start ads;
struct cmd_ds_802_11_reset reset; struct cmd_ds_802_11_reset reset;
struct cmd_ds_802_11_ad_hoc_result result; struct cmd_ds_802_11_ad_hoc_result result;
@ -678,13 +708,10 @@ struct cmd_ds_command {
struct cmd_ds_802_11_rate_adapt_rateset rateset; struct cmd_ds_802_11_rate_adapt_rateset rateset;
struct cmd_ds_mac_multicast_adr madr; struct cmd_ds_mac_multicast_adr madr;
struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_ad_hoc_join adj;
struct cmd_ds_802_11_radio_control radio;
struct cmd_ds_802_11_rf_channel rfchannel;
struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi rssi;
struct cmd_ds_802_11_rssi_rsp rssirsp; struct cmd_ds_802_11_rssi_rsp rssirsp;
struct cmd_ds_802_11_disassociate dassociate; struct cmd_ds_802_11_disassociate dassociate;
struct cmd_ds_802_11_mac_address macadd; struct cmd_ds_802_11_mac_address macadd;
struct cmd_ds_802_11_enable_rsn enbrsn;
struct cmd_ds_802_11_key_material keymaterial; struct cmd_ds_802_11_key_material keymaterial;
struct cmd_ds_mac_reg_access macreg; struct cmd_ds_mac_reg_access macreg;
struct cmd_ds_bbp_reg_access bbpreg; struct cmd_ds_bbp_reg_access bbpreg;
@ -694,8 +721,6 @@ struct cmd_ds_command {
struct cmd_ds_802_11d_domain_info domaininfo; struct cmd_ds_802_11d_domain_info domaininfo;
struct cmd_ds_802_11d_domain_info domaininforesp; struct cmd_ds_802_11d_domain_info domaininforesp;
struct cmd_ds_802_11_sleep_params sleep_params;
struct cmd_ds_802_11_inactivity_timeout inactivity_timeout;
struct cmd_ds_802_11_tpc_cfg tpccfg; struct cmd_ds_802_11_tpc_cfg tpccfg;
struct cmd_ds_802_11_pwr_cfg pwrcfg; struct cmd_ds_802_11_pwr_cfg pwrcfg;
struct cmd_ds_802_11_afc afc; struct cmd_ds_802_11_afc afc;
@ -705,7 +730,6 @@ struct cmd_ds_command {
struct cmd_ds_bt_access bt; struct cmd_ds_bt_access bt;
struct cmd_ds_fwt_access fwt; struct cmd_ds_fwt_access fwt;
struct cmd_ds_get_tsf gettsf; struct cmd_ds_get_tsf gettsf;
struct cmd_ds_802_11_subscribe_event subscribe_event;
struct cmd_ds_802_11_beacon_control bcn_ctrl; struct cmd_ds_802_11_beacon_control bcn_ctrl;
} params; } params;
} __attribute__ ((packed)); } __attribute__ ((packed));

View File

@ -243,7 +243,7 @@ static inline void if_cs_disable_ints(struct if_cs_card *card)
static irqreturn_t if_cs_interrupt(int irq, void *data) static irqreturn_t if_cs_interrupt(int irq, void *data)
{ {
struct if_cs_card *card = data; struct if_cs_card *card = (struct if_cs_card *)data;
u16 int_cause; u16 int_cause;
lbs_deb_enter(LBS_DEB_CS); lbs_deb_enter(LBS_DEB_CS);
@ -647,7 +647,6 @@ static int if_cs_get_int_status(struct lbs_private *priv, u8 *ireg)
struct if_cs_card *card = (struct if_cs_card *)priv->card; struct if_cs_card *card = (struct if_cs_card *)priv->card;
int ret = 0; int ret = 0;
u16 int_cause; u16 int_cause;
u8 *cmdbuf;
*ireg = 0; *ireg = 0;
lbs_deb_enter(LBS_DEB_CS); lbs_deb_enter(LBS_DEB_CS);
@ -679,14 +678,7 @@ sbi_get_int_status_exit:
/* Card has a command result for us */ /* Card has a command result for us */
if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) { if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {
spin_lock(&priv->driver_lock); spin_lock(&priv->driver_lock);
if (!priv->cur_cmd) { ret = if_cs_receive_cmdres(priv, priv->upld_buf, &priv->upld_len);
cmdbuf = priv->upld_buf;
priv->hisregcpy &= ~IF_CS_C_S_RX_UPLD_RDY;
} else {
cmdbuf = (u8 *) priv->cur_cmd->cmdbuf;
}
ret = if_cs_receive_cmdres(priv, cmdbuf, &priv->upld_len);
spin_unlock(&priv->driver_lock); spin_unlock(&priv->driver_lock);
if (ret < 0) if (ret < 0)
lbs_pr_err("could not receive cmd from card\n"); lbs_pr_err("could not receive cmd from card\n");

View File

@ -136,12 +136,6 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
spin_lock_irqsave(&card->priv->driver_lock, flags); spin_lock_irqsave(&card->priv->driver_lock, flags);
if (!card->priv->cur_cmd) {
lbs_deb_sdio("discarding spurious response\n");
ret = 0;
goto out;
}
if (size > LBS_CMD_BUFFER_SIZE) { if (size > LBS_CMD_BUFFER_SIZE) {
lbs_deb_sdio("response packet too large (%d bytes)\n", lbs_deb_sdio("response packet too large (%d bytes)\n",
(int)size); (int)size);
@ -149,7 +143,7 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
goto out; goto out;
} }
memcpy(card->priv->cur_cmd->cmdbuf, buffer, size); memcpy(card->priv->upld_buf, buffer, size);
card->priv->upld_len = size; card->priv->upld_len = size;
card->int_cause |= MRVDRV_CMD_UPLD_RDY; card->int_cause |= MRVDRV_CMD_UPLD_RDY;

View File

@ -16,6 +16,9 @@
#include "cmd.h" #include "cmd.h"
#include "if_usb.h" #include "if_usb.h"
#define INSANEDEBUG 0
#define lbs_deb_usb2(...) do { if (INSANEDEBUG) lbs_deb_usbd(__VA_ARGS__); } while (0)
#define MESSAGE_HEADER_LEN 4 #define MESSAGE_HEADER_LEN 4
static char *lbs_fw_name = "usb8388.bin"; static char *lbs_fw_name = "usb8388.bin";
@ -32,17 +35,16 @@ MODULE_DEVICE_TABLE(usb, if_usb_table);
static void if_usb_receive(struct urb *urb); static void if_usb_receive(struct urb *urb);
static void if_usb_receive_fwload(struct urb *urb); static void if_usb_receive_fwload(struct urb *urb);
static int if_usb_prog_firmware(struct usb_card_rec *cardp); static int if_usb_prog_firmware(struct if_usb_card *cardp);
static int if_usb_host_to_card(struct lbs_private *priv, static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
u8 type, uint8_t *payload, uint16_t nb);
u8 *payload, static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *);
u16 nb);
static int if_usb_get_int_status(struct lbs_private *priv, u8 *);
static int if_usb_read_event_cause(struct lbs_private *); static int if_usb_read_event_cause(struct lbs_private *);
static int usb_tx_block(struct usb_card_rec *cardp, u8 *payload, u16 nb); static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
static void if_usb_free(struct usb_card_rec *cardp); uint16_t nb);
static int if_usb_submit_rx_urb(struct usb_card_rec *cardp); static void if_usb_free(struct if_usb_card *cardp);
static int if_usb_reset_device(struct usb_card_rec *cardp); static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
static int if_usb_reset_device(struct if_usb_card *cardp);
/** /**
* @brief call back function to handle the status of the URB * @brief call back function to handle the status of the URB
@ -51,18 +53,16 @@ static int if_usb_reset_device(struct usb_card_rec *cardp);
*/ */
static void if_usb_write_bulk_callback(struct urb *urb) static void if_usb_write_bulk_callback(struct urb *urb)
{ {
struct usb_card_rec *cardp = (struct usb_card_rec *) urb->context; struct if_usb_card *cardp = (struct if_usb_card *) urb->context;
/* handle the transmission complete validations */ /* handle the transmission complete validations */
if (urb->status == 0) { if (urb->status == 0) {
struct lbs_private *priv = cardp->priv; struct lbs_private *priv = cardp->priv;
/* lbs_deb_usb2(&urb->dev->dev, "URB status is successful\n");
lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n"); lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n",
lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n", urb->actual_length);
urb->actual_length);
*/
/* Used for both firmware TX and regular TX. priv isn't /* Used for both firmware TX and regular TX. priv isn't
* valid at firmware load time. * valid at firmware load time.
@ -79,10 +79,10 @@ static void if_usb_write_bulk_callback(struct urb *urb)
/** /**
* @brief free tx/rx urb, skb and rx buffer * @brief free tx/rx urb, skb and rx buffer
* @param cardp pointer usb_card_rec * @param cardp pointer if_usb_card
* @return N/A * @return N/A
*/ */
static void if_usb_free(struct usb_card_rec *cardp) static void if_usb_free(struct if_usb_card *cardp)
{ {
lbs_deb_enter(LBS_DEB_USB); lbs_deb_enter(LBS_DEB_USB);
@ -96,26 +96,47 @@ static void if_usb_free(struct usb_card_rec *cardp)
usb_free_urb(cardp->rx_urb); usb_free_urb(cardp->rx_urb);
cardp->rx_urb = NULL; cardp->rx_urb = NULL;
kfree(cardp->bulk_out_buffer); kfree(cardp->ep_out_buf);
cardp->bulk_out_buffer = NULL; cardp->ep_out_buf = NULL;
lbs_deb_leave(LBS_DEB_USB); lbs_deb_leave(LBS_DEB_USB);
} }
static void if_usb_set_boot2_ver(struct lbs_private *priv) static void if_usb_setup_firmware(struct lbs_private *priv)
{ {
struct cmd_ds_set_boot2_ver b2_cmd; struct cmd_ds_set_boot2_ver b2_cmd;
struct cmd_ds_802_11_fw_wake_method wake_method;
b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
b2_cmd.action = 0; b2_cmd.action = 0;
b2_cmd.version = priv->boot2_version; b2_cmd.version = priv->boot2_version;
if (lbs_cmd(priv, CMD_SET_BOOT2_VER, b2_cmd, NULL, 0)) if (lbs_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd))
lbs_deb_usb("Setting boot2 version failed\n"); lbs_deb_usb("Setting boot2 version failed\n");
priv->wol_gpio = 2; /* Wake via GPIO2... */
priv->wol_gap = 20; /* ... after 20ms */
lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA);
wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
wake_method.action = cpu_to_le16(CMD_ACT_GET);
if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
lbs_pr_info("Firmware does not seem to support PS mode\n");
} else {
if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
lbs_deb_usb("Firmware seems to support PS with wake-via-command\n");
priv->ps_supported = 1;
} else {
/* The versions which boot up this way don't seem to
work even if we set it to the command interrupt */
lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
}
}
} }
static void if_usb_fw_timeo(unsigned long priv) static void if_usb_fw_timeo(unsigned long priv)
{ {
struct usb_card_rec *cardp = (void *)priv; struct if_usb_card *cardp = (void *)priv;
if (cardp->fwdnldover) { if (cardp->fwdnldover) {
lbs_deb_usb("Download complete, no event. Assuming success\n"); lbs_deb_usb("Download complete, no event. Assuming success\n");
@ -125,6 +146,7 @@ static void if_usb_fw_timeo(unsigned long priv)
} }
wake_up(&cardp->fw_wq); wake_up(&cardp->fw_wq);
} }
/** /**
* @brief sets the configuration values * @brief sets the configuration values
* @param ifnum interface number * @param ifnum interface number
@ -138,12 +160,12 @@ static int if_usb_probe(struct usb_interface *intf,
struct usb_host_interface *iface_desc; struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *endpoint;
struct lbs_private *priv; struct lbs_private *priv;
struct usb_card_rec *cardp; struct if_usb_card *cardp;
int i; int i;
udev = interface_to_usbdev(intf); udev = interface_to_usbdev(intf);
cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL); cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
if (!cardp) { if (!cardp) {
lbs_pr_err("Out of memory allocating private data.\n"); lbs_pr_err("Out of memory allocating private data.\n");
goto error; goto error;
@ -156,7 +178,7 @@ static int if_usb_probe(struct usb_interface *intf,
iface_desc = intf->cur_altsetting; iface_desc = intf->cur_altsetting;
lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X" lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
" bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n", " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
le16_to_cpu(udev->descriptor.bcdUSB), le16_to_cpu(udev->descriptor.bcdUSB),
udev->descriptor.bDeviceClass, udev->descriptor.bDeviceClass,
udev->descriptor.bDeviceSubClass, udev->descriptor.bDeviceSubClass,
@ -164,63 +186,42 @@ static int if_usb_probe(struct usb_interface *intf,
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc; endpoint = &iface_desc->endpoint[i].desc;
if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) if (usb_endpoint_is_bulk_in(endpoint)) {
&& ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
USB_ENDPOINT_XFER_BULK)) { cardp->ep_in = usb_endpoint_num(endpoint);
/* we found a bulk in endpoint */
lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
le16_to_cpu(endpoint->wMaxPacketSize)); lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
lbs_deb_usbd(&udev->dev, } else if (usb_endpoint_is_bulk_out(endpoint)) {
"Rx URB allocation failed\n"); cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
goto dealloc; cardp->ep_out = usb_endpoint_num(endpoint);
}
cardp->bulk_in_size = lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
le16_to_cpu(endpoint->wMaxPacketSize); lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
cardp->bulk_in_endpointAddr =
(endpoint->
bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n",
endpoint->bEndpointAddress);
}
if (((endpoint->
bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
USB_DIR_OUT)
&& ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_BULK)) {
/* We found bulk out endpoint */
if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
lbs_deb_usbd(&udev->dev,
"Tx URB allocation failed\n");
goto dealloc;
}
cardp->bulk_out_size =
le16_to_cpu(endpoint->wMaxPacketSize);
lbs_deb_usbd(&udev->dev,
"Bulk out size is %d\n",
le16_to_cpu(endpoint->wMaxPacketSize));
cardp->bulk_out_endpointAddr =
endpoint->bEndpointAddress;
lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n",
endpoint->bEndpointAddress);
cardp->bulk_out_buffer =
kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
GFP_KERNEL);
if (!cardp->bulk_out_buffer) {
lbs_deb_usbd(&udev->dev,
"Could not allocate buffer\n");
goto dealloc;
}
} }
} }
if (!cardp->ep_out_size || !cardp->ep_in_size) {
lbs_deb_usbd(&udev->dev, "Endpoints not found\n");
goto dealloc;
}
if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
lbs_deb_usbd(&udev->dev, "Rx URB allocation failed\n");
goto dealloc;
}
if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
lbs_deb_usbd(&udev->dev, "Tx URB allocation failed\n");
goto dealloc;
}
cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, GFP_KERNEL);
if (!cardp->ep_out_buf) {
lbs_deb_usbd(&udev->dev, "Could not allocate buffer\n");
goto dealloc;
}
/* Upload firmware */ /* Upload firmware */
cardp->rinfo.cardp = cardp;
if (if_usb_prog_firmware(cardp)) { if (if_usb_prog_firmware(cardp)) {
lbs_deb_usbd(&udev->dev, "FW upload failed"); lbs_deb_usbd(&udev->dev, "FW upload failed\n");
goto err_prog_firmware; goto err_prog_firmware;
} }
@ -240,7 +241,7 @@ static int if_usb_probe(struct usb_interface *intf,
if (lbs_start_card(priv)) if (lbs_start_card(priv))
goto err_start_card; goto err_start_card;
if_usb_set_boot2_ver(priv); if_usb_setup_firmware(priv);
usb_get_dev(udev); usb_get_dev(udev);
usb_set_intfdata(intf, cardp); usb_set_intfdata(intf, cardp);
@ -265,25 +266,19 @@ error:
*/ */
static void if_usb_disconnect(struct usb_interface *intf) static void if_usb_disconnect(struct usb_interface *intf)
{ {
struct usb_card_rec *cardp = usb_get_intfdata(intf); struct if_usb_card *cardp = usb_get_intfdata(intf);
struct lbs_private *priv = (struct lbs_private *) cardp->priv; struct lbs_private *priv = (struct lbs_private *) cardp->priv;
lbs_deb_enter(LBS_DEB_MAIN); lbs_deb_enter(LBS_DEB_MAIN);
/* Update Surprise removed to TRUE */
cardp->surprise_removed = 1; cardp->surprise_removed = 1;
if (priv) { if (priv) {
priv->surpriseremoved = 1; priv->surpriseremoved = 1;
lbs_stop_card(priv); lbs_stop_card(priv);
lbs_remove_card(priv); lbs_remove_card(priv);
} }
/* this is (apparently?) necessary for future usage of the device */
lbs_prepare_and_send_command(priv, CMD_802_11_RESET, CMD_ACT_HALT,
0, 0, NULL);
/* Unlink and free urb */ /* Unlink and free urb */
if_usb_free(cardp); if_usb_free(cardp);
@ -298,98 +293,75 @@ static void if_usb_disconnect(struct usb_interface *intf)
* @param priv pointer to struct lbs_private * @param priv pointer to struct lbs_private
* @return 0 * @return 0
*/ */
static int if_usb_send_fw_pkt(struct usb_card_rec *cardp) static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
{ {
struct FWData *fwdata; struct fwdata *fwdata = cardp->ep_out_buf;
struct fwheader *fwheader; uint8_t *firmware = cardp->fw->data;
u8 *firmware = cardp->fw->data;
fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
if (!fwdata)
return -1;
fwheader = &fwdata->fwheader;
/* If we got a CRC failure on the last block, back
up and retry it */
if (!cardp->CRC_OK) { if (!cardp->CRC_OK) {
cardp->totalbytes = cardp->fwlastblksent; cardp->totalbytes = cardp->fwlastblksent;
cardp->fwseqnum = cardp->lastseqnum - 1; cardp->fwseqnum--;
} }
/* lbs_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n",
lbs_deb_usbd(&cardp->udev->dev, "totalbytes = %d\n", cardp->totalbytes);
cardp->totalbytes);
*/
memcpy(fwheader, &firmware[cardp->totalbytes], /* struct fwdata (which we sent to the card) has an
extra __le32 field in between the header and the data,
which is not in the struct fwheader in the actual
firmware binary. Insert the seqnum in the middle... */
memcpy(&fwdata->hdr, &firmware[cardp->totalbytes],
sizeof(struct fwheader)); sizeof(struct fwheader));
cardp->fwlastblksent = cardp->totalbytes; cardp->fwlastblksent = cardp->totalbytes;
cardp->totalbytes += sizeof(struct fwheader); cardp->totalbytes += sizeof(struct fwheader);
/* lbs_deb_usbd(&cardp->udev->dev,"Copy Data\n"); */
memcpy(fwdata->data, &firmware[cardp->totalbytes], memcpy(fwdata->data, &firmware[cardp->totalbytes],
le32_to_cpu(fwdata->fwheader.datalength)); le32_to_cpu(fwdata->hdr.datalength));
/* lbs_deb_usb2(&cardp->udev->dev, "Data length = %d\n",
lbs_deb_usbd(&cardp->udev->dev, le32_to_cpu(fwdata->hdr.datalength));
"Data length = %d\n", le32_to_cpu(fwdata->fwheader.datalength));
*/
cardp->fwseqnum = cardp->fwseqnum + 1; fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
fwdata->seqnum = cpu_to_le32(cardp->fwseqnum); usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
cardp->lastseqnum = cardp->fwseqnum; le32_to_cpu(fwdata->hdr.datalength));
cardp->totalbytes += le32_to_cpu(fwdata->fwheader.datalength);
if (fwheader->dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) { if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
/* lbs_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
lbs_deb_usbd(&cardp->udev->dev, "There are data to follow\n"); lbs_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
lbs_deb_usbd(&cardp->udev->dev, cardp->fwseqnum, cardp->totalbytes);
"seqnum = %d totalbytes = %d\n", cardp->fwseqnum, } else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
cardp->totalbytes); lbs_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
*/ lbs_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
} else if (fwdata->fwheader.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
/*
lbs_deb_usbd(&cardp->udev->dev,
"Host has finished FW downloading\n");
lbs_deb_usbd(&cardp->udev->dev,
"Donwloading FW JUMP BLOCK\n");
*/
memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
cardp->fwfinalblk = 1; cardp->fwfinalblk = 1;
} }
/* lbs_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n",
lbs_deb_usbd(&cardp->udev->dev, cardp->totalbytes);
"The firmware download is done size is %d\n",
cardp->totalbytes);
*/
kfree(fwdata);
return 0; return 0;
} }
static int if_usb_reset_device(struct usb_card_rec *cardp) static int if_usb_reset_device(struct if_usb_card *cardp)
{ {
struct cmd_ds_command *cmd = (void *)&cardp->bulk_out_buffer[4]; struct cmd_ds_command *cmd = cardp->ep_out_buf + 4;
int ret; int ret;
lbs_deb_enter(LBS_DEB_USB); lbs_deb_enter(LBS_DEB_USB);
*(__le32 *)cardp->bulk_out_buffer = cpu_to_le32(CMD_TYPE_REQUEST); *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
cmd->command = cpu_to_le16(CMD_802_11_RESET); cmd->command = cpu_to_le16(CMD_802_11_RESET);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
cmd->result = cpu_to_le16(0); cmd->result = cpu_to_le16(0);
cmd->seqnum = cpu_to_le16(0x5a5a); cmd->seqnum = cpu_to_le16(0x5a5a);
cmd->params.reset.action = cpu_to_le16(CMD_ACT_HALT); cmd->params.reset.action = cpu_to_le16(CMD_ACT_HALT);
usb_tx_block(cardp, cardp->bulk_out_buffer, 4 + S_DS_GEN + sizeof(struct cmd_ds_802_11_reset)); usb_tx_block(cardp, cardp->ep_out_buf, 4 + S_DS_GEN + sizeof(struct cmd_ds_802_11_reset));
msleep(100); msleep(100);
ret = usb_reset_device(cardp->udev); ret = usb_reset_device(cardp->udev);
@ -407,7 +379,7 @@ static int if_usb_reset_device(struct usb_card_rec *cardp)
* @param nb data length * @param nb data length
* @return 0 or -1 * @return 0 or -1
*/ */
static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb) static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb)
{ {
int ret = -1; int ret = -1;
@ -419,17 +391,16 @@ static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb)
usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
usb_sndbulkpipe(cardp->udev, usb_sndbulkpipe(cardp->udev,
cardp->bulk_out_endpointAddr), cardp->ep_out),
payload, nb, if_usb_write_bulk_callback, cardp); payload, nb, if_usb_write_bulk_callback, cardp);
cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) { if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
/* transfer failed */
lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret); lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
ret = -1; ret = -1;
} else { } else {
/* lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb success\n"); */ lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
ret = 0; ret = 0;
} }
@ -437,11 +408,10 @@ tx_ret:
return ret; return ret;
} }
static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp, static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
void (*callbackfn)(struct urb *urb)) void (*callbackfn)(struct urb *urb))
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct read_cb_info *rinfo = &cardp->rinfo;
int ret = -1; int ret = -1;
if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) { if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
@ -449,27 +419,25 @@ static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp,
goto rx_ret; goto rx_ret;
} }
rinfo->skb = skb; cardp->rx_skb = skb;
/* Fill the receive configuration URB and initialise the Rx call back */ /* Fill the receive configuration URB and initialise the Rx call back */
usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
usb_rcvbulkpipe(cardp->udev, usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
cardp->bulk_in_endpointAddr),
(void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET), (void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET),
MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
rinfo); cardp);
cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
/* lbs_deb_usbd(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); */ lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
/* handle failure conditions */
lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret); lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
kfree_skb(skb); kfree_skb(skb);
rinfo->skb = NULL; cardp->rx_skb = NULL;
ret = -1; ret = -1;
} else { } else {
/* lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB success\n"); */ lbs_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n");
ret = 0; ret = 0;
} }
@ -477,27 +445,26 @@ rx_ret:
return ret; return ret;
} }
static int if_usb_submit_rx_urb_fwload(struct usb_card_rec *cardp) static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp)
{ {
return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload); return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
} }
static int if_usb_submit_rx_urb(struct usb_card_rec *cardp) static int if_usb_submit_rx_urb(struct if_usb_card *cardp)
{ {
return __if_usb_submit_rx_urb(cardp, &if_usb_receive); return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
} }
static void if_usb_receive_fwload(struct urb *urb) static void if_usb_receive_fwload(struct urb *urb)
{ {
struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; struct if_usb_card *cardp = urb->context;
struct sk_buff *skb = rinfo->skb; struct sk_buff *skb = cardp->rx_skb;
struct usb_card_rec *cardp = (struct usb_card_rec *)rinfo->cardp;
struct fwsyncheader *syncfwheader; struct fwsyncheader *syncfwheader;
struct bootcmdrespStr bootcmdresp; struct bootcmdresp bootcmdresp;
if (urb->status) { if (urb->status) {
lbs_deb_usbd(&cardp->udev->dev, lbs_deb_usbd(&cardp->udev->dev,
"URB status is failed during fw load\n"); "URB status is failed during fw load\n");
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
@ -510,8 +477,8 @@ static void if_usb_receive_fwload(struct urb *urb)
lbs_pr_info("Firmware ready event received\n"); lbs_pr_info("Firmware ready event received\n");
wake_up(&cardp->fw_wq); wake_up(&cardp->fw_wq);
} else { } else {
lbs_deb_usb("Waiting for confirmation; got %x %x\n", le32_to_cpu(tmp[0]), lbs_deb_usb("Waiting for confirmation; got %x %x\n",
le32_to_cpu(tmp[1])); le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1]));
if_usb_submit_rx_urb_fwload(cardp); if_usb_submit_rx_urb_fwload(cardp);
} }
kfree_skb(skb); kfree_skb(skb);
@ -520,37 +487,36 @@ static void if_usb_receive_fwload(struct urb *urb)
if (cardp->bootcmdresp <= 0) { if (cardp->bootcmdresp <= 0) {
memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET, memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
sizeof(bootcmdresp)); sizeof(bootcmdresp));
if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
kfree_skb(skb); kfree_skb(skb);
if_usb_submit_rx_urb_fwload(cardp); if_usb_submit_rx_urb_fwload(cardp);
cardp->bootcmdresp = 1; cardp->bootcmdresp = 1;
lbs_deb_usbd(&cardp->udev->dev, lbs_deb_usbd(&cardp->udev->dev,
"Received valid boot command response\n"); "Received valid boot command response\n");
return; return;
} }
if (bootcmdresp.u32magicnumber != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) { if (bootcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
if (bootcmdresp.u32magicnumber == cpu_to_le32(CMD_TYPE_REQUEST) || if (bootcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) ||
bootcmdresp.u32magicnumber == cpu_to_le32(CMD_TYPE_DATA) || bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
bootcmdresp.u32magicnumber == cpu_to_le32(CMD_TYPE_INDICATION)) { bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
if (!cardp->bootcmdresp) if (!cardp->bootcmdresp)
lbs_pr_info("Firmware already seems alive; resetting\n"); lbs_pr_info("Firmware already seems alive; resetting\n");
cardp->bootcmdresp = -1; cardp->bootcmdresp = -1;
} else { } else {
lbs_pr_info("boot cmd response wrong magic number (0x%x)\n", lbs_pr_info("boot cmd response wrong magic number (0x%x)\n",
le32_to_cpu(bootcmdresp.u32magicnumber)); le32_to_cpu(bootcmdresp.magic));
} }
} else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) { } else if (bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) {
lbs_pr_info( lbs_pr_info("boot cmd response cmd_tag error (%d)\n",
"boot cmd response cmd_tag error (%d)\n", bootcmdresp.cmd);
bootcmdresp.u8cmd_tag); } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
} else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) { lbs_pr_info("boot cmd response result error (%d)\n",
lbs_pr_info( bootcmdresp.result);
"boot cmd response result error (%d)\n",
bootcmdresp.u8result);
} else { } else {
cardp->bootcmdresp = 1; cardp->bootcmdresp = 1;
lbs_deb_usbd(&cardp->udev->dev, lbs_deb_usbd(&cardp->udev->dev,
"Received valid boot command response\n"); "Received valid boot command response\n");
} }
kfree_skb(skb); kfree_skb(skb);
if_usb_submit_rx_urb_fwload(cardp); if_usb_submit_rx_urb_fwload(cardp);
@ -565,20 +531,15 @@ static void if_usb_receive_fwload(struct urb *urb)
} }
memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET, memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
sizeof(struct fwsyncheader)); sizeof(struct fwsyncheader));
if (!syncfwheader->cmd) { if (!syncfwheader->cmd) {
/* lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
lbs_deb_usbd(&cardp->udev->dev, lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
"FW received Blk with correct CRC\n"); le32_to_cpu(syncfwheader->seqnum));
lbs_deb_usbd(&cardp->udev->dev,
"FW received Blk seqnum = %d\n",
syncfwheader->seqnum);
*/
cardp->CRC_OK = 1; cardp->CRC_OK = 1;
} else { } else {
lbs_deb_usbd(&cardp->udev->dev, lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
"FW received Blk with CRC error\n");
cardp->CRC_OK = 0; cardp->CRC_OK = 0;
} }
@ -605,13 +566,12 @@ static void if_usb_receive_fwload(struct urb *urb)
#define MRVDRV_MIN_PKT_LEN 30 #define MRVDRV_MIN_PKT_LEN 30
static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
struct usb_card_rec *cardp, struct if_usb_card *cardp,
struct lbs_private *priv) struct lbs_private *priv)
{ {
if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) { || recvlength < MRVDRV_MIN_PKT_LEN) {
lbs_deb_usbd(&cardp->udev->dev, lbs_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n");
"Packet length is Invalid\n");
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
@ -619,19 +579,19 @@ static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
skb_reserve(skb, IPFIELD_ALIGN_OFFSET); skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
skb_put(skb, recvlength); skb_put(skb, recvlength);
skb_pull(skb, MESSAGE_HEADER_LEN); skb_pull(skb, MESSAGE_HEADER_LEN);
lbs_process_rxed_packet(priv, skb); lbs_process_rxed_packet(priv, skb);
priv->upld_len = (recvlength - MESSAGE_HEADER_LEN); priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
} }
static inline void process_cmdrequest(int recvlength, u8 *recvbuff, static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
struct sk_buff *skb, struct sk_buff *skb,
struct usb_card_rec *cardp, struct if_usb_card *cardp,
struct lbs_private *priv) struct lbs_private *priv)
{ {
u8 *cmdbuf;
if (recvlength > LBS_CMD_BUFFER_SIZE) { if (recvlength > LBS_CMD_BUFFER_SIZE) {
lbs_deb_usbd(&cardp->udev->dev, lbs_deb_usbd(&cardp->udev->dev,
"The receive buffer is too large\n"); "The receive buffer is too large\n");
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
@ -640,18 +600,9 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
BUG(); BUG();
spin_lock(&priv->driver_lock); spin_lock(&priv->driver_lock);
/* take care of cur_cmd = NULL case by reading the
* data to clear the interrupt */
if (!priv->cur_cmd) {
cmdbuf = priv->upld_buf;
priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
} else
cmdbuf = (u8 *) priv->cur_cmd->cmdbuf;
cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY; cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY;
priv->upld_len = (recvlength - MESSAGE_HEADER_LEN); priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN, memcpy(priv->upld_buf, recvbuff + MESSAGE_HEADER_LEN, priv->upld_len);
priv->upld_len);
kfree_skb(skb); kfree_skb(skb);
lbs_interrupt(priv); lbs_interrupt(priv);
@ -659,8 +610,6 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
lbs_deb_usbd(&cardp->udev->dev, lbs_deb_usbd(&cardp->udev->dev,
"Wake up main thread to handle cmd response\n"); "Wake up main thread to handle cmd response\n");
return;
} }
/** /**
@ -672,30 +621,26 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
*/ */
static void if_usb_receive(struct urb *urb) static void if_usb_receive(struct urb *urb)
{ {
struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; struct if_usb_card *cardp = urb->context;
struct sk_buff *skb = rinfo->skb; struct sk_buff *skb = cardp->rx_skb;
struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp;
struct lbs_private *priv = cardp->priv; struct lbs_private *priv = cardp->priv;
int recvlength = urb->actual_length; int recvlength = urb->actual_length;
u8 *recvbuff = NULL; uint8_t *recvbuff = NULL;
u32 recvtype = 0; uint32_t recvtype = 0;
__le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
lbs_deb_enter(LBS_DEB_USB); lbs_deb_enter(LBS_DEB_USB);
if (recvlength) { if (recvlength) {
__le32 tmp;
if (urb->status) { if (urb->status) {
lbs_deb_usbd(&cardp->udev->dev, lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n",
"URB status is failed\n"); urb->status);
kfree_skb(skb); kfree_skb(skb);
goto setup_for_next; goto setup_for_next;
} }
recvbuff = skb->data + IPFIELD_ALIGN_OFFSET; recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
memcpy(&tmp, recvbuff, sizeof(u32)); recvtype = le32_to_cpu(pkt[0]);
recvtype = le32_to_cpu(tmp);
lbs_deb_usbd(&cardp->udev->dev, lbs_deb_usbd(&cardp->udev->dev,
"Recv length = 0x%x, Recv type = 0x%X\n", "Recv length = 0x%x, Recv type = 0x%X\n",
recvlength, recvtype); recvlength, recvtype);
@ -716,9 +661,13 @@ static void if_usb_receive(struct urb *urb)
case CMD_TYPE_INDICATION: case CMD_TYPE_INDICATION:
/* Event cause handling */ /* Event cause handling */
spin_lock(&priv->driver_lock); spin_lock(&priv->driver_lock);
cardp->usb_event_cause = le32_to_cpu(*(__le32 *) (recvbuff + MESSAGE_HEADER_LEN));
cardp->usb_event_cause = le32_to_cpu(pkt[1]);
lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n", lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n",
cardp->usb_event_cause); cardp->usb_event_cause);
/* Icky undocumented magic special case */
if (cardp->usb_event_cause & 0xffff0000) { if (cardp->usb_event_cause & 0xffff0000) {
lbs_send_tx_feedback(priv); lbs_send_tx_feedback(priv);
spin_unlock(&priv->driver_lock); spin_unlock(&priv->driver_lock);
@ -732,7 +681,7 @@ static void if_usb_receive(struct urb *urb)
goto rx_exit; goto rx_exit;
default: default:
lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n", lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
recvtype); recvtype);
kfree_skb(skb); kfree_skb(skb);
break; break;
} }
@ -751,55 +700,48 @@ rx_exit:
* @param len number of bytes * @param len number of bytes
* @return 0 or -1 * @return 0 or -1
*/ */
static int if_usb_host_to_card(struct lbs_private *priv, static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
u8 type, uint8_t *payload, uint16_t nb)
u8 *payload,
u16 nb)
{ {
struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; struct if_usb_card *cardp = priv->card;
lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type); lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type);
lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb); lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb);
if (type == MVMS_CMD) { if (type == MVMS_CMD) {
__le32 tmp = cpu_to_le32(CMD_TYPE_REQUEST); *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
priv->dnld_sent = DNLD_CMD_SENT; priv->dnld_sent = DNLD_CMD_SENT;
memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
MESSAGE_HEADER_LEN);
} else { } else {
__le32 tmp = cpu_to_le32(CMD_TYPE_DATA); *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA);
priv->dnld_sent = DNLD_DATA_SENT; priv->dnld_sent = DNLD_DATA_SENT;
memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
MESSAGE_HEADER_LEN);
} }
memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb);
return usb_tx_block(cardp, cardp->bulk_out_buffer, return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN);
nb + MESSAGE_HEADER_LEN);
} }
/* called with priv->driver_lock held */ /* called with priv->driver_lock held */
static int if_usb_get_int_status(struct lbs_private *priv, u8 *ireg) static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *ireg)
{ {
struct usb_card_rec *cardp = priv->card; struct if_usb_card *cardp = priv->card;
*ireg = cardp->usb_int_cause; *ireg = cardp->usb_int_cause;
cardp->usb_int_cause = 0; cardp->usb_int_cause = 0;
lbs_deb_usbd(&cardp->udev->dev,"Int cause is 0x%X\n", *ireg); lbs_deb_usbd(&cardp->udev->dev, "Int cause is 0x%X\n", *ireg);
return 0; return 0;
} }
static int if_usb_read_event_cause(struct lbs_private *priv) static int if_usb_read_event_cause(struct lbs_private *priv)
{ {
struct usb_card_rec *cardp = priv->card; struct if_usb_card *cardp = priv->card;
priv->eventcause = cardp->usb_event_cause; priv->eventcause = cardp->usb_event_cause;
/* Re-submit rx urb here to avoid event lost issue */ /* Re-submit rx urb here to avoid event lost issue */
if_usb_submit_rx_urb(cardp); if_usb_submit_rx_urb(cardp);
return 0; return 0;
} }
@ -809,20 +751,17 @@ static int if_usb_read_event_cause(struct lbs_private *priv)
* 2:Boot from FW in EEPROM * 2:Boot from FW in EEPROM
* @return 0 * @return 0
*/ */
static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue) static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
{ {
struct bootcmdstr sbootcmd; struct bootcmd *bootcmd = cardp->ep_out_buf;
int i;
/* Prepare command */ /* Prepare command */
sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER); bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
sbootcmd.u8cmd_tag = ivalue; bootcmd->cmd = ivalue;
for (i=0; i<11; i++) memset(bootcmd->pad, 0, sizeof(bootcmd->pad));
sbootcmd.au8dumy[i]=0x00;
memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
/* Issue command */ /* Issue command */
usb_tx_block(cardp, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd));
return 0; return 0;
} }
@ -835,10 +774,10 @@ static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue)
* len image length * len image length
* @return 0 or -1 * @return 0 or -1
*/ */
static int check_fwfile_format(u8 *data, u32 totlen) static int check_fwfile_format(uint8_t *data, uint32_t totlen)
{ {
u32 bincmd, exit; uint32_t bincmd, exit;
u32 blksize, offset, len; uint32_t blksize, offset, len;
int ret; int ret;
ret = 1; ret = 1;
@ -876,7 +815,7 @@ static int check_fwfile_format(u8 *data, u32 totlen)
} }
static int if_usb_prog_firmware(struct usb_card_rec *cardp) static int if_usb_prog_firmware(struct if_usb_card *cardp)
{ {
int i = 0; int i = 0;
static int reset_count = 10; static int reset_count = 10;
@ -953,11 +892,11 @@ restart:
goto release_fw; goto release_fw;
} }
release_fw: release_fw:
release_firmware(cardp->fw); release_firmware(cardp->fw);
cardp->fw = NULL; cardp->fw = NULL;
done: done:
lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
return ret; return ret;
} }
@ -966,36 +905,38 @@ done:
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
{ {
struct usb_card_rec *cardp = usb_get_intfdata(intf); struct if_usb_card *cardp = usb_get_intfdata(intf);
struct lbs_private *priv = cardp->priv; struct lbs_private *priv = cardp->priv;
int ret;
lbs_deb_enter(LBS_DEB_USB); lbs_deb_enter(LBS_DEB_USB);
if (priv->psstate != PS_STATE_FULL_POWER) if (priv->psstate != PS_STATE_FULL_POWER)
return -1; return -1;
netif_device_detach(priv->dev); ret = lbs_suspend(priv);
netif_device_detach(priv->mesh_dev); if (ret)
goto out;
/* Unlink tx & rx urb */ /* Unlink tx & rx urb */
usb_kill_urb(cardp->tx_urb); usb_kill_urb(cardp->tx_urb);
usb_kill_urb(cardp->rx_urb); usb_kill_urb(cardp->rx_urb);
out:
lbs_deb_leave(LBS_DEB_USB); lbs_deb_leave(LBS_DEB_USB);
return 0; return ret;
} }
static int if_usb_resume(struct usb_interface *intf) static int if_usb_resume(struct usb_interface *intf)
{ {
struct usb_card_rec *cardp = usb_get_intfdata(intf); struct if_usb_card *cardp = usb_get_intfdata(intf);
struct lbs_private *priv = cardp->priv; struct lbs_private *priv = cardp->priv;
lbs_deb_enter(LBS_DEB_USB); lbs_deb_enter(LBS_DEB_USB);
if_usb_submit_rx_urb(cardp); if_usb_submit_rx_urb(cardp);
netif_device_attach(priv->dev); lbs_resume(priv);
netif_device_attach(priv->mesh_dev);
lbs_deb_leave(LBS_DEB_USB); lbs_deb_leave(LBS_DEB_USB);
return 0; return 0;
@ -1039,5 +980,5 @@ module_init(if_usb_init_module);
module_exit(if_usb_exit_module); module_exit(if_usb_exit_module);
MODULE_DESCRIPTION("8388 USB WLAN Driver"); MODULE_DESCRIPTION("8388 USB WLAN Driver");
MODULE_AUTHOR("Marvell International Ltd."); MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc.");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -9,72 +9,67 @@ struct lbs_private;
/** /**
* This file contains definition for USB interface. * This file contains definition for USB interface.
*/ */
#define CMD_TYPE_REQUEST 0xF00DFACE #define CMD_TYPE_REQUEST 0xF00DFACE
#define CMD_TYPE_DATA 0xBEADC0DE #define CMD_TYPE_DATA 0xBEADC0DE
#define CMD_TYPE_INDICATION 0xBEEFFACE #define CMD_TYPE_INDICATION 0xBEEFFACE
#define IPFIELD_ALIGN_OFFSET 2 #define IPFIELD_ALIGN_OFFSET 2
#define BOOT_CMD_FW_BY_USB 0x01 #define BOOT_CMD_FW_BY_USB 0x01
#define BOOT_CMD_FW_IN_EEPROM 0x02 #define BOOT_CMD_FW_IN_EEPROM 0x02
#define BOOT_CMD_UPDATE_BOOT2 0x03 #define BOOT_CMD_UPDATE_BOOT2 0x03
#define BOOT_CMD_UPDATE_FW 0x04 #define BOOT_CMD_UPDATE_FW 0x04
#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */ #define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* LVRM */
struct bootcmdstr struct bootcmd
{ {
__le32 u32magicnumber; __le32 magic;
u8 u8cmd_tag; uint8_t cmd;
u8 au8dumy[11]; uint8_t pad[11];
}; };
#define BOOT_CMD_RESP_OK 0x0001 #define BOOT_CMD_RESP_OK 0x0001
#define BOOT_CMD_RESP_FAIL 0x0000 #define BOOT_CMD_RESP_FAIL 0x0000
struct bootcmdrespStr struct bootcmdresp
{ {
__le32 u32magicnumber; __le32 magic;
u8 u8cmd_tag; uint8_t cmd;
u8 u8result; uint8_t result;
u8 au8dumy[2]; uint8_t pad[2];
};
/* read callback private data */
struct read_cb_info {
struct usb_card_rec *cardp;
struct sk_buff *skb;
}; };
/** USB card description structure*/ /** USB card description structure*/
struct usb_card_rec { struct if_usb_card {
struct usb_device *udev; struct usb_device *udev;
struct urb *rx_urb, *tx_urb; struct urb *rx_urb, *tx_urb;
struct lbs_private *priv; struct lbs_private *priv;
struct read_cb_info rinfo;
int bulk_in_size; struct sk_buff *rx_skb;
u8 bulk_in_endpointAddr; uint32_t usb_event_cause;
uint8_t usb_int_cause;
u8 *bulk_out_buffer; uint8_t ep_in;
int bulk_out_size; uint8_t ep_out;
u8 bulk_out_endpointAddr;
int8_t bootcmdresp;
int ep_in_size;
void *ep_out_buf;
int ep_out_size;
const struct firmware *fw; const struct firmware *fw;
struct timer_list fw_timeout; struct timer_list fw_timeout;
wait_queue_head_t fw_wq; wait_queue_head_t fw_wq;
u8 CRC_OK; uint32_t fwseqnum;
u32 fwseqnum; uint32_t totalbytes;
u32 lastseqnum; uint32_t fwlastblksent;
u32 totalbytes; uint8_t CRC_OK;
u32 fwlastblksent; uint8_t fwdnldover;
u8 fwdnldover; uint8_t fwfinalblk;
u8 fwfinalblk; uint8_t surprise_removed;
u8 surprise_removed;
u32 usb_event_cause;
u8 usb_int_cause;
s8 bootcmdresp;
}; };
/** fwheader */ /** fwheader */
@ -87,10 +82,10 @@ struct fwheader {
#define FW_MAX_DATA_BLK_SIZE 600 #define FW_MAX_DATA_BLK_SIZE 600
/** FWData */ /** FWData */
struct FWData { struct fwdata {
struct fwheader fwheader; struct fwheader hdr;
__le32 seqnum; __le32 seqnum;
u8 data[FW_MAX_DATA_BLK_SIZE]; uint8_t data[0];
}; };
/** fwsyncheader */ /** fwsyncheader */
@ -102,7 +97,5 @@ struct fwsyncheader {
#define FW_HAS_DATA_TO_RECV 0x00000001 #define FW_HAS_DATA_TO_RECV 0x00000001
#define FW_HAS_LAST_BLOCK 0x00000004 #define FW_HAS_LAST_BLOCK 0x00000004
#define FW_DATA_XMIT_SIZE \
sizeof(struct fwheader) + le32_to_cpu(fwdata->fwheader.datalength) + sizeof(u32)
#endif #endif

View File

@ -781,8 +781,8 @@ int lbs_ret_80211_associate(struct lbs_private *priv,
priv->numSNRNF = 0; priv->numSNRNF = 0;
netif_carrier_on(priv->dev); netif_carrier_on(priv->dev);
netif_wake_queue(priv->dev); if (!priv->tx_pending_len)
netif_wake_queue(priv->dev);
memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER; wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@ -865,7 +865,8 @@ int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
priv->curbssparams.ssid_len = bss->ssid_len; priv->curbssparams.ssid_len = bss->ssid_len;
netif_carrier_on(priv->dev); netif_carrier_on(priv->dev);
netif_wake_queue(priv->dev); if (!priv->tx_pending_len)
netif_wake_queue(priv->dev);
memset(&wrqu, 0, sizeof(wrqu)); memset(&wrqu, 0, sizeof(wrqu));
memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);

View File

@ -6,7 +6,6 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/freezer.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
@ -345,7 +344,7 @@ static ssize_t lbs_mesh_set(struct device *dev,
if (enable == !!priv->mesh_dev) if (enable == !!priv->mesh_dev)
return count; return count;
ret = lbs_mesh_config(priv, enable); ret = lbs_mesh_config(priv, enable, priv->curbssparams.channel);
if (ret) if (ret)
return ret; return ret;
@ -477,6 +476,13 @@ static void lbs_tx_timeout(struct net_device *dev)
to kick it somehow? */ to kick it somehow? */
lbs_host_to_card_done(priv); lbs_host_to_card_done(priv);
/* More often than not, this actually happens because the
firmware has crapped itself -- rather than just a very
busy medium. So send a harmless command, and if/when
_that_ times out, we'll kick it in the head. */
lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
0, 0, NULL);
lbs_deb_leave(LBS_DEB_TX); lbs_deb_leave(LBS_DEB_TX);
} }
@ -489,19 +495,9 @@ void lbs_host_to_card_done(struct lbs_private *priv)
priv->dnld_sent = DNLD_RES_RECEIVED; priv->dnld_sent = DNLD_RES_RECEIVED;
/* Wake main thread if commands are pending */ /* Wake main thread if commands are pending */
if (!priv->cur_cmd) if (!priv->cur_cmd || priv->tx_pending_len > 0)
wake_up_interruptible(&priv->waitq); wake_up_interruptible(&priv->waitq);
/* Don't wake netif queues if we're in monitor mode and
a TX packet is already pending, or if there are commands
queued to be sent. */
if (!priv->currenttxskb && list_empty(&priv->cmdpendingq)) {
if (priv->dev && 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_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
} }
EXPORT_SYMBOL_GPL(lbs_host_to_card_done); EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
@ -663,8 +659,6 @@ static int lbs_thread(void *data)
init_waitqueue_entry(&wait, current); init_waitqueue_entry(&wait, current);
set_freezable();
for (;;) { for (;;) {
int shouldsleep; int shouldsleep;
@ -675,12 +669,16 @@ static int lbs_thread(void *data)
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irq(&priv->driver_lock); spin_lock_irq(&priv->driver_lock);
if (priv->surpriseremoved) if (kthread_should_stop())
shouldsleep = 0; /* Bye */ shouldsleep = 0; /* Bye */
else if (priv->surpriseremoved)
shouldsleep = 1; /* We need to wait until we're _told_ to die */
else if (priv->psstate == PS_STATE_SLEEP) else if (priv->psstate == PS_STATE_SLEEP)
shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */ shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */
else if (priv->intcounter) else if (priv->intcounter)
shouldsleep = 0; /* Interrupt pending. Deal with it now */ shouldsleep = 0; /* Interrupt pending. Deal with it now */
else if (priv->cmd_timed_out)
shouldsleep = 0; /* Command timed out. Recover */
else if (!priv->fw_ready) else if (!priv->fw_ready)
shouldsleep = 1; /* Firmware not ready. We're waiting for it */ shouldsleep = 1; /* Firmware not ready. We're waiting for it */
else if (priv->dnld_sent) else if (priv->dnld_sent)
@ -708,17 +706,19 @@ static int lbs_thread(void *data)
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&priv->waitq, &wait); remove_wait_queue(&priv->waitq, &wait);
try_to_freeze();
lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d\n", lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
priv->intcounter, priv->currenttxskb, priv->dnld_sent); priv->intcounter, priv->currenttxskb, priv->dnld_sent);
if (kthread_should_stop() || priv->surpriseremoved) { if (kthread_should_stop()) {
lbs_deb_thread("main-thread: break from main thread: surpriseremoved=0x%x\n", lbs_deb_thread("main-thread: break from main thread\n");
priv->surpriseremoved);
break; break;
} }
if (priv->surpriseremoved) {
lbs_deb_thread("adapter removed; waiting to die...\n");
continue;
}
spin_lock_irq(&priv->driver_lock); spin_lock_irq(&priv->driver_lock);
@ -749,6 +749,26 @@ static int lbs_thread(void *data)
spin_lock_irq(&priv->driver_lock); spin_lock_irq(&priv->driver_lock);
} }
if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
if (++priv->nr_retries > 10) {
lbs_pr_info("Excessive timeouts submitting command %x\n",
le16_to_cpu(cmdnode->cmdbuf->command));
lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
priv->nr_retries = 0;
} else {
priv->cur_cmd = NULL;
lbs_pr_info("requeueing command %x due to timeout (#%d)\n",
le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries);
/* Stick it back at the _top_ of the pending queue
for immediate resubmission */
list_add(&cmdnode->list, &priv->cmdpendingq);
}
}
priv->cmd_timed_out = 0;
/* Any Card Event */ /* Any Card Event */
if (priv->hisregcpy & MRVDRV_CARDEVENT) { if (priv->hisregcpy & MRVDRV_CARDEVENT) {
lbs_deb_thread("main-thread: Card Event Activity\n"); lbs_deb_thread("main-thread: Card Event Activity\n");
@ -834,6 +854,58 @@ static int lbs_thread(void *data)
return 0; return 0;
} }
static int lbs_suspend_callback(struct lbs_private *priv, unsigned long dummy,
struct cmd_header *cmd)
{
lbs_deb_fw("HOST_SLEEP_ACTIVATE succeeded\n");
netif_device_detach(priv->dev);
if (priv->mesh_dev)
netif_device_detach(priv->mesh_dev);
priv->fw_ready = 0;
return 0;
}
int lbs_suspend(struct lbs_private *priv)
{
struct cmd_header cmd;
int ret;
if (priv->wol_criteria == 0xffffffff) {
lbs_pr_info("Suspend attempt without configuring wake params!\n");
return -EINVAL;
}
memset(&cmd, 0, sizeof(cmd));
ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd,
sizeof(cmd), lbs_suspend_callback, 0);
if (ret)
lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret);
return ret;
}
EXPORT_SYMBOL_GPL(lbs_suspend);
int lbs_resume(struct lbs_private *priv)
{
priv->fw_ready = 1;
/* Firmware doesn't seem to give us RX packets any more
until we send it some command. Might as well update */
lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
0, 0, NULL);
netif_device_attach(priv->dev);
if (priv->mesh_dev)
netif_device_attach(priv->mesh_dev);
return 0;
}
EXPORT_SYMBOL_GPL(lbs_resume);
/** /**
* @brief This function downloads firmware image, gets * @brief This function downloads firmware image, gets
* HW spec from firmware and set basic parameters to * HW spec from firmware and set basic parameters to
@ -879,35 +951,21 @@ done:
static void command_timer_fn(unsigned long data) static void command_timer_fn(unsigned long data)
{ {
struct lbs_private *priv = (struct lbs_private *)data; struct lbs_private *priv = (struct lbs_private *)data;
struct cmd_ctrl_node *node;
unsigned long flags; unsigned long flags;
node = priv->cur_cmd;
if (node == NULL) {
lbs_deb_fw("ptempnode empty\n");
return;
}
if (!node->cmdbuf) {
lbs_deb_fw("cmd is NULL\n");
return;
}
lbs_deb_fw("command_timer_fn fired, cmd %x\n", node->cmdbuf->command);
if (!priv->fw_ready)
return;
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
priv->cur_cmd = NULL;
spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_fw("re-sending same command because of timeout\n"); if (!priv->cur_cmd) {
lbs_queue_cmd(priv, node, 0); lbs_pr_info("Command timer expired; no pending command\n");
goto out;
}
lbs_pr_info("Command %x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command));
priv->cmd_timed_out = 1;
wake_up_interruptible(&priv->waitq); wake_up_interruptible(&priv->waitq);
out:
return; spin_unlock_irqrestore(&priv->driver_lock, flags);
} }
static int lbs_init_adapter(struct lbs_private *priv) static int lbs_init_adapter(struct lbs_private *priv)
@ -1055,6 +1113,9 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
sprintf(priv->mesh_ssid, "mesh"); sprintf(priv->mesh_ssid, "mesh");
priv->mesh_ssid_len = 4; priv->mesh_ssid_len = 4;
priv->wol_criteria = 0xffffffff;
priv->wol_gpio = 0xff;
goto done; goto done;
err_init_adapter: err_init_adapter:
@ -1130,8 +1191,33 @@ int lbs_start_card(struct lbs_private *priv)
} }
if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
lbs_pr_err("cannot register lbs_rtap attribute\n"); lbs_pr_err("cannot register lbs_rtap attribute\n");
if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
lbs_pr_err("cannot register lbs_mesh attribute\n"); /* Enable mesh, if supported, and work out which TLV it uses.
0x100 + 291 is an unofficial value used in 5.110.20.pXX
0x100 + 37 is the official value used in 5.110.21.pXX
but we check them in that order because 20.pXX doesn't
give an error -- it just silently fails. */
/* 5.110.20.pXX firmware will fail the command if the channel
doesn't match the existing channel. But only if the TLV
is correct. If the channel is wrong, _BOTH_ versions will
give an error to 0x100+291, and allow 0x100+37 to succeed.
It's just that 5.110.20.pXX will not have done anything
useful */
lbs_update_channel(priv);
priv->mesh_tlv = 0x100 + 291;
if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) {
priv->mesh_tlv = 0x100 + 37;
if (lbs_mesh_config(priv, 1, priv->curbssparams.channel))
priv->mesh_tlv = 0;
}
if (priv->mesh_tlv) {
lbs_add_mesh(priv);
if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
lbs_pr_err("cannot register lbs_mesh attribute\n");
}
lbs_debugfs_init_one(priv, dev); lbs_debugfs_init_one(priv, dev);
@ -1160,11 +1246,13 @@ int lbs_stop_card(struct lbs_private *priv)
lbs_debugfs_remove_one(priv); lbs_debugfs_remove_one(priv);
device_remove_file(&dev->dev, &dev_attr_lbs_rtap); device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
device_remove_file(&dev->dev, &dev_attr_lbs_mesh); if (priv->mesh_tlv)
device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
/* Flush pending command nodes */ /* Flush pending command nodes */
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
cmdnode->result = -ENOENT;
cmdnode->cmdwaitqwoken = 1; cmdnode->cmdwaitqwoken = 1;
wake_up_interruptible(&cmdnode->cmdwait_q); wake_up_interruptible(&cmdnode->cmdwait_q);
} }
@ -1347,12 +1435,6 @@ void lbs_interrupt(struct lbs_private *priv)
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++; priv->intcounter++;
if (priv->psstate == PS_STATE_SLEEP) if (priv->psstate == PS_STATE_SLEEP)

View File

@ -590,13 +590,13 @@ int lbs_scan_networks(struct lbs_private *priv,
netif_stop_queue(priv->dev); netif_stop_queue(priv->dev);
netif_carrier_off(priv->dev); netif_carrier_off(priv->dev);
if (priv->mesh_dev) { if (priv->mesh_dev) {
netif_stop_queue(priv->mesh_dev); netif_stop_queue(priv->mesh_dev);
netif_carrier_off(priv->mesh_dev); netif_carrier_off(priv->mesh_dev);
} }
/* Prepare to continue an interrupted scan */ /* Prepare to continue an interrupted scan */
lbs_deb_scan("chan_count %d, last_scanned_channel %d\n", lbs_deb_scan("chan_count %d, last_scanned_channel %d\n",
chan_count, priv->last_scanned_channel); chan_count, priv->last_scanned_channel);
curr_chans = chan_list; curr_chans = chan_list;
/* advance channel list by already-scanned-channels */ /* advance channel list by already-scanned-channels */
if (priv->last_scanned_channel > 0) { if (priv->last_scanned_channel > 0) {
@ -659,11 +659,13 @@ out2:
out: out:
if (priv->connect_status == LBS_CONNECTED) { if (priv->connect_status == LBS_CONNECTED) {
netif_carrier_on(priv->dev); netif_carrier_on(priv->dev);
netif_wake_queue(priv->dev); if (!priv->tx_pending_len)
netif_wake_queue(priv->dev);
} }
if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) { if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) {
netif_carrier_on(priv->mesh_dev); netif_carrier_on(priv->mesh_dev);
netif_wake_queue(priv->mesh_dev); if (!priv->tx_pending_len)
netif_wake_queue(priv->mesh_dev);
} }
kfree(chan_list); kfree(chan_list);

View File

@ -734,6 +734,13 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_enter(LBS_DEB_WEXT);
if (!priv->ps_supported) {
if (vwrq->disabled)
return 0;
else
return -EINVAL;
}
/* PS is currently supported only in Infrastructure mode /* PS is currently supported only in Infrastructure mode
* Remove this check if it is to be supported in IBSS mode also * Remove this check if it is to be supported in IBSS mode also
*/ */
@ -1000,9 +1007,8 @@ static int lbs_mesh_set_freq(struct net_device *dev,
else if (priv->mode == IW_MODE_ADHOC) else if (priv->mode == IW_MODE_ADHOC)
lbs_stop_adhoc_network(priv); lbs_stop_adhoc_network(priv);
} }
priv->curbssparams.channel = fwrq->m; lbs_mesh_config(priv, 1, fwrq->m);
lbs_mesh_config(priv, 0); lbs_update_channel(priv);
lbs_mesh_config(priv, 1);
ret = 0; ret = 0;
out: out:
@ -2010,7 +2016,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
priv->mesh_ssid_len = dwrq->length; priv->mesh_ssid_len = dwrq->length;
} }
lbs_mesh_config(priv, 1); lbs_mesh_config(priv, 1, priv->curbssparams.channel);
out: out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret; return ret;