1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-11-27 17:15:00 +02:00

Updating libertas wireless driver to latest version.

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@10235 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
ryd 2008-01-24 03:03:04 +00:00
parent d32a09bb67
commit 03e8a3a945
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.
# See /LICENSE for more information.
@ -33,6 +33,8 @@ endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
$(Build/Patch)
$(if $(QUILT),touch $(PKG_BUILD_DIR)/.quilt_used)
endef
define Build/Compile
@ -42,7 +44,7 @@ define Build/Compile
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" \
EXTRA_CFLAGS="-I$(PKG_BUILD_DIR) -DCONFIG_LIBERTAS_DEBUG -include compat.h -I$(STAGING_DIR)/usr/include/mac80211" \
modules
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)
{
u8 i;
u8 size = sizeof(region_code_mapping)/
sizeof(struct region_code_mapping);
for (i = 0; region[i] && i < COUNTRY_CODE_LEN; 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,
COUNTRY_CODE_LEN))
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)
{
u8 i;
for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
u8 size = sizeof(region_code_mapping)
/ sizeof(struct region_code_mapping);
for (i = 0; i < size; i++) {
if (region_code_mapping[i].code == code)
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;
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++) {
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)
{
struct chan_freq_power *cf;
u16 cnt;
u16 i;
u32 freq = 0;
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)
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;
/* 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);
ret = lbs_get_channel(priv);
if (ret > 0)
priv->curbssparams.channel = (u8) ret;
if (ret > 0) {
priv->curbssparams.channel = ret;
ret = 0;
}
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
@ -184,7 +185,7 @@ void lbs_sync_channel(struct work_struct *work)
sync_channel);
lbs_deb_enter(LBS_DEB_ASSOC);
if (update_channel(priv) != 0)
if (lbs_update_channel(priv))
lbs_pr_info("Channel synchronization failed.");
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);
ret = update_channel(priv);
if (ret < 0) {
lbs_deb_assoc("ASSOC: channel: error getting channel.");
ret = lbs_update_channel(priv);
if (ret) {
lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
goto done;
}
if (assoc_req->channel == priv->curbssparams.channel)
goto done;
if (priv->mesh_dev) {
/* Disconnect mesh while associating -- otherwise it
won't let us change channels */
lbs_mesh_config(priv, 0);
/* Change mesh channel first; 21.p21 firmware won't let
you change channel otherwise (even though it'll return
an error to this */
lbs_mesh_config(priv, 0, assoc_req->channel);
}
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);
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
* it since the firmware is supposed to return the new channel, but
* whatever... */
ret = update_channel(priv);
if (ret < 0)
lbs_deb_assoc("ASSOC: channel: error getting channel.");
ret = lbs_update_channel(priv);
if (ret) {
lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
goto done;
}
if (assoc_req->channel != priv->curbssparams.channel) {
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 */
set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
restore_mesh:
if (priv->mesh_dev)
lbs_mesh_config(priv, 1);
lbs_mesh_config(priv, 1, priv->curbssparams.channel);
done:
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,
struct assoc_request * assoc_req)
struct assoc_request *assoc_req)
{
int i;
int ret = 0;
@ -261,22 +266,11 @@ static int assoc_helper_wep_keys(struct lbs_private *priv,
lbs_deb_enter(LBS_DEB_ASSOC);
/* Set or remove WEP keys */
if ( assoc_req->wep_keys[0].len
|| assoc_req->wep_keys[1].len
|| assoc_req->wep_keys[2].len
|| assoc_req->wep_keys[3].len) {
ret = lbs_prepare_and_send_command(priv,
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 (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)
ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_ADD, assoc_req);
else
ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, assoc_req);
if (ret)
goto out;
@ -286,6 +280,7 @@ static int assoc_helper_wep_keys(struct lbs_private *priv,
priv->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE;
else
priv->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE;
ret = lbs_set_mac_packet_filter(priv);
if (ret)
goto out;
@ -295,7 +290,7 @@ static int assoc_helper_wep_keys(struct lbs_private *priv,
/* Copy WEP keys into priv wep key fields */
for (i = 0; i < 4; 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;
@ -310,8 +305,8 @@ static int assoc_helper_secinfo(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
int ret = 0;
u32 do_wpa;
u32 rsn = 0;
uint16_t do_wpa;
uint16_t rsn = 0;
lbs_deb_enter(LBS_DEB_ASSOC);
@ -328,28 +323,19 @@ static int assoc_helper_secinfo(struct lbs_private *priv,
*/
/* Get RSN enabled/disabled */
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_ENABLE_RSN,
CMD_ACT_GET,
CMD_OPTION_WAITFORRSP,
0, &rsn);
ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn);
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;
}
/* 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)
goto out;
/* Set RSN enabled/disabled */
rsn = do_wpa;
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_ENABLE_RSN,
CMD_ACT_SET,
CMD_OPTION_WAITFORRSP,
0, &rsn);
ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &do_wpa);
out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);

File diff suppressed because it is too large Load Diff

View File

@ -6,16 +6,26 @@
#include "hostcmd.h"
#include "dev.h"
#define lbs_cmd(priv, cmdnr, cmd, callback, callback_arg) \
__lbs_cmd(priv, cmdnr, &(cmd).hdr, sizeof(cmd), \
callback, callback_arg)
/* lbs_cmd() infers the size of the buffer to copy data back into, from
the size of the target of the pointer. Since the command to be sent
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) \
__lbs_cmd(priv, cmdnr, &(cmd).hdr, sizeof(cmd), \
lbs_cmd_copyback, (unsigned long) &cmd)
#define lbs_cmd_with_response(priv, cmdnr, cmd) \
lbs_cmd(priv, cmdnr, 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,
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 *),
unsigned long callback_arg);
@ -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_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 */

View File

@ -43,14 +43,15 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
msleep_interruptible(1000);
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 */
netif_stop_queue(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 */
memset(priv->SNR, 0x00, sizeof(priv->SNR));
memset(priv->NF, 0x00, sizeof(priv->NF));
@ -145,29 +146,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
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,
struct cmd_ds_command *resp)
{
@ -394,23 +372,6 @@ static int lbs_ret_get_log(struct lbs_private *priv,
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,
struct cmd_ds_command *resp)
{
@ -428,25 +389,6 @@ static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
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,
unsigned long dummy,
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_GET_AFC):
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));
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_CONTROL):
case CMD_RET(CMD_802_11_SET_WEP):
case CMD_RET(CMD_802_11_RESET):
case CMD_RET(CMD_802_11_AUTHENTICATE):
case CMD_RET(CMD_802_11_RADIO_CONTROL):
case CMD_RET(CMD_802_11_BEACON_STOP):
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):
ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
break;
@ -551,35 +487,22 @@ static inline int handle_cmd_response(struct lbs_private *priv,
ret = lbs_ret_802_11d_domain_info(priv, resp);
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):
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));
spin_unlock_irqrestore(&priv->driver_lock, flags);
break;
case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
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));
spin_unlock_irqrestore(&priv->driver_lock, flags);
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):
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));
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):
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));
spin_unlock_irqrestore(&priv->driver_lock, flags);
break;
case CMD_RET(CMD_BT_ACCESS):
spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->cur_cmd->pdata_buf)
memcpy(priv->cur_cmd->pdata_buf,
if (priv->cur_cmd->callback_arg)
memcpy((void *)priv->cur_cmd->callback_arg,
&resp->params.bt.addr1, 2 * ETH_ALEN);
spin_unlock_irqrestore(&priv->driver_lock, flags);
break;
case CMD_RET(CMD_FWT_ACCESS):
spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->cur_cmd->pdata_buf)
memcpy(priv->cur_cmd->pdata_buf, &resp->params.fwt,
if (priv->cur_cmd->callback_arg)
memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
sizeof(resp->params.fwt));
spin_unlock_irqrestore(&priv->driver_lock, flags);
break;
@ -611,7 +534,7 @@ static inline int handle_cmd_response(struct lbs_private *priv,
default:
lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
resp->command);
le16_to_cpu(resp->command));
break;
}
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)
{
u16 respcmd;
uint16_t respcmd, curcmd;
struct cmd_header *resp;
int ret = 0;
ulong flags;
u16 result;
unsigned long flags;
uint16_t result;
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);
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);
goto done;
}
resp = priv->cur_cmd->cmdbuf;
resp = (void *)priv->upld_buf;
curcmd = le16_to_cpu(resp->command);
respcmd = le16_to_cpu(resp->command);
result = le16_to_cpu(resp->result);
lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n",
respcmd, priv->upld_len, jiffies);
lbs_deb_host("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n",
respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies);
lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len);
if (!(respcmd & 0x8000)) {
lbs_deb_host("invalid response!\n");
priv->cur_cmd_retcode = -1;
__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
priv->cur_cmd = NULL;
if (resp->seqnum != resp->seqnum) {
lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
le16_to_cpu(resp->seqnum), le16_to_cpu(resp->seqnum));
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
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. */
priv->cur_cmd_retcode = result;
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);
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_cleanup_and_insert_cmd(priv, priv->cur_cmd);
priv->cur_cmd = NULL;
lbs_complete_command(priv, priv->cur_cmd, result);
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = 0;
@ -730,9 +676,7 @@ int lbs_process_rx_command(struct lbs_private *priv)
break;
}
__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
priv->cur_cmd = NULL;
lbs_complete_command(priv, priv->cur_cmd, result);
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
@ -751,8 +695,7 @@ int lbs_process_rx_command(struct lbs_private *priv)
if (priv->cur_cmd) {
/* Clean up and Put current command back to cmdfreeq */
__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
priv->cur_cmd = NULL;
lbs_complete_command(priv, priv->cur_cmd, result);
}
spin_unlock_irqrestore(&priv->driver_lock, flags);
@ -762,6 +705,30 @@ done:
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 ret = 0;
@ -810,9 +777,13 @@ int lbs_process_event(struct lbs_private *priv)
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:
lbs_deb_cmd("EVENT: awake\n");
/* handle unexpected PS AWAKE event */
if (priv->psstate == PS_STATE_FULL_POWER) {
lbs_deb_cmd(
@ -875,9 +846,10 @@ int lbs_process_event(struct lbs_private *priv)
}
lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
priv->mesh_connect_status = LBS_CONNECTED;
if (priv->mesh_open == 1) {
netif_wake_queue(priv->mesh_dev);
if (priv->mesh_open) {
netif_carrier_on(priv->mesh_dev);
if (!priv->tx_pending_len)
netif_wake_queue(priv->mesh_dev);
}
priv->mode = IW_MODE_ADHOC;
schedule_work(&priv->sync_channel);

View File

@ -10,6 +10,7 @@
#include "decl.h"
#include "host.h"
#include "debugfs.h"
#include "cmd.h"
static struct dentry *lbs_dir;
static char *szStates[] = {
@ -103,71 +104,64 @@ static ssize_t lbs_sleepparams_write(struct file *file,
loff_t *ppos)
{
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;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
buf_size = min(count, len - 1);
if (copy_from_user(buf, user_buf, buf_size)) {
res = -EFAULT;
ret = -EFAULT;
goto out_unlock;
}
res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
if (res != 6) {
res = -EFAULT;
ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
if (ret != 6) {
ret = -EINVAL;
goto out_unlock;
}
priv->sp.sp_error = p1;
priv->sp.sp_offset = p2;
priv->sp.sp_stabletime = p3;
priv->sp.sp_calcontrol = p4;
priv->sp.sp_extsleepclk = p5;
priv->sp.sp_reserved = p6;
sp.sp_error = p1;
sp.sp_offset = p2;
sp.sp_stabletime = p3;
sp.sp_calcontrol = p4;
sp.sp_extsleepclk = p5;
sp.sp_reserved = p6;
res = lbs_prepare_and_send_command(priv,
CMD_802_11_SLEEP_PARAMS,
CMD_ACT_SET,
CMD_OPTION_WAITFORRSP, 0, NULL);
if (!res)
res = count;
else
res = -EINVAL;
ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
if (!ret)
ret = count;
else if (ret > 0)
ret = -EINVAL;
out_unlock:
free_page(addr);
return res;
return ret;
}
static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
ssize_t res;
ssize_t ret;
size_t pos = 0;
struct sleep_params sp;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
res = lbs_prepare_and_send_command(priv,
CMD_802_11_SLEEP_PARAMS,
CMD_ACT_GET,
CMD_OPTION_WAITFORRSP, 0, NULL);
if (res) {
res = -EFAULT;
ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
if (ret)
goto out_unlock;
}
pos += snprintf(buf, len, "%d %d %d %d %d %d\n", priv->sp.sp_error,
priv->sp.sp_offset, priv->sp.sp_stabletime,
priv->sp.sp_calcontrol, priv->sp.sp_extsleepclk,
priv->sp.sp_reserved);
pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
sp.sp_offset, sp.sp_stabletime,
sp.sp_calcontrol, sp.sp_extsleepclk,
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:
free_page(addr);
return res;
return ret;
}
static ssize_t lbs_extscan(struct file *file, const char __user *userbuf,
@ -295,7 +289,7 @@ static ssize_t lbs_setuserscan(struct file *file,
if (!buf)
return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
res = -EFAULT;
@ -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
* 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;
uint16_t length;
ssize_t pos = 0;
while (pos < size) {
u16 length;
tlv_h = (struct mrvlietypesheader *) tlv;
if (tlv_h->type == le_type)
return tlv_h;
if (tlv_h->len == 0)
if (!tlv_h->len)
return NULL;
length = le16_to_cpu(tlv_h->len) +
sizeof(struct mrvlietypesheader);
if (tlv_h->type == cpu_to_le16(tlv_type))
return tlv_h;
length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h);
pos += length;
tlv += length;
}
@ -373,100 +366,100 @@ static void *lbs_tlv_find(u16 tlv_type, const u8 *tlv, u16 size)
}
/*
* This just gets the bitmap of currently subscribed events. Used when
* adding an additonal event subscription.
*/
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)
static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t 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;
ssize_t res = 0;
ssize_t ret = 0;
size_t pos = 0;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
char *buf;
u8 value;
u8 freq;
int events = 0;
struct cmd_ds_802_11_subscribe_event *subscribed = kzalloc(
sizeof(struct cmd_ds_802_11_subscribe_event),
GFP_KERNEL);
struct mrvlietypes_thresholds *got;
buf = (char *)get_zeroed_page(GFP_KERNEL);
if (!buf)
return -ENOMEM;
res = lbs_prepare_and_send_command(priv,
CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
CMD_OPTION_WAITFORRSP, 0, subscribed);
if (res) {
kfree(subscribed);
return res;
subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL);
if (!subscribed) {
ret = -ENOMEM;
goto out_page;
}
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));
if (got) {
value = got->value;
freq = got->freq;
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);
if (got)
pos += snprintf(buf, len, "%d %d %d\n", value, freq,
!!(events & event_mask));
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
free_page(addr);
return res;
out_page:
free_page((unsigned long)buf);
return ret;
}
static ssize_t lbs_threshold_write(
u16 tlv_type, u16 event_mask,
struct file *file,
const char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
struct file *file,
const char __user *userbuf, 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 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);
if (copy_from_user(buf, userbuf, buf_size)) {
res = -EFAULT;
goto out_unlock;
ret = -EFAULT;
goto out_page;
}
res = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
if (res != 3) {
res = -EFAULT;
goto out_unlock;
ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
if (ret != 3) {
ret = -EINVAL;
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)
new_mask = curr_mask | event_mask;
@ -474,147 +467,128 @@ static ssize_t lbs_threshold_write(
new_mask = curr_mask & ~event_mask;
/* 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;
out_unlock:
free_page(addr);
return res;
tlv = (void *)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(*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(
struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
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(
struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
{
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(
struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
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(
struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
{
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(
struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
file, userbuf, count, ppos);
file, userbuf, count, ppos);
}
static ssize_t lbs_failcount_write(
struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
{
return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
file, userbuf, count, ppos);
file, userbuf, count, ppos);
}
static ssize_t lbs_highrssi_read(
struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
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(
struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
{
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(
struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
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(
struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
{
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(
struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
file, userbuf, count, ppos);
file, userbuf, count, ppos);
}
static ssize_t lbs_bcnmiss_write(
struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
{
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,
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 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_execute_next_command(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 */
int lbs_process_rx_command(struct lbs_private *priv);
void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
struct cmd_ctrl_node *ptempcmd);
void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
int result);
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);
@ -77,4 +72,5 @@ int lbs_stop_card(struct lbs_private *priv);
int lbs_reset_device(struct lbs_private *priv);
void lbs_host_to_card_done(struct lbs_private *priv);
int lbs_update_channel(struct lbs_private *priv);
#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 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 */
/* This section defines 802.11 specific contants */

View File

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

View File

@ -8,6 +8,8 @@
#include "dev.h"
#include "join.h"
#include "wext.h"
#include "cmd.h"
static const char * mesh_stat_strings[]= {
"drop_duplicate_bcast",
"drop_ttl_zero",
@ -142,6 +144,16 @@ static void lbs_ethtool_get_stats(struct net_device * dev,
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)
@ -162,11 +174,57 @@ static void lbs_ethtool_get_strings(struct net_device *dev,
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 = {
.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,
.set_wol = lbs_ethtool_set_wol,
};

View File

@ -73,6 +73,9 @@
#define CMD_802_11_SET_AFC 0x003c
#define CMD_802_11_GET_AFC 0x003d
#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_MAC_ADDRESS 0x004d
#define CMD_802_11_LED_GPIO_CTRL 0x004e
@ -82,8 +85,10 @@
#define CMD_802_11_KEY_MATERIAL 0x005e
#define CMD_802_11_SLEEP_PARAMS 0x0066
#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_PWR_CFG 0x0073
#define CMD_802_11_FW_WAKE_METHOD 0x0074
#define CMD_802_11_SUBSCRIBE_EVENT 0x0075
#define CMD_802_11_RATE_ADAPT_RATESET 0x0076
#define CMD_802_11_TX_RATE_QUERY 0x007f
@ -204,6 +209,11 @@
#define CMD_TYPE_MAX_PSP 0x0001
#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 */
enum cmd_bt_access_opts {
/* 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 list_head list;
/* wait for finish or not */
u16 wait_option;
int result;
/* command response */
void *pdata_buf;
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *);
unsigned long callback_arg;
/* command data */
@ -158,6 +156,8 @@ struct cmd_ds_802_11_reset {
};
struct cmd_ds_802_11_subscribe_event {
struct cmd_header hdr;
__le16 action;
__le16 events;
@ -166,7 +166,7 @@ struct cmd_ds_802_11_subscribe_event {
* 40 bytes. However, future firmware might add additional TLVs, so I
* 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_header hdr;
/* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
__le16 action;
@ -265,8 +267,8 @@ struct cmd_ds_802_11_set_wep {
__le16 keyindex;
/* 40, 128bit or TXWEP */
u8 keytype[4];
u8 keymaterial[4][16];
uint8_t keytype[4];
uint8_t keymaterial[4][16];
};
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_header hdr;
__le16 action;
__le16 control;
};
@ -355,6 +359,8 @@ struct cmd_ds_802_11_beacon_control {
};
struct cmd_ds_802_11_sleep_params {
struct cmd_header hdr;
/* ACT_GET/ACT_SET */
__le16 action;
@ -368,16 +374,18 @@ struct cmd_ds_802_11_sleep_params {
__le16 stabletime;
/* control periodic calibration */
u8 calcontrol;
uint8_t calcontrol;
/* control the use of external sleep clock */
u8 externalsleepclk;
uint8_t externalsleepclk;
/* reserved field, should be set to zero */
__le16 reserved;
};
struct cmd_ds_802_11_inactivity_timeout {
struct cmd_header hdr;
/* ACT_GET/ACT_SET */
__le16 action;
@ -441,6 +449,20 @@ struct cmd_ds_set_boot2_ver {
__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 {
__le16 action;
__le16 nullpktinterval;
@ -516,6 +538,8 @@ struct cmd_ds_802_11_ad_hoc_join {
} __attribute__ ((packed));
struct cmd_ds_802_11_enable_rsn {
struct cmd_header hdr;
__le16 action;
__le16 enable;
} __attribute__ ((packed));
@ -540,6 +564,13 @@ struct MrvlIEtype_keyParamSet {
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 {
__le16 action;
struct MrvlIEtype_keyParamSet keyParamSet[2];
@ -663,7 +694,6 @@ struct cmd_ds_command {
struct cmd_ds_mac_control macctrl;
struct cmd_ds_802_11_associate associate;
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_reset reset;
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_mac_multicast_adr madr;
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_rsp rssirsp;
struct cmd_ds_802_11_disassociate dassociate;
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_mac_reg_access macreg;
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 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_pwr_cfg pwrcfg;
struct cmd_ds_802_11_afc afc;
@ -705,7 +730,6 @@ struct cmd_ds_command {
struct cmd_ds_bt_access bt;
struct cmd_ds_fwt_access fwt;
struct cmd_ds_get_tsf gettsf;
struct cmd_ds_802_11_subscribe_event subscribe_event;
struct cmd_ds_802_11_beacon_control bcn_ctrl;
} params;
} __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)
{
struct if_cs_card *card = data;
struct if_cs_card *card = (struct if_cs_card *)data;
u16 int_cause;
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;
int ret = 0;
u16 int_cause;
u8 *cmdbuf;
*ireg = 0;
lbs_deb_enter(LBS_DEB_CS);
@ -679,14 +678,7 @@ sbi_get_int_status_exit:
/* Card has a command result for us */
if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {
spin_lock(&priv->driver_lock);
if (!priv->cur_cmd) {
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);
ret = if_cs_receive_cmdres(priv, priv->upld_buf, &priv->upld_len);
spin_unlock(&priv->driver_lock);
if (ret < 0)
lbs_pr_err("could not receive cmd from card\n");

View File

@ -19,7 +19,7 @@
* current block size.
*
* As SDIO is still new to the kernel, it is unfortunately common with
* bugs in the host controllers related to that. One such bug is that
* bugs in the host controllers related to that. One such bug is that
* controllers cannot do transfers that aren't a multiple of 4 bytes.
* If you don't have time to fix the host controller driver, you can
* work around the problem by modifying if_sdio_host_to_card() and
@ -136,12 +136,6 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
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) {
lbs_deb_sdio("response packet too large (%d bytes)\n",
(int)size);
@ -149,7 +143,7 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
goto out;
}
memcpy(card->priv->cur_cmd->cmdbuf, buffer, size);
memcpy(card->priv->upld_buf, buffer, size);
card->priv->upld_len = size;
card->int_cause |= MRVDRV_CMD_UPLD_RDY;

View File

@ -16,6 +16,9 @@
#include "cmd.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
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_fwload(struct urb *urb);
static int if_usb_prog_firmware(struct usb_card_rec *cardp);
static int if_usb_host_to_card(struct lbs_private *priv,
u8 type,
u8 *payload,
u16 nb);
static int if_usb_get_int_status(struct lbs_private *priv, u8 *);
static int if_usb_prog_firmware(struct if_usb_card *cardp);
static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
uint8_t *payload, uint16_t nb);
static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *);
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 void if_usb_free(struct usb_card_rec *cardp);
static int if_usb_submit_rx_urb(struct usb_card_rec *cardp);
static int if_usb_reset_device(struct usb_card_rec *cardp);
static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
uint16_t nb);
static void if_usb_free(struct if_usb_card *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
@ -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)
{
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 */
if (urb->status == 0) {
struct lbs_private *priv = cardp->priv;
/*
lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n");
lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n",
urb->actual_length);
*/
lbs_deb_usb2(&urb->dev->dev, "URB status is successful\n");
lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n",
urb->actual_length);
/* Used for both firmware TX and regular TX. priv isn't
* 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
* @param cardp pointer usb_card_rec
* @param cardp pointer if_usb_card
* @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);
@ -96,26 +96,47 @@ static void if_usb_free(struct usb_card_rec *cardp)
usb_free_urb(cardp->rx_urb);
cardp->rx_urb = NULL;
kfree(cardp->bulk_out_buffer);
cardp->bulk_out_buffer = NULL;
kfree(cardp->ep_out_buf);
cardp->ep_out_buf = NULL;
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_802_11_fw_wake_method wake_method;
b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
b2_cmd.action = 0;
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");
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)
{
struct usb_card_rec *cardp = (void *)priv;
struct if_usb_card *cardp = (void *)priv;
if (cardp->fwdnldover) {
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);
}
/**
* @brief sets the configuration values
* @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_endpoint_descriptor *endpoint;
struct lbs_private *priv;
struct usb_card_rec *cardp;
struct if_usb_card *cardp;
int i;
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) {
lbs_pr_err("Out of memory allocating private data.\n");
goto error;
@ -151,12 +173,12 @@ static int if_usb_probe(struct usb_interface *intf,
setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp);
init_waitqueue_head(&cardp->fw_wq);
cardp->udev = udev;
iface_desc = intf->cur_altsetting;
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),
udev->descriptor.bDeviceClass,
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) {
endpoint = &iface_desc->endpoint[i].desc;
if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
&& ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_BULK)) {
/* we found a bulk in endpoint */
lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n",
le16_to_cpu(endpoint->wMaxPacketSize));
if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
lbs_deb_usbd(&udev->dev,
"Rx URB allocation failed\n");
goto dealloc;
}
cardp->bulk_in_size =
le16_to_cpu(endpoint->wMaxPacketSize);
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 (usb_endpoint_is_bulk_in(endpoint)) {
cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
cardp->ep_in = usb_endpoint_num(endpoint);
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);
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);
}
}
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 */
cardp->rinfo.cardp = 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;
}
@ -240,7 +241,7 @@ static int if_usb_probe(struct usb_interface *intf,
if (lbs_start_card(priv))
goto err_start_card;
if_usb_set_boot2_ver(priv);
if_usb_setup_firmware(priv);
usb_get_dev(udev);
usb_set_intfdata(intf, cardp);
@ -265,25 +266,19 @@ error:
*/
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;
lbs_deb_enter(LBS_DEB_MAIN);
/* Update Surprise removed to TRUE */
cardp->surprise_removed = 1;
if (priv) {
priv->surpriseremoved = 1;
lbs_stop_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 */
if_usb_free(cardp);
@ -298,98 +293,75 @@ static void if_usb_disconnect(struct usb_interface *intf)
* @param priv pointer to struct lbs_private
* @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 fwheader *fwheader;
u8 *firmware = cardp->fw->data;
fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
if (!fwdata)
return -1;
fwheader = &fwdata->fwheader;
struct fwdata *fwdata = cardp->ep_out_buf;
uint8_t *firmware = cardp->fw->data;
/* If we got a CRC failure on the last block, back
up and retry it */
if (!cardp->CRC_OK) {
cardp->totalbytes = cardp->fwlastblksent;
cardp->fwseqnum = cardp->lastseqnum - 1;
cardp->fwseqnum--;
}
/*
lbs_deb_usbd(&cardp->udev->dev, "totalbytes = %d\n",
cardp->totalbytes);
*/
lbs_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n",
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));
cardp->fwlastblksent = cardp->totalbytes;
cardp->totalbytes += sizeof(struct fwheader);
/* lbs_deb_usbd(&cardp->udev->dev,"Copy Data\n"); */
memcpy(fwdata->data, &firmware[cardp->totalbytes],
le32_to_cpu(fwdata->fwheader.datalength));
le32_to_cpu(fwdata->hdr.datalength));
/*
lbs_deb_usbd(&cardp->udev->dev,
"Data length = %d\n", le32_to_cpu(fwdata->fwheader.datalength));
*/
lbs_deb_usb2(&cardp->udev->dev, "Data length = %d\n",
le32_to_cpu(fwdata->hdr.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);
cardp->lastseqnum = cardp->fwseqnum;
cardp->totalbytes += le32_to_cpu(fwdata->fwheader.datalength);
usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
le32_to_cpu(fwdata->hdr.datalength));
if (fwheader->dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
/*
lbs_deb_usbd(&cardp->udev->dev, "There are data to follow\n");
lbs_deb_usbd(&cardp->udev->dev,
"seqnum = %d totalbytes = %d\n", cardp->fwseqnum,
cardp->totalbytes);
*/
memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
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_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
cardp->fwseqnum, cardp->totalbytes);
} else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
lbs_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
lbs_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
} 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;
}
/*
lbs_deb_usbd(&cardp->udev->dev,
"The firmware download is done size is %d\n",
cardp->totalbytes);
*/
kfree(fwdata);
lbs_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n",
cardp->totalbytes);
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;
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->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
cmd->result = cpu_to_le16(0);
cmd->seqnum = cpu_to_le16(0x5a5a);
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);
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
* @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;
@ -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_sndbulkpipe(cardp->udev,
cardp->bulk_out_endpointAddr),
cardp->ep_out),
payload, nb, if_usb_write_bulk_callback, cardp);
cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
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);
ret = -1;
} 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;
}
@ -437,11 +408,10 @@ tx_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))
{
struct sk_buff *skb;
struct read_cb_info *rinfo = &cardp->rinfo;
int ret = -1;
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;
}
rinfo->skb = skb;
cardp->rx_skb = skb;
/* Fill the receive configuration URB and initialise the Rx call back */
usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
usb_rcvbulkpipe(cardp->udev,
cardp->bulk_in_endpointAddr),
usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
(void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET),
MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
rinfo);
cardp);
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))) {
/* handle failure conditions */
lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
kfree_skb(skb);
rinfo->skb = NULL;
cardp->rx_skb = NULL;
ret = -1;
} 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;
}
@ -477,27 +445,26 @@ rx_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);
}
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);
}
static void if_usb_receive_fwload(struct urb *urb)
{
struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
struct sk_buff *skb = rinfo->skb;
struct usb_card_rec *cardp = (struct usb_card_rec *)rinfo->cardp;
struct if_usb_card *cardp = urb->context;
struct sk_buff *skb = cardp->rx_skb;
struct fwsyncheader *syncfwheader;
struct bootcmdrespStr bootcmdresp;
struct bootcmdresp bootcmdresp;
if (urb->status) {
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);
return;
}
@ -510,8 +477,8 @@ static void if_usb_receive_fwload(struct urb *urb)
lbs_pr_info("Firmware ready event received\n");
wake_up(&cardp->fw_wq);
} else {
lbs_deb_usb("Waiting for confirmation; got %x %x\n", le32_to_cpu(tmp[0]),
le32_to_cpu(tmp[1]));
lbs_deb_usb("Waiting for confirmation; got %x %x\n",
le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1]));
if_usb_submit_rx_urb_fwload(cardp);
}
kfree_skb(skb);
@ -520,37 +487,36 @@ static void if_usb_receive_fwload(struct urb *urb)
if (cardp->bootcmdresp <= 0) {
memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
sizeof(bootcmdresp));
if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
kfree_skb(skb);
if_usb_submit_rx_urb_fwload(cardp);
cardp->bootcmdresp = 1;
lbs_deb_usbd(&cardp->udev->dev,
"Received valid boot command response\n");
"Received valid boot command response\n");
return;
}
if (bootcmdresp.u32magicnumber != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
if (bootcmdresp.u32magicnumber == cpu_to_le32(CMD_TYPE_REQUEST) ||
bootcmdresp.u32magicnumber == cpu_to_le32(CMD_TYPE_DATA) ||
bootcmdresp.u32magicnumber == cpu_to_le32(CMD_TYPE_INDICATION)) {
if (bootcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
if (bootcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) ||
bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
if (!cardp->bootcmdresp)
lbs_pr_info("Firmware already seems alive; resetting\n");
cardp->bootcmdresp = -1;
} else {
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) {
lbs_pr_info(
"boot cmd response cmd_tag error (%d)\n",
bootcmdresp.u8cmd_tag);
} else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) {
lbs_pr_info(
"boot cmd response result error (%d)\n",
bootcmdresp.u8result);
} else if (bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) {
lbs_pr_info("boot cmd response cmd_tag error (%d)\n",
bootcmdresp.cmd);
} else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
lbs_pr_info("boot cmd response result error (%d)\n",
bootcmdresp.result);
} else {
cardp->bootcmdresp = 1;
lbs_deb_usbd(&cardp->udev->dev,
"Received valid boot command response\n");
"Received valid boot command response\n");
}
kfree_skb(skb);
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,
sizeof(struct fwsyncheader));
sizeof(struct fwsyncheader));
if (!syncfwheader->cmd) {
/*
lbs_deb_usbd(&cardp->udev->dev,
"FW received Blk with correct CRC\n");
lbs_deb_usbd(&cardp->udev->dev,
"FW received Blk seqnum = %d\n",
syncfwheader->seqnum);
*/
lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
le32_to_cpu(syncfwheader->seqnum));
cardp->CRC_OK = 1;
} else {
lbs_deb_usbd(&cardp->udev->dev,
"FW received Blk with CRC error\n");
lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
cardp->CRC_OK = 0;
}
@ -605,13 +566,12 @@ static void if_usb_receive_fwload(struct urb *urb)
#define MRVDRV_MIN_PKT_LEN 30
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)
{
if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE +
MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) {
lbs_deb_usbd(&cardp->udev->dev,
"Packet length is Invalid\n");
if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
|| recvlength < MRVDRV_MIN_PKT_LEN) {
lbs_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n");
kfree_skb(skb);
return;
}
@ -619,19 +579,19 @@ static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
skb_put(skb, recvlength);
skb_pull(skb, MESSAGE_HEADER_LEN);
lbs_process_rxed_packet(priv, skb);
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 usb_card_rec *cardp,
struct if_usb_card *cardp,
struct lbs_private *priv)
{
u8 *cmdbuf;
if (recvlength > LBS_CMD_BUFFER_SIZE) {
lbs_deb_usbd(&cardp->udev->dev,
"The receive buffer is too large\n");
"The receive buffer is too large\n");
kfree_skb(skb);
return;
}
@ -640,18 +600,9 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
BUG();
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;
priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN,
priv->upld_len);
memcpy(priv->upld_buf, recvbuff + MESSAGE_HEADER_LEN, priv->upld_len);
kfree_skb(skb);
lbs_interrupt(priv);
@ -659,8 +610,6 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
lbs_deb_usbd(&cardp->udev->dev,
"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)
{
struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
struct sk_buff *skb = rinfo->skb;
struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp;
struct if_usb_card *cardp = urb->context;
struct sk_buff *skb = cardp->rx_skb;
struct lbs_private *priv = cardp->priv;
int recvlength = urb->actual_length;
u8 *recvbuff = NULL;
u32 recvtype = 0;
uint8_t *recvbuff = NULL;
uint32_t recvtype = 0;
__le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
lbs_deb_enter(LBS_DEB_USB);
if (recvlength) {
__le32 tmp;
if (urb->status) {
lbs_deb_usbd(&cardp->udev->dev,
"URB status is failed\n");
lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n",
urb->status);
kfree_skb(skb);
goto setup_for_next;
}
recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
memcpy(&tmp, recvbuff, sizeof(u32));
recvtype = le32_to_cpu(tmp);
recvtype = le32_to_cpu(pkt[0]);
lbs_deb_usbd(&cardp->udev->dev,
"Recv length = 0x%x, Recv type = 0x%X\n",
recvlength, recvtype);
@ -716,9 +661,13 @@ static void if_usb_receive(struct urb *urb)
case CMD_TYPE_INDICATION:
/* Event cause handling */
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",
cardp->usb_event_cause);
cardp->usb_event_cause);
/* Icky undocumented magic special case */
if (cardp->usb_event_cause & 0xffff0000) {
lbs_send_tx_feedback(priv);
spin_unlock(&priv->driver_lock);
@ -732,7 +681,7 @@ static void if_usb_receive(struct urb *urb)
goto rx_exit;
default:
lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
recvtype);
recvtype);
kfree_skb(skb);
break;
}
@ -751,55 +700,48 @@ rx_exit:
* @param len number of bytes
* @return 0 or -1
*/
static int if_usb_host_to_card(struct lbs_private *priv,
u8 type,
u8 *payload,
u16 nb)
static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
uint8_t *payload, uint16_t 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,"size after = %d\n", nb);
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;
memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
MESSAGE_HEADER_LEN);
} 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;
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,
nb + MESSAGE_HEADER_LEN);
return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN);
}
/* 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;
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;
}
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;
/* Re-submit rx urb here to avoid event lost issue */
if_usb_submit_rx_urb(cardp);
return 0;
}
@ -809,20 +751,17 @@ static int if_usb_read_event_cause(struct lbs_private *priv)
* 2:Boot from FW in EEPROM
* @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;
int i;
struct bootcmd *bootcmd = cardp->ep_out_buf;
/* Prepare command */
sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
sbootcmd.u8cmd_tag = ivalue;
for (i=0; i<11; i++)
sbootcmd.au8dumy[i]=0x00;
memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
bootcmd->cmd = ivalue;
memset(bootcmd->pad, 0, sizeof(bootcmd->pad));
/* 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;
}
@ -835,10 +774,10 @@ static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue)
* len image length
* @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;
u32 blksize, offset, len;
uint32_t bincmd, exit;
uint32_t blksize, offset, len;
int ret;
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;
static int reset_count = 10;
@ -937,7 +876,7 @@ restart:
/* ... and wait for the process to complete */
wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover);
del_timer_sync(&cardp->fw_timeout);
usb_kill_urb(cardp->rx_urb);
@ -953,11 +892,11 @@ restart:
goto release_fw;
}
release_fw:
release_fw:
release_firmware(cardp->fw);
cardp->fw = NULL;
done:
done:
lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
return ret;
}
@ -966,36 +905,38 @@ done:
#ifdef CONFIG_PM
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;
int ret;
lbs_deb_enter(LBS_DEB_USB);
if (priv->psstate != PS_STATE_FULL_POWER)
return -1;
netif_device_detach(priv->dev);
netif_device_detach(priv->mesh_dev);
ret = lbs_suspend(priv);
if (ret)
goto out;
/* Unlink tx & rx urb */
usb_kill_urb(cardp->tx_urb);
usb_kill_urb(cardp->rx_urb);
out:
lbs_deb_leave(LBS_DEB_USB);
return 0;
return ret;
}
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;
lbs_deb_enter(LBS_DEB_USB);
if_usb_submit_rx_urb(cardp);
netif_device_attach(priv->dev);
netif_device_attach(priv->mesh_dev);
lbs_resume(priv);
lbs_deb_leave(LBS_DEB_USB);
return 0;
@ -1039,5 +980,5 @@ module_init(if_usb_init_module);
module_exit(if_usb_exit_module);
MODULE_DESCRIPTION("8388 USB WLAN Driver");
MODULE_AUTHOR("Marvell International Ltd.");
MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc.");
MODULE_LICENSE("GPL");

View File

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

View File

@ -781,8 +781,8 @@ int lbs_ret_80211_associate(struct lbs_private *priv,
priv->numSNRNF = 0;
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);
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;
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));
memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);

View File

@ -6,7 +6,6 @@
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/freezer.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
@ -256,7 +255,7 @@ static int lbs_add_rtap(struct lbs_private *priv);
static void lbs_remove_rtap(struct lbs_private *priv);
static int lbs_add_mesh(struct lbs_private *priv);
static void lbs_remove_mesh(struct lbs_private *priv);
/**
* Get function for sysfs attribute rtap
@ -345,10 +344,10 @@ static ssize_t lbs_mesh_set(struct device *dev,
if (enable == !!priv->mesh_dev)
return count;
ret = lbs_mesh_config(priv, enable);
ret = lbs_mesh_config(priv, enable, priv->curbssparams.channel);
if (ret)
return ret;
if (enable)
lbs_add_mesh(priv);
else
@ -402,7 +401,7 @@ static int lbs_dev_open(struct net_device *dev)
netif_carrier_on(dev);
} else {
priv->infra_open = 1;
if (priv->connect_status == LBS_CONNECTED)
netif_carrier_on(dev);
else
@ -434,7 +433,7 @@ static int lbs_mesh_stop(struct net_device *dev)
netif_stop_queue(dev);
netif_carrier_off(dev);
spin_unlock_irq(&priv->driver_lock);
return 0;
}
@ -454,7 +453,7 @@ static int lbs_eth_stop(struct net_device *dev)
priv->infra_open = 0;
netif_stop_queue(dev);
spin_unlock_irq(&priv->driver_lock);
return 0;
}
@ -477,6 +476,13 @@ static void lbs_tx_timeout(struct net_device *dev)
to kick it somehow? */
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);
}
@ -489,19 +495,9 @@ void lbs_host_to_card_done(struct lbs_private *priv)
priv->dnld_sent = DNLD_RES_RECEIVED;
/* 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);
/* 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);
}
EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
@ -663,8 +659,6 @@ static int lbs_thread(void *data)
init_waitqueue_entry(&wait, current);
set_freezable();
for (;;) {
int shouldsleep;
@ -675,12 +669,16 @@ static int lbs_thread(void *data)
set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irq(&priv->driver_lock);
if (priv->surpriseremoved)
if (kthread_should_stop())
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)
shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */
else if (priv->intcounter)
shouldsleep = 0; /* Interrupt pending. Deal with it now */
else if (priv->cmd_timed_out)
shouldsleep = 0; /* Command timed out. Recover */
else if (!priv->fw_ready)
shouldsleep = 1; /* Firmware not ready. We're waiting for it */
else if (priv->dnld_sent)
@ -708,17 +706,19 @@ static int lbs_thread(void *data)
set_current_state(TASK_RUNNING);
remove_wait_queue(&priv->waitq, &wait);
try_to_freeze();
lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
priv->intcounter, priv->currenttxskb, priv->dnld_sent);
if (kthread_should_stop() || priv->surpriseremoved) {
lbs_deb_thread("main-thread: break from main thread: surpriseremoved=0x%x\n",
priv->surpriseremoved);
if (kthread_should_stop()) {
lbs_deb_thread("main-thread: break from main thread\n");
break;
}
if (priv->surpriseremoved) {
lbs_deb_thread("adapter removed; waiting to die...\n");
continue;
}
spin_lock_irq(&priv->driver_lock);
@ -749,6 +749,26 @@ static int lbs_thread(void *data)
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 */
if (priv->hisregcpy & MRVDRV_CARDEVENT) {
lbs_deb_thread("main-thread: Card Event Activity\n");
@ -834,6 +854,58 @@ static int lbs_thread(void *data)
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
* HW spec from firmware and set basic parameters to
@ -879,35 +951,21 @@ done:
static void command_timer_fn(unsigned long data)
{
struct lbs_private *priv = (struct lbs_private *)data;
struct cmd_ctrl_node *node;
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);
priv->cur_cmd = NULL;
spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_fw("re-sending same command because of timeout\n");
lbs_queue_cmd(priv, node, 0);
if (!priv->cur_cmd) {
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);
return;
out:
spin_unlock_irqrestore(&priv->driver_lock, flags);
}
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");
priv->mesh_ssid_len = 4;
priv->wol_criteria = 0xffffffff;
priv->wol_gpio = 0xff;
goto done;
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))
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);
@ -1160,11 +1246,13 @@ int lbs_stop_card(struct lbs_private *priv)
lbs_debugfs_remove_one(priv);
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 */
spin_lock_irqsave(&priv->driver_lock, flags);
list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
cmdnode->result = -ENOENT;
cmdnode->cmdwaitqwoken = 1;
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);
if (!spin_trylock(&priv->driver_lock)) {
spin_unlock(&priv->driver_lock);
printk(KERN_CRIT "%s called without driver_lock held\n", __func__);
WARN_ON(1);
}
priv->intcounter++;
if (priv->psstate == PS_STATE_SLEEP)

View File

@ -590,13 +590,13 @@ int lbs_scan_networks(struct lbs_private *priv,
netif_stop_queue(priv->dev);
netif_carrier_off(priv->dev);
if (priv->mesh_dev) {
netif_stop_queue(priv->mesh_dev);
netif_carrier_off(priv->mesh_dev);
netif_stop_queue(priv->mesh_dev);
netif_carrier_off(priv->mesh_dev);
}
/* Prepare to continue an interrupted scan */
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;
/* advance channel list by already-scanned-channels */
if (priv->last_scanned_channel > 0) {
@ -659,11 +659,13 @@ out2:
out:
if (priv->connect_status == LBS_CONNECTED) {
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)) {
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);

View File

@ -93,8 +93,8 @@ int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(priv->mesh_dev);
if (priv->tx_pending_len) {
/* This can happen if packets come in on the mesh and eth
device simultaneously -- there's no mutual exclusion on
/* This can happen if packets come in on the mesh and eth
device simultaneously -- there's no mutual exclusion on
hard_start_xmit() calls between devices. */
lbs_deb_tx("Packet on %s while busy\n", dev->name);
ret = NETDEV_TX_BUSY;

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);
if (!priv->ps_supported) {
if (vwrq->disabled)
return 0;
else
return -EINVAL;
}
/* PS is currently supported only in Infrastructure mode
* 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)
lbs_stop_adhoc_network(priv);
}
priv->curbssparams.channel = fwrq->m;
lbs_mesh_config(priv, 0);
lbs_mesh_config(priv, 1);
lbs_mesh_config(priv, 1, fwrq->m);
lbs_update_channel(priv);
ret = 0;
out:
@ -2010,7 +2016,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
priv->mesh_ssid_len = dwrq->length;
}
lbs_mesh_config(priv, 1);
lbs_mesh_config(priv, 1, priv->curbssparams.channel);
out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;