mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-12-24 05:34:36 +02:00
[package] libertas: use driver from compat-wireless instead of our own (deprecated) one
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@17982 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
parent
4cce3b1620
commit
ab969ad78e
@ -1,59 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2007 - 2008 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=kmod-libertas
|
||||
PKG_RELEASE:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
# XXX: current version needs 'get_unaligned_le16' helper introduced in 2.6.26
|
||||
define KernelPackage/libertas
|
||||
SUBMENU:=Wireless Drivers
|
||||
DEPENDS:=+kmod-ieee80211 @LINUX_2_6 @!LINUX_2_6_21||!LINUX_2_6_25
|
||||
TITLE:=Marvell 88W8015 Wireless Driver
|
||||
FILES:= \
|
||||
$(PKG_BUILD_DIR)/libertas.$(LINUX_KMOD_SUFFIX) \
|
||||
$(PKG_BUILD_DIR)/usb8xxx.$(LINUX_KMOD_SUFFIX)
|
||||
AUTOLOAD:=$(call AutoLoad,30,libertas usb8xxx)
|
||||
endef
|
||||
|
||||
FW_NAME:=usb8388-5.110.22.p23.bin
|
||||
|
||||
define Download/firmware
|
||||
URL:=http://dev.laptop.org/pub/firmware/libertas
|
||||
FILE:=$(FW_NAME)
|
||||
MD5SUM=5e38f55719df3d0c58dd3bd02575a09c
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
$(Build/Patch)
|
||||
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) -DCONFIG_LIBERTAS_DEBUG -I$(STAGING_DIR)/usr/include/mac80211" \
|
||||
modules
|
||||
endef
|
||||
|
||||
define KernelPackage/libertas/install
|
||||
$(INSTALL_DIR) $(1)/lib/firmware
|
||||
$(INSTALL_BIN) $(DL_DIR)/$(FW_NAME) $(1)/lib/firmware/usb8388.bin
|
||||
$(INSTALL_DATA) ./files/LICENSE $(1)/lib/firmware/usb8388.LICENSE
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,libertas))
|
||||
$(eval $(call Download,firmware))
|
@ -1,33 +0,0 @@
|
||||
Copyright (c) 2006, One Laptop per Child and Marvell Corporation.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution. Redistribution and use in binary form, without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions must reproduce the above copyright notice and the
|
||||
following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
* Neither the name of Marvell Corporation nor the names of its suppliers
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
* No reverse engineering, decompilation, or disassembly of this software
|
||||
is permitted.
|
||||
* You may not use or attempt to use this software in conjunction with
|
||||
any product that is offered by a third party as a replacement,
|
||||
substitute or alternative to a Marvell Product where a Marvell Product
|
||||
is defined as a proprietary wireless LAN embedded client solution of
|
||||
Marvell or a Marvell Affiliate.
|
||||
|
||||
DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
|
||||
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
@ -1,144 +0,0 @@
|
||||
diff --git a/scan.c b/scan.c
|
||||
index 387d487..d9cde10 100644
|
||||
--- a/scan.c
|
||||
+++ b/scan.c
|
||||
@@ -4,6 +4,7 @@
|
||||
* IOCTL handlers as well as command preperation and response routines
|
||||
* for sending scan commands to the firmware.
|
||||
*/
|
||||
+#include <linux/version.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
@@ -13,6 +14,14 @@
|
||||
#include "scan.h"
|
||||
#include "cmd.h"
|
||||
|
||||
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
|
||||
+#define IWE(func, ...) func(info, __VA_ARGS__)
|
||||
+#define LCP_LEN iwe_stream_lcp_len(info)
|
||||
+#else
|
||||
+#define IWE(func, ...) func(__VA_ARGS__)
|
||||
+#define LCP_LEN IW_EV_LCP_LEN
|
||||
+#endif
|
||||
+
|
||||
//! Approximate amount of data needed to pass a scan result back to iwlist
|
||||
#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
|
||||
+ IW_ESSID_MAX_SIZE \
|
||||
@@ -776,6 +785,7 @@ out:
|
||||
#define MAX_CUSTOM_LEN 64
|
||||
|
||||
static inline char *lbs_translate_scan(struct lbs_private *priv,
|
||||
+ struct iw_request_info *info,
|
||||
char *start, char *stop,
|
||||
struct bss_descriptor *bss)
|
||||
{
|
||||
@@ -801,24 +811,24 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
||||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
|
||||
- start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
|
||||
+ start = IWE(iwe_stream_add_event, start, stop, &iwe, IW_EV_ADDR_LEN);
|
||||
|
||||
/* SSID */
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.flags = 1;
|
||||
iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE);
|
||||
- start = iwe_stream_add_point(start, stop, &iwe, bss->ssid);
|
||||
+ start = IWE(iwe_stream_add_point, start, stop, &iwe, bss->ssid);
|
||||
|
||||
/* Mode */
|
||||
iwe.cmd = SIOCGIWMODE;
|
||||
iwe.u.mode = bss->mode;
|
||||
- start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
|
||||
+ start = IWE(iwe_stream_add_event, start, stop, &iwe, IW_EV_UINT_LEN);
|
||||
|
||||
/* Frequency */
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = (long)cfp->freq * 100000;
|
||||
iwe.u.freq.e = 1;
|
||||
- start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
|
||||
+ start = IWE(iwe_stream_add_event, start, stop, &iwe, IW_EV_FREQ_LEN);
|
||||
|
||||
/* Add quality statistics */
|
||||
iwe.cmd = IWEVQUAL;
|
||||
@@ -852,7 +862,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
||||
nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
|
||||
iwe.u.qual.level = CAL_RSSI(snr, nf);
|
||||
}
|
||||
- start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
|
||||
+ start = IWE(iwe_stream_add_event, start, stop, &iwe, IW_EV_QUAL_LEN);
|
||||
|
||||
/* Add encryption capability */
|
||||
iwe.cmd = SIOCGIWENCODE;
|
||||
@@ -862,9 +872,9 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
}
|
||||
iwe.u.data.length = 0;
|
||||
- start = iwe_stream_add_point(start, stop, &iwe, bss->ssid);
|
||||
+ start = IWE(iwe_stream_add_point, start, stop, &iwe, bss->ssid);
|
||||
|
||||
- current_val = start + IW_EV_LCP_LEN;
|
||||
+ current_val = start + LCP_LEN;
|
||||
|
||||
iwe.cmd = SIOCGIWRATE;
|
||||
iwe.u.bitrate.fixed = 0;
|
||||
@@ -874,19 +884,19 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
||||
for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
|
||||
/* Bit rate given in 500 kb/s units */
|
||||
iwe.u.bitrate.value = bss->rates[j] * 500000;
|
||||
- current_val = iwe_stream_add_value(start, current_val,
|
||||
+ current_val = IWE(iwe_stream_add_value, start, current_val,
|
||||
stop, &iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate
|
||||
&& !lbs_ssid_cmp(priv->curbssparams.ssid,
|
||||
priv->curbssparams.ssid_len,
|
||||
bss->ssid, bss->ssid_len)) {
|
||||
iwe.u.bitrate.value = 22 * 500000;
|
||||
- current_val = iwe_stream_add_value(start, current_val,
|
||||
+ current_val = IWE(iwe_stream_add_value, start, current_val,
|
||||
stop, &iwe, IW_EV_PARAM_LEN);
|
||||
}
|
||||
/* Check if we added any event */
|
||||
- if((current_val - start) > IW_EV_LCP_LEN)
|
||||
+ if((current_val - start) > LCP_LEN)
|
||||
start = current_val;
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
@@ -895,7 +905,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
||||
memcpy(buf, bss->wpa_ie, bss->wpa_ie_len);
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = bss->wpa_ie_len;
|
||||
- start = iwe_stream_add_point(start, stop, &iwe, buf);
|
||||
+ start = IWE(iwe_stream_add_point, start, stop, &iwe, buf);
|
||||
}
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
@@ -904,7 +914,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
||||
memcpy(buf, bss->rsn_ie, bss->rsn_ie_len);
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = bss->rsn_ie_len;
|
||||
- start = iwe_stream_add_point(start, stop, &iwe, buf);
|
||||
+ start = IWE(iwe_stream_add_point, start, stop, &iwe, buf);
|
||||
}
|
||||
|
||||
if (bss->mesh) {
|
||||
@@ -915,7 +925,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
|
||||
p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc");
|
||||
iwe.u.data.length = p - custom;
|
||||
if (iwe.u.data.length)
|
||||
- start = iwe_stream_add_point(start, stop, &iwe, custom);
|
||||
+ start = IWE(iwe_stream_add_point, start, stop, &iwe, custom);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -1036,7 +1046,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
|
||||
}
|
||||
|
||||
/* Translate to WE format this entry */
|
||||
- next_ev = lbs_translate_scan(priv, ev, stop, iter_bss);
|
||||
+ next_ev = lbs_translate_scan(priv, info, ev, stop, iter_bss);
|
||||
if (next_ev == NULL)
|
||||
continue;
|
||||
ev = next_ev;
|
@ -1,698 +0,0 @@
|
||||
/**
|
||||
* This file contains functions for 802.11D.
|
||||
*/
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/wireless.h>
|
||||
|
||||
#include "host.h"
|
||||
#include "decl.h"
|
||||
#include "11d.h"
|
||||
#include "dev.h"
|
||||
#include "wext.h"
|
||||
|
||||
#define TX_PWR_DEFAULT 10
|
||||
|
||||
static struct region_code_mapping region_code_mapping[] = {
|
||||
{"US ", 0x10}, /* US FCC */
|
||||
{"CA ", 0x10}, /* IC Canada */
|
||||
{"SG ", 0x10}, /* Singapore */
|
||||
{"EU ", 0x30}, /* ETSI */
|
||||
{"AU ", 0x30}, /* Australia */
|
||||
{"KR ", 0x30}, /* Republic Of Korea */
|
||||
{"ES ", 0x31}, /* Spain */
|
||||
{"FR ", 0x32}, /* France */
|
||||
{"JP ", 0x40}, /* Japan */
|
||||
};
|
||||
|
||||
/* Following 2 structure defines the supported channels */
|
||||
static struct chan_freq_power channel_freq_power_UN_BG[] = {
|
||||
{1, 2412, TX_PWR_DEFAULT},
|
||||
{2, 2417, TX_PWR_DEFAULT},
|
||||
{3, 2422, TX_PWR_DEFAULT},
|
||||
{4, 2427, TX_PWR_DEFAULT},
|
||||
{5, 2432, TX_PWR_DEFAULT},
|
||||
{6, 2437, TX_PWR_DEFAULT},
|
||||
{7, 2442, TX_PWR_DEFAULT},
|
||||
{8, 2447, TX_PWR_DEFAULT},
|
||||
{9, 2452, TX_PWR_DEFAULT},
|
||||
{10, 2457, TX_PWR_DEFAULT},
|
||||
{11, 2462, TX_PWR_DEFAULT},
|
||||
{12, 2467, TX_PWR_DEFAULT},
|
||||
{13, 2472, TX_PWR_DEFAULT},
|
||||
{14, 2484, TX_PWR_DEFAULT}
|
||||
};
|
||||
|
||||
static u8 lbs_region_2_code(u8 *region)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
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++) {
|
||||
if (!memcmp(region, region_code_mapping[i].region,
|
||||
COUNTRY_CODE_LEN))
|
||||
return (region_code_mapping[i].code);
|
||||
}
|
||||
|
||||
/* default is US */
|
||||
return (region_code_mapping[0].code);
|
||||
}
|
||||
|
||||
static u8 *lbs_code_2_region(u8 code)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
|
||||
if (region_code_mapping[i].code == code)
|
||||
return (region_code_mapping[i].region);
|
||||
}
|
||||
/* default is US */
|
||||
return (region_code_mapping[0].region);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function finds the nrchan-th chan after the firstchan
|
||||
* @param band band
|
||||
* @param firstchan first channel number
|
||||
* @param nrchan number of channels
|
||||
* @return the nrchan-th chan number
|
||||
*/
|
||||
static u8 lbs_get_chan_11d(u8 firstchan, u8 nrchan, u8 *chan)
|
||||
/*find the nrchan-th chan after the firstchan*/
|
||||
{
|
||||
u8 i;
|
||||
struct chan_freq_power *cfp;
|
||||
u8 cfp_no;
|
||||
|
||||
cfp = channel_freq_power_UN_BG;
|
||||
cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG);
|
||||
|
||||
for (i = 0; i < cfp_no; i++) {
|
||||
if ((cfp + i)->channel == firstchan) {
|
||||
lbs_deb_11d("firstchan found\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < cfp_no) {
|
||||
/*if beyond the boundary */
|
||||
if (i + nrchan < cfp_no) {
|
||||
*chan = (cfp + i + nrchan)->channel;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function Checks if chan txpwr is learned from AP/IBSS
|
||||
* @param chan chan number
|
||||
* @param parsed_region_chan pointer to parsed_region_chan_11d
|
||||
* @return TRUE; FALSE
|
||||
*/
|
||||
static u8 lbs_channel_known_11d(u8 chan,
|
||||
struct parsed_region_chan_11d * parsed_region_chan)
|
||||
{
|
||||
struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
|
||||
u8 nr_chan = parsed_region_chan->nr_chan;
|
||||
u8 i = 0;
|
||||
|
||||
lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr,
|
||||
sizeof(struct chan_power_11d) * nr_chan);
|
||||
|
||||
for (i = 0; i < nr_chan; i++) {
|
||||
if (chan == chanpwr[i].chan) {
|
||||
lbs_deb_11d("found chan %d\n", chan);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
lbs_deb_11d("chan %d not found\n", chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 lbs_chan_2_freq(u8 chan)
|
||||
{
|
||||
struct chan_freq_power *cf;
|
||||
u16 i;
|
||||
u32 freq = 0;
|
||||
|
||||
cf = channel_freq_power_UN_BG;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) {
|
||||
if (chan == cf[i].channel)
|
||||
freq = cf[i].freq;
|
||||
}
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
static int generate_domain_info_11d(struct parsed_region_chan_11d
|
||||
*parsed_region_chan,
|
||||
struct lbs_802_11d_domain_reg *domaininfo)
|
||||
{
|
||||
u8 nr_subband = 0;
|
||||
|
||||
u8 nr_chan = parsed_region_chan->nr_chan;
|
||||
u8 nr_parsedchan = 0;
|
||||
|
||||
u8 firstchan = 0, nextchan = 0, maxpwr = 0;
|
||||
|
||||
u8 i, flag = 0;
|
||||
|
||||
memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
|
||||
COUNTRY_CODE_LEN);
|
||||
|
||||
lbs_deb_11d("nrchan %d\n", nr_chan);
|
||||
lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan,
|
||||
sizeof(struct parsed_region_chan_11d));
|
||||
|
||||
for (i = 0; i < nr_chan; i++) {
|
||||
if (!flag) {
|
||||
flag = 1;
|
||||
nextchan = firstchan =
|
||||
parsed_region_chan->chanpwr[i].chan;
|
||||
maxpwr = parsed_region_chan->chanpwr[i].pwr;
|
||||
nr_parsedchan = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
|
||||
parsed_region_chan->chanpwr[i].pwr == maxpwr) {
|
||||
nextchan++;
|
||||
nr_parsedchan++;
|
||||
} else {
|
||||
domaininfo->subband[nr_subband].firstchan = firstchan;
|
||||
domaininfo->subband[nr_subband].nrchan =
|
||||
nr_parsedchan;
|
||||
domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
|
||||
nr_subband++;
|
||||
nextchan = firstchan =
|
||||
parsed_region_chan->chanpwr[i].chan;
|
||||
maxpwr = parsed_region_chan->chanpwr[i].pwr;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
domaininfo->subband[nr_subband].firstchan = firstchan;
|
||||
domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
|
||||
domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
|
||||
nr_subband++;
|
||||
}
|
||||
domaininfo->nr_subband = nr_subband;
|
||||
|
||||
lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
|
||||
lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
|
||||
COUNTRY_CODE_LEN + 1 +
|
||||
sizeof(struct ieeetypes_subbandset) * nr_subband);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
|
||||
* @param region_chan pointer to struct region_channel
|
||||
* @param *parsed_region_chan pointer to parsed_region_chan_11d
|
||||
* @return N/A
|
||||
*/
|
||||
static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_chan,
|
||||
struct parsed_region_chan_11d *
|
||||
parsed_region_chan)
|
||||
{
|
||||
u8 i;
|
||||
struct chan_freq_power *cfp;
|
||||
|
||||
if (region_chan == NULL) {
|
||||
lbs_deb_11d("region_chan is NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cfp = region_chan->CFP;
|
||||
if (cfp == NULL) {
|
||||
lbs_deb_11d("cfp is NULL \n");
|
||||
return;
|
||||
}
|
||||
|
||||
parsed_region_chan->band = region_chan->band;
|
||||
parsed_region_chan->region = region_chan->region;
|
||||
memcpy(parsed_region_chan->countrycode,
|
||||
lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
|
||||
|
||||
lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
|
||||
parsed_region_chan->band);
|
||||
|
||||
for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
|
||||
parsed_region_chan->chanpwr[i].chan = cfp->channel;
|
||||
parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
|
||||
lbs_deb_11d("chan %d, pwr %d\n",
|
||||
parsed_region_chan->chanpwr[i].chan,
|
||||
parsed_region_chan->chanpwr[i].pwr);
|
||||
}
|
||||
parsed_region_chan->nr_chan = region_chan->nrcfp;
|
||||
|
||||
lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
|
||||
* @param region region ID
|
||||
* @param band band
|
||||
* @param chan chan
|
||||
* @return TRUE;FALSE
|
||||
*/
|
||||
static u8 lbs_region_chan_supported_11d(u8 region, u8 chan)
|
||||
{
|
||||
struct chan_freq_power *cfp;
|
||||
int cfp_no;
|
||||
u8 idx;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_11D);
|
||||
|
||||
cfp = lbs_get_region_cfp_table(region, &cfp_no);
|
||||
if (cfp == NULL)
|
||||
return 0;
|
||||
|
||||
for (idx = 0; idx < cfp_no; idx++) {
|
||||
if (chan == (cfp + idx)->channel) {
|
||||
/* If Mrvl Chip Supported? */
|
||||
if ((cfp + idx)->unsupported) {
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/*chan is not in the region table */
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function checks if chan txpwr is learned from AP/IBSS
|
||||
* @param chan chan number
|
||||
* @param parsed_region_chan pointer to parsed_region_chan_11d
|
||||
* @return 0
|
||||
*/
|
||||
static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
|
||||
countryinfo,
|
||||
u8 band,
|
||||
struct parsed_region_chan_11d *
|
||||
parsed_region_chan)
|
||||
{
|
||||
u8 nr_subband, nrchan;
|
||||
u8 lastchan, firstchan;
|
||||
u8 region;
|
||||
u8 curchan = 0;
|
||||
|
||||
u8 idx = 0; /*chan index in parsed_region_chan */
|
||||
|
||||
u8 j, i;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_11D);
|
||||
|
||||
/*validation Rules:
|
||||
1. valid region Code
|
||||
2. First Chan increment
|
||||
3. channel range no overlap
|
||||
4. channel is valid?
|
||||
5. channel is supported by region?
|
||||
6. Others
|
||||
*/
|
||||
|
||||
lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
|
||||
|
||||
if ((*(countryinfo->countrycode)) == 0
|
||||
|| (countryinfo->len <= COUNTRY_CODE_LEN)) {
|
||||
/* No region Info or Wrong region info: treat as No 11D info */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*Step1: check region_code */
|
||||
parsed_region_chan->region = region =
|
||||
lbs_region_2_code(countryinfo->countrycode);
|
||||
|
||||
lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
|
||||
lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
|
||||
COUNTRY_CODE_LEN);
|
||||
|
||||
parsed_region_chan->band = band;
|
||||
|
||||
memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
|
||||
COUNTRY_CODE_LEN);
|
||||
|
||||
nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
|
||||
sizeof(struct ieeetypes_subbandset);
|
||||
|
||||
for (j = 0, lastchan = 0; j < nr_subband; j++) {
|
||||
|
||||
if (countryinfo->subband[j].firstchan <= lastchan) {
|
||||
/*Step2&3. Check First Chan Num increment and no overlap */
|
||||
lbs_deb_11d("chan %d>%d, overlap\n",
|
||||
countryinfo->subband[j].firstchan, lastchan);
|
||||
continue;
|
||||
}
|
||||
|
||||
firstchan = countryinfo->subband[j].firstchan;
|
||||
nrchan = countryinfo->subband[j].nrchan;
|
||||
|
||||
for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
|
||||
/*step4: channel is supported? */
|
||||
|
||||
if (!lbs_get_chan_11d(firstchan, i, &curchan)) {
|
||||
/* Chan is not found in UN table */
|
||||
lbs_deb_11d("chan is not supported: %d \n", i);
|
||||
break;
|
||||
}
|
||||
|
||||
lastchan = curchan;
|
||||
|
||||
if (lbs_region_chan_supported_11d(region, curchan)) {
|
||||
/*step5: Check if curchan is supported by mrvl in region */
|
||||
parsed_region_chan->chanpwr[idx].chan = curchan;
|
||||
parsed_region_chan->chanpwr[idx].pwr =
|
||||
countryinfo->subband[j].maxtxpwr;
|
||||
idx++;
|
||||
} else {
|
||||
/*not supported and ignore the chan */
|
||||
lbs_deb_11d(
|
||||
"i %d, chan %d unsupported in region %x, band %d\n",
|
||||
i, curchan, region, band);
|
||||
}
|
||||
}
|
||||
|
||||
/*Step6: Add other checking if any */
|
||||
|
||||
}
|
||||
|
||||
parsed_region_chan->nr_chan = idx;
|
||||
|
||||
lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
|
||||
lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
|
||||
2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
|
||||
|
||||
done:
|
||||
lbs_deb_enter(LBS_DEB_11D);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function calculates the scan type for channels
|
||||
* @param chan chan number
|
||||
* @param parsed_region_chan pointer to parsed_region_chan_11d
|
||||
* @return PASSIVE if chan is unknown; ACTIVE if chan is known
|
||||
*/
|
||||
u8 lbs_get_scan_type_11d(u8 chan,
|
||||
struct parsed_region_chan_11d * parsed_region_chan)
|
||||
{
|
||||
u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_11D);
|
||||
|
||||
if (lbs_channel_known_11d(chan, parsed_region_chan)) {
|
||||
lbs_deb_11d("found, do active scan\n");
|
||||
scan_type = CMD_SCAN_TYPE_ACTIVE;
|
||||
} else {
|
||||
lbs_deb_11d("not found, do passive scan\n");
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
|
||||
return scan_type;
|
||||
|
||||
}
|
||||
|
||||
void lbs_init_11d(struct lbs_private *priv)
|
||||
{
|
||||
priv->enable11d = 0;
|
||||
memset(&(priv->parsed_region_chan), 0,
|
||||
sizeof(struct parsed_region_chan_11d));
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function sets DOMAIN INFO to FW
|
||||
* @param priv pointer to struct lbs_private
|
||||
* @return 0; -1
|
||||
*/
|
||||
static int set_domain_info_11d(struct lbs_private *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!priv->enable11d) {
|
||||
lbs_deb_11d("dnld domain Info with 11d disabled\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
|
||||
CMD_ACT_SET,
|
||||
CMD_OPTION_WAITFORRSP, 0, NULL);
|
||||
if (ret)
|
||||
lbs_deb_11d("fail to dnld domain info\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function setups scan channels
|
||||
* @param priv pointer to struct lbs_private
|
||||
* @param band band
|
||||
* @return 0
|
||||
*/
|
||||
int lbs_set_universaltable(struct lbs_private *priv, u8 band)
|
||||
{
|
||||
u16 size = sizeof(struct chan_freq_power);
|
||||
u16 i = 0;
|
||||
|
||||
memset(priv->universal_channel, 0,
|
||||
sizeof(priv->universal_channel));
|
||||
|
||||
priv->universal_channel[i].nrcfp =
|
||||
sizeof(channel_freq_power_UN_BG) / size;
|
||||
lbs_deb_11d("BG-band nrcfp %d\n",
|
||||
priv->universal_channel[i].nrcfp);
|
||||
|
||||
priv->universal_channel[i].CFP = channel_freq_power_UN_BG;
|
||||
priv->universal_channel[i].valid = 1;
|
||||
priv->universal_channel[i].region = UNIVERSAL_REGION_CODE;
|
||||
priv->universal_channel[i].band = band;
|
||||
i++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function implements command CMD_802_11D_DOMAIN_INFO
|
||||
* @param priv pointer to struct lbs_private
|
||||
* @param cmd pointer to cmd buffer
|
||||
* @param cmdno cmd ID
|
||||
* @param cmdOption cmd action
|
||||
* @return 0
|
||||
*/
|
||||
int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd, u16 cmdno,
|
||||
u16 cmdoption)
|
||||
{
|
||||
struct cmd_ds_802_11d_domain_info *pdomaininfo =
|
||||
&cmd->params.domaininfo;
|
||||
struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
|
||||
u8 nr_subband = priv->domainreg.nr_subband;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_11D);
|
||||
|
||||
lbs_deb_11d("nr_subband=%x\n", nr_subband);
|
||||
|
||||
cmd->command = cpu_to_le16(cmdno);
|
||||
pdomaininfo->action = cpu_to_le16(cmdoption);
|
||||
if (cmdoption == CMD_ACT_GET) {
|
||||
cmd->size =
|
||||
cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
|
||||
lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
|
||||
le16_to_cpu(cmd->size));
|
||||
goto done;
|
||||
}
|
||||
|
||||
domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
|
||||
memcpy(domain->countrycode, priv->domainreg.countrycode,
|
||||
sizeof(domain->countrycode));
|
||||
|
||||
domain->header.len =
|
||||
cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
|
||||
sizeof(domain->countrycode));
|
||||
|
||||
if (nr_subband) {
|
||||
memcpy(domain->subband, priv->domainreg.subband,
|
||||
nr_subband * sizeof(struct ieeetypes_subbandset));
|
||||
|
||||
cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
|
||||
le16_to_cpu(domain->header.len) +
|
||||
sizeof(struct mrvlietypesheader) +
|
||||
S_DS_GEN);
|
||||
} else {
|
||||
cmd->size =
|
||||
cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
|
||||
}
|
||||
|
||||
lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
|
||||
|
||||
done:
|
||||
lbs_deb_enter(LBS_DEB_11D);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function parses countryinfo from AP and download country info to FW
|
||||
* @param priv pointer to struct lbs_private
|
||||
* @param resp pointer to command response buffer
|
||||
* @return 0; -1
|
||||
*/
|
||||
int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
|
||||
{
|
||||
struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
|
||||
struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
|
||||
u16 action = le16_to_cpu(domaininfo->action);
|
||||
s16 ret = 0;
|
||||
u8 nr_subband = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_11D);
|
||||
|
||||
lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
|
||||
(int)le16_to_cpu(resp->size));
|
||||
|
||||
nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
|
||||
sizeof(struct ieeetypes_subbandset);
|
||||
|
||||
lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
|
||||
|
||||
if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
|
||||
lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case CMD_ACT_SET: /*Proc Set action */
|
||||
break;
|
||||
|
||||
case CMD_ACT_GET:
|
||||
break;
|
||||
default:
|
||||
lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function parses countryinfo from AP and download country info to FW
|
||||
* @param priv pointer to struct lbs_private
|
||||
* @return 0; -1
|
||||
*/
|
||||
int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
|
||||
struct bss_descriptor * bss)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_11D);
|
||||
if (priv->enable11d) {
|
||||
memset(&priv->parsed_region_chan, 0,
|
||||
sizeof(struct parsed_region_chan_11d));
|
||||
ret = parse_domain_info_11d(&bss->countryinfo, 0,
|
||||
&priv->parsed_region_chan);
|
||||
|
||||
if (ret == -1) {
|
||||
lbs_deb_11d("error parsing domain_info from AP\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
memset(&priv->domainreg, 0,
|
||||
sizeof(struct lbs_802_11d_domain_reg));
|
||||
generate_domain_info_11d(&priv->parsed_region_chan,
|
||||
&priv->domainreg);
|
||||
|
||||
ret = set_domain_info_11d(priv);
|
||||
|
||||
if (ret) {
|
||||
lbs_deb_11d("error setting domain info\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function generates 11D info from user specified regioncode and download to FW
|
||||
* @param priv pointer to struct lbs_private
|
||||
* @return 0; -1
|
||||
*/
|
||||
int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv)
|
||||
{
|
||||
int ret;
|
||||
struct region_channel *region_chan;
|
||||
u8 j;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_11D);
|
||||
lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band);
|
||||
|
||||
if (priv->enable11d) {
|
||||
/* update parsed_region_chan_11; dnld domaininf to FW */
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) {
|
||||
region_chan = &priv->region_channel[j];
|
||||
|
||||
lbs_deb_11d("%d region_chan->band %d\n", j,
|
||||
region_chan->band);
|
||||
|
||||
if (!region_chan || !region_chan->valid
|
||||
|| !region_chan->CFP)
|
||||
continue;
|
||||
if (region_chan->band != priv->curbssparams.band)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (j >= ARRAY_SIZE(priv->region_channel)) {
|
||||
lbs_deb_11d("region_chan not found, band %d\n",
|
||||
priv->curbssparams.band);
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memset(&priv->parsed_region_chan, 0,
|
||||
sizeof(struct parsed_region_chan_11d));
|
||||
lbs_generate_parsed_region_chan_11d(region_chan,
|
||||
&priv->
|
||||
parsed_region_chan);
|
||||
|
||||
memset(&priv->domainreg, 0,
|
||||
sizeof(struct lbs_802_11d_domain_reg));
|
||||
generate_domain_info_11d(&priv->parsed_region_chan,
|
||||
&priv->domainreg);
|
||||
|
||||
ret = set_domain_info_11d(priv);
|
||||
|
||||
if (ret) {
|
||||
lbs_deb_11d("error setting domain info\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
/**
|
||||
* This header file contains data structures and
|
||||
* function declarations of 802.11d
|
||||
*/
|
||||
#ifndef _LBS_11D_
|
||||
#define _LBS_11D_
|
||||
|
||||
#include "types.h"
|
||||
#include "defs.h"
|
||||
|
||||
#define UNIVERSAL_REGION_CODE 0xff
|
||||
|
||||
/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr)
|
||||
*/
|
||||
#define MRVDRV_MAX_SUBBAND_802_11D 83
|
||||
|
||||
#define COUNTRY_CODE_LEN 3
|
||||
#define MAX_NO_OF_CHAN 40
|
||||
|
||||
struct cmd_ds_command;
|
||||
|
||||
/** Data structure for Country IE*/
|
||||
struct ieeetypes_subbandset {
|
||||
u8 firstchan;
|
||||
u8 nrchan;
|
||||
u8 maxtxpwr;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieeetypes_countryinfoset {
|
||||
u8 element_id;
|
||||
u8 len;
|
||||
u8 countrycode[COUNTRY_CODE_LEN];
|
||||
struct ieeetypes_subbandset subband[1];
|
||||
};
|
||||
|
||||
struct ieeetypes_countryinfofullset {
|
||||
u8 element_id;
|
||||
u8 len;
|
||||
u8 countrycode[COUNTRY_CODE_LEN];
|
||||
struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_domainparamset {
|
||||
struct mrvlietypesheader header;
|
||||
u8 countrycode[COUNTRY_CODE_LEN];
|
||||
struct ieeetypes_subbandset subband[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_802_11d_domain_info {
|
||||
__le16 action;
|
||||
struct mrvlietypes_domainparamset domain;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/** domain regulatory information */
|
||||
struct lbs_802_11d_domain_reg {
|
||||
/** country Code*/
|
||||
u8 countrycode[COUNTRY_CODE_LEN];
|
||||
/** No. of subband*/
|
||||
u8 nr_subband;
|
||||
struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
|
||||
};
|
||||
|
||||
struct chan_power_11d {
|
||||
u8 chan;
|
||||
u8 pwr;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct parsed_region_chan_11d {
|
||||
u8 band;
|
||||
u8 region;
|
||||
s8 countrycode[COUNTRY_CODE_LEN];
|
||||
struct chan_power_11d chanpwr[MAX_NO_OF_CHAN];
|
||||
u8 nr_chan;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct region_code_mapping {
|
||||
u8 region[COUNTRY_CODE_LEN];
|
||||
u8 code;
|
||||
};
|
||||
|
||||
struct lbs_private;
|
||||
|
||||
u8 lbs_get_scan_type_11d(u8 chan,
|
||||
struct parsed_region_chan_11d *parsed_region_chan);
|
||||
|
||||
u32 lbs_chan_2_freq(u8 chan);
|
||||
|
||||
void lbs_init_11d(struct lbs_private *priv);
|
||||
|
||||
int lbs_set_universaltable(struct lbs_private *priv, u8 band);
|
||||
|
||||
int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd, u16 cmdno,
|
||||
u16 cmdOption);
|
||||
|
||||
int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp);
|
||||
|
||||
struct bss_descriptor;
|
||||
int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
|
||||
struct bss_descriptor * bss);
|
||||
|
||||
int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv);
|
||||
|
||||
#endif
|
@ -1,16 +0,0 @@
|
||||
Copyright (c) 2003-2006, Marvell International Ltd.
|
||||
All Rights Reserved
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of version 2 of the GNU General Public License as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
@ -1,15 +0,0 @@
|
||||
libertas-objs := main.o wext.o \
|
||||
rx.o tx.o cmd.o \
|
||||
cmdresp.o scan.o \
|
||||
11d.o \
|
||||
debugfs.o \
|
||||
ethtool.o assoc.o ioctl.o
|
||||
|
||||
usb8xxx-objs += if_usb.o
|
||||
libertas_cs-objs += if_cs.o
|
||||
libertas_sdio-objs += if_sdio.o
|
||||
|
||||
obj-$(CONFIG_LIBERTAS) += libertas.o
|
||||
obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
|
||||
obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o
|
||||
obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o
|
@ -1,646 +0,0 @@
|
||||
================================================================================
|
||||
README for USB8388
|
||||
|
||||
(c) Copyright © 2003-2006, Marvell International Ltd.
|
||||
All Rights Reserved
|
||||
|
||||
This software file (the "File") is distributed by Marvell International
|
||||
Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
(the "License"). You may use, redistribute and/or modify this File in
|
||||
accordance with the terms and conditions of the License, a copy of which
|
||||
is available along with the File in the license.txt file or by writing to
|
||||
the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
|
||||
|
||||
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
||||
this warranty disclaimer.
|
||||
================================================================================
|
||||
|
||||
=====================
|
||||
DRIVER LOADING
|
||||
=====================
|
||||
|
||||
o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/
|
||||
|
||||
o. Load driver by using the following command:
|
||||
|
||||
insmod usb8388.ko [fw_name=usb8388.bin]
|
||||
|
||||
=====================
|
||||
IWPRIV COMMAND
|
||||
=====================
|
||||
|
||||
NAME
|
||||
This manual describes the usage of private commands used in Marvell WLAN
|
||||
Linux Driver. All the commands available in Wlanconfig will not be available
|
||||
in the iwpriv.
|
||||
|
||||
SYNOPSIS
|
||||
iwpriv <ethX> <command> [sub-command] ...
|
||||
|
||||
iwpriv ethX setregioncode <n>
|
||||
iwpriv ethX getregioncode
|
||||
|
||||
Version 5 Command:
|
||||
iwpriv ethX ledgpio <n>
|
||||
|
||||
BT Commands:
|
||||
The blinding table (BT) contains a list of mac addresses that will be,
|
||||
by default, ignored by the firmware. It is also possible to invert this
|
||||
behavior so that we will ignore all traffic except for the portion
|
||||
coming from mac addresess in the list. It is primarily used for
|
||||
debugging and testing networks. It can be edited and inspected with
|
||||
the following commands:
|
||||
|
||||
iwpriv ethX bt_reset
|
||||
iwpriv ethX bt_add <mac_address>
|
||||
iwpriv ethX bt_del <mac_address>
|
||||
iwpriv ethX bt_list <id>
|
||||
iwpriv ethX bt_get_invert <n>
|
||||
iwpriv ethX bt_set_invert <n>
|
||||
|
||||
FWT Commands:
|
||||
The forwarding table (FWT) is a feature used to manage mesh network
|
||||
routing in the firmware. The FWT is essentially a routing table that
|
||||
associates a destination mac address (da) with a next hop receiver
|
||||
address (ra). The FWT can be inspected and edited with the following
|
||||
iwpriv commands, which are described in greater detail below.
|
||||
Eventually, the table will be automatically maintained by a custom
|
||||
routing protocol.
|
||||
|
||||
NOTE: FWT commands replace the previous DFT commands. What were the DFT
|
||||
commands?, you might ask. They were an earlier API to the firmware that
|
||||
implemented a simple MAC-layer forwarding mechanism. In the unlikely
|
||||
event that you were using these commands, you must migrate to the new
|
||||
FWT commands which can be used to achieve the same functionality.
|
||||
|
||||
iwpriv ethX fwt_add [parameters]
|
||||
iwpriv ethX fwt_del [parameters]
|
||||
iwpriv ethX fwt_lookup [parameters]
|
||||
iwpriv ethX fwt_list [parameters]
|
||||
iwpriv ethX fwt_list_route [parameters]
|
||||
iwpriv ethX fwt_list_neigh [parameters]
|
||||
iwpriv ethX fwt_reset [parameters]
|
||||
iwpriv ethX fwt_cleanup
|
||||
iwpriv ethX fwt_time
|
||||
|
||||
MESH Commands:
|
||||
|
||||
The MESH commands are used to configure various features of the mesh
|
||||
routing protocol. The following commands are supported:
|
||||
|
||||
iwpriv ethX mesh_get_ttl
|
||||
iwpriv ethX mesh_set_ttl ttl
|
||||
iwpriv ethX mesh_get_bcastr rate
|
||||
iwpriv ethX mesh_set_bcastr rate
|
||||
iwpriv ethX get_rreq_delay
|
||||
iwpriv ethX set_rreq_delay delay
|
||||
iwpriv ethX get_route_exp
|
||||
iwpriv ethX set_route_exp time
|
||||
iwpriv ethX get_link_costs
|
||||
iwpriv ethX set_link_costs "cost54 cost36 cost11 cost1"
|
||||
|
||||
DESCRIPTION
|
||||
Those commands are used to send additional commands to the Marvell WLAN
|
||||
card via the Linux device driver.
|
||||
|
||||
The ethX parameter specifies the network device that is to be used to
|
||||
perform this command on. it could be eth0, eth1 etc.
|
||||
|
||||
setregioncode
|
||||
This command is used to set the region code in the station.
|
||||
where value is 'region code' for various regions like
|
||||
USA FCC, Canada IC, Spain, France, Europe ETSI, Japan ...
|
||||
|
||||
Usage:
|
||||
iwpriv ethX setregioncode 0x10: set region code to USA (0x10).
|
||||
|
||||
getregioncode
|
||||
This command is used to get the region code information set in the
|
||||
station.
|
||||
|
||||
ledgpio
|
||||
This command is used to set/get LEDs.
|
||||
|
||||
iwpriv ethX ledgpio <LEDs>
|
||||
will set the corresponding LED for the GPIO Line.
|
||||
|
||||
iwpriv ethX ledgpio
|
||||
will give u which LEDs are Enabled.
|
||||
|
||||
Usage:
|
||||
iwpriv eth1 ledgpio 1 0 2 1 3 4
|
||||
will enable
|
||||
LED 1 -> GPIO 0
|
||||
LED 2 -> GPIO 1
|
||||
LED 3 -> GPIO 4
|
||||
|
||||
iwpriv eth1 ledgpio
|
||||
shows LED information in the format as mentioned above.
|
||||
|
||||
Note: LED0 is invalid
|
||||
Note: Maximum Number of LEDs are 16.
|
||||
|
||||
bcn_control
|
||||
This command is used to enable disable beacons. This can also be used
|
||||
to set beacon interval.
|
||||
|
||||
Usage:
|
||||
iwpriv ethX bcn_control [enable] [beacon_interval]
|
||||
|
||||
enable: 0 to disable beacon. 1 to enable beacon.
|
||||
beacon_interval: 20 - 1000ms.
|
||||
|
||||
Examples:
|
||||
1. iwpriv ethX bcn_control
|
||||
Returns (x, y), where x if 1, indicates beacon is enabled, y
|
||||
beacon period.
|
||||
2. iwpriv ethX bcn_control 0
|
||||
Turns off beacon transmission.
|
||||
3. iwpriv ethX bcn_control 1 500
|
||||
Enable beacon with beacon interval 500ms.
|
||||
|
||||
|
||||
ledbhv
|
||||
Command iwpriv mshX ledbhv can be used to change default LEDs behaviors.
|
||||
A given LED behavior can be on, off or blinking. The duty/cycle can be set
|
||||
when behavior is programmed as blinking.
|
||||
|
||||
Usage:
|
||||
|
||||
1. To get default LED behavior
|
||||
iwpriv mshX ledbhv <firmware state>
|
||||
|
||||
2. To set or change default LED behavior
|
||||
iwpriv mshX ledbhv <firmware state> <lednum> <behavior> <arg>
|
||||
|
||||
firmware state: The following are some of the relevant states.
|
||||
00: disconnected
|
||||
01: firmware is scanning
|
||||
02: firmware is connected and awake
|
||||
03: firmware is sleeping
|
||||
04: connected deep sleep
|
||||
06: firmware disconnected link lost
|
||||
07: firmware disconnected disassociated
|
||||
09: data transfer while firmware is associated and not scanning.
|
||||
If firmware is already in this state, LED behavior does not change
|
||||
on this data transfer.
|
||||
10: firmware idle, not scanning, not disconnected or disassociated.
|
||||
|
||||
lednum: 1 or 2 for first and second LED.
|
||||
|
||||
behavior: 0 for steady ON, 1 - steady off and 2- blinking.
|
||||
|
||||
arg: It is used when behavior is 2 to set duty and cycle. It is defined as
|
||||
(duty << 4 | cycle). Here duty could be 0..4 and cycle 0..5 for 34,
|
||||
74, 149, 298, 596, 1192 ms respectively.
|
||||
|
||||
Examples:
|
||||
|
||||
1. To get default behavior for scan
|
||||
iwpriv mshX ledbhv 1
|
||||
|
||||
2. To get default behavior while data transfer
|
||||
iwpriv mshX ledbhv 9
|
||||
|
||||
3. To turn off LED 2
|
||||
iwpriv mshX ledbhv 2 2 1 0
|
||||
iwpriv mshX ledbhv 10 2 1 0
|
||||
|
||||
4. To enable LED 2 and blink LED 1 while data transfer.
|
||||
iwpriv mshX ledbhv 9 2 0 0
|
||||
iwpriv mshX ledbhv 9 1 2 4
|
||||
|
||||
5. To change duty cycle of LED 2 during data transfer
|
||||
iwpriv mshX ledbhv 9 2 2 36
|
||||
|
||||
6. To turn ON LED 2 when firmware is disassociated/disconnected.
|
||||
iwpriv mshX ledbhv 0 2 0 0
|
||||
|
||||
|
||||
fwt_add
|
||||
This command is used to insert an entry into the FWT table. The list of
|
||||
parameters must follow the following structure:
|
||||
|
||||
iwpriv ethX fwt_add da ra [metric dir rate ssn dsn hopcount ttl expiration sleepmode snr]
|
||||
|
||||
The parameters between brackets are optional, but they must appear in
|
||||
the order specified. For example, if you want to specify the metric,
|
||||
you must also specify the dir, ssn, and dsn but you need not specify the
|
||||
hopcount, expiration, sleepmode, or snr. Any unspecified parameters
|
||||
will be assigned the defaults specified below.
|
||||
|
||||
The different parameters are:-
|
||||
da -- DA MAC address in the form 00:11:22:33:44:55
|
||||
ra -- RA MAC address in the form 00:11:22:33:44:55
|
||||
metric -- route metric (cost: smaller-metric routes are
|
||||
preferred, default is 0)
|
||||
dir -- direction (1 for direct, 0 for reverse,
|
||||
default is 1)
|
||||
rate -- data rate used for transmission to the RA,
|
||||
as specified for the rateadapt command,
|
||||
default is 3 (11Mbps)
|
||||
ssn -- Source Sequence Number (time at the RA for
|
||||
reverse routes. Default is 0)
|
||||
dsn -- Destination Sequence Number (time at the DA
|
||||
for direct routes. Default is 0)
|
||||
hopcount -- hop count (currently unused, default is 0)
|
||||
ttl -- TTL (Only used in reverse entries)
|
||||
expiration -- entry expiration (in ticks, where a tick is
|
||||
1024us, or ~ 1ms. Use 0 for an indefinite
|
||||
entry, default is 0)
|
||||
sleepmode -- RA's sleep mode (currently unused, default is
|
||||
0)
|
||||
snr -- SNR in the link to RA (currently unused,
|
||||
default is 0)
|
||||
|
||||
The command does not return anything.
|
||||
|
||||
fwt_del
|
||||
This command is used to remove an entry to the FWT table. The list of
|
||||
parameters must follow the following structure:
|
||||
|
||||
iwpriv ethX fwt_del da ra [dir]
|
||||
|
||||
where the different parameters are:-
|
||||
da -- DA MAC address (in the form "00:11:22:33:44:55")
|
||||
ra -- RA MAC address (in the form "00:11:22:33:44:55")
|
||||
dir -- direction (1 for direct, 0 for reverse,
|
||||
default is 1)
|
||||
|
||||
The command does not return anything.
|
||||
|
||||
fwt_lookup
|
||||
This command is used to get the best route in the FWT table to a given
|
||||
host. The only parameter is the MAC address of the host that is being
|
||||
looked for.
|
||||
|
||||
iwpriv ethX fwt_lookup da
|
||||
|
||||
where:-
|
||||
da -- DA MAC address (in the form "00:11:22:33:44:55")
|
||||
|
||||
The command returns an output string identical to the one returned by
|
||||
fwt_list described below.
|
||||
|
||||
|
||||
fwt_list
|
||||
This command is used to list a route from the FWT table. The only
|
||||
parameter is the index into the table. If you want to list all the
|
||||
routes in a table, start with index=0, and keep listing until you get a
|
||||
"(null)" string. Note that the indicies may change as the fwt is
|
||||
updated. It is expected that most users will not use fwt_list directly,
|
||||
but that a utility similar to the traditional route command will be used
|
||||
to invoke fwt_list over and over.
|
||||
|
||||
iwpriv ethX fwt_list index
|
||||
|
||||
The output is a string of the following form:
|
||||
|
||||
da ra valid metric dir rate ssn dsn hopcount ttl expiration
|
||||
sleepmode snr precursor
|
||||
|
||||
where the different fields are:-
|
||||
da -- DA MAC address (in the form "00:11:22:33:44:55")
|
||||
ra -- RA MAC address (in the form "00:11:22:33:44:55")
|
||||
valid -- whether the route is valid (0 if not valid)
|
||||
metric -- route metric (cost: smaller-metric routes are preferred)
|
||||
dir -- direction (1 for direct, 0 for reverse)
|
||||
rate -- data rate used for transmission to the RA,
|
||||
as specified for the rateadapt command
|
||||
ssn -- Source Sequence Number (time at the RA for reverse routes)
|
||||
dsn -- Destination Sequence Number (time at the DA for direct routes)
|
||||
hopcount -- hop count (currently unused)
|
||||
ttl -- TTL (only used in reverse entries)
|
||||
expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
|
||||
sleepmode -- RA's sleep mode (currently unused)
|
||||
snr -- SNR in the link to RA (currently unused)
|
||||
precursor -- predecessor in direct routes
|
||||
|
||||
fwt_list_route
|
||||
This command is equivalent to fwt_list.
|
||||
|
||||
fwt_list_neigh
|
||||
This command is used to list a neighbor from the FWT table. The only
|
||||
parameter is the neighbor ID. If you want to list all the neighbors in a
|
||||
table, start with nid=0, and keep incrementing nid until you get a
|
||||
"(null)" string. Note that the nid from a fwt_list_route command can be
|
||||
used as an input to this command. Also note that this command is meant
|
||||
mostly for debugging. It is expected that users will use fwt_lookup.
|
||||
One important reason for this is that the neighbor id may change as the
|
||||
neighbor table is altered.
|
||||
|
||||
iwpriv ethX fwt_list_neigh nid
|
||||
|
||||
The output is a string of the following form:
|
||||
|
||||
ra sleepmode snr references
|
||||
|
||||
where the different fields are:-
|
||||
ra -- RA MAC address (in the form "00:11:22:33:44:55")
|
||||
sleepmode -- RA's sleep mode (currently unused)
|
||||
snr -- SNR in the link to RA (currently unused)
|
||||
references -- RA's reference counter
|
||||
|
||||
fwt_reset
|
||||
This command is used to reset the FWT table, getting rid of all the
|
||||
entries. There are no input parameters.
|
||||
|
||||
iwpriv ethX fwt_reset
|
||||
|
||||
The command does not return anything.
|
||||
|
||||
fwt_cleanup
|
||||
This command is used to perform user-based garbage recollection. The
|
||||
FWT table is checked, and all the entries that are expired or invalid
|
||||
are cleaned. Note that this is exported to the driver for debugging
|
||||
purposes, as garbage collection is also fired by the firmware when in
|
||||
space problems. There are no input parameters.
|
||||
|
||||
iwpriv ethX fwt_cleanup
|
||||
|
||||
The command does returns the number of invalid/expired routes deleted.
|
||||
|
||||
fwt_time
|
||||
This command returns a card's internal time representation. It is this
|
||||
time that is used to represent the expiration times of FWT entries. The
|
||||
number is not consistent from card to card; it is simply a timer count.
|
||||
The fwt_time command is used to inspect the timer so that expiration
|
||||
times reported by fwt_list can be properly interpreted.
|
||||
|
||||
iwpriv ethX fwt_time
|
||||
|
||||
mesh_get_ttl
|
||||
|
||||
The mesh ttl is the number of hops a mesh packet can traverse before it
|
||||
is dropped. This parameter is used to prevent infinite loops in the
|
||||
mesh network. The value returned by this function is the ttl assigned
|
||||
to all mesh packets. Currently there is no way to control the ttl on a
|
||||
per packet or per socket basis.
|
||||
|
||||
iwpriv ethX mesh_get_ttl
|
||||
|
||||
mesh_set_ttl ttl
|
||||
|
||||
Set the ttl. The argument must be between 0 and 255.
|
||||
|
||||
iwpriv ethX mesh_set_ttl <ttl>
|
||||
|
||||
mesh_get_bcastr
|
||||
|
||||
Shows the rate index used for mesh broadcast and multicast packets.
|
||||
Rates are expressed in 2 * Mb/s, ie 11Mb/s is 22, 5.5Mb/s is 11, etc.
|
||||
|
||||
iwpriv ethX mesh_get_bcastr rate
|
||||
|
||||
mesh_set_bcastr rate
|
||||
|
||||
Sets the rate index for mesh broadcast and muticast packets. Rates are
|
||||
expressed in expressed in 2 * Mb/s, ie 11Mb/s is 22, 5.5Mb/s is 11, etc.
|
||||
|
||||
iwpriv ethX mesh_set_bcastr rate
|
||||
|
||||
get_rreq_delay
|
||||
|
||||
Shows the delay to forward a RREQ frame. This delay allows the node to
|
||||
forward just the best route in case the same RREQ arrives to the node
|
||||
through different routes. The argument is shown in 1/100 seconds.
|
||||
|
||||
iwpriv ethX get_rreq_delay
|
||||
|
||||
set_rreq_delay delay
|
||||
|
||||
Sets the RREQ forward delay. The delay is interpreted as 1/100 seconds.
|
||||
|
||||
iwpriv ethX set_rreq_delay delay
|
||||
|
||||
get_route_exp
|
||||
|
||||
Shows the mesh route expiration time, in seconds.
|
||||
|
||||
iwpriv ethX get_route_exp
|
||||
|
||||
set_route_exp time
|
||||
|
||||
Gets the mesh route, expiration time, in seconds.
|
||||
|
||||
iwpriv ethX set_route_exp time
|
||||
|
||||
get_link_costs
|
||||
|
||||
Gets the mesh hop base cost for each used rate. The output gives us the
|
||||
base cost for hops at 54Mbps, 36Mbps, 11Mbps and 1Mbps, in that order.
|
||||
The base cost gets divided by a battery state factor to get the actual
|
||||
cost. A cost of 0 means that rate is deactivated.
|
||||
|
||||
iwpriv ethX get_link_costs
|
||||
|
||||
set_link_costs "cost54 cost36 cost11 cost1"
|
||||
|
||||
Sets the mesh hop base cost for the used speeds. The input parameter
|
||||
will specify the cost for hops at 54Mbps, 36Mbps, 11Mbps and 1Mbps, in
|
||||
that order. A cost of 0 will disable a specific rate.
|
||||
|
||||
iwpriv ethX set_link_costs "cost54 cost36 cost11 cost1"
|
||||
|
||||
=========================
|
||||
ETHTOOL
|
||||
=========================
|
||||
|
||||
|
||||
Use the -i option to retrieve version information from the driver.
|
||||
|
||||
# ethtool -i eth0
|
||||
driver: libertas
|
||||
version: COMM-USB8388-318.p4
|
||||
firmware-version: 5.110.7
|
||||
bus-info:
|
||||
|
||||
Use the -e option to read the EEPROM contents of the card.
|
||||
|
||||
Usage:
|
||||
ethtool -e ethX [raw on|off] [offset N] [length N]
|
||||
|
||||
-e retrieves and prints an EEPROM dump for the specified ethernet
|
||||
device. When raw is enabled, then it dumps the raw EEPROM data
|
||||
to stdout. The length and offset parameters allow dumping cer-
|
||||
tain portions of the EEPROM. Default is to dump the entire EEP-
|
||||
ROM.
|
||||
|
||||
# ethtool -e eth0 offset 0 length 16
|
||||
Offset Values
|
||||
------ ------
|
||||
0x0000 38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00
|
||||
|
||||
========================
|
||||
DEBUGFS COMMANDS
|
||||
========================
|
||||
|
||||
those commands are used via debugfs interface
|
||||
|
||||
===========
|
||||
rdmac
|
||||
rdbbp
|
||||
rdrf
|
||||
These commands are used to read the MAC, BBP and RF registers from the
|
||||
card. These commands take one parameter that specifies the offset
|
||||
location that is to be read. This parameter must be specified in
|
||||
hexadecimal (its possible to preceed preceding the number with a "0x").
|
||||
|
||||
Path: /debugfs/libertas_wireless/ethX/registers/
|
||||
|
||||
Usage:
|
||||
echo "0xa123" > rdmac ; cat rdmac
|
||||
echo "0xa123" > rdbbp ; cat rdbbp
|
||||
echo "0xa123" > rdrf ; cat rdrf
|
||||
wrmac
|
||||
wrbbp
|
||||
wrrf
|
||||
These commands are used to write the MAC, BBP and RF registers in the
|
||||
card. These commands take two parameters that specify the offset
|
||||
location and the value that is to be written. This parameters must
|
||||
be specified in hexadecimal (its possible to preceed the number
|
||||
with a "0x").
|
||||
|
||||
Usage:
|
||||
echo "0xa123 0xaa" > wrmac
|
||||
echo "0xa123 0xaa" > wrbbp
|
||||
echo "0xa123 0xaa" > wrrf
|
||||
|
||||
sleepparams
|
||||
This command is used to set the sleepclock configurations
|
||||
|
||||
Path: /debugfs/libertas_wireless/ethX/
|
||||
|
||||
Usage:
|
||||
cat sleepparams: reads the current sleepclock configuration
|
||||
|
||||
echo "p1 p2 p3 p4 p5 p6" > sleepparams: writes the sleepclock configuration.
|
||||
|
||||
where:
|
||||
p1 is Sleep clock error in ppm (0-65535)
|
||||
p2 is Wakeup offset in usec (0-65535)
|
||||
p3 is Clock stabilization time in usec (0-65535)
|
||||
p4 is Control periodic calibration (0-2)
|
||||
p5 is Control the use of external sleep clock (0-2)
|
||||
p6 is reserved for debug (0-65535)
|
||||
|
||||
subscribed_events
|
||||
|
||||
The subscribed_events directory contains the interface for the
|
||||
subscribed events API.
|
||||
|
||||
Path: /debugfs/libertas_wireless/ethX/subscribed_events/
|
||||
|
||||
Each event is represented by a filename. Each filename consists of the
|
||||
following three fields:
|
||||
Value Frequency Subscribed
|
||||
|
||||
To read the current values for a given event, do:
|
||||
cat event
|
||||
To set the current values, do:
|
||||
echo "60 2 1" > event
|
||||
|
||||
Frequency field specifies the reporting frequency for this event.
|
||||
If it is set to 0, then the event is reported only once, and then
|
||||
automatically unsubscribed. If it is set to 1, then the event is
|
||||
reported every time it occurs. If it is set to N, then the event is
|
||||
reported every Nth time it occurs.
|
||||
|
||||
beacon_missed
|
||||
Value field specifies the number of consecutive missing beacons which
|
||||
triggers the LINK_LOSS event. This event is generated only once after
|
||||
which the firmware resets its state. At initialization, the LINK_LOSS
|
||||
event is subscribed by default. The default value of MissedBeacons is
|
||||
60.
|
||||
|
||||
failure_count
|
||||
Value field specifies the consecutive failure count threshold which
|
||||
triggers the generation of the MAX_FAIL event. Once this event is
|
||||
generated, the consecutive failure count is reset to 0.
|
||||
At initialization, the MAX_FAIL event is NOT subscribed by
|
||||
default.
|
||||
|
||||
high_rssi
|
||||
This event is generated when the average received RSSI in beacons goes
|
||||
above a threshold, specified by Value.
|
||||
|
||||
low_rssi
|
||||
This event is generated when the average received RSSI in beacons goes
|
||||
below a threshold, specified by Value.
|
||||
|
||||
high_snr
|
||||
This event is generated when the average received SNR in beacons goes
|
||||
above a threshold, specified by Value.
|
||||
|
||||
low_snr
|
||||
This event is generated when the average received SNR in beacons goes
|
||||
below a threshold, specified by Value.
|
||||
|
||||
extscan
|
||||
This command is used to do a specific scan.
|
||||
|
||||
Path: /debugfs/libertas_wireless/ethX/
|
||||
|
||||
Usage: echo "SSID" > extscan
|
||||
|
||||
Example:
|
||||
echo "LINKSYS-AP" > extscan
|
||||
|
||||
To see the results of use getscantable command.
|
||||
|
||||
getscantable
|
||||
|
||||
Display the current contents of the driver scan table (ie. get the
|
||||
scan results).
|
||||
|
||||
Path: /debugfs/libertas_wireless/ethX/
|
||||
|
||||
Usage:
|
||||
cat getscantable
|
||||
|
||||
setuserscan
|
||||
Initiate a customized scan and retrieve the results
|
||||
|
||||
|
||||
Path: /debugfs/libertas_wireless/ethX/
|
||||
|
||||
Usage:
|
||||
echo "[ARGS]" > setuserscan
|
||||
|
||||
where [ARGS]:
|
||||
|
||||
bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan
|
||||
ssid="[SSID]" specify a SSID filter for the scan
|
||||
keep=[0 or 1] keep the previous scan results (1), discard (0)
|
||||
dur=[scan time] time to scan for each channel in milliseconds
|
||||
type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any)
|
||||
|
||||
Any combination of the above arguments can be supplied on the command
|
||||
line. If dur tokens are absent, the driver default setting will be used.
|
||||
The bssid and ssid fields, if blank, will produce an unfiltered scan.
|
||||
The type field will default to 3 (Any) and the keep field will default
|
||||
to 0 (Discard).
|
||||
|
||||
Examples:
|
||||
1) Perform a passive scan on all channels for 20 ms per channel:
|
||||
echo "dur=20" > setuserscan
|
||||
|
||||
2) Perform an active scan for a specific SSID:
|
||||
echo "ssid="TestAP"" > setuserscan
|
||||
|
||||
3) Scan all available channels (B/G, A bands) for a specific BSSID, keep
|
||||
the current scan table intact, update existing or append new scan data:
|
||||
echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan
|
||||
|
||||
4) Scan for all infrastructure networks.
|
||||
Keep the previous scan table intact. Update any duplicate BSSID/SSID
|
||||
matches with the new scan data:
|
||||
echo "type=1 keep=1" > setuserscan
|
||||
|
||||
All entries in the scan table (not just the new scan data when keep=1)
|
||||
will be displayed upon completion by use of the getscantable ioctl.
|
||||
|
||||
==============================================================================
|
File diff suppressed because it is too large
Load Diff
@ -1,39 +0,0 @@
|
||||
/* Copyright (C) 2006, Red Hat, Inc. */
|
||||
|
||||
#ifndef _LBS_ASSOC_H_
|
||||
#define _LBS_ASSOC_H_
|
||||
|
||||
#include "dev.h"
|
||||
|
||||
void lbs_association_worker(struct work_struct *work);
|
||||
struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
|
||||
|
||||
struct cmd_ds_command;
|
||||
int lbs_cmd_80211_authenticate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd,
|
||||
void *pdata_buf);
|
||||
int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd,
|
||||
void *pdata_buf);
|
||||
int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd);
|
||||
int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd,
|
||||
void *pdata_buf);
|
||||
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd);
|
||||
int lbs_cmd_80211_associate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd,
|
||||
void *pdata_buf);
|
||||
|
||||
int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp);
|
||||
int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv);
|
||||
int lbs_ret_80211_disassociate(struct lbs_private *priv);
|
||||
int lbs_ret_80211_associate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp);
|
||||
|
||||
int lbs_stop_adhoc_network(struct lbs_private *priv);
|
||||
|
||||
int lbs_send_deauthentication(struct lbs_private *priv);
|
||||
|
||||
#endif /* _LBS_ASSOC_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,60 +0,0 @@
|
||||
/* Copyright (C) 2007, Red Hat, Inc. */
|
||||
|
||||
#ifndef _LBS_CMD_H_
|
||||
#define _LBS_CMD_H_
|
||||
|
||||
#include "hostcmd.h"
|
||||
#include "dev.h"
|
||||
|
||||
/* 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, lbs_cmd_copyback, (unsigned long) (cmd))
|
||||
|
||||
void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
|
||||
struct cmd_header *in_cmd, int in_cmd_size);
|
||||
|
||||
int __lbs_cmd(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_copyback(struct lbs_private *priv, unsigned long extra,
|
||||
struct cmd_header *resp);
|
||||
|
||||
int lbs_update_hw_spec(struct lbs_private *priv);
|
||||
|
||||
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
|
||||
struct cmd_ds_mesh_access *cmd);
|
||||
|
||||
int lbs_get_data_rate(struct lbs_private *priv);
|
||||
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, 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);
|
||||
int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
|
||||
struct assoc_request *assoc);
|
||||
|
||||
#endif /* _LBS_CMD_H */
|
@ -1,700 +0,0 @@
|
||||
/**
|
||||
* This file contains the handling of command
|
||||
* responses as well as events generated by firmware.
|
||||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include "host.h"
|
||||
#include "decl.h"
|
||||
#include "defs.h"
|
||||
#include "dev.h"
|
||||
#include "assoc.h"
|
||||
#include "wext.h"
|
||||
|
||||
/**
|
||||
* @brief This function handles disconnect event. it
|
||||
* reports disconnect to upper layer, clean tx/rx packets,
|
||||
* reset link state etc.
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @return n/a
|
||||
*/
|
||||
void lbs_mac_event_disconnected(struct lbs_private *priv)
|
||||
{
|
||||
union iwreq_data wrqu;
|
||||
|
||||
if (priv->connect_status != LBS_CONNECTED)
|
||||
return;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ASSOC);
|
||||
|
||||
memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
|
||||
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
|
||||
/*
|
||||
* Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
|
||||
* It causes problem in the Supplicant
|
||||
*/
|
||||
|
||||
msleep_interruptible(1000);
|
||||
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, 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));
|
||||
memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
|
||||
memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
|
||||
memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
|
||||
priv->nextSNRNF = 0;
|
||||
priv->numSNRNF = 0;
|
||||
priv->connect_status = LBS_DISCONNECTED;
|
||||
|
||||
/* Clear out associated SSID and BSSID since connection is
|
||||
* no longer valid.
|
||||
*/
|
||||
memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
|
||||
memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE);
|
||||
priv->curbssparams.ssid_len = 0;
|
||||
|
||||
if (priv->psstate != PS_STATE_FULL_POWER) {
|
||||
/* make firmware to exit PS mode */
|
||||
lbs_deb_cmd("disconnected, so exit PS mode\n");
|
||||
lbs_ps_wakeup(priv, 0);
|
||||
}
|
||||
lbs_deb_leave(LBS_DEB_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles MIC failure event.
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @para event the event id
|
||||
* @return n/a
|
||||
*/
|
||||
static void handle_mic_failureevent(struct lbs_private *priv, u32 event)
|
||||
{
|
||||
char buf[50];
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
|
||||
|
||||
if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
|
||||
strcat(buf, "unicast ");
|
||||
} else {
|
||||
strcat(buf, "multicast ");
|
||||
}
|
||||
|
||||
lbs_send_iwevcustom_event(priv, buf);
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
}
|
||||
|
||||
static int lbs_ret_reg_access(struct lbs_private *priv,
|
||||
u16 type, struct cmd_ds_command *resp)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
switch (type) {
|
||||
case CMD_RET(CMD_MAC_REG_ACCESS):
|
||||
{
|
||||
struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
|
||||
|
||||
priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
|
||||
priv->offsetvalue.value = le32_to_cpu(reg->value);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_RET(CMD_BBP_REG_ACCESS):
|
||||
{
|
||||
struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
|
||||
|
||||
priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
|
||||
priv->offsetvalue.value = reg->value;
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_RET(CMD_RF_REG_ACCESS):
|
||||
{
|
||||
struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
|
||||
|
||||
priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
|
||||
priv->offsetvalue.value = reg->value;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp)
|
||||
{
|
||||
struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
|
||||
u16 oid = le16_to_cpu(smib->oid);
|
||||
u16 querytype = le16_to_cpu(smib->querytype);
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
|
||||
querytype);
|
||||
lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
|
||||
|
||||
if (querytype == CMD_ACT_GET) {
|
||||
switch (oid) {
|
||||
case FRAGTHRESH_I:
|
||||
priv->fragthsd =
|
||||
le16_to_cpu(*((__le16 *)(smib->value)));
|
||||
lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
|
||||
priv->fragthsd);
|
||||
break;
|
||||
case RTSTHRESH_I:
|
||||
priv->rtsthsd =
|
||||
le16_to_cpu(*((__le16 *)(smib->value)));
|
||||
lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
|
||||
priv->rtsthsd);
|
||||
break;
|
||||
case SHORT_RETRYLIM_I:
|
||||
priv->txretrycount =
|
||||
le16_to_cpu(*((__le16 *)(smib->value)));
|
||||
lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
|
||||
priv->rtsthsd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp)
|
||||
{
|
||||
struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
priv->txpowerlevel = le16_to_cpu(rtp->currentlevel);
|
||||
|
||||
lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp)
|
||||
{
|
||||
struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
if (rates->action == CMD_ACT_GET) {
|
||||
priv->enablehwauto = le16_to_cpu(rates->enablehwauto);
|
||||
priv->ratebitmap = le16_to_cpu(rates->bitmap);
|
||||
}
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lbs_ret_802_11_rssi(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp)
|
||||
{
|
||||
struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
/* store the non average value */
|
||||
priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
|
||||
priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
|
||||
|
||||
priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
|
||||
priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
|
||||
|
||||
priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
|
||||
CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
|
||||
priv->NF[TYPE_BEACON][TYPE_NOAVG]);
|
||||
|
||||
priv->RSSI[TYPE_BEACON][TYPE_AVG] =
|
||||
CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
|
||||
priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
|
||||
|
||||
lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
|
||||
priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
|
||||
priv->RSSI[TYPE_BEACON][TYPE_AVG]);
|
||||
|
||||
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)
|
||||
{
|
||||
struct cmd_ds_802_11_beacon_control *bcn_ctrl =
|
||||
&resp->params.bcn_ctrl;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
if (bcn_ctrl->action == CMD_ACT_GET) {
|
||||
priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
|
||||
priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
|
||||
}
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int handle_cmd_response(struct lbs_private *priv,
|
||||
struct cmd_header *cmd_response)
|
||||
{
|
||||
struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
uint16_t respcmd = le16_to_cpu(resp->command);
|
||||
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
|
||||
switch (respcmd) {
|
||||
case CMD_RET(CMD_MAC_REG_ACCESS):
|
||||
case CMD_RET(CMD_BBP_REG_ACCESS):
|
||||
case CMD_RET(CMD_RF_REG_ACCESS):
|
||||
ret = lbs_ret_reg_access(priv, respcmd, resp);
|
||||
break;
|
||||
|
||||
case CMD_RET_802_11_ASSOCIATE:
|
||||
case CMD_RET(CMD_802_11_ASSOCIATE):
|
||||
case CMD_RET(CMD_802_11_REASSOCIATE):
|
||||
ret = lbs_ret_80211_associate(priv, resp);
|
||||
break;
|
||||
|
||||
case CMD_RET(CMD_802_11_DISASSOCIATE):
|
||||
case CMD_RET(CMD_802_11_DEAUTHENTICATE):
|
||||
ret = lbs_ret_80211_disassociate(priv);
|
||||
break;
|
||||
|
||||
case CMD_RET(CMD_802_11_AD_HOC_START):
|
||||
case CMD_RET(CMD_802_11_AD_HOC_JOIN):
|
||||
ret = lbs_ret_80211_ad_hoc_start(priv, resp);
|
||||
break;
|
||||
|
||||
case CMD_RET(CMD_802_11_SNMP_MIB):
|
||||
ret = lbs_ret_802_11_snmp_mib(priv, resp);
|
||||
break;
|
||||
|
||||
case CMD_RET(CMD_802_11_RF_TX_POWER):
|
||||
ret = lbs_ret_802_11_rf_tx_power(priv, resp);
|
||||
break;
|
||||
|
||||
case CMD_RET(CMD_802_11_SET_AFC):
|
||||
case CMD_RET(CMD_802_11_GET_AFC):
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
|
||||
sizeof(struct cmd_ds_802_11_afc));
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
break;
|
||||
|
||||
case CMD_RET(CMD_MAC_MULTICAST_ADR):
|
||||
case CMD_RET(CMD_802_11_RESET):
|
||||
case CMD_RET(CMD_802_11_AUTHENTICATE):
|
||||
case CMD_RET(CMD_802_11_BEACON_STOP):
|
||||
break;
|
||||
|
||||
case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
|
||||
ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
|
||||
break;
|
||||
|
||||
case CMD_RET(CMD_802_11_RSSI):
|
||||
ret = lbs_ret_802_11_rssi(priv, resp);
|
||||
break;
|
||||
|
||||
case CMD_RET(CMD_802_11_AD_HOC_STOP):
|
||||
ret = lbs_ret_80211_ad_hoc_stop(priv);
|
||||
break;
|
||||
|
||||
case CMD_RET(CMD_802_11D_DOMAIN_INFO):
|
||||
ret = lbs_ret_802_11d_domain_info(resp);
|
||||
break;
|
||||
|
||||
case CMD_RET(CMD_802_11_TPC_CFG):
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
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((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_GET_TSF):
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
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->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->callback_arg)
|
||||
memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
|
||||
sizeof(resp->params.fwt));
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
break;
|
||||
case CMD_RET(CMD_802_11_BEACON_CTRL):
|
||||
ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
|
||||
break;
|
||||
|
||||
default:
|
||||
lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
|
||||
le16_to_cpu(resp->command));
|
||||
break;
|
||||
}
|
||||
lbs_deb_leave(LBS_DEB_HOST);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
|
||||
{
|
||||
uint16_t respcmd, curcmd;
|
||||
struct cmd_header *resp;
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
uint16_t result;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
|
||||
if (!priv->cur_cmd) {
|
||||
lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
|
||||
ret = -1;
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
goto done;
|
||||
}
|
||||
|
||||
resp = (void *)data;
|
||||
curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
|
||||
respcmd = le16_to_cpu(resp->command);
|
||||
result = le16_to_cpu(resp->result);
|
||||
|
||||
lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
|
||||
respcmd, le16_to_cpu(resp->seqnum), len);
|
||||
lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
|
||||
|
||||
if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
|
||||
lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
|
||||
le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
if (respcmd != CMD_RET(curcmd) &&
|
||||
respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_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[1];
|
||||
u16 action = le16_to_cpu(psmode->action);
|
||||
|
||||
lbs_deb_host(
|
||||
"CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
|
||||
result, action);
|
||||
|
||||
if (result) {
|
||||
lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
|
||||
result);
|
||||
/*
|
||||
* We should not re-try enter-ps command in
|
||||
* ad-hoc mode. It takes place in
|
||||
* lbs_execute_next_command().
|
||||
*/
|
||||
if (priv->mode == IW_MODE_ADHOC &&
|
||||
action == CMD_SUBCMD_ENTER_PS)
|
||||
priv->psmode = LBS802_11POWERMODECAM;
|
||||
} else if (action == CMD_SUBCMD_ENTER_PS) {
|
||||
priv->needtowakeup = 0;
|
||||
priv->psstate = PS_STATE_AWAKE;
|
||||
|
||||
lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
|
||||
if (priv->connect_status != LBS_CONNECTED) {
|
||||
/*
|
||||
* When Deauth Event received before Enter_PS command
|
||||
* response, We need to wake up the firmware.
|
||||
*/
|
||||
lbs_deb_host(
|
||||
"disconnected, invoking lbs_ps_wakeup\n");
|
||||
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
mutex_unlock(&priv->lock);
|
||||
lbs_ps_wakeup(priv, 0);
|
||||
mutex_lock(&priv->lock);
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
}
|
||||
} else if (action == CMD_SUBCMD_EXIT_PS) {
|
||||
priv->needtowakeup = 0;
|
||||
priv->psstate = PS_STATE_FULL_POWER;
|
||||
lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
|
||||
} else {
|
||||
lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
|
||||
}
|
||||
|
||||
lbs_complete_command(priv, priv->cur_cmd, result);
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* If the command is not successful, cleanup and return failure */
|
||||
if ((result != 0 || !(respcmd & 0x8000))) {
|
||||
lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
|
||||
result, respcmd);
|
||||
/*
|
||||
* Handling errors here
|
||||
*/
|
||||
switch (respcmd) {
|
||||
case CMD_RET(CMD_GET_HW_SPEC):
|
||||
case CMD_RET(CMD_802_11_RESET):
|
||||
lbs_deb_host("CMD_RESP: reset failed\n");
|
||||
break;
|
||||
|
||||
}
|
||||
lbs_complete_command(priv, priv->cur_cmd, result);
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
if (priv->cur_cmd && priv->cur_cmd->callback) {
|
||||
ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
|
||||
resp);
|
||||
} else
|
||||
ret = handle_cmd_response(priv, resp);
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
|
||||
if (priv->cur_cmd) {
|
||||
/* Clean up and Put current command back to cmdfreeq */
|
||||
lbs_complete_command(priv, priv->cur_cmd, result);
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
done:
|
||||
mutex_unlock(&priv->lock);
|
||||
lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lbs_send_confirmwake(struct lbs_private *priv)
|
||||
{
|
||||
struct cmd_header cmd;
|
||||
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_hex(LBS_DEB_HOST, "wake confirm", (u8 *) &cmd,
|
||||
sizeof(cmd));
|
||||
|
||||
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &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, u32 event)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
switch (event) {
|
||||
case MACREG_INT_CODE_LINK_SENSED:
|
||||
lbs_deb_cmd("EVENT: link sensed\n");
|
||||
break;
|
||||
|
||||
case MACREG_INT_CODE_DEAUTHENTICATED:
|
||||
lbs_deb_cmd("EVENT: deauthenticated\n");
|
||||
lbs_mac_event_disconnected(priv);
|
||||
break;
|
||||
|
||||
case MACREG_INT_CODE_DISASSOCIATED:
|
||||
lbs_deb_cmd("EVENT: disassociated\n");
|
||||
lbs_mac_event_disconnected(priv);
|
||||
break;
|
||||
|
||||
case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
|
||||
lbs_deb_cmd("EVENT: link lost\n");
|
||||
lbs_mac_event_disconnected(priv);
|
||||
break;
|
||||
|
||||
case MACREG_INT_CODE_PS_SLEEP:
|
||||
lbs_deb_cmd("EVENT: ps sleep\n");
|
||||
|
||||
/* handle unexpected PS SLEEP event */
|
||||
if (priv->psstate == PS_STATE_FULL_POWER) {
|
||||
lbs_deb_cmd(
|
||||
"EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
|
||||
break;
|
||||
}
|
||||
priv->psstate = PS_STATE_PRE_SLEEP;
|
||||
|
||||
lbs_ps_confirm_sleep(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: ps awake\n");
|
||||
/* handle unexpected PS AWAKE event */
|
||||
if (priv->psstate == PS_STATE_FULL_POWER) {
|
||||
lbs_deb_cmd(
|
||||
"EVENT: In FULL POWER mode - ignore PS AWAKE\n");
|
||||
break;
|
||||
}
|
||||
|
||||
priv->psstate = PS_STATE_AWAKE;
|
||||
|
||||
if (priv->needtowakeup) {
|
||||
/*
|
||||
* wait for the command processing to finish
|
||||
* before resuming sending
|
||||
* priv->needtowakeup will be set to FALSE
|
||||
* in lbs_ps_wakeup()
|
||||
*/
|
||||
lbs_deb_cmd("waking up ...\n");
|
||||
lbs_ps_wakeup(priv, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case MACREG_INT_CODE_MIC_ERR_UNICAST:
|
||||
lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
|
||||
handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
|
||||
break;
|
||||
|
||||
case MACREG_INT_CODE_MIC_ERR_MULTICAST:
|
||||
lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
|
||||
handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
|
||||
break;
|
||||
|
||||
case MACREG_INT_CODE_MIB_CHANGED:
|
||||
lbs_deb_cmd("EVENT: MIB CHANGED\n");
|
||||
break;
|
||||
case MACREG_INT_CODE_INIT_DONE:
|
||||
lbs_deb_cmd("EVENT: INIT DONE\n");
|
||||
break;
|
||||
case MACREG_INT_CODE_ADHOC_BCN_LOST:
|
||||
lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
|
||||
break;
|
||||
case MACREG_INT_CODE_RSSI_LOW:
|
||||
lbs_pr_alert("EVENT: rssi low\n");
|
||||
break;
|
||||
case MACREG_INT_CODE_SNR_LOW:
|
||||
lbs_pr_alert("EVENT: snr low\n");
|
||||
break;
|
||||
case MACREG_INT_CODE_MAX_FAIL:
|
||||
lbs_pr_alert("EVENT: max fail\n");
|
||||
break;
|
||||
case MACREG_INT_CODE_RSSI_HIGH:
|
||||
lbs_pr_alert("EVENT: rssi high\n");
|
||||
break;
|
||||
case MACREG_INT_CODE_SNR_HIGH:
|
||||
lbs_pr_alert("EVENT: snr high\n");
|
||||
break;
|
||||
|
||||
case MACREG_INT_CODE_MESH_AUTO_STARTED:
|
||||
/* Ignore spurious autostart events if autostart is disabled */
|
||||
if (!priv->mesh_autostart_enabled) {
|
||||
lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
|
||||
break;
|
||||
}
|
||||
lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
|
||||
priv->mesh_connect_status = LBS_CONNECTED;
|
||||
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);
|
||||
break;
|
||||
|
||||
default:
|
||||
lbs_pr_alert("EVENT: unknown event id %d\n", event);
|
||||
break;
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
#ifndef __COMPAT_H
|
||||
#define __COMPAT_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused
|
||||
|
||||
static inline char *print_mac(char *buf, const u8 *addr)
|
||||
{
|
||||
sprintf(buf, MAC_FMT,
|
||||
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,968 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/string.h>
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include "dev.h"
|
||||
#include "decl.h"
|
||||
#include "host.h"
|
||||
#include "debugfs.h"
|
||||
#include "cmd.h"
|
||||
|
||||
static struct dentry *lbs_dir;
|
||||
static char *szStates[] = {
|
||||
"Connected",
|
||||
"Disconnected"
|
||||
};
|
||||
|
||||
#ifdef PROC_DEBUG
|
||||
static void lbs_debug_init(struct lbs_private *priv);
|
||||
#endif
|
||||
|
||||
static int open_file_generic(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = inode->i_private;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t write_file_dummy(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const size_t len = PAGE_SIZE;
|
||||
|
||||
static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct lbs_private *priv = file->private_data;
|
||||
size_t pos = 0;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
ssize_t res;
|
||||
|
||||
pos += snprintf(buf+pos, len-pos, "state = %s\n",
|
||||
szStates[priv->connect_status]);
|
||||
pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
|
||||
(u32) priv->regioncode);
|
||||
|
||||
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
|
||||
|
||||
free_page(addr);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct lbs_private *priv = file->private_data;
|
||||
size_t pos = 0;
|
||||
int numscansdone = 0, res;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
struct bss_descriptor * iter_bss;
|
||||
|
||||
pos += snprintf(buf+pos, len-pos,
|
||||
"# | ch | rssi | bssid | cap | Qual | SSID \n");
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
list_for_each_entry (iter_bss, &priv->network_list, list) {
|
||||
u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
|
||||
u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
|
||||
u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
|
||||
|
||||
pos += snprintf(buf+pos, len-pos,
|
||||
"%02u| %03d | %04d | %s |",
|
||||
numscansdone, iter_bss->channel, iter_bss->rssi,
|
||||
print_mac(mac, iter_bss->bssid));
|
||||
pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
|
||||
pos += snprintf(buf+pos, len-pos, "%c%c%c |",
|
||||
ibss ? 'A' : 'I', privacy ? 'P' : ' ',
|
||||
spectrum_mgmt ? 'S' : ' ');
|
||||
pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
|
||||
pos += snprintf(buf+pos, len-pos, " %s\n",
|
||||
escape_essid(iter_bss->ssid, iter_bss->ssid_len));
|
||||
|
||||
numscansdone++;
|
||||
}
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
|
||||
|
||||
free_page(addr);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t lbs_sleepparams_write(struct file *file,
|
||||
const char __user *user_buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct lbs_private *priv = file->private_data;
|
||||
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)) {
|
||||
ret = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
|
||||
if (ret != 6) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
sp.sp_error = p1;
|
||||
sp.sp_offset = p2;
|
||||
sp.sp_stabletime = p3;
|
||||
sp.sp_calcontrol = p4;
|
||||
sp.sp_extsleepclk = p5;
|
||||
sp.sp_reserved = p6;
|
||||
|
||||
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 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 ret;
|
||||
size_t pos = 0;
|
||||
struct sleep_params sp;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
|
||||
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", sp.sp_error,
|
||||
sp.sp_offset, sp.sp_stabletime,
|
||||
sp.sp_calcontrol, sp.sp_extsleepclk,
|
||||
sp.sp_reserved);
|
||||
|
||||
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
|
||||
|
||||
out_unlock:
|
||||
free_page(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
|
||||
* get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
|
||||
* firmware. Here's an example:
|
||||
* 04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
|
||||
* 00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
|
||||
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
*
|
||||
* The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
|
||||
* 00 00 are the data bytes of this TLV. For this TLV, their meaning is
|
||||
* defined in mrvlietypes_thresholds
|
||||
*
|
||||
* This function searches in this TLV data chunk for a given TLV type
|
||||
* 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(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
|
||||
{
|
||||
struct mrvlietypesheader *tlv_h;
|
||||
uint16_t length;
|
||||
ssize_t pos = 0;
|
||||
|
||||
while (pos < size) {
|
||||
tlv_h = (struct mrvlietypesheader *) tlv;
|
||||
if (!tlv_h->len)
|
||||
return NULL;
|
||||
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;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
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 ret = 0;
|
||||
size_t pos = 0;
|
||||
char *buf;
|
||||
u8 value;
|
||||
u8 freq;
|
||||
int events = 0;
|
||||
|
||||
buf = (char *)get_zeroed_page(GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
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);
|
||||
|
||||
out_page:
|
||||
free_page((unsigned long)buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
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 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)) {
|
||||
ret = -EFAULT;
|
||||
goto out_page;
|
||||
}
|
||||
ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
|
||||
if (ret != 3) {
|
||||
ret = -EINVAL;
|
||||
goto out_page;
|
||||
}
|
||||
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;
|
||||
else
|
||||
new_mask = curr_mask & ~event_mask;
|
||||
|
||||
/* Now everything is set and we can send stuff down to the firmware */
|
||||
|
||||
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 action, the event mask, and one TLV */
|
||||
events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + 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)
|
||||
{
|
||||
return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
|
||||
file, userbuf, count, 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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct lbs_private *priv = file->private_data;
|
||||
struct lbs_offset_value offval;
|
||||
ssize_t pos = 0;
|
||||
int ret;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
|
||||
offval.offset = priv->mac_offset;
|
||||
offval.value = 0;
|
||||
|
||||
ret = lbs_prepare_and_send_command(priv,
|
||||
CMD_MAC_REG_ACCESS, 0,
|
||||
CMD_OPTION_WAITFORRSP, 0, &offval);
|
||||
mdelay(10);
|
||||
pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
|
||||
priv->mac_offset, priv->offsetvalue.value);
|
||||
|
||||
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
|
||||
free_page(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t lbs_rdmac_write(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;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
|
||||
buf_size = min(count, len - 1);
|
||||
if (copy_from_user(buf, userbuf, buf_size)) {
|
||||
res = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
|
||||
res = count;
|
||||
out_unlock:
|
||||
free_page(addr);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t lbs_wrmac_write(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;
|
||||
u32 offset, value;
|
||||
struct lbs_offset_value offval;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
|
||||
buf_size = min(count, len - 1);
|
||||
if (copy_from_user(buf, userbuf, buf_size)) {
|
||||
res = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
res = sscanf(buf, "%x %x", &offset, &value);
|
||||
if (res != 2) {
|
||||
res = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
offval.offset = offset;
|
||||
offval.value = value;
|
||||
res = lbs_prepare_and_send_command(priv,
|
||||
CMD_MAC_REG_ACCESS, 1,
|
||||
CMD_OPTION_WAITFORRSP, 0, &offval);
|
||||
mdelay(10);
|
||||
|
||||
res = count;
|
||||
out_unlock:
|
||||
free_page(addr);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct lbs_private *priv = file->private_data;
|
||||
struct lbs_offset_value offval;
|
||||
ssize_t pos = 0;
|
||||
int ret;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
|
||||
offval.offset = priv->bbp_offset;
|
||||
offval.value = 0;
|
||||
|
||||
ret = lbs_prepare_and_send_command(priv,
|
||||
CMD_BBP_REG_ACCESS, 0,
|
||||
CMD_OPTION_WAITFORRSP, 0, &offval);
|
||||
mdelay(10);
|
||||
pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
|
||||
priv->bbp_offset, priv->offsetvalue.value);
|
||||
|
||||
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
|
||||
free_page(addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t lbs_rdbbp_write(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;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
|
||||
buf_size = min(count, len - 1);
|
||||
if (copy_from_user(buf, userbuf, buf_size)) {
|
||||
res = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
|
||||
res = count;
|
||||
out_unlock:
|
||||
free_page(addr);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t lbs_wrbbp_write(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;
|
||||
u32 offset, value;
|
||||
struct lbs_offset_value offval;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
|
||||
buf_size = min(count, len - 1);
|
||||
if (copy_from_user(buf, userbuf, buf_size)) {
|
||||
res = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
res = sscanf(buf, "%x %x", &offset, &value);
|
||||
if (res != 2) {
|
||||
res = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
offval.offset = offset;
|
||||
offval.value = value;
|
||||
res = lbs_prepare_and_send_command(priv,
|
||||
CMD_BBP_REG_ACCESS, 1,
|
||||
CMD_OPTION_WAITFORRSP, 0, &offval);
|
||||
mdelay(10);
|
||||
|
||||
res = count;
|
||||
out_unlock:
|
||||
free_page(addr);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct lbs_private *priv = file->private_data;
|
||||
struct lbs_offset_value offval;
|
||||
ssize_t pos = 0;
|
||||
int ret;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
|
||||
offval.offset = priv->rf_offset;
|
||||
offval.value = 0;
|
||||
|
||||
ret = lbs_prepare_and_send_command(priv,
|
||||
CMD_RF_REG_ACCESS, 0,
|
||||
CMD_OPTION_WAITFORRSP, 0, &offval);
|
||||
mdelay(10);
|
||||
pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
|
||||
priv->rf_offset, priv->offsetvalue.value);
|
||||
|
||||
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
|
||||
free_page(addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t lbs_rdrf_write(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;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
|
||||
buf_size = min(count, len - 1);
|
||||
if (copy_from_user(buf, userbuf, buf_size)) {
|
||||
res = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
|
||||
res = count;
|
||||
out_unlock:
|
||||
free_page(addr);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t lbs_wrrf_write(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;
|
||||
u32 offset, value;
|
||||
struct lbs_offset_value offval;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
|
||||
buf_size = min(count, len - 1);
|
||||
if (copy_from_user(buf, userbuf, buf_size)) {
|
||||
res = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
res = sscanf(buf, "%x %x", &offset, &value);
|
||||
if (res != 2) {
|
||||
res = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
offval.offset = offset;
|
||||
offval.value = value;
|
||||
res = lbs_prepare_and_send_command(priv,
|
||||
CMD_RF_REG_ACCESS, 1,
|
||||
CMD_OPTION_WAITFORRSP, 0, &offval);
|
||||
mdelay(10);
|
||||
|
||||
res = count;
|
||||
out_unlock:
|
||||
free_page(addr);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define FOPS(fread, fwrite) { \
|
||||
.owner = THIS_MODULE, \
|
||||
.open = open_file_generic, \
|
||||
.read = (fread), \
|
||||
.write = (fwrite), \
|
||||
}
|
||||
|
||||
struct lbs_debugfs_files {
|
||||
char *name;
|
||||
int perm;
|
||||
struct file_operations fops;
|
||||
};
|
||||
|
||||
static struct lbs_debugfs_files debugfs_files[] = {
|
||||
{ "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
|
||||
{ "getscantable", 0444, FOPS(lbs_getscantable,
|
||||
write_file_dummy), },
|
||||
{ "sleepparams", 0644, FOPS(lbs_sleepparams_read,
|
||||
lbs_sleepparams_write), },
|
||||
};
|
||||
|
||||
static struct lbs_debugfs_files debugfs_events_files[] = {
|
||||
{"low_rssi", 0644, FOPS(lbs_lowrssi_read,
|
||||
lbs_lowrssi_write), },
|
||||
{"low_snr", 0644, FOPS(lbs_lowsnr_read,
|
||||
lbs_lowsnr_write), },
|
||||
{"failure_count", 0644, FOPS(lbs_failcount_read,
|
||||
lbs_failcount_write), },
|
||||
{"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
|
||||
lbs_bcnmiss_write), },
|
||||
{"high_rssi", 0644, FOPS(lbs_highrssi_read,
|
||||
lbs_highrssi_write), },
|
||||
{"high_snr", 0644, FOPS(lbs_highsnr_read,
|
||||
lbs_highsnr_write), },
|
||||
};
|
||||
|
||||
static struct lbs_debugfs_files debugfs_regs_files[] = {
|
||||
{"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
|
||||
{"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
|
||||
{"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
|
||||
{"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
|
||||
{"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
|
||||
{"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
|
||||
};
|
||||
|
||||
void lbs_debugfs_init(void)
|
||||
{
|
||||
if (!lbs_dir)
|
||||
lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void lbs_debugfs_remove(void)
|
||||
{
|
||||
if (lbs_dir)
|
||||
debugfs_remove(lbs_dir);
|
||||
return;
|
||||
}
|
||||
|
||||
void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
|
||||
{
|
||||
int i;
|
||||
struct lbs_debugfs_files *files;
|
||||
if (!lbs_dir)
|
||||
goto exit;
|
||||
|
||||
priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
|
||||
if (!priv->debugfs_dir)
|
||||
goto exit;
|
||||
|
||||
for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
|
||||
files = &debugfs_files[i];
|
||||
priv->debugfs_files[i] = debugfs_create_file(files->name,
|
||||
files->perm,
|
||||
priv->debugfs_dir,
|
||||
priv,
|
||||
&files->fops);
|
||||
}
|
||||
|
||||
priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
|
||||
if (!priv->events_dir)
|
||||
goto exit;
|
||||
|
||||
for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
|
||||
files = &debugfs_events_files[i];
|
||||
priv->debugfs_events_files[i] = debugfs_create_file(files->name,
|
||||
files->perm,
|
||||
priv->events_dir,
|
||||
priv,
|
||||
&files->fops);
|
||||
}
|
||||
|
||||
priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
|
||||
if (!priv->regs_dir)
|
||||
goto exit;
|
||||
|
||||
for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
|
||||
files = &debugfs_regs_files[i];
|
||||
priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
|
||||
files->perm,
|
||||
priv->regs_dir,
|
||||
priv,
|
||||
&files->fops);
|
||||
}
|
||||
|
||||
#ifdef PROC_DEBUG
|
||||
lbs_debug_init(priv);
|
||||
#endif
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void lbs_debugfs_remove_one(struct lbs_private *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
|
||||
debugfs_remove(priv->debugfs_regs_files[i]);
|
||||
|
||||
debugfs_remove(priv->regs_dir);
|
||||
|
||||
for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
|
||||
debugfs_remove(priv->debugfs_events_files[i]);
|
||||
|
||||
debugfs_remove(priv->events_dir);
|
||||
#ifdef PROC_DEBUG
|
||||
debugfs_remove(priv->debugfs_debug);
|
||||
#endif
|
||||
for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
|
||||
debugfs_remove(priv->debugfs_files[i]);
|
||||
debugfs_remove(priv->debugfs_dir);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* debug entry */
|
||||
|
||||
#ifdef PROC_DEBUG
|
||||
|
||||
#define item_size(n) (FIELD_SIZEOF(struct lbs_private, n))
|
||||
#define item_addr(n) (offsetof(struct lbs_private, n))
|
||||
|
||||
|
||||
struct debug_data {
|
||||
char name[32];
|
||||
u32 size;
|
||||
size_t addr;
|
||||
};
|
||||
|
||||
/* To debug any member of struct lbs_private, simply add one line here.
|
||||
*/
|
||||
static struct debug_data items[] = {
|
||||
{"psmode", item_size(psmode), item_addr(psmode)},
|
||||
{"psstate", item_size(psstate), item_addr(psstate)},
|
||||
};
|
||||
|
||||
static int num_of_items = ARRAY_SIZE(items);
|
||||
|
||||
/**
|
||||
* @brief proc read function
|
||||
*
|
||||
* @param page pointer to buffer
|
||||
* @param s read data starting position
|
||||
* @param off offset
|
||||
* @param cnt counter
|
||||
* @param eof end of file flag
|
||||
* @param data data to output
|
||||
* @return number of output data
|
||||
*/
|
||||
static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int val = 0;
|
||||
size_t pos = 0;
|
||||
ssize_t res;
|
||||
char *p;
|
||||
int i;
|
||||
struct debug_data *d;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
|
||||
p = buf;
|
||||
|
||||
d = (struct debug_data *)file->private_data;
|
||||
|
||||
for (i = 0; i < num_of_items; i++) {
|
||||
if (d[i].size == 1)
|
||||
val = *((u8 *) d[i].addr);
|
||||
else if (d[i].size == 2)
|
||||
val = *((u16 *) d[i].addr);
|
||||
else if (d[i].size == 4)
|
||||
val = *((u32 *) d[i].addr);
|
||||
else if (d[i].size == 8)
|
||||
val = *((u64 *) d[i].addr);
|
||||
|
||||
pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
|
||||
}
|
||||
|
||||
res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
|
||||
|
||||
free_page(addr);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief proc write function
|
||||
*
|
||||
* @param f file pointer
|
||||
* @param buf pointer to data buffer
|
||||
* @param cnt data number to write
|
||||
* @param data data to write
|
||||
* @return number of data
|
||||
*/
|
||||
static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
|
||||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
int r, i;
|
||||
char *pdata;
|
||||
char *p;
|
||||
char *p0;
|
||||
char *p1;
|
||||
char *p2;
|
||||
struct debug_data *d = (struct debug_data *)f->private_data;
|
||||
|
||||
pdata = kmalloc(cnt, GFP_KERNEL);
|
||||
if (pdata == NULL)
|
||||
return 0;
|
||||
|
||||
if (copy_from_user(pdata, buf, cnt)) {
|
||||
lbs_deb_debugfs("Copy from user failed\n");
|
||||
kfree(pdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p0 = pdata;
|
||||
for (i = 0; i < num_of_items; i++) {
|
||||
do {
|
||||
p = strstr(p0, d[i].name);
|
||||
if (p == NULL)
|
||||
break;
|
||||
p1 = strchr(p, '\n');
|
||||
if (p1 == NULL)
|
||||
break;
|
||||
p0 = p1++;
|
||||
p2 = strchr(p, '=');
|
||||
if (!p2)
|
||||
break;
|
||||
p2++;
|
||||
r = simple_strtoul(p2, NULL, 0);
|
||||
if (d[i].size == 1)
|
||||
*((u8 *) d[i].addr) = (u8) r;
|
||||
else if (d[i].size == 2)
|
||||
*((u16 *) d[i].addr) = (u16) r;
|
||||
else if (d[i].size == 4)
|
||||
*((u32 *) d[i].addr) = (u32) r;
|
||||
else if (d[i].size == 8)
|
||||
*((u64 *) d[i].addr) = (u64) r;
|
||||
break;
|
||||
} while (1);
|
||||
}
|
||||
kfree(pdata);
|
||||
|
||||
return (ssize_t)cnt;
|
||||
}
|
||||
|
||||
static struct file_operations lbs_debug_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = open_file_generic,
|
||||
.write = lbs_debugfs_write,
|
||||
.read = lbs_debugfs_read,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief create debug proc file
|
||||
*
|
||||
* @param priv pointer struct lbs_private
|
||||
* @param dev pointer net_device
|
||||
* @return N/A
|
||||
*/
|
||||
static void lbs_debug_init(struct lbs_private *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!priv->debugfs_dir)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_of_items; i++)
|
||||
items[i].addr += (size_t) priv;
|
||||
|
||||
priv->debugfs_debug = debugfs_create_file("debug", 0644,
|
||||
priv->debugfs_dir, &items[0],
|
||||
&lbs_debug_fops);
|
||||
}
|
||||
#endif
|
@ -1,10 +0,0 @@
|
||||
#ifndef _LBS_DEBUGFS_H_
|
||||
#define _LBS_DEBUGFS_H_
|
||||
|
||||
void lbs_debugfs_init(void);
|
||||
void lbs_debugfs_remove(void);
|
||||
|
||||
void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev);
|
||||
void lbs_debugfs_remove_one(struct lbs_private *priv);
|
||||
|
||||
#endif
|
@ -1,78 +0,0 @@
|
||||
/**
|
||||
* This file contains declaration referring to
|
||||
* functions defined in other source files
|
||||
*/
|
||||
|
||||
#ifndef _LBS_DECL_H_
|
||||
#define _LBS_DECL_H_
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
/** Function Prototype Declaration */
|
||||
struct lbs_private;
|
||||
struct sk_buff;
|
||||
struct net_device;
|
||||
struct cmd_ctrl_node;
|
||||
struct cmd_ds_command;
|
||||
|
||||
void lbs_set_mac_control(struct lbs_private *priv);
|
||||
|
||||
void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count);
|
||||
|
||||
int lbs_free_cmd_buffer(struct lbs_private *priv);
|
||||
|
||||
int lbs_prepare_and_send_command(struct lbs_private *priv,
|
||||
u16 cmd_no,
|
||||
u16 cmd_action,
|
||||
u16 wait_option, u32 cmd_oid, void *pdata_buf);
|
||||
|
||||
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, u32 event);
|
||||
void lbs_queue_event(struct lbs_private *priv, u32 event);
|
||||
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
|
||||
|
||||
int lbs_set_radio_control(struct lbs_private *priv);
|
||||
u32 lbs_fw_index_to_data_rate(u8 index);
|
||||
u8 lbs_data_rate_to_fw_index(u32 rate);
|
||||
|
||||
/** The proc fs interface */
|
||||
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
|
||||
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);
|
||||
|
||||
int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *);
|
||||
|
||||
void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
|
||||
void lbs_ps_confirm_sleep(struct lbs_private *priv);
|
||||
void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
|
||||
|
||||
struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
|
||||
struct lbs_private *priv,
|
||||
u8 band,
|
||||
u16 channel);
|
||||
|
||||
void lbs_mac_event_disconnected(struct lbs_private *priv);
|
||||
|
||||
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
|
||||
|
||||
/* main.c */
|
||||
struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
|
||||
int *cfp_no);
|
||||
struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
|
||||
int lbs_remove_card(struct lbs_private *priv);
|
||||
int lbs_start_card(struct lbs_private *priv);
|
||||
int lbs_stop_card(struct lbs_private *priv);
|
||||
void lbs_host_to_card_done(struct lbs_private *priv);
|
||||
|
||||
int lbs_update_channel(struct lbs_private *priv);
|
||||
|
||||
#ifndef CONFIG_IEEE80211
|
||||
const char *escape_essid(const char *essid, u8 essid_len);
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,384 +0,0 @@
|
||||
/**
|
||||
* This header file contains global constant/enum definitions,
|
||||
* global variable declaration.
|
||||
*/
|
||||
#ifndef _LBS_DEFS_H_
|
||||
#define _LBS_DEFS_H_
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#ifdef CONFIG_LIBERTAS_DEBUG
|
||||
#define DEBUG
|
||||
#define PROC_DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef DRV_NAME
|
||||
#define DRV_NAME "libertas"
|
||||
#endif
|
||||
|
||||
|
||||
#define LBS_DEB_ENTER 0x00000001
|
||||
#define LBS_DEB_LEAVE 0x00000002
|
||||
#define LBS_DEB_MAIN 0x00000004
|
||||
#define LBS_DEB_NET 0x00000008
|
||||
#define LBS_DEB_MESH 0x00000010
|
||||
#define LBS_DEB_WEXT 0x00000020
|
||||
#define LBS_DEB_IOCTL 0x00000040
|
||||
#define LBS_DEB_SCAN 0x00000080
|
||||
#define LBS_DEB_ASSOC 0x00000100
|
||||
#define LBS_DEB_JOIN 0x00000200
|
||||
#define LBS_DEB_11D 0x00000400
|
||||
#define LBS_DEB_DEBUGFS 0x00000800
|
||||
#define LBS_DEB_ETHTOOL 0x00001000
|
||||
#define LBS_DEB_HOST 0x00002000
|
||||
#define LBS_DEB_CMD 0x00004000
|
||||
#define LBS_DEB_RX 0x00008000
|
||||
#define LBS_DEB_TX 0x00010000
|
||||
#define LBS_DEB_USB 0x00020000
|
||||
#define LBS_DEB_CS 0x00040000
|
||||
#define LBS_DEB_FW 0x00080000
|
||||
#define LBS_DEB_THREAD 0x00100000
|
||||
#define LBS_DEB_HEX 0x00200000
|
||||
#define LBS_DEB_SDIO 0x00400000
|
||||
|
||||
extern unsigned int lbs_debug;
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LBS_DEB_LL(grp, grpnam, fmt, args...) \
|
||||
do { if ((lbs_debug & (grp)) == (grp)) \
|
||||
printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \
|
||||
in_interrupt() ? " (INT)" : "", ## args); } while (0)
|
||||
#else
|
||||
#define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define lbs_deb_enter(grp) \
|
||||
LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s()\n", __func__);
|
||||
#define lbs_deb_enter_args(grp, fmt, args...) \
|
||||
LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt ")\n", __func__, ## args);
|
||||
#define lbs_deb_leave(grp) \
|
||||
LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s()\n", __func__);
|
||||
#define lbs_deb_leave_args(grp, fmt, args...) \
|
||||
LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s(), " fmt "\n", \
|
||||
__func__, ##args);
|
||||
#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args)
|
||||
#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args)
|
||||
#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args)
|
||||
#define lbs_deb_wext(fmt, args...) LBS_DEB_LL(LBS_DEB_WEXT, " wext", fmt, ##args)
|
||||
#define lbs_deb_ioctl(fmt, args...) LBS_DEB_LL(LBS_DEB_IOCTL, " ioctl", fmt, ##args)
|
||||
#define lbs_deb_scan(fmt, args...) LBS_DEB_LL(LBS_DEB_SCAN, " scan", fmt, ##args)
|
||||
#define lbs_deb_assoc(fmt, args...) LBS_DEB_LL(LBS_DEB_ASSOC, " assoc", fmt, ##args)
|
||||
#define lbs_deb_join(fmt, args...) LBS_DEB_LL(LBS_DEB_JOIN, " join", fmt, ##args)
|
||||
#define lbs_deb_11d(fmt, args...) LBS_DEB_LL(LBS_DEB_11D, " 11d", fmt, ##args)
|
||||
#define lbs_deb_debugfs(fmt, args...) LBS_DEB_LL(LBS_DEB_DEBUGFS, " debugfs", fmt, ##args)
|
||||
#define lbs_deb_ethtool(fmt, args...) LBS_DEB_LL(LBS_DEB_ETHTOOL, " ethtool", fmt, ##args)
|
||||
#define lbs_deb_host(fmt, args...) LBS_DEB_LL(LBS_DEB_HOST, " host", fmt, ##args)
|
||||
#define lbs_deb_cmd(fmt, args...) LBS_DEB_LL(LBS_DEB_CMD, " cmd", fmt, ##args)
|
||||
#define lbs_deb_rx(fmt, args...) LBS_DEB_LL(LBS_DEB_RX, " rx", fmt, ##args)
|
||||
#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args)
|
||||
#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args)
|
||||
#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args)
|
||||
#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
|
||||
#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
|
||||
#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
|
||||
#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " thread", fmt, ##args)
|
||||
|
||||
#define lbs_pr_info(format, args...) \
|
||||
printk(KERN_INFO DRV_NAME": " format, ## args)
|
||||
#define lbs_pr_err(format, args...) \
|
||||
printk(KERN_ERR DRV_NAME": " format, ## args)
|
||||
#define lbs_pr_alert(format, args...) \
|
||||
printk(KERN_ALERT DRV_NAME": " format, ## args)
|
||||
|
||||
#ifdef DEBUG
|
||||
static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (len &&
|
||||
(lbs_debug & LBS_DEB_HEX) &&
|
||||
(lbs_debug & grp))
|
||||
{
|
||||
for (i = 1; i <= len; i++) {
|
||||
if ((i & 0xf) == 1) {
|
||||
if (i != 1)
|
||||
printk("\n");
|
||||
printk(DRV_NAME " %s: ", prompt);
|
||||
}
|
||||
printk("%02x ", (u8) * buf);
|
||||
buf++;
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define lbs_deb_hex(grp,prompt,buf,len) do {} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/** Buffer Constants */
|
||||
|
||||
/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
|
||||
* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
|
||||
* driver has more local TxPDs. Each TxPD on the host memory is associated
|
||||
* with a Tx control node. The driver maintains 8 RxPD descriptors for
|
||||
* station firmware to store Rx packet information.
|
||||
*
|
||||
* Current version of MAC has a 32x6 multicast address buffer.
|
||||
*
|
||||
* 802.11b can have up to 14 channels, the driver keeps the
|
||||
* BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
|
||||
*/
|
||||
|
||||
#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
|
||||
#define LBS_NUM_CMD_BUFFERS 10
|
||||
#define LBS_CMD_BUFFER_SIZE (2 * 1024)
|
||||
#define MRVDRV_MAX_CHANNEL_SIZE 14
|
||||
#define MRVDRV_ASSOCIATION_TIME_OUT 255
|
||||
#define MRVDRV_SNAP_HEADER_LEN 8
|
||||
|
||||
#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 */
|
||||
|
||||
#define MRVDRV_MAX_BSS_DESCRIPTS 16
|
||||
#define MRVDRV_MAX_REGION_CODE 6
|
||||
|
||||
#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
|
||||
#define MRVDRV_MIN_MULTIPLE_DTIM 1
|
||||
#define MRVDRV_MAX_MULTIPLE_DTIM 5
|
||||
#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1
|
||||
|
||||
#define MRVDRV_DEFAULT_LISTEN_INTERVAL 10
|
||||
|
||||
#define MRVDRV_CHANNELS_PER_SCAN 4
|
||||
#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
|
||||
|
||||
#define MRVDRV_MIN_BEACON_INTERVAL 20
|
||||
#define MRVDRV_MAX_BEACON_INTERVAL 10000
|
||||
#define MRVDRV_BEACON_INTERVAL 100
|
||||
|
||||
#define MARVELL_MESH_IE_LENGTH 9
|
||||
|
||||
/** INT status Bit Definition*/
|
||||
#define MRVDRV_TX_DNLD_RDY 0x0001
|
||||
#define MRVDRV_RX_UPLD_RDY 0x0002
|
||||
#define MRVDRV_CMD_DNLD_RDY 0x0004
|
||||
#define MRVDRV_CMD_UPLD_RDY 0x0008
|
||||
#define MRVDRV_CARDEVENT 0x0010
|
||||
|
||||
/** TxPD status */
|
||||
|
||||
/* Station firmware use TxPD status field to report final Tx transmit
|
||||
* result, Bit masks are used to present combined situations.
|
||||
*/
|
||||
|
||||
#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
|
||||
#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
|
||||
|
||||
/** Tx mesh flag */
|
||||
/* Currently we are using normal WDS flag as mesh flag.
|
||||
* TODO: change to proper mesh flag when MAC understands it.
|
||||
*/
|
||||
#define TxPD_CONTROL_WDS_FRAME (1<<17)
|
||||
#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
|
||||
|
||||
/** RxPD status */
|
||||
|
||||
#define MRVDRV_RXPD_STATUS_OK 0x0001
|
||||
|
||||
/** RxPD status - Received packet types */
|
||||
/** Rx mesh flag */
|
||||
/* Currently we are using normal WDS flag as mesh flag.
|
||||
* TODO: change to proper mesh flag when MAC understands it.
|
||||
*/
|
||||
#define RxPD_CONTROL_WDS_FRAME (0x40)
|
||||
#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
|
||||
|
||||
/** RSSI-related defines */
|
||||
/* RSSI constants are used to implement 802.11 RSSI threshold
|
||||
* indication. if the Rx packet signal got too weak for 5 consecutive
|
||||
* times, miniport driver (driver) will report this event to wrapper
|
||||
*/
|
||||
|
||||
#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96)
|
||||
|
||||
/** RTS/FRAG related defines */
|
||||
#define MRVDRV_RTS_MIN_VALUE 0
|
||||
#define MRVDRV_RTS_MAX_VALUE 2347
|
||||
#define MRVDRV_FRAG_MIN_VALUE 256
|
||||
#define MRVDRV_FRAG_MAX_VALUE 2346
|
||||
|
||||
/* This is for firmware specific length */
|
||||
#define EXTRA_LEN 36
|
||||
|
||||
#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
|
||||
(ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN)
|
||||
|
||||
#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
|
||||
(ETH_FRAME_LEN + sizeof(struct rxpd) \
|
||||
+ MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
|
||||
|
||||
#define CMD_F_HOSTCMD (1 << 0)
|
||||
#define FW_CAPINFO_WPA (1 << 0)
|
||||
|
||||
#define KEY_LEN_WPA_AES 16
|
||||
#define KEY_LEN_WPA_TKIP 32
|
||||
#define KEY_LEN_WEP_104 13
|
||||
#define KEY_LEN_WEP_40 5
|
||||
|
||||
#define RF_ANTENNA_1 0x1
|
||||
#define RF_ANTENNA_2 0x2
|
||||
#define RF_ANTENNA_AUTO 0xFFFF
|
||||
|
||||
#define BAND_B (0x01)
|
||||
#define BAND_G (0x02)
|
||||
#define ALL_802_11_BANDS (BAND_B | BAND_G)
|
||||
|
||||
/** MACRO DEFINITIONS */
|
||||
#define CAL_NF(NF) ((s32)(-(s32)(NF)))
|
||||
#define CAL_RSSI(SNR, NF) ((s32)((s32)(SNR) + CAL_NF(NF)))
|
||||
#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI)))
|
||||
|
||||
#define DEFAULT_BCN_AVG_FACTOR 8
|
||||
#define DEFAULT_DATA_AVG_FACTOR 8
|
||||
#define AVG_SCALE 100
|
||||
#define CAL_AVG_SNR_NF(AVG, SNRNF, N) \
|
||||
(((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \
|
||||
((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
|
||||
AVG_SCALE)) / N))
|
||||
|
||||
#define MAX_RATES 14
|
||||
|
||||
#define MAX_LEDS 8
|
||||
|
||||
/** Global Variable Declaration */
|
||||
extern const char lbs_driver_version[];
|
||||
extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE];
|
||||
|
||||
extern u8 lbs_bg_rates[MAX_RATES];
|
||||
|
||||
/** ENUM definition*/
|
||||
/** SNRNF_TYPE */
|
||||
enum SNRNF_TYPE {
|
||||
TYPE_BEACON = 0,
|
||||
TYPE_RXPD,
|
||||
MAX_TYPE_B
|
||||
};
|
||||
|
||||
/** SNRNF_DATA*/
|
||||
enum SNRNF_DATA {
|
||||
TYPE_NOAVG = 0,
|
||||
TYPE_AVG,
|
||||
MAX_TYPE_AVG
|
||||
};
|
||||
|
||||
/** LBS_802_11_POWER_MODE */
|
||||
enum LBS_802_11_POWER_MODE {
|
||||
LBS802_11POWERMODECAM,
|
||||
LBS802_11POWERMODEMAX_PSP,
|
||||
LBS802_11POWERMODEFAST_PSP,
|
||||
/*not a real mode, defined as an upper bound */
|
||||
LBS802_11POWEMODEMAX
|
||||
};
|
||||
|
||||
/** PS_STATE */
|
||||
enum PS_STATE {
|
||||
PS_STATE_FULL_POWER,
|
||||
PS_STATE_AWAKE,
|
||||
PS_STATE_PRE_SLEEP,
|
||||
PS_STATE_SLEEP
|
||||
};
|
||||
|
||||
/** DNLD_STATE */
|
||||
enum DNLD_STATE {
|
||||
DNLD_RES_RECEIVED,
|
||||
DNLD_DATA_SENT,
|
||||
DNLD_CMD_SENT
|
||||
};
|
||||
|
||||
/** LBS_MEDIA_STATE */
|
||||
enum LBS_MEDIA_STATE {
|
||||
LBS_CONNECTED,
|
||||
LBS_DISCONNECTED
|
||||
};
|
||||
|
||||
/** LBS_802_11_PRIVACY_FILTER */
|
||||
enum LBS_802_11_PRIVACY_FILTER {
|
||||
LBS802_11PRIVFILTERACCEPTALL,
|
||||
LBS802_11PRIVFILTER8021XWEP
|
||||
};
|
||||
|
||||
/** mv_ms_type */
|
||||
enum mv_ms_type {
|
||||
MVMS_DAT = 0,
|
||||
MVMS_CMD = 1,
|
||||
MVMS_TXDONE = 2,
|
||||
MVMS_EVENT
|
||||
};
|
||||
|
||||
/** SNMP_MIB_INDEX_e */
|
||||
enum SNMP_MIB_INDEX_e {
|
||||
DESIRED_BSSTYPE_I = 0,
|
||||
OP_RATESET_I,
|
||||
BCNPERIOD_I,
|
||||
DTIMPERIOD_I,
|
||||
ASSOCRSP_TIMEOUT_I,
|
||||
RTSTHRESH_I,
|
||||
SHORT_RETRYLIM_I,
|
||||
LONG_RETRYLIM_I,
|
||||
FRAGTHRESH_I,
|
||||
DOT11D_I,
|
||||
DOT11H_I,
|
||||
MANUFID_I,
|
||||
PRODID_I,
|
||||
MANUF_OUI_I,
|
||||
MANUF_NAME_I,
|
||||
MANUF_PRODNAME_I,
|
||||
MANUF_PRODVER_I,
|
||||
};
|
||||
|
||||
/** KEY_TYPE_ID */
|
||||
enum KEY_TYPE_ID {
|
||||
KEY_TYPE_ID_WEP = 0,
|
||||
KEY_TYPE_ID_TKIP,
|
||||
KEY_TYPE_ID_AES
|
||||
};
|
||||
|
||||
/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
|
||||
enum KEY_INFO_WPA {
|
||||
KEY_INFO_WPA_MCAST = 0x01,
|
||||
KEY_INFO_WPA_UNICAST = 0x02,
|
||||
KEY_INFO_WPA_ENABLED = 0x04
|
||||
};
|
||||
|
||||
/** SNMP_MIB_VALUE_e */
|
||||
enum SNMP_MIB_VALUE_e {
|
||||
SNMP_MIB_VALUE_INFRA = 1,
|
||||
SNMP_MIB_VALUE_ADHOC
|
||||
};
|
||||
|
||||
/* Default values for fwt commands. */
|
||||
#define FWT_DEFAULT_METRIC 0
|
||||
#define FWT_DEFAULT_DIR 1
|
||||
/* Default Rate, 11Mbps */
|
||||
#define FWT_DEFAULT_RATE 3
|
||||
#define FWT_DEFAULT_SSN 0xffffffff
|
||||
#define FWT_DEFAULT_DSN 0
|
||||
#define FWT_DEFAULT_HOPCOUNT 0
|
||||
#define FWT_DEFAULT_TTL 0
|
||||
#define FWT_DEFAULT_EXPIRATION 0
|
||||
#define FWT_DEFAULT_SLEEPMODE 0
|
||||
#define FWT_DEFAULT_SNR 0
|
||||
|
||||
#endif
|
@ -1,404 +0,0 @@
|
||||
/**
|
||||
* This file contains definitions and data structures specific
|
||||
* to Marvell 802.11 NIC. It contains the Device Information
|
||||
* structure struct lbs_private..
|
||||
*/
|
||||
#ifndef _LBS_DEV_H_
|
||||
#define _LBS_DEV_H_
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <net/ieee80211.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "hostcmd.h"
|
||||
|
||||
extern struct ethtool_ops lbs_ethtool_ops;
|
||||
|
||||
#define MAX_BSSID_PER_CHANNEL 16
|
||||
|
||||
#define NR_TX_QUEUE 3
|
||||
|
||||
/* For the extended Scan */
|
||||
#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \
|
||||
MRVDRV_MAX_CHANNEL_SIZE + 1
|
||||
|
||||
#define MAX_REGION_CHANNEL_NUM 2
|
||||
|
||||
/** Chan-freq-TxPower mapping table*/
|
||||
struct chan_freq_power {
|
||||
/** channel Number */
|
||||
u16 channel;
|
||||
/** frequency of this channel */
|
||||
u32 freq;
|
||||
/** Max allowed Tx power level */
|
||||
u16 maxtxpower;
|
||||
/** TRUE:channel unsupported; FLASE:supported*/
|
||||
u8 unsupported;
|
||||
};
|
||||
|
||||
/** region-band mapping table*/
|
||||
struct region_channel {
|
||||
/** TRUE if this entry is valid */
|
||||
u8 valid;
|
||||
/** region code for US, Japan ... */
|
||||
u8 region;
|
||||
/** band B/G/A, used for BAND_CONFIG cmd */
|
||||
u8 band;
|
||||
/** Actual No. of elements in the array below */
|
||||
u8 nrcfp;
|
||||
/** chan-freq-txpower mapping table*/
|
||||
struct chan_freq_power *CFP;
|
||||
};
|
||||
|
||||
struct lbs_802_11_security {
|
||||
u8 WPAenabled;
|
||||
u8 WPA2enabled;
|
||||
u8 wep_enabled;
|
||||
u8 auth_mode;
|
||||
};
|
||||
|
||||
/** Current Basic Service Set State Structure */
|
||||
struct current_bss_params {
|
||||
/** bssid */
|
||||
u8 bssid[ETH_ALEN];
|
||||
/** ssid */
|
||||
u8 ssid[IW_ESSID_MAX_SIZE + 1];
|
||||
u8 ssid_len;
|
||||
|
||||
/** band */
|
||||
u8 band;
|
||||
/** channel */
|
||||
u8 channel;
|
||||
/** zero-terminated array of supported data rates */
|
||||
u8 rates[MAX_RATES + 1];
|
||||
};
|
||||
|
||||
/** sleep_params */
|
||||
struct sleep_params {
|
||||
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 */
|
||||
struct lbs_mesh_stats {
|
||||
u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
|
||||
u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
|
||||
u32 fwd_drop_ttl; /* Fwd: TTL zero */
|
||||
u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
|
||||
u32 fwd_drop_noroute; /* Fwd: No route to Destination */
|
||||
u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
|
||||
u32 drop_blind; /* Rx: Dropped by blinding table */
|
||||
u32 tx_failed_cnt; /* Tx: Failed transmissions */
|
||||
};
|
||||
|
||||
/** Private structure for the MV device */
|
||||
struct lbs_private {
|
||||
int mesh_open;
|
||||
int infra_open;
|
||||
int mesh_autostart_enabled;
|
||||
|
||||
char name[DEV_NAME_LEN];
|
||||
|
||||
void *card;
|
||||
struct net_device *dev;
|
||||
|
||||
struct net_device_stats stats;
|
||||
struct net_device *mesh_dev; /* Virtual device */
|
||||
struct net_device *rtap_net_dev;
|
||||
|
||||
struct iw_statistics wstats;
|
||||
struct lbs_mesh_stats mstats;
|
||||
struct dentry *debugfs_dir;
|
||||
struct dentry *debugfs_debug;
|
||||
struct dentry *debugfs_files[6];
|
||||
|
||||
struct dentry *events_dir;
|
||||
struct dentry *debugfs_events_files[6];
|
||||
|
||||
struct dentry *regs_dir;
|
||||
struct dentry *debugfs_regs_files[6];
|
||||
|
||||
u32 mac_offset;
|
||||
u32 bbp_offset;
|
||||
u32 rf_offset;
|
||||
|
||||
/* Download sent:
|
||||
bit0 1/0=data_sent/data_tx_done,
|
||||
bit1 1/0=cmd_sent/cmd_tx_done,
|
||||
all other bits reserved 0 */
|
||||
u8 dnld_sent;
|
||||
|
||||
/** thread to service interrupts */
|
||||
struct task_struct *main_thread;
|
||||
wait_queue_head_t waitq;
|
||||
struct workqueue_struct *work_thread;
|
||||
|
||||
/** Scanning */
|
||||
struct delayed_work scan_work;
|
||||
struct delayed_work assoc_work;
|
||||
struct work_struct sync_channel;
|
||||
/* remember which channel was scanned last, != 0 if currently scanning */
|
||||
int scan_channel;
|
||||
u8 scan_ssid[IW_ESSID_MAX_SIZE + 1];
|
||||
u8 scan_ssid_len;
|
||||
|
||||
/** Hardware access */
|
||||
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
|
||||
|
||||
/* Wake On LAN */
|
||||
uint32_t wol_criteria;
|
||||
uint8_t wol_gpio;
|
||||
uint8_t wol_gap;
|
||||
|
||||
/** Wlan adapter data structure*/
|
||||
/** STATUS variables */
|
||||
u32 fwrelease;
|
||||
u32 fwcapinfo;
|
||||
|
||||
struct mutex lock;
|
||||
|
||||
/* TX packet ready to be sent... */
|
||||
int tx_pending_len; /* -1 while building packet */
|
||||
|
||||
u8 tx_pending_buf[LBS_UPLD_SIZE];
|
||||
/* protected by hard_start_xmit serialization */
|
||||
|
||||
/** command-related variables */
|
||||
u16 seqnum;
|
||||
|
||||
struct cmd_ctrl_node *cmd_array;
|
||||
/** Current command */
|
||||
struct cmd_ctrl_node *cur_cmd;
|
||||
int cur_cmd_retcode;
|
||||
/** command Queues */
|
||||
/** Free command buffers */
|
||||
struct list_head cmdfreeq;
|
||||
/** Pending command buffers */
|
||||
struct list_head cmdpendingq;
|
||||
|
||||
wait_queue_head_t cmd_pending;
|
||||
|
||||
/* Command responses sent from the hardware to the driver */
|
||||
u8 resp_idx;
|
||||
u8 resp_buf[2][LBS_UPLD_SIZE];
|
||||
u32 resp_len[2];
|
||||
|
||||
/* Events sent from hardware to driver */
|
||||
struct kfifo *event_fifo;
|
||||
|
||||
/* nickname */
|
||||
u8 nodename[16];
|
||||
|
||||
/** spin locks */
|
||||
spinlock_t driver_lock;
|
||||
|
||||
/** Timers */
|
||||
struct timer_list command_timer;
|
||||
int nr_retries;
|
||||
int cmd_timed_out;
|
||||
|
||||
/** 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;
|
||||
|
||||
/* IW_MODE_* */
|
||||
u8 mode;
|
||||
|
||||
/* Scan results list */
|
||||
struct list_head network_list;
|
||||
struct list_head network_free_list;
|
||||
struct bss_descriptor *networks;
|
||||
|
||||
u16 beacon_period;
|
||||
u8 beacon_enable;
|
||||
u8 adhoccreate;
|
||||
|
||||
/** capability Info used in Association, start, join */
|
||||
u16 capability;
|
||||
|
||||
/** MAC address information */
|
||||
u8 current_addr[ETH_ALEN];
|
||||
u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
|
||||
u32 nr_of_multicastmacaddr;
|
||||
|
||||
/** 802.11 statistics */
|
||||
// struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
|
||||
|
||||
u16 enablehwauto;
|
||||
u16 ratebitmap;
|
||||
|
||||
u32 fragthsd;
|
||||
u32 rtsthsd;
|
||||
|
||||
u8 txretrycount;
|
||||
|
||||
/** Tx-related variables (for single packet tx) */
|
||||
struct sk_buff *currenttxskb;
|
||||
|
||||
/** NIC Operation characteristics */
|
||||
u16 mac_control;
|
||||
u32 connect_status;
|
||||
u32 mesh_connect_status;
|
||||
u16 regioncode;
|
||||
u16 txpowerlevel;
|
||||
|
||||
/** POWER MANAGEMENT AND PnP SUPPORT */
|
||||
u8 surpriseremoved;
|
||||
|
||||
u16 psmode; /* Wlan802_11PowermodeCAM=disable
|
||||
Wlan802_11PowermodeMAX_PSP=enable */
|
||||
u32 psstate;
|
||||
char ps_supported;
|
||||
u8 needtowakeup;
|
||||
|
||||
struct assoc_request * pending_assoc_req;
|
||||
struct assoc_request * in_progress_assoc_req;
|
||||
|
||||
/** Encryption parameter */
|
||||
struct lbs_802_11_security secinfo;
|
||||
|
||||
/** WEP keys */
|
||||
struct enc_key wep_keys[4];
|
||||
u16 wep_tx_keyidx;
|
||||
|
||||
/** WPA keys */
|
||||
struct enc_key wpa_mcast_key;
|
||||
struct enc_key wpa_unicast_key;
|
||||
|
||||
/** WPA Information Elements*/
|
||||
u8 wpa_ie[MAX_WPA_IE_LEN];
|
||||
u8 wpa_ie_len;
|
||||
|
||||
/** Requested Signal Strength*/
|
||||
u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
|
||||
u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
|
||||
u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
|
||||
u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
|
||||
u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
|
||||
u16 nextSNRNF;
|
||||
u16 numSNRNF;
|
||||
|
||||
u8 radioon;
|
||||
u32 preamble;
|
||||
|
||||
/** data rate stuff */
|
||||
u8 cur_rate;
|
||||
u8 auto_rate;
|
||||
|
||||
/** RF calibration data */
|
||||
|
||||
#define MAX_REGION_CHANNEL_NUM 2
|
||||
/** region channel data */
|
||||
struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
|
||||
|
||||
struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM];
|
||||
|
||||
/** 11D and Domain Regulatory Data */
|
||||
struct lbs_802_11d_domain_reg domainreg;
|
||||
struct parsed_region_chan_11d parsed_region_chan;
|
||||
|
||||
/** FSM variable for 11d support */
|
||||
u32 enable11d;
|
||||
|
||||
/** MISCELLANEOUS */
|
||||
struct lbs_offset_value offsetvalue;
|
||||
|
||||
u32 monitormode;
|
||||
u8 fw_ready;
|
||||
};
|
||||
|
||||
extern struct cmd_confirm_sleep confirm_sleep;
|
||||
|
||||
/**
|
||||
* @brief Structure used to store information for each beacon/probe response
|
||||
*/
|
||||
struct bss_descriptor {
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
||||
u8 ssid[IW_ESSID_MAX_SIZE + 1];
|
||||
u8 ssid_len;
|
||||
|
||||
u16 capability;
|
||||
u32 rssi;
|
||||
u32 channel;
|
||||
u16 beaconperiod;
|
||||
u32 atimwindow;
|
||||
|
||||
/* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
|
||||
u8 mode;
|
||||
|
||||
/* zero-terminated array of supported data rates */
|
||||
u8 rates[MAX_RATES + 1];
|
||||
|
||||
unsigned long last_scanned;
|
||||
|
||||
union ieeetypes_phyparamset phyparamset;
|
||||
union IEEEtypes_ssparamset ssparamset;
|
||||
|
||||
struct ieeetypes_countryinfofullset countryinfo;
|
||||
|
||||
u8 wpa_ie[MAX_WPA_IE_LEN];
|
||||
size_t wpa_ie_len;
|
||||
u8 rsn_ie[MAX_WPA_IE_LEN];
|
||||
size_t rsn_ie_len;
|
||||
|
||||
u8 mesh;
|
||||
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/** Association request
|
||||
*
|
||||
* Encapsulates all the options that describe a specific assocation request
|
||||
* or configuration of the wireless card's radio, mode, and security settings.
|
||||
*/
|
||||
struct assoc_request {
|
||||
#define ASSOC_FLAG_SSID 1
|
||||
#define ASSOC_FLAG_CHANNEL 2
|
||||
#define ASSOC_FLAG_BAND 3
|
||||
#define ASSOC_FLAG_MODE 4
|
||||
#define ASSOC_FLAG_BSSID 5
|
||||
#define ASSOC_FLAG_WEP_KEYS 6
|
||||
#define ASSOC_FLAG_WEP_TX_KEYIDX 7
|
||||
#define ASSOC_FLAG_WPA_MCAST_KEY 8
|
||||
#define ASSOC_FLAG_WPA_UCAST_KEY 9
|
||||
#define ASSOC_FLAG_SECINFO 10
|
||||
#define ASSOC_FLAG_WPA_IE 11
|
||||
unsigned long flags;
|
||||
|
||||
u8 ssid[IW_ESSID_MAX_SIZE + 1];
|
||||
u8 ssid_len;
|
||||
u8 channel;
|
||||
u8 band;
|
||||
u8 mode;
|
||||
u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
|
||||
|
||||
/** WEP keys */
|
||||
struct enc_key wep_keys[4];
|
||||
u16 wep_tx_keyidx;
|
||||
|
||||
/** WPA keys */
|
||||
struct enc_key wpa_mcast_key;
|
||||
struct enc_key wpa_unicast_key;
|
||||
|
||||
struct lbs_802_11_security secinfo;
|
||||
|
||||
/** WPA Information Elements*/
|
||||
u8 wpa_ie[MAX_WPA_IE_LEN];
|
||||
u8 wpa_ie_len;
|
||||
|
||||
/* BSS to associate with for infrastructure of Ad-Hoc join */
|
||||
struct bss_descriptor bss;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,196 +0,0 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "host.h"
|
||||
#include "decl.h"
|
||||
#include "defs.h"
|
||||
#include "dev.h"
|
||||
#include "wext.h"
|
||||
#include "cmd.h"
|
||||
|
||||
static const char * mesh_stat_strings[]= {
|
||||
"drop_duplicate_bcast",
|
||||
"drop_ttl_zero",
|
||||
"drop_no_fwd_route",
|
||||
"drop_no_buffers",
|
||||
"fwded_unicast_cnt",
|
||||
"fwded_bcast_cnt",
|
||||
"drop_blind_table",
|
||||
"tx_failed_cnt"
|
||||
};
|
||||
|
||||
static void lbs_ethtool_get_drvinfo(struct net_device *dev,
|
||||
struct ethtool_drvinfo *info)
|
||||
{
|
||||
struct lbs_private *priv = (struct lbs_private *) dev->priv;
|
||||
|
||||
snprintf(info->fw_version, 32, "%u.%u.%u.p%u",
|
||||
priv->fwrelease >> 24 & 0xff,
|
||||
priv->fwrelease >> 16 & 0xff,
|
||||
priv->fwrelease >> 8 & 0xff,
|
||||
priv->fwrelease & 0xff);
|
||||
strcpy(info->driver, "libertas");
|
||||
strcpy(info->version, lbs_driver_version);
|
||||
}
|
||||
|
||||
/* All 8388 parts have 16KiB EEPROM size at the time of writing.
|
||||
* In case that changes this needs fixing.
|
||||
*/
|
||||
#define LBS_EEPROM_LEN 16384
|
||||
|
||||
static int lbs_ethtool_get_eeprom_len(struct net_device *dev)
|
||||
{
|
||||
return LBS_EEPROM_LEN;
|
||||
}
|
||||
|
||||
static int lbs_ethtool_get_eeprom(struct net_device *dev,
|
||||
struct ethtool_eeprom *eeprom, u8 * bytes)
|
||||
{
|
||||
struct lbs_private *priv = (struct lbs_private *) dev->priv;
|
||||
struct cmd_ds_802_11_eeprom_access cmd;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ETHTOOL);
|
||||
|
||||
if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN ||
|
||||
eeprom->len > LBS_EEPROM_READ_LEN) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) -
|
||||
LBS_EEPROM_READ_LEN + eeprom->len);
|
||||
cmd.action = cpu_to_le16(CMD_ACT_GET);
|
||||
cmd.offset = cpu_to_le16(eeprom->offset);
|
||||
cmd.len = cpu_to_le16(eeprom->len);
|
||||
ret = lbs_cmd_with_response(priv, CMD_802_11_EEPROM_ACCESS, &cmd);
|
||||
if (!ret)
|
||||
memcpy(bytes, cmd.value, eeprom->len);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_ETHTOOL, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void lbs_ethtool_get_stats(struct net_device *dev,
|
||||
struct ethtool_stats *stats, uint64_t *data)
|
||||
{
|
||||
struct lbs_private *priv = dev->priv;
|
||||
struct cmd_ds_mesh_access mesh_access;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ETHTOOL);
|
||||
|
||||
/* Get Mesh Statistics */
|
||||
ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
|
||||
|
||||
if (ret) {
|
||||
memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
|
||||
return;
|
||||
}
|
||||
|
||||
priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
|
||||
priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
|
||||
priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
|
||||
priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
|
||||
priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
|
||||
priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
|
||||
priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
|
||||
priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
|
||||
|
||||
data[0] = priv->mstats.fwd_drop_rbt;
|
||||
data[1] = priv->mstats.fwd_drop_ttl;
|
||||
data[2] = priv->mstats.fwd_drop_noroute;
|
||||
data[3] = priv->mstats.fwd_drop_nobuf;
|
||||
data[4] = priv->mstats.fwd_unicast_cnt;
|
||||
data[5] = priv->mstats.fwd_bcast_cnt;
|
||||
data[6] = priv->mstats.drop_blind;
|
||||
data[7] = priv->mstats.tx_failed_cnt;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ETHTOOL);
|
||||
}
|
||||
|
||||
static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset)
|
||||
{
|
||||
struct lbs_private *priv = dev->priv;
|
||||
|
||||
if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
|
||||
return MESH_STATS_NUM;
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static void lbs_ethtool_get_strings(struct net_device *dev,
|
||||
uint32_t stringset, uint8_t *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ETHTOOL);
|
||||
|
||||
switch (stringset) {
|
||||
case ETH_SS_STATS:
|
||||
for (i=0; i < MESH_STATS_NUM; i++) {
|
||||
memcpy(s + i * ETH_GSTRING_LEN,
|
||||
mesh_stat_strings[i],
|
||||
ETH_GSTRING_LEN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
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,
|
||||
};
|
||||
|
@ -1,292 +0,0 @@
|
||||
/**
|
||||
* This file contains definitions of WLAN commands.
|
||||
*/
|
||||
|
||||
#ifndef _LBS_HOST_H_
|
||||
#define _LBS_HOST_H_
|
||||
|
||||
/** PUBLIC DEFINITIONS */
|
||||
#define DEFAULT_AD_HOC_CHANNEL 6
|
||||
#define DEFAULT_AD_HOC_CHANNEL_A 36
|
||||
|
||||
/** IEEE 802.11 oids */
|
||||
#define OID_802_11_SSID 0x00008002
|
||||
#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008
|
||||
#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009
|
||||
#define OID_802_11_RTS_THRESHOLD 0x0000800A
|
||||
#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D
|
||||
#define OID_802_11_SUPPORTED_RATES 0x0000800E
|
||||
#define OID_802_11_STATISTICS 0x00008012
|
||||
#define OID_802_11_TX_RETRYCOUNT 0x0000801D
|
||||
#define OID_802_11D_ENABLE 0x00008020
|
||||
|
||||
#define CMD_OPTION_WAITFORRSP 0x0002
|
||||
|
||||
/** Host command IDs */
|
||||
|
||||
/* Return command are almost always the same as the host command, but with
|
||||
* bit 15 set high. There are a few exceptions, though...
|
||||
*/
|
||||
#define CMD_RET(cmd) (0x8000 | cmd)
|
||||
|
||||
/* Return command convention exceptions: */
|
||||
#define CMD_RET_802_11_ASSOCIATE 0x8012
|
||||
|
||||
/* Command codes */
|
||||
#define CMD_GET_HW_SPEC 0x0003
|
||||
#define CMD_EEPROM_UPDATE 0x0004
|
||||
#define CMD_802_11_RESET 0x0005
|
||||
#define CMD_802_11_SCAN 0x0006
|
||||
#define CMD_802_11_GET_LOG 0x000b
|
||||
#define CMD_MAC_MULTICAST_ADR 0x0010
|
||||
#define CMD_802_11_AUTHENTICATE 0x0011
|
||||
#define CMD_802_11_EEPROM_ACCESS 0x0059
|
||||
#define CMD_802_11_ASSOCIATE 0x0050
|
||||
#define CMD_802_11_SET_WEP 0x0013
|
||||
#define CMD_802_11_GET_STAT 0x0014
|
||||
#define CMD_802_3_GET_STAT 0x0015
|
||||
#define CMD_802_11_SNMP_MIB 0x0016
|
||||
#define CMD_MAC_REG_MAP 0x0017
|
||||
#define CMD_BBP_REG_MAP 0x0018
|
||||
#define CMD_MAC_REG_ACCESS 0x0019
|
||||
#define CMD_BBP_REG_ACCESS 0x001a
|
||||
#define CMD_RF_REG_ACCESS 0x001b
|
||||
#define CMD_802_11_RADIO_CONTROL 0x001c
|
||||
#define CMD_802_11_RF_CHANNEL 0x001d
|
||||
#define CMD_802_11_RF_TX_POWER 0x001e
|
||||
#define CMD_802_11_RSSI 0x001f
|
||||
#define CMD_802_11_RF_ANTENNA 0x0020
|
||||
#define CMD_802_11_PS_MODE 0x0021
|
||||
#define CMD_802_11_DATA_RATE 0x0022
|
||||
#define CMD_RF_REG_MAP 0x0023
|
||||
#define CMD_802_11_DEAUTHENTICATE 0x0024
|
||||
#define CMD_802_11_REASSOCIATE 0x0025
|
||||
#define CMD_802_11_DISASSOCIATE 0x0026
|
||||
#define CMD_MAC_CONTROL 0x0028
|
||||
#define CMD_802_11_AD_HOC_START 0x002b
|
||||
#define CMD_802_11_AD_HOC_JOIN 0x002c
|
||||
#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e
|
||||
#define CMD_802_11_ENABLE_RSN 0x002f
|
||||
#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
|
||||
#define CMD_802_11_EEPROM_ACCESS 0x0059
|
||||
#define CMD_802_11_BAND_CONFIG 0x0058
|
||||
#define CMD_802_11D_DOMAIN_INFO 0x005b
|
||||
#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_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
|
||||
#define CMD_GET_TSF 0x0080
|
||||
#define CMD_BT_ACCESS 0x0087
|
||||
#define CMD_FWT_ACCESS 0x0095
|
||||
#define CMD_802_11_MONITOR_MODE 0x0098
|
||||
#define CMD_MESH_ACCESS 0x009b
|
||||
#define CMD_MESH_CONFIG 0x00a3
|
||||
#define CMD_SET_BOOT2_VER 0x00a5
|
||||
#define CMD_802_11_BEACON_CTRL 0x00b0
|
||||
|
||||
/* For the IEEE Power Save */
|
||||
#define CMD_SUBCMD_ENTER_PS 0x0030
|
||||
#define CMD_SUBCMD_EXIT_PS 0x0031
|
||||
#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034
|
||||
#define CMD_SUBCMD_FULL_POWERDOWN 0x0035
|
||||
#define CMD_SUBCMD_FULL_POWERUP 0x0036
|
||||
|
||||
#define CMD_ENABLE_RSN 0x0001
|
||||
#define CMD_DISABLE_RSN 0x0000
|
||||
|
||||
#define CMD_ACT_GET 0x0000
|
||||
#define CMD_ACT_SET 0x0001
|
||||
#define CMD_ACT_GET_AES 0x0002
|
||||
#define CMD_ACT_SET_AES 0x0003
|
||||
#define CMD_ACT_REMOVE_AES 0x0004
|
||||
|
||||
/* Define action or option for CMD_802_11_SET_WEP */
|
||||
#define CMD_ACT_ADD 0x0002
|
||||
#define CMD_ACT_REMOVE 0x0004
|
||||
#define CMD_ACT_USE_DEFAULT 0x0008
|
||||
|
||||
#define CMD_TYPE_WEP_40_BIT 0x01
|
||||
#define CMD_TYPE_WEP_104_BIT 0x02
|
||||
|
||||
#define CMD_NUM_OF_WEP_KEYS 4
|
||||
|
||||
#define CMD_WEP_KEY_INDEX_MASK 0x3fff
|
||||
|
||||
/* Define action or option for CMD_802_11_RESET */
|
||||
#define CMD_ACT_HALT 0x0003
|
||||
|
||||
/* Define action or option for CMD_802_11_SCAN */
|
||||
#define CMD_BSS_TYPE_BSS 0x0001
|
||||
#define CMD_BSS_TYPE_IBSS 0x0002
|
||||
#define CMD_BSS_TYPE_ANY 0x0003
|
||||
|
||||
/* Define action or option for CMD_802_11_SCAN */
|
||||
#define CMD_SCAN_TYPE_ACTIVE 0x0000
|
||||
#define CMD_SCAN_TYPE_PASSIVE 0x0001
|
||||
|
||||
#define CMD_SCAN_RADIO_TYPE_BG 0
|
||||
|
||||
#define CMD_SCAN_PROBE_DELAY_TIME 0
|
||||
|
||||
/* Define action or option for CMD_MAC_CONTROL */
|
||||
#define CMD_ACT_MAC_RX_ON 0x0001
|
||||
#define CMD_ACT_MAC_TX_ON 0x0002
|
||||
#define CMD_ACT_MAC_LOOPBACK_ON 0x0004
|
||||
#define CMD_ACT_MAC_WEP_ENABLE 0x0008
|
||||
#define CMD_ACT_MAC_INT_ENABLE 0x0010
|
||||
#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020
|
||||
#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040
|
||||
#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
|
||||
#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
|
||||
#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
|
||||
|
||||
/* Define action or option for CMD_802_11_RADIO_CONTROL */
|
||||
#define CMD_TYPE_AUTO_PREAMBLE 0x0001
|
||||
#define CMD_TYPE_SHORT_PREAMBLE 0x0002
|
||||
#define CMD_TYPE_LONG_PREAMBLE 0x0003
|
||||
|
||||
/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
|
||||
#define CMD_SUBSCRIBE_RSSI_LOW 0x0001
|
||||
#define CMD_SUBSCRIBE_SNR_LOW 0x0002
|
||||
#define CMD_SUBSCRIBE_FAILCOUNT 0x0004
|
||||
#define CMD_SUBSCRIBE_BCNMISS 0x0008
|
||||
#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010
|
||||
#define CMD_SUBSCRIBE_SNR_HIGH 0x0020
|
||||
|
||||
#define TURN_ON_RF 0x01
|
||||
#define RADIO_ON 0x01
|
||||
#define RADIO_OFF 0x00
|
||||
|
||||
#define SET_AUTO_PREAMBLE 0x05
|
||||
#define SET_SHORT_PREAMBLE 0x03
|
||||
#define SET_LONG_PREAMBLE 0x01
|
||||
|
||||
/* Define action or option for CMD_802_11_RF_CHANNEL */
|
||||
#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00
|
||||
#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01
|
||||
|
||||
/* Define action or option for CMD_802_11_RF_TX_POWER */
|
||||
#define CMD_ACT_TX_POWER_OPT_GET 0x0000
|
||||
#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007
|
||||
#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004
|
||||
#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000
|
||||
|
||||
#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007
|
||||
#define CMD_ACT_TX_POWER_INDEX_MID 0x0004
|
||||
#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000
|
||||
|
||||
/* Define action or option for CMD_802_11_DATA_RATE */
|
||||
#define CMD_ACT_SET_TX_AUTO 0x0000
|
||||
#define CMD_ACT_SET_TX_FIX_RATE 0x0001
|
||||
#define CMD_ACT_GET_TX_RATE 0x0002
|
||||
|
||||
#define CMD_ACT_SET_RX 0x0001
|
||||
#define CMD_ACT_SET_TX 0x0002
|
||||
#define CMD_ACT_SET_BOTH 0x0003
|
||||
#define CMD_ACT_GET_RX 0x0004
|
||||
#define CMD_ACT_GET_TX 0x0008
|
||||
#define CMD_ACT_GET_BOTH 0x000c
|
||||
|
||||
/* Define action or option for CMD_802_11_PS_MODE */
|
||||
#define CMD_TYPE_CAM 0x0000
|
||||
#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
|
||||
* are mapped to 1-4. These old commands are no longer maintained and
|
||||
* should not be called.
|
||||
*/
|
||||
CMD_ACT_BT_ACCESS_ADD = 5,
|
||||
CMD_ACT_BT_ACCESS_DEL,
|
||||
CMD_ACT_BT_ACCESS_LIST,
|
||||
CMD_ACT_BT_ACCESS_RESET,
|
||||
CMD_ACT_BT_ACCESS_SET_INVERT,
|
||||
CMD_ACT_BT_ACCESS_GET_INVERT
|
||||
};
|
||||
|
||||
/* Define action or option for CMD_FWT_ACCESS */
|
||||
enum cmd_fwt_access_opts {
|
||||
CMD_ACT_FWT_ACCESS_ADD = 1,
|
||||
CMD_ACT_FWT_ACCESS_DEL,
|
||||
CMD_ACT_FWT_ACCESS_LOOKUP,
|
||||
CMD_ACT_FWT_ACCESS_LIST,
|
||||
CMD_ACT_FWT_ACCESS_LIST_ROUTE,
|
||||
CMD_ACT_FWT_ACCESS_LIST_NEIGHBOR,
|
||||
CMD_ACT_FWT_ACCESS_RESET,
|
||||
CMD_ACT_FWT_ACCESS_CLEANUP,
|
||||
CMD_ACT_FWT_ACCESS_TIME,
|
||||
};
|
||||
|
||||
/* Define action or option for CMD_MESH_ACCESS */
|
||||
enum cmd_mesh_access_opts {
|
||||
CMD_ACT_MESH_GET_TTL = 1,
|
||||
CMD_ACT_MESH_SET_TTL,
|
||||
CMD_ACT_MESH_GET_STATS,
|
||||
CMD_ACT_MESH_GET_ANYCAST,
|
||||
CMD_ACT_MESH_SET_ANYCAST,
|
||||
CMD_ACT_MESH_SET_LINK_COSTS,
|
||||
CMD_ACT_MESH_GET_LINK_COSTS,
|
||||
CMD_ACT_MESH_SET_BCAST_RATE,
|
||||
CMD_ACT_MESH_GET_BCAST_RATE,
|
||||
CMD_ACT_MESH_SET_RREQ_DELAY,
|
||||
CMD_ACT_MESH_GET_RREQ_DELAY,
|
||||
CMD_ACT_MESH_SET_ROUTE_EXP,
|
||||
CMD_ACT_MESH_GET_ROUTE_EXP,
|
||||
CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
|
||||
CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
|
||||
};
|
||||
|
||||
/** Card Event definition */
|
||||
#define MACREG_INT_CODE_TX_PPA_FREE 0
|
||||
#define MACREG_INT_CODE_TX_DMA_DONE 1
|
||||
#define MACREG_INT_CODE_LINK_LOST_W_SCAN 2
|
||||
#define MACREG_INT_CODE_LINK_LOST_NO_SCAN 3
|
||||
#define MACREG_INT_CODE_LINK_SENSED 4
|
||||
#define MACREG_INT_CODE_CMD_FINISHED 5
|
||||
#define MACREG_INT_CODE_MIB_CHANGED 6
|
||||
#define MACREG_INT_CODE_INIT_DONE 7
|
||||
#define MACREG_INT_CODE_DEAUTHENTICATED 8
|
||||
#define MACREG_INT_CODE_DISASSOCIATED 9
|
||||
#define MACREG_INT_CODE_PS_AWAKE 10
|
||||
#define MACREG_INT_CODE_PS_SLEEP 11
|
||||
#define MACREG_INT_CODE_MIC_ERR_MULTICAST 13
|
||||
#define MACREG_INT_CODE_MIC_ERR_UNICAST 14
|
||||
#define MACREG_INT_CODE_WM_AWAKE 15
|
||||
#define MACREG_INT_CODE_DEEP_SLEEP_AWAKE 16
|
||||
#define MACREG_INT_CODE_ADHOC_BCN_LOST 17
|
||||
#define MACREG_INT_CODE_HOST_AWAKE 18
|
||||
#define MACREG_INT_CODE_STOP_TX 19
|
||||
#define MACREG_INT_CODE_START_TX 20
|
||||
#define MACREG_INT_CODE_CHANNEL_SWITCH 21
|
||||
#define MACREG_INT_CODE_MEASUREMENT_RDY 22
|
||||
#define MACREG_INT_CODE_WMM_CHANGE 23
|
||||
#define MACREG_INT_CODE_BG_SCAN_REPORT 24
|
||||
#define MACREG_INT_CODE_RSSI_LOW 25
|
||||
#define MACREG_INT_CODE_SNR_LOW 26
|
||||
#define MACREG_INT_CODE_MAX_FAIL 27
|
||||
#define MACREG_INT_CODE_RSSI_HIGH 28
|
||||
#define MACREG_INT_CODE_SNR_HIGH 29
|
||||
#define MACREG_INT_CODE_MESH_AUTO_STARTED 35
|
||||
#define MACREG_INT_CODE_FIRMWARE_READY 48
|
||||
|
||||
#endif
|
@ -1,730 +0,0 @@
|
||||
/*
|
||||
* This file contains the function prototypes, data structure
|
||||
* and defines for all the host/station commands
|
||||
*/
|
||||
#ifndef _LBS_HOSTCMD_H
|
||||
#define _LBS_HOSTCMD_H
|
||||
|
||||
#include <linux/wireless.h>
|
||||
#include "11d.h"
|
||||
#include "types.h"
|
||||
|
||||
/* 802.11-related definitions */
|
||||
|
||||
/* TxPD descriptor */
|
||||
struct txpd {
|
||||
/* Current Tx packet status */
|
||||
__le32 tx_status;
|
||||
/* Tx control */
|
||||
__le32 tx_control;
|
||||
__le32 tx_packet_location;
|
||||
/* Tx packet length */
|
||||
__le16 tx_packet_length;
|
||||
/* First 2 byte of destination MAC address */
|
||||
u8 tx_dest_addr_high[2];
|
||||
/* Last 4 byte of destination MAC address */
|
||||
u8 tx_dest_addr_low[4];
|
||||
/* Pkt Priority */
|
||||
u8 priority;
|
||||
/* Pkt Trasnit Power control */
|
||||
u8 powermgmt;
|
||||
/* Amount of time the packet has been queued in the driver (units = 2ms) */
|
||||
u8 pktdelay_2ms;
|
||||
/* reserved */
|
||||
u8 reserved1;
|
||||
};
|
||||
|
||||
/* RxPD Descriptor */
|
||||
struct rxpd {
|
||||
/* Current Rx packet status */
|
||||
__le16 status;
|
||||
|
||||
/* SNR */
|
||||
u8 snr;
|
||||
|
||||
/* Tx control */
|
||||
u8 rx_control;
|
||||
|
||||
/* Pkt length */
|
||||
__le16 pkt_len;
|
||||
|
||||
/* Noise Floor */
|
||||
u8 nf;
|
||||
|
||||
/* Rx Packet Rate */
|
||||
u8 rx_rate;
|
||||
|
||||
/* Pkt addr */
|
||||
__le32 pkt_ptr;
|
||||
|
||||
/* Next Rx RxPD addr */
|
||||
__le32 next_rxpd_ptr;
|
||||
|
||||
/* Pkt Priority */
|
||||
u8 priority;
|
||||
u8 reserved[3];
|
||||
};
|
||||
|
||||
struct cmd_header {
|
||||
__le16 command;
|
||||
__le16 size;
|
||||
__le16 seqnum;
|
||||
__le16 result;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ctrl_node {
|
||||
struct list_head list;
|
||||
int result;
|
||||
/* command response */
|
||||
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *);
|
||||
unsigned long callback_arg;
|
||||
/* command data */
|
||||
struct cmd_header *cmdbuf;
|
||||
/* wait queue */
|
||||
u16 cmdwaitqwoken;
|
||||
wait_queue_head_t cmdwait_q;
|
||||
};
|
||||
|
||||
/* Generic structure to hold all key types. */
|
||||
struct enc_key {
|
||||
u16 len;
|
||||
u16 flags; /* KEY_INFO_* from defs.h */
|
||||
u16 type; /* KEY_TYPE_* from defs.h */
|
||||
u8 key[32];
|
||||
};
|
||||
|
||||
/* lbs_offset_value */
|
||||
struct lbs_offset_value {
|
||||
u32 offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
/* Define general data structure */
|
||||
/* cmd_DS_GEN */
|
||||
struct cmd_ds_gen {
|
||||
__le16 command;
|
||||
__le16 size;
|
||||
__le16 seqnum;
|
||||
__le16 result;
|
||||
void *cmdresp[0];
|
||||
};
|
||||
|
||||
#define S_DS_GEN sizeof(struct cmd_ds_gen)
|
||||
|
||||
|
||||
/*
|
||||
* Define data structure for CMD_GET_HW_SPEC
|
||||
* This structure defines the response for the GET_HW_SPEC command
|
||||
*/
|
||||
struct cmd_ds_get_hw_spec {
|
||||
struct cmd_header hdr;
|
||||
|
||||
/* HW Interface version number */
|
||||
__le16 hwifversion;
|
||||
/* HW version number */
|
||||
__le16 version;
|
||||
/* Max number of TxPD FW can handle */
|
||||
__le16 nr_txpd;
|
||||
/* Max no of Multicast address */
|
||||
__le16 nr_mcast_adr;
|
||||
/* MAC address */
|
||||
u8 permanentaddr[6];
|
||||
|
||||
/* region Code */
|
||||
__le16 regioncode;
|
||||
|
||||
/* Number of antenna used */
|
||||
__le16 nr_antenna;
|
||||
|
||||
/* FW release number, example 0x01030304 = 2.3.4p1 */
|
||||
__le32 fwrelease;
|
||||
|
||||
/* Base Address of TxPD queue */
|
||||
__le32 wcb_base;
|
||||
/* Read Pointer of RxPd queue */
|
||||
__le32 rxpd_rdptr;
|
||||
|
||||
/* Write Pointer of RxPd queue */
|
||||
__le32 rxpd_wrptr;
|
||||
|
||||
/*FW/HW capability */
|
||||
__le32 fwcapinfo;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_802_11_reset {
|
||||
__le16 action;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_subscribe_event {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le16 action;
|
||||
__le16 events;
|
||||
|
||||
/* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a
|
||||
* number of TLVs. From the v5.1 manual, those TLVs would add up to
|
||||
* 40 bytes. However, future firmware might add additional TLVs, so I
|
||||
* bump this up a bit.
|
||||
*/
|
||||
uint8_t tlv[128];
|
||||
};
|
||||
|
||||
/*
|
||||
* This scan handle Country Information IE(802.11d compliant)
|
||||
* Define data structure for CMD_802_11_SCAN
|
||||
*/
|
||||
struct cmd_ds_802_11_scan {
|
||||
struct cmd_header hdr;
|
||||
|
||||
uint8_t bsstype;
|
||||
uint8_t bssid[ETH_ALEN];
|
||||
uint8_t tlvbuffer[0];
|
||||
#if 0
|
||||
mrvlietypes_ssidparamset_t ssidParamSet;
|
||||
mrvlietypes_chanlistparamset_t ChanListParamSet;
|
||||
mrvlietypes_ratesparamset_t OpRateSet;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_scan_rsp {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le16 bssdescriptsize;
|
||||
uint8_t nr_sets;
|
||||
uint8_t bssdesc_and_tlvbuffer[0];
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_get_log {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le32 mcasttxframe;
|
||||
__le32 failed;
|
||||
__le32 retry;
|
||||
__le32 multiretry;
|
||||
__le32 framedup;
|
||||
__le32 rtssuccess;
|
||||
__le32 rtsfailure;
|
||||
__le32 ackfailure;
|
||||
__le32 rxfrag;
|
||||
__le32 mcastrxframe;
|
||||
__le32 fcserror;
|
||||
__le32 txframe;
|
||||
__le32 wepundecryptable;
|
||||
};
|
||||
|
||||
struct cmd_ds_mac_control {
|
||||
struct cmd_header hdr;
|
||||
__le16 action;
|
||||
u16 reserved;
|
||||
};
|
||||
|
||||
struct cmd_ds_mac_multicast_adr {
|
||||
__le16 action;
|
||||
__le16 nr_of_adrs;
|
||||
u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_authenticate {
|
||||
u8 macaddr[ETH_ALEN];
|
||||
u8 authtype;
|
||||
u8 reserved[10];
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_deauthenticate {
|
||||
u8 macaddr[6];
|
||||
__le16 reasoncode;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_associate {
|
||||
u8 peerstaaddr[6];
|
||||
__le16 capability;
|
||||
__le16 listeninterval;
|
||||
__le16 bcnperiod;
|
||||
u8 dtimperiod;
|
||||
|
||||
#if 0
|
||||
mrvlietypes_ssidparamset_t ssidParamSet;
|
||||
mrvlietypes_phyparamset_t phyparamset;
|
||||
mrvlietypes_ssparamset_t ssparamset;
|
||||
mrvlietypes_ratesparamset_t ratesParamSet;
|
||||
#endif
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_802_11_disassociate {
|
||||
u8 destmacaddr[6];
|
||||
__le16 reasoncode;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_associate_rsp {
|
||||
struct ieeetypes_assocrsp assocRsp;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_ad_hoc_result {
|
||||
u8 pad[3];
|
||||
u8 bssid[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_set_wep {
|
||||
struct cmd_header hdr;
|
||||
|
||||
/* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
|
||||
__le16 action;
|
||||
|
||||
/* key Index selected for Tx */
|
||||
__le16 keyindex;
|
||||
|
||||
/* 40, 128bit or TXWEP */
|
||||
uint8_t keytype[4];
|
||||
uint8_t keymaterial[4][16];
|
||||
};
|
||||
|
||||
struct cmd_ds_802_3_get_stat {
|
||||
__le32 xmitok;
|
||||
__le32 rcvok;
|
||||
__le32 xmiterror;
|
||||
__le32 rcverror;
|
||||
__le32 rcvnobuffer;
|
||||
__le32 rcvcrcerror;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_get_stat {
|
||||
__le32 txfragmentcnt;
|
||||
__le32 mcasttxframecnt;
|
||||
__le32 failedcnt;
|
||||
__le32 retrycnt;
|
||||
__le32 Multipleretrycnt;
|
||||
__le32 rtssuccesscnt;
|
||||
__le32 rtsfailurecnt;
|
||||
__le32 ackfailurecnt;
|
||||
__le32 frameduplicatecnt;
|
||||
__le32 rxfragmentcnt;
|
||||
__le32 mcastrxframecnt;
|
||||
__le32 fcserrorcnt;
|
||||
__le32 bcasttxframecnt;
|
||||
__le32 bcastrxframecnt;
|
||||
__le32 txbeacon;
|
||||
__le32 rxbeacon;
|
||||
__le32 wepundecryptable;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_snmp_mib {
|
||||
__le16 querytype;
|
||||
__le16 oid;
|
||||
__le16 bufsize;
|
||||
u8 value[128];
|
||||
};
|
||||
|
||||
struct cmd_ds_mac_reg_map {
|
||||
__le16 buffersize;
|
||||
u8 regmap[128];
|
||||
__le16 reserved;
|
||||
};
|
||||
|
||||
struct cmd_ds_bbp_reg_map {
|
||||
__le16 buffersize;
|
||||
u8 regmap[128];
|
||||
__le16 reserved;
|
||||
};
|
||||
|
||||
struct cmd_ds_rf_reg_map {
|
||||
__le16 buffersize;
|
||||
u8 regmap[64];
|
||||
__le16 reserved;
|
||||
};
|
||||
|
||||
struct cmd_ds_mac_reg_access {
|
||||
__le16 action;
|
||||
__le16 offset;
|
||||
__le32 value;
|
||||
};
|
||||
|
||||
struct cmd_ds_bbp_reg_access {
|
||||
__le16 action;
|
||||
__le16 offset;
|
||||
u8 value;
|
||||
u8 reserved[3];
|
||||
};
|
||||
|
||||
struct cmd_ds_rf_reg_access {
|
||||
__le16 action;
|
||||
__le16 offset;
|
||||
u8 value;
|
||||
u8 reserved[3];
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_radio_control {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le16 action;
|
||||
__le16 control;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_beacon_control {
|
||||
__le16 action;
|
||||
__le16 beacon_enable;
|
||||
__le16 beacon_period;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_sleep_params {
|
||||
struct cmd_header hdr;
|
||||
|
||||
/* ACT_GET/ACT_SET */
|
||||
__le16 action;
|
||||
|
||||
/* Sleep clock error in ppm */
|
||||
__le16 error;
|
||||
|
||||
/* Wakeup offset in usec */
|
||||
__le16 offset;
|
||||
|
||||
/* Clock stabilization time in usec */
|
||||
__le16 stabletime;
|
||||
|
||||
/* control periodic calibration */
|
||||
uint8_t calcontrol;
|
||||
|
||||
/* control the use of external sleep clock */
|
||||
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;
|
||||
|
||||
/* Inactivity timeout in msec */
|
||||
__le16 timeout;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_rf_channel {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le16 action;
|
||||
__le16 channel;
|
||||
__le16 rftype; /* unused */
|
||||
__le16 reserved; /* unused */
|
||||
u8 channellist[32]; /* unused */
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_rssi {
|
||||
/* weighting factor */
|
||||
__le16 N;
|
||||
|
||||
__le16 reserved_0;
|
||||
__le16 reserved_1;
|
||||
__le16 reserved_2;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_rssi_rsp {
|
||||
__le16 SNR;
|
||||
__le16 noisefloor;
|
||||
__le16 avgSNR;
|
||||
__le16 avgnoisefloor;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_mac_address {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le16 action;
|
||||
u8 macadd[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_rf_tx_power {
|
||||
__le16 action;
|
||||
__le16 currentlevel;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_rf_antenna {
|
||||
__le16 action;
|
||||
|
||||
/* Number of antennas or 0xffff(diversity) */
|
||||
__le16 antennamode;
|
||||
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_monitor_mode {
|
||||
__le16 action;
|
||||
__le16 mode;
|
||||
};
|
||||
|
||||
struct cmd_ds_set_boot2_ver {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le16 action;
|
||||
__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;
|
||||
__le16 multipledtim;
|
||||
__le16 reserved;
|
||||
__le16 locallisteninterval;
|
||||
};
|
||||
|
||||
struct cmd_confirm_sleep {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le16 action;
|
||||
__le16 nullpktinterval;
|
||||
__le16 multipledtim;
|
||||
__le16 reserved;
|
||||
__le16 locallisteninterval;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_data_rate {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le16 action;
|
||||
__le16 reserved;
|
||||
u8 rates[MAX_RATES];
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_rate_adapt_rateset {
|
||||
__le16 action;
|
||||
__le16 enablehwauto;
|
||||
__le16 bitmap;
|
||||
};
|
||||
|
||||
struct cmd_ds_802_11_ad_hoc_start {
|
||||
u8 ssid[IW_ESSID_MAX_SIZE];
|
||||
u8 bsstype;
|
||||
__le16 beaconperiod;
|
||||
u8 dtimperiod;
|
||||
union IEEEtypes_ssparamset ssparamset;
|
||||
union ieeetypes_phyparamset phyparamset;
|
||||
__le16 probedelay;
|
||||
__le16 capability;
|
||||
u8 rates[MAX_RATES];
|
||||
u8 tlv_memory_size_pad[100];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct adhoc_bssdesc {
|
||||
u8 bssid[6];
|
||||
u8 ssid[32];
|
||||
u8 type;
|
||||
__le16 beaconperiod;
|
||||
u8 dtimperiod;
|
||||
__le64 timestamp;
|
||||
__le64 localtime;
|
||||
union ieeetypes_phyparamset phyparamset;
|
||||
union IEEEtypes_ssparamset ssparamset;
|
||||
__le16 capability;
|
||||
u8 rates[MAX_RATES];
|
||||
|
||||
/* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
|
||||
* Adhoc join command and will cause a binary layout mismatch with
|
||||
* the firmware
|
||||
*/
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_802_11_ad_hoc_join {
|
||||
struct adhoc_bssdesc bss;
|
||||
__le16 failtimeout;
|
||||
__le16 probedelay;
|
||||
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_802_11_enable_rsn {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le16 action;
|
||||
__le16 enable;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct MrvlIEtype_keyParamSet {
|
||||
/* type ID */
|
||||
__le16 type;
|
||||
|
||||
/* length of Payload */
|
||||
__le16 length;
|
||||
|
||||
/* type of key: WEP=0, TKIP=1, AES=2 */
|
||||
__le16 keytypeid;
|
||||
|
||||
/* key control Info specific to a keytypeid */
|
||||
__le16 keyinfo;
|
||||
|
||||
/* length of key */
|
||||
__le16 keylen;
|
||||
|
||||
/* key material of size keylen */
|
||||
u8 key[32];
|
||||
};
|
||||
|
||||
struct cmd_ds_host_sleep {
|
||||
struct cmd_header hdr;
|
||||
__le32 criteria;
|
||||
uint8_t gpio;
|
||||
uint8_t gap;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_802_11_key_material {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le16 action;
|
||||
struct MrvlIEtype_keyParamSet keyParamSet[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_802_11_eeprom_access {
|
||||
struct cmd_header hdr;
|
||||
__le16 action;
|
||||
__le16 offset;
|
||||
__le16 len;
|
||||
/* firmware says it returns a maximum of 20 bytes */
|
||||
#define LBS_EEPROM_READ_LEN 20
|
||||
u8 value[LBS_EEPROM_READ_LEN];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_802_11_tpc_cfg {
|
||||
__le16 action;
|
||||
u8 enable;
|
||||
s8 P0;
|
||||
s8 P1;
|
||||
s8 P2;
|
||||
u8 usesnr;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_802_11_led_ctrl {
|
||||
__le16 action;
|
||||
__le16 numled;
|
||||
u8 data[288];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_802_11_afc {
|
||||
__le16 afc_auto;
|
||||
union {
|
||||
struct {
|
||||
__le16 threshold;
|
||||
__le16 period;
|
||||
};
|
||||
struct {
|
||||
__le16 timing_offset; /* signed */
|
||||
__le16 carrier_offset; /* signed */
|
||||
};
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_tx_rate_query {
|
||||
__le16 txrate;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_get_tsf {
|
||||
__le64 tsfvalue;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_bt_access {
|
||||
__le16 action;
|
||||
__le32 id;
|
||||
u8 addr1[ETH_ALEN];
|
||||
u8 addr2[ETH_ALEN];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cmd_ds_fwt_access {
|
||||
__le16 action;
|
||||
__le32 id;
|
||||
u8 valid;
|
||||
u8 da[ETH_ALEN];
|
||||
u8 dir;
|
||||
u8 ra[ETH_ALEN];
|
||||
__le32 ssn;
|
||||
__le32 dsn;
|
||||
__le32 metric;
|
||||
u8 rate;
|
||||
u8 hopcount;
|
||||
u8 ttl;
|
||||
__le32 expiration;
|
||||
u8 sleepmode;
|
||||
__le32 snr;
|
||||
__le32 references;
|
||||
u8 prec[ETH_ALEN];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
struct cmd_ds_mesh_config {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le16 action;
|
||||
__le16 channel;
|
||||
__le16 type;
|
||||
__le16 length;
|
||||
u8 data[128]; /* last position reserved */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
struct cmd_ds_mesh_access {
|
||||
struct cmd_header hdr;
|
||||
|
||||
__le16 action;
|
||||
__le32 data[32]; /* last position reserved */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Number of stats counters returned by the firmware */
|
||||
#define MESH_STATS_NUM 8
|
||||
|
||||
struct cmd_ds_command {
|
||||
/* command header */
|
||||
__le16 command;
|
||||
__le16 size;
|
||||
__le16 seqnum;
|
||||
__le16 result;
|
||||
|
||||
/* command Body */
|
||||
union {
|
||||
struct cmd_ds_802_11_ps_mode psmode;
|
||||
struct cmd_ds_802_11_associate associate;
|
||||
struct cmd_ds_802_11_deauthenticate deauth;
|
||||
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;
|
||||
struct cmd_ds_802_11_authenticate auth;
|
||||
struct cmd_ds_802_11_get_stat gstat;
|
||||
struct cmd_ds_802_3_get_stat gstat_8023;
|
||||
struct cmd_ds_802_11_snmp_mib smib;
|
||||
struct cmd_ds_802_11_rf_tx_power txp;
|
||||
struct cmd_ds_802_11_rf_antenna rant;
|
||||
struct cmd_ds_802_11_monitor_mode monitor;
|
||||
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_rssi rssi;
|
||||
struct cmd_ds_802_11_rssi_rsp rssirsp;
|
||||
struct cmd_ds_802_11_disassociate dassociate;
|
||||
struct cmd_ds_mac_reg_access macreg;
|
||||
struct cmd_ds_bbp_reg_access bbpreg;
|
||||
struct cmd_ds_rf_reg_access rfreg;
|
||||
|
||||
struct cmd_ds_802_11d_domain_info domaininfo;
|
||||
struct cmd_ds_802_11d_domain_info domaininforesp;
|
||||
|
||||
struct cmd_ds_802_11_tpc_cfg tpccfg;
|
||||
struct cmd_ds_802_11_afc afc;
|
||||
struct cmd_ds_802_11_led_ctrl ledgpio;
|
||||
|
||||
struct cmd_tx_rate_query txrate;
|
||||
struct cmd_ds_bt_access bt;
|
||||
struct cmd_ds_fwt_access fwt;
|
||||
struct cmd_ds_get_tsf gettsf;
|
||||
struct cmd_ds_802_11_beacon_control bcn_ctrl;
|
||||
} params;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif
|
@ -1,932 +0,0 @@
|
||||
/*
|
||||
|
||||
Driver for the Marvell 8385 based compact flash WLAN cards.
|
||||
|
||||
(C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include <pcmcia/cs_types.h>
|
||||
#include <pcmcia/cs.h>
|
||||
#include <pcmcia/cistpl.h>
|
||||
#include <pcmcia/ds.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
|
||||
#define DRV_NAME "libertas_cs"
|
||||
|
||||
#include "decl.h"
|
||||
#include "defs.h"
|
||||
#include "dev.h"
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Module stuff */
|
||||
/********************************************************************/
|
||||
|
||||
MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
|
||||
MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Data structures */
|
||||
/********************************************************************/
|
||||
|
||||
struct if_cs_card {
|
||||
struct pcmcia_device *p_dev;
|
||||
struct lbs_private *priv;
|
||||
void __iomem *iobase;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Hardware access */
|
||||
/********************************************************************/
|
||||
|
||||
/* This define enables wrapper functions which allow you
|
||||
to dump all register accesses. You normally won't this,
|
||||
except for development */
|
||||
/* #define DEBUG_IO */
|
||||
|
||||
#ifdef DEBUG_IO
|
||||
static int debug_output = 0;
|
||||
#else
|
||||
/* This way the compiler optimizes the printk's away */
|
||||
#define debug_output 0
|
||||
#endif
|
||||
|
||||
static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
|
||||
{
|
||||
unsigned int val = ioread8(card->iobase + reg);
|
||||
if (debug_output)
|
||||
printk(KERN_INFO "inb %08x<%02x\n", reg, val);
|
||||
return val;
|
||||
}
|
||||
static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
|
||||
{
|
||||
unsigned int val = ioread16(card->iobase + reg);
|
||||
if (debug_output)
|
||||
printk(KERN_INFO "inw %08x<%04x\n", reg, val);
|
||||
return val;
|
||||
}
|
||||
static inline void if_cs_read16_rep(
|
||||
struct if_cs_card *card,
|
||||
uint reg,
|
||||
void *buf,
|
||||
unsigned long count)
|
||||
{
|
||||
if (debug_output)
|
||||
printk(KERN_INFO "insw %08x<(0x%lx words)\n",
|
||||
reg, count);
|
||||
ioread16_rep(card->iobase + reg, buf, count);
|
||||
}
|
||||
|
||||
static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
|
||||
{
|
||||
if (debug_output)
|
||||
printk(KERN_INFO "outb %08x>%02x\n", reg, val);
|
||||
iowrite8(val, card->iobase + reg);
|
||||
}
|
||||
|
||||
static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
|
||||
{
|
||||
if (debug_output)
|
||||
printk(KERN_INFO "outw %08x>%04x\n", reg, val);
|
||||
iowrite16(val, card->iobase + reg);
|
||||
}
|
||||
|
||||
static inline void if_cs_write16_rep(
|
||||
struct if_cs_card *card,
|
||||
uint reg,
|
||||
void *buf,
|
||||
unsigned long count)
|
||||
{
|
||||
if (debug_output)
|
||||
printk(KERN_INFO "outsw %08x>(0x%lx words)\n",
|
||||
reg, count);
|
||||
iowrite16_rep(card->iobase + reg, buf, count);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* I know that polling/delaying is frowned upon. However, this procedure
|
||||
* with polling is needed while downloading the firmware. At this stage,
|
||||
* the hardware does unfortunately not create any interrupts.
|
||||
*
|
||||
* Fortunately, this function is never used once the firmware is in
|
||||
* the card. :-)
|
||||
*
|
||||
* As a reference, see the "Firmware Specification v5.1", page 18
|
||||
* and 19. I did not follow their suggested timing to the word,
|
||||
* but this works nice & fast anyway.
|
||||
*/
|
||||
static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
u8 val = if_cs_read8(card, addr);
|
||||
if (val == reg)
|
||||
return i;
|
||||
udelay(500);
|
||||
}
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Host control registers and their bit definitions */
|
||||
|
||||
#define IF_CS_H_STATUS 0x00000000
|
||||
#define IF_CS_H_STATUS_TX_OVER 0x0001
|
||||
#define IF_CS_H_STATUS_RX_OVER 0x0002
|
||||
#define IF_CS_H_STATUS_DNLD_OVER 0x0004
|
||||
|
||||
#define IF_CS_H_INT_CAUSE 0x00000002
|
||||
#define IF_CS_H_IC_TX_OVER 0x0001
|
||||
#define IF_CS_H_IC_RX_OVER 0x0002
|
||||
#define IF_CS_H_IC_DNLD_OVER 0x0004
|
||||
#define IF_CS_H_IC_POWER_DOWN 0x0008
|
||||
#define IF_CS_H_IC_HOST_EVENT 0x0010
|
||||
#define IF_CS_H_IC_MASK 0x001f
|
||||
|
||||
#define IF_CS_H_INT_MASK 0x00000004
|
||||
#define IF_CS_H_IM_MASK 0x001f
|
||||
|
||||
#define IF_CS_H_WRITE_LEN 0x00000014
|
||||
|
||||
#define IF_CS_H_WRITE 0x00000016
|
||||
|
||||
#define IF_CS_H_CMD_LEN 0x00000018
|
||||
|
||||
#define IF_CS_H_CMD 0x0000001A
|
||||
|
||||
#define IF_CS_C_READ_LEN 0x00000024
|
||||
|
||||
#define IF_CS_H_READ 0x00000010
|
||||
|
||||
/* Card control registers and their bit definitions */
|
||||
|
||||
#define IF_CS_C_STATUS 0x00000020
|
||||
#define IF_CS_C_S_TX_DNLD_RDY 0x0001
|
||||
#define IF_CS_C_S_RX_UPLD_RDY 0x0002
|
||||
#define IF_CS_C_S_CMD_DNLD_RDY 0x0004
|
||||
#define IF_CS_C_S_CMD_UPLD_RDY 0x0008
|
||||
#define IF_CS_C_S_CARDEVENT 0x0010
|
||||
#define IF_CS_C_S_MASK 0x001f
|
||||
#define IF_CS_C_S_STATUS_MASK 0x7f00
|
||||
|
||||
#define IF_CS_C_INT_CAUSE 0x00000022
|
||||
#define IF_CS_C_IC_MASK 0x001f
|
||||
|
||||
#define IF_CS_C_SQ_READ_LOW 0x00000028
|
||||
#define IF_CS_C_SQ_HELPER_OK 0x10
|
||||
|
||||
#define IF_CS_C_CMD_LEN 0x00000030
|
||||
|
||||
#define IF_CS_C_CMD 0x00000012
|
||||
|
||||
#define IF_CS_SCRATCH 0x0000003F
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* I/O */
|
||||
/********************************************************************/
|
||||
|
||||
/*
|
||||
* Called from if_cs_host_to_card to send a command to the hardware
|
||||
*/
|
||||
static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
|
||||
{
|
||||
struct if_cs_card *card = (struct if_cs_card *)priv->card;
|
||||
int ret = -1;
|
||||
int loops = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
/* Is hardware ready? */
|
||||
while (1) {
|
||||
u16 val = if_cs_read16(card, IF_CS_C_STATUS);
|
||||
if (val & IF_CS_C_S_CMD_DNLD_RDY)
|
||||
break;
|
||||
if (++loops > 100) {
|
||||
lbs_pr_err("card not ready for commands\n");
|
||||
goto done;
|
||||
}
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
if_cs_write16(card, IF_CS_H_CMD_LEN, nb);
|
||||
|
||||
if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2);
|
||||
/* Are we supposed to transfer an odd amount of bytes? */
|
||||
if (nb & 1)
|
||||
if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]);
|
||||
|
||||
/* "Assert the download over interrupt command in the Host
|
||||
* status register" */
|
||||
if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
|
||||
|
||||
/* "Assert the download over interrupt command in the Card
|
||||
* interrupt case register" */
|
||||
if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called from if_cs_host_to_card to send a data to the hardware
|
||||
*/
|
||||
static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
|
||||
{
|
||||
struct if_cs_card *card = (struct if_cs_card *)priv->card;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
if_cs_write16(card, IF_CS_H_WRITE_LEN, nb);
|
||||
|
||||
/* write even number of bytes, then odd byte if necessary */
|
||||
if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2);
|
||||
if (nb & 1)
|
||||
if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]);
|
||||
|
||||
if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER);
|
||||
if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CS);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the command result out of the card.
|
||||
*/
|
||||
static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret = -1;
|
||||
u16 val;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
/* is hardware ready? */
|
||||
val = if_cs_read16(priv->card, IF_CS_C_STATUS);
|
||||
if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) {
|
||||
lbs_pr_err("card not ready for CMD\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
*len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN);
|
||||
if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
|
||||
lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* read even number of bytes, then odd byte if necessary */
|
||||
if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16));
|
||||
if (*len & 1)
|
||||
data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD);
|
||||
|
||||
/* This is a workaround for a firmware that reports too much
|
||||
* bytes */
|
||||
*len -= 8;
|
||||
ret = 0;
|
||||
|
||||
/* Clear this flag again */
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
priv->dnld_sent = DNLD_RES_RECEIVED;
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
u16 len;
|
||||
u8 *data;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
len = if_cs_read16(priv->card, IF_CS_C_READ_LEN);
|
||||
if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
|
||||
lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
|
||||
priv->stats.rx_dropped++;
|
||||
goto dat_err;
|
||||
}
|
||||
|
||||
skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
|
||||
if (!skb)
|
||||
goto out;
|
||||
skb_put(skb, len);
|
||||
skb_reserve(skb, 2);/* 16 byte align */
|
||||
data = skb->data;
|
||||
|
||||
/* read even number of bytes, then odd byte if necessary */
|
||||
if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16));
|
||||
if (len & 1)
|
||||
data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ);
|
||||
|
||||
dat_err:
|
||||
if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER);
|
||||
if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb);
|
||||
return skb;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Interrupts */
|
||||
/********************************************************************/
|
||||
|
||||
static inline void if_cs_enable_ints(struct if_cs_card *card)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
if_cs_write16(card, IF_CS_H_INT_MASK, 0);
|
||||
}
|
||||
|
||||
static inline void if_cs_disable_ints(struct if_cs_card *card)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t if_cs_interrupt(int irq, void *data)
|
||||
{
|
||||
struct if_cs_card *card = data;
|
||||
struct lbs_private *priv = card->priv;
|
||||
u16 cause;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
|
||||
if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK);
|
||||
|
||||
lbs_deb_cs("cause 0x%04x\n", cause);
|
||||
if (cause == 0) {
|
||||
/* Not for us */
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (cause == 0xffff) {
|
||||
/* Read in junk, the card has probably been removed */
|
||||
card->priv->surpriseremoved = 1;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* TODO: I'm not sure what the best ordering is */
|
||||
|
||||
cause = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
|
||||
|
||||
if (cause & IF_CS_C_S_RX_UPLD_RDY) {
|
||||
struct sk_buff *skb;
|
||||
lbs_deb_cs("rx packet\n");
|
||||
skb = if_cs_receive_data(priv);
|
||||
if (skb)
|
||||
lbs_process_rxed_packet(priv, skb);
|
||||
}
|
||||
|
||||
if (cause & IF_CS_H_IC_TX_OVER) {
|
||||
lbs_deb_cs("tx over\n");
|
||||
lbs_host_to_card_done(priv);
|
||||
}
|
||||
|
||||
if (cause & IF_CS_C_S_CMD_UPLD_RDY) {
|
||||
unsigned long flags;
|
||||
u8 i;
|
||||
|
||||
lbs_deb_cs("cmd upload ready\n");
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
i = (priv->resp_idx == 0) ? 1 : 0;
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
BUG_ON(priv->resp_len[i]);
|
||||
if_cs_receive_cmdres(priv, priv->resp_buf[i],
|
||||
&priv->resp_len[i]);
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
lbs_notify_command_response(priv, i);
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
}
|
||||
|
||||
if (cause & IF_CS_H_IC_HOST_EVENT) {
|
||||
u16 event = if_cs_read16(priv->card, IF_CS_C_STATUS)
|
||||
& IF_CS_C_S_STATUS_MASK;
|
||||
if_cs_write16(priv->card, IF_CS_H_INT_CAUSE,
|
||||
IF_CS_H_IC_HOST_EVENT);
|
||||
lbs_deb_cs("eventcause 0x%04x\n", event);
|
||||
lbs_queue_event(priv, event >> 8 & 0xff);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Firmware */
|
||||
/********************************************************************/
|
||||
|
||||
/*
|
||||
* Tries to program the helper firmware.
|
||||
*
|
||||
* Return 0 on success
|
||||
*/
|
||||
static int if_cs_prog_helper(struct if_cs_card *card)
|
||||
{
|
||||
int ret = 0;
|
||||
int sent = 0;
|
||||
u8 scratch;
|
||||
const struct firmware *fw;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
scratch = if_cs_read8(card, IF_CS_SCRATCH);
|
||||
|
||||
/* "If the value is 0x5a, the firmware is already
|
||||
* downloaded successfully"
|
||||
*/
|
||||
if (scratch == 0x5a)
|
||||
goto done;
|
||||
|
||||
/* "If the value is != 00, it is invalid value of register */
|
||||
if (scratch != 0x00) {
|
||||
ret = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* TODO: make firmware file configurable */
|
||||
ret = request_firmware(&fw, "libertas_cs_helper.fw",
|
||||
&handle_to_dev(card->p_dev));
|
||||
if (ret) {
|
||||
lbs_pr_err("can't load helper firmware\n");
|
||||
ret = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
lbs_deb_cs("helper size %td\n", fw->size);
|
||||
|
||||
/* "Set the 5 bytes of the helper image to 0" */
|
||||
/* Not needed, this contains an ARM branch instruction */
|
||||
|
||||
for (;;) {
|
||||
/* "the number of bytes to send is 256" */
|
||||
int count = 256;
|
||||
int remain = fw->size - sent;
|
||||
|
||||
if (remain < count)
|
||||
count = remain;
|
||||
|
||||
/* "write the number of bytes to be sent to the I/O Command
|
||||
* write length register" */
|
||||
if_cs_write16(card, IF_CS_H_CMD_LEN, count);
|
||||
|
||||
/* "write this to I/O Command port register as 16 bit writes */
|
||||
if (count)
|
||||
if_cs_write16_rep(card, IF_CS_H_CMD,
|
||||
&fw->data[sent],
|
||||
count >> 1);
|
||||
|
||||
/* "Assert the download over interrupt command in the Host
|
||||
* status register" */
|
||||
if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
|
||||
|
||||
/* "Assert the download over interrupt command in the Card
|
||||
* interrupt case register" */
|
||||
if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
|
||||
|
||||
/* "The host polls the Card Status register ... for 50 ms before
|
||||
declaring a failure */
|
||||
ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
|
||||
IF_CS_C_S_CMD_DNLD_RDY);
|
||||
if (ret < 0) {
|
||||
lbs_pr_err("can't download helper at 0x%x, ret %d\n",
|
||||
sent, ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
break;
|
||||
|
||||
sent += count;
|
||||
}
|
||||
|
||||
release_firmware(fw);
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int if_cs_prog_real(struct if_cs_card *card)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
int ret = 0;
|
||||
int retry = 0;
|
||||
int len = 0;
|
||||
int sent;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
/* TODO: make firmware file configurable */
|
||||
ret = request_firmware(&fw, "libertas_cs.fw",
|
||||
&handle_to_dev(card->p_dev));
|
||||
if (ret) {
|
||||
lbs_pr_err("can't load firmware\n");
|
||||
ret = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
lbs_deb_cs("fw size %td\n", fw->size);
|
||||
|
||||
ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);
|
||||
if (ret < 0) {
|
||||
lbs_pr_err("helper firmware doesn't answer\n");
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
for (sent = 0; sent < fw->size; sent += len) {
|
||||
len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);
|
||||
if (len & 1) {
|
||||
retry++;
|
||||
lbs_pr_info("odd, need to retry this firmware block\n");
|
||||
} else {
|
||||
retry = 0;
|
||||
}
|
||||
|
||||
if (retry > 20) {
|
||||
lbs_pr_err("could not download firmware\n");
|
||||
ret = -ENODEV;
|
||||
goto err_release;
|
||||
}
|
||||
if (retry) {
|
||||
sent -= len;
|
||||
}
|
||||
|
||||
|
||||
if_cs_write16(card, IF_CS_H_CMD_LEN, len);
|
||||
|
||||
if_cs_write16_rep(card, IF_CS_H_CMD,
|
||||
&fw->data[sent],
|
||||
(len+1) >> 1);
|
||||
if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
|
||||
if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
|
||||
|
||||
ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
|
||||
IF_CS_C_S_CMD_DNLD_RDY);
|
||||
if (ret < 0) {
|
||||
lbs_pr_err("can't download firmware at 0x%x\n", sent);
|
||||
goto err_release;
|
||||
}
|
||||
}
|
||||
|
||||
ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
|
||||
if (ret < 0) {
|
||||
lbs_pr_err("firmware download failed\n");
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
goto done;
|
||||
|
||||
|
||||
err_release:
|
||||
release_firmware(fw);
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Callback functions for libertas.ko */
|
||||
/********************************************************************/
|
||||
|
||||
/* Send commands or data packets to the card */
|
||||
static int if_cs_host_to_card(struct lbs_private *priv,
|
||||
u8 type,
|
||||
u8 *buf,
|
||||
u16 nb)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb);
|
||||
|
||||
switch (type) {
|
||||
case MVMS_DAT:
|
||||
priv->dnld_sent = DNLD_DATA_SENT;
|
||||
if_cs_send_data(priv, buf, nb);
|
||||
ret = 0;
|
||||
break;
|
||||
case MVMS_CMD:
|
||||
priv->dnld_sent = DNLD_CMD_SENT;
|
||||
ret = if_cs_send_cmd(priv, buf, nb);
|
||||
break;
|
||||
default:
|
||||
lbs_pr_err("%s: unsupported type %d\n", __FUNCTION__, type);
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Card Services */
|
||||
/********************************************************************/
|
||||
|
||||
/*
|
||||
* After a card is removed, if_cs_release() will unregister the
|
||||
* device, and release the PCMCIA configuration. If the device is
|
||||
* still open, this will be postponed until it is closed.
|
||||
*/
|
||||
static void if_cs_release(struct pcmcia_device *p_dev)
|
||||
{
|
||||
struct if_cs_card *card = p_dev->priv;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
free_irq(p_dev->irq.AssignedIRQ, card);
|
||||
pcmcia_disable_device(p_dev);
|
||||
if (card->iobase)
|
||||
ioport_unmap(card->iobase);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CS);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This creates an "instance" of the driver, allocating local data
|
||||
* structures for one device. The device is registered with Card
|
||||
* Services.
|
||||
*
|
||||
* The dev_link structure is initialized, but we don't actually
|
||||
* configure the card at this point -- we wait until we receive a card
|
||||
* insertion event.
|
||||
*/
|
||||
static int if_cs_probe(struct pcmcia_device *p_dev)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
struct lbs_private *priv;
|
||||
struct if_cs_card *card;
|
||||
/* CIS parsing */
|
||||
tuple_t tuple;
|
||||
cisparse_t parse;
|
||||
cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
|
||||
cistpl_io_t *io = &cfg->io;
|
||||
u_char buf[64];
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
|
||||
if (!card) {
|
||||
lbs_pr_err("error in kzalloc\n");
|
||||
goto out;
|
||||
}
|
||||
card->p_dev = p_dev;
|
||||
p_dev->priv = card;
|
||||
|
||||
p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
|
||||
p_dev->irq.Handler = NULL;
|
||||
p_dev->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
|
||||
|
||||
p_dev->conf.Attributes = 0;
|
||||
p_dev->conf.IntType = INT_MEMORY_AND_IO;
|
||||
|
||||
tuple.Attributes = 0;
|
||||
tuple.TupleData = buf;
|
||||
tuple.TupleDataMax = sizeof(buf);
|
||||
tuple.TupleOffset = 0;
|
||||
|
||||
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
|
||||
if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 ||
|
||||
(ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 ||
|
||||
(ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0)
|
||||
{
|
||||
lbs_pr_err("error in pcmcia_get_first_tuple etc\n");
|
||||
goto out1;
|
||||
}
|
||||
|
||||
p_dev->conf.ConfigIndex = cfg->index;
|
||||
|
||||
/* Do we need to allocate an interrupt? */
|
||||
if (cfg->irq.IRQInfo1) {
|
||||
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
|
||||
}
|
||||
|
||||
/* IO window settings */
|
||||
if (cfg->io.nwin != 1) {
|
||||
lbs_pr_err("wrong CIS (check number of IO windows)\n");
|
||||
ret = -ENODEV;
|
||||
goto out1;
|
||||
}
|
||||
p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
|
||||
p_dev->io.BasePort1 = io->win[0].base;
|
||||
p_dev->io.NumPorts1 = io->win[0].len;
|
||||
|
||||
/* This reserves IO space but doesn't actually enable it */
|
||||
ret = pcmcia_request_io(p_dev, &p_dev->io);
|
||||
if (ret) {
|
||||
lbs_pr_err("error in pcmcia_request_io\n");
|
||||
goto out1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate an interrupt line. Note that this does not assign
|
||||
* a handler to the interrupt, unless the 'Handler' member of
|
||||
* the irq structure is initialized.
|
||||
*/
|
||||
if (p_dev->conf.Attributes & CONF_ENABLE_IRQ) {
|
||||
ret = pcmcia_request_irq(p_dev, &p_dev->irq);
|
||||
if (ret) {
|
||||
lbs_pr_err("error in pcmcia_request_irq\n");
|
||||
goto out1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize io access */
|
||||
card->iobase = ioport_map(p_dev->io.BasePort1, p_dev->io.NumPorts1);
|
||||
if (!card->iobase) {
|
||||
lbs_pr_err("error in ioport_map\n");
|
||||
ret = -EIO;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This actually configures the PCMCIA socket -- setting up
|
||||
* the I/O windows and the interrupt mapping, and putting the
|
||||
* card and host interface into "Memory and IO" mode.
|
||||
*/
|
||||
ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
|
||||
if (ret) {
|
||||
lbs_pr_err("error in pcmcia_request_configuration\n");
|
||||
goto out2;
|
||||
}
|
||||
|
||||
/* Finally, report what we've done */
|
||||
lbs_deb_cs("irq %d, io 0x%04x-0x%04x\n",
|
||||
p_dev->irq.AssignedIRQ, p_dev->io.BasePort1,
|
||||
p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1);
|
||||
|
||||
|
||||
/* Load the firmware early, before calling into libertas.ko */
|
||||
ret = if_cs_prog_helper(card);
|
||||
if (ret == 0)
|
||||
ret = if_cs_prog_real(card);
|
||||
if (ret)
|
||||
goto out2;
|
||||
|
||||
/* Make this card known to the libertas driver */
|
||||
priv = lbs_add_card(card, &p_dev->dev);
|
||||
if (!priv) {
|
||||
ret = -ENOMEM;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
/* Finish setting up fields in lbs_private */
|
||||
card->priv = priv;
|
||||
priv->card = card;
|
||||
priv->hw_host_to_card = if_cs_host_to_card;
|
||||
priv->fw_ready = 1;
|
||||
|
||||
/* Now actually get the IRQ */
|
||||
ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt,
|
||||
IRQF_SHARED, DRV_NAME, card);
|
||||
if (ret) {
|
||||
lbs_pr_err("error in request_irq\n");
|
||||
goto out3;
|
||||
}
|
||||
|
||||
/* Clear any interrupt cause that happend while sending
|
||||
* firmware/initializing card */
|
||||
if_cs_write16(card, IF_CS_C_INT_CAUSE, IF_CS_C_IC_MASK);
|
||||
if_cs_enable_ints(card);
|
||||
|
||||
/* And finally bring the card up */
|
||||
if (lbs_start_card(priv) != 0) {
|
||||
lbs_pr_err("could not activate card\n");
|
||||
goto out3;
|
||||
}
|
||||
|
||||
/* The firmware for the CF card supports powersave */
|
||||
priv->ps_supported = 1;
|
||||
|
||||
ret = 0;
|
||||
goto out;
|
||||
|
||||
out3:
|
||||
lbs_remove_card(priv);
|
||||
out2:
|
||||
ioport_unmap(card->iobase);
|
||||
out1:
|
||||
pcmcia_disable_device(p_dev);
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This deletes a driver "instance". The device is de-registered with
|
||||
* Card Services. If it has been released, all local data structures
|
||||
* are freed. Otherwise, the structures will be freed when the device
|
||||
* is released.
|
||||
*/
|
||||
static void if_cs_detach(struct pcmcia_device *p_dev)
|
||||
{
|
||||
struct if_cs_card *card = p_dev->priv;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
lbs_stop_card(card->priv);
|
||||
lbs_remove_card(card->priv);
|
||||
if_cs_disable_ints(card);
|
||||
if_cs_release(p_dev);
|
||||
kfree(card);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Module initialization */
|
||||
/********************************************************************/
|
||||
|
||||
static struct pcmcia_device_id if_cs_ids[] = {
|
||||
PCMCIA_DEVICE_MANF_CARD(0x02df, 0x8103),
|
||||
PCMCIA_DEVICE_NULL,
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
|
||||
|
||||
|
||||
static struct pcmcia_driver lbs_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.drv = {
|
||||
.name = DRV_NAME,
|
||||
},
|
||||
.probe = if_cs_probe,
|
||||
.remove = if_cs_detach,
|
||||
.id_table = if_cs_ids,
|
||||
};
|
||||
|
||||
|
||||
static int __init if_cs_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
ret = pcmcia_register_driver(&lbs_driver);
|
||||
lbs_deb_leave(LBS_DEB_CS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void __exit if_cs_exit(void)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
pcmcia_unregister_driver(&lbs_driver);
|
||||
lbs_deb_leave(LBS_DEB_CS);
|
||||
}
|
||||
|
||||
|
||||
module_init(if_cs_init);
|
||||
module_exit(if_cs_exit);
|
File diff suppressed because it is too large
Load Diff
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* linux/drivers/net/wireless/libertas/if_sdio.h
|
||||
*
|
||||
* Copyright 2007 Pierre Ossman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _LBS_IF_SDIO_H
|
||||
#define _LBS_IF_SDIO_H
|
||||
|
||||
#define IF_SDIO_IOPORT 0x00
|
||||
|
||||
#define IF_SDIO_H_INT_MASK 0x04
|
||||
#define IF_SDIO_H_INT_OFLOW 0x08
|
||||
#define IF_SDIO_H_INT_UFLOW 0x04
|
||||
#define IF_SDIO_H_INT_DNLD 0x02
|
||||
#define IF_SDIO_H_INT_UPLD 0x01
|
||||
|
||||
#define IF_SDIO_H_INT_STATUS 0x05
|
||||
#define IF_SDIO_H_INT_RSR 0x06
|
||||
#define IF_SDIO_H_INT_STATUS2 0x07
|
||||
|
||||
#define IF_SDIO_RD_BASE 0x10
|
||||
|
||||
#define IF_SDIO_STATUS 0x20
|
||||
#define IF_SDIO_IO_RDY 0x08
|
||||
#define IF_SDIO_CIS_RDY 0x04
|
||||
#define IF_SDIO_UL_RDY 0x02
|
||||
#define IF_SDIO_DL_RDY 0x01
|
||||
|
||||
#define IF_SDIO_C_INT_MASK 0x24
|
||||
#define IF_SDIO_C_INT_STATUS 0x28
|
||||
#define IF_SDIO_C_INT_RSR 0x2C
|
||||
|
||||
#define IF_SDIO_SCRATCH 0x34
|
||||
#define IF_SDIO_SCRATCH_OLD 0x80fe
|
||||
#define IF_SDIO_FIRMWARE_OK 0xfedc
|
||||
|
||||
#define IF_SDIO_EVENT 0x80fc
|
||||
|
||||
#endif
|
@ -1,967 +0,0 @@
|
||||
/**
|
||||
* This file contains functions used in USB interface module.
|
||||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/usb.h>
|
||||
#ifdef CONFIG_OLPC
|
||||
#include <asm/olpc.h>
|
||||
#endif
|
||||
|
||||
#define DRV_NAME "usb8xxx"
|
||||
|
||||
#include "host.h"
|
||||
#include "decl.h"
|
||||
#include "defs.h"
|
||||
#include "dev.h"
|
||||
#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";
|
||||
module_param_named(fw_name, lbs_fw_name, charp, 0644);
|
||||
|
||||
static struct usb_device_id if_usb_table[] = {
|
||||
/* Enter the device signature inside */
|
||||
{ USB_DEVICE(0x1286, 0x2001) },
|
||||
{ USB_DEVICE(0x05a3, 0x8388) },
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
|
||||
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 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 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
|
||||
* @param urb pointer to urb structure
|
||||
* @return N/A
|
||||
*/
|
||||
static void if_usb_write_bulk_callback(struct urb *urb)
|
||||
{
|
||||
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_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.
|
||||
*/
|
||||
if (priv)
|
||||
lbs_host_to_card_done(priv);
|
||||
} else {
|
||||
/* print the failure status number for debug */
|
||||
lbs_pr_info("URB in failure status: %d\n", urb->status);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief free tx/rx urb, skb and rx buffer
|
||||
* @param cardp pointer if_usb_card
|
||||
* @return N/A
|
||||
*/
|
||||
static void if_usb_free(struct if_usb_card *cardp)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_USB);
|
||||
|
||||
/* Unlink tx & rx urb */
|
||||
usb_kill_urb(cardp->tx_urb);
|
||||
usb_kill_urb(cardp->rx_urb);
|
||||
|
||||
usb_free_urb(cardp->tx_urb);
|
||||
cardp->tx_urb = NULL;
|
||||
|
||||
usb_free_urb(cardp->rx_urb);
|
||||
cardp->rx_urb = NULL;
|
||||
|
||||
kfree(cardp->ep_out_buf);
|
||||
cardp->ep_out_buf = NULL;
|
||||
|
||||
lbs_deb_leave(LBS_DEB_USB);
|
||||
}
|
||||
|
||||
static void if_usb_setup_firmware(struct lbs_private *priv)
|
||||
{
|
||||
struct if_usb_card *cardp = priv->card;
|
||||
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 = cardp->boot2_version;
|
||||
|
||||
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 if_usb_card *cardp = (void *)priv;
|
||||
|
||||
if (cardp->fwdnldover) {
|
||||
lbs_deb_usb("Download complete, no event. Assuming success\n");
|
||||
} else {
|
||||
lbs_pr_err("Download timed out\n");
|
||||
cardp->surprise_removed = 1;
|
||||
}
|
||||
wake_up(&cardp->fw_wq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief sets the configuration values
|
||||
* @param ifnum interface number
|
||||
* @param id pointer to usb_device_id
|
||||
* @return 0 on success, error code on failure
|
||||
*/
|
||||
static int if_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev;
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
struct lbs_private *priv;
|
||||
struct if_usb_card *cardp;
|
||||
int i;
|
||||
|
||||
udev = interface_to_usbdev(intf);
|
||||
|
||||
cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
|
||||
if (!cardp) {
|
||||
lbs_pr_err("Out of memory allocating private data.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
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",
|
||||
le16_to_cpu(udev->descriptor.bcdUSB),
|
||||
udev->descriptor.bDeviceClass,
|
||||
udev->descriptor.bDeviceSubClass,
|
||||
udev->descriptor.bDeviceProtocol);
|
||||
|
||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
||||
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);
|
||||
|
||||
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 */
|
||||
if (if_usb_prog_firmware(cardp)) {
|
||||
lbs_deb_usbd(&udev->dev, "FW upload failed\n");
|
||||
goto err_prog_firmware;
|
||||
}
|
||||
|
||||
if (!(priv = lbs_add_card(cardp, &udev->dev)))
|
||||
goto err_prog_firmware;
|
||||
|
||||
cardp->priv = priv;
|
||||
cardp->priv->fw_ready = 1;
|
||||
|
||||
priv->hw_host_to_card = if_usb_host_to_card;
|
||||
cardp->boot2_version = udev->descriptor.bcdDevice;
|
||||
|
||||
if_usb_submit_rx_urb(cardp);
|
||||
|
||||
if (lbs_start_card(priv))
|
||||
goto err_start_card;
|
||||
|
||||
if_usb_setup_firmware(priv);
|
||||
|
||||
usb_get_dev(udev);
|
||||
usb_set_intfdata(intf, cardp);
|
||||
|
||||
return 0;
|
||||
|
||||
err_start_card:
|
||||
lbs_remove_card(priv);
|
||||
err_prog_firmware:
|
||||
if_usb_reset_device(cardp);
|
||||
dealloc:
|
||||
if_usb_free(cardp);
|
||||
|
||||
error:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief free resource and cleanup
|
||||
* @param intf USB interface structure
|
||||
* @return N/A
|
||||
*/
|
||||
static void if_usb_disconnect(struct usb_interface *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);
|
||||
|
||||
cardp->surprise_removed = 1;
|
||||
|
||||
if (priv) {
|
||||
priv->surpriseremoved = 1;
|
||||
lbs_stop_card(priv);
|
||||
lbs_remove_card(priv);
|
||||
}
|
||||
|
||||
/* Unlink and free urb */
|
||||
if_usb_free(cardp);
|
||||
|
||||
usb_set_intfdata(intf, NULL);
|
||||
usb_put_dev(interface_to_usbdev(intf));
|
||||
|
||||
lbs_deb_leave(LBS_DEB_MAIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function download FW
|
||||
* @param priv pointer to struct lbs_private
|
||||
* @return 0
|
||||
*/
|
||||
static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
|
||||
{
|
||||
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--;
|
||||
}
|
||||
|
||||
lbs_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n",
|
||||
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);
|
||||
|
||||
memcpy(fwdata->data, &firmware[cardp->totalbytes],
|
||||
le32_to_cpu(fwdata->hdr.datalength));
|
||||
|
||||
lbs_deb_usb2(&cardp->udev->dev, "Data length = %d\n",
|
||||
le32_to_cpu(fwdata->hdr.datalength));
|
||||
|
||||
fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
|
||||
cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
|
||||
|
||||
usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
|
||||
le32_to_cpu(fwdata->hdr.datalength));
|
||||
|
||||
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");
|
||||
|
||||
cardp->fwfinalblk = 1;
|
||||
}
|
||||
|
||||
lbs_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n",
|
||||
cardp->totalbytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int if_usb_reset_device(struct if_usb_card *cardp)
|
||||
{
|
||||
struct cmd_ds_command *cmd = cardp->ep_out_buf + 4;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_USB);
|
||||
|
||||
*(__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->ep_out_buf, 4 + S_DS_GEN + sizeof(struct cmd_ds_802_11_reset));
|
||||
|
||||
msleep(100);
|
||||
ret = usb_reset_device(cardp->udev);
|
||||
msleep(100);
|
||||
|
||||
#ifdef CONFIG_OLPC
|
||||
if (ret && machine_is_olpc()) {
|
||||
printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
|
||||
olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function transfer the data to the device.
|
||||
* @param priv pointer to struct lbs_private
|
||||
* @param payload pointer to payload data
|
||||
* @param nb data length
|
||||
* @return 0 or -1
|
||||
*/
|
||||
static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
/* check if device is removed */
|
||||
if (cardp->surprise_removed) {
|
||||
lbs_deb_usbd(&cardp->udev->dev, "Device removed\n");
|
||||
goto tx_ret;
|
||||
}
|
||||
|
||||
usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
|
||||
usb_sndbulkpipe(cardp->udev,
|
||||
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))) {
|
||||
lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
|
||||
ret = -1;
|
||||
} else {
|
||||
lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
tx_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
|
||||
void (*callbackfn)(struct urb *urb))
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int ret = -1;
|
||||
|
||||
if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
|
||||
lbs_pr_err("No free skb\n");
|
||||
goto rx_ret;
|
||||
}
|
||||
|
||||
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->ep_in),
|
||||
(void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET),
|
||||
MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
|
||||
cardp);
|
||||
|
||||
cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
|
||||
|
||||
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))) {
|
||||
lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
|
||||
kfree_skb(skb);
|
||||
cardp->rx_skb = NULL;
|
||||
ret = -1;
|
||||
} else {
|
||||
lbs_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
rx_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 if_usb_card *cardp)
|
||||
{
|
||||
return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
|
||||
}
|
||||
|
||||
static void if_usb_receive_fwload(struct urb *urb)
|
||||
{
|
||||
struct if_usb_card *cardp = urb->context;
|
||||
struct sk_buff *skb = cardp->rx_skb;
|
||||
struct fwsyncheader *syncfwheader;
|
||||
struct bootcmdresp bootcmdresp;
|
||||
|
||||
if (urb->status) {
|
||||
lbs_deb_usbd(&cardp->udev->dev,
|
||||
"URB status is failed during fw load\n");
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cardp->fwdnldover) {
|
||||
__le32 *tmp = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
|
||||
|
||||
if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
|
||||
tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
|
||||
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]));
|
||||
if_usb_submit_rx_urb_fwload(cardp);
|
||||
}
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
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");
|
||||
return;
|
||||
}
|
||||
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.magic));
|
||||
}
|
||||
} 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");
|
||||
}
|
||||
kfree_skb(skb);
|
||||
if_usb_submit_rx_urb_fwload(cardp);
|
||||
return;
|
||||
}
|
||||
|
||||
syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
|
||||
if (!syncfwheader) {
|
||||
lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
|
||||
sizeof(struct fwsyncheader));
|
||||
|
||||
if (!syncfwheader->cmd) {
|
||||
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");
|
||||
cardp->CRC_OK = 0;
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
/* reschedule timer for 200ms hence */
|
||||
mod_timer(&cardp->fw_timeout, jiffies + (HZ/5));
|
||||
|
||||
if (cardp->fwfinalblk) {
|
||||
cardp->fwdnldover = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if_usb_send_fw_pkt(cardp);
|
||||
|
||||
exit:
|
||||
if_usb_submit_rx_urb_fwload(cardp);
|
||||
|
||||
kfree(syncfwheader);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#define MRVDRV_MIN_PKT_LEN 30
|
||||
|
||||
static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
|
||||
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");
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
|
||||
skb_put(skb, recvlength);
|
||||
skb_pull(skb, MESSAGE_HEADER_LEN);
|
||||
|
||||
lbs_process_rxed_packet(priv, skb);
|
||||
}
|
||||
|
||||
static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
|
||||
struct sk_buff *skb,
|
||||
struct if_usb_card *cardp,
|
||||
struct lbs_private *priv)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
if (recvlength > LBS_CMD_BUFFER_SIZE) {
|
||||
lbs_deb_usbd(&cardp->udev->dev,
|
||||
"The receive buffer is too large\n");
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in_interrupt())
|
||||
BUG();
|
||||
|
||||
spin_lock(&priv->driver_lock);
|
||||
|
||||
i = (priv->resp_idx == 0) ? 1 : 0;
|
||||
BUG_ON(priv->resp_len[i]);
|
||||
priv->resp_len[i] = (recvlength - MESSAGE_HEADER_LEN);
|
||||
memcpy(priv->resp_buf[i], recvbuff + MESSAGE_HEADER_LEN,
|
||||
priv->resp_len[i]);
|
||||
kfree_skb(skb);
|
||||
lbs_notify_command_response(priv, i);
|
||||
|
||||
spin_unlock(&priv->driver_lock);
|
||||
|
||||
lbs_deb_usbd(&cardp->udev->dev,
|
||||
"Wake up main thread to handle cmd response\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function reads of the packet into the upload buff,
|
||||
* wake up the main thread and initialise the Rx callack.
|
||||
*
|
||||
* @param urb pointer to struct urb
|
||||
* @return N/A
|
||||
*/
|
||||
static void if_usb_receive(struct urb *urb)
|
||||
{
|
||||
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;
|
||||
uint8_t *recvbuff = NULL;
|
||||
uint32_t recvtype = 0;
|
||||
__le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
|
||||
uint32_t event;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_USB);
|
||||
|
||||
if (recvlength) {
|
||||
if (urb->status) {
|
||||
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;
|
||||
recvtype = le32_to_cpu(pkt[0]);
|
||||
lbs_deb_usbd(&cardp->udev->dev,
|
||||
"Recv length = 0x%x, Recv type = 0x%X\n",
|
||||
recvlength, recvtype);
|
||||
} else if (urb->status) {
|
||||
kfree_skb(skb);
|
||||
goto rx_exit;
|
||||
}
|
||||
|
||||
switch (recvtype) {
|
||||
case CMD_TYPE_DATA:
|
||||
process_cmdtypedata(recvlength, skb, cardp, priv);
|
||||
break;
|
||||
|
||||
case CMD_TYPE_REQUEST:
|
||||
process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
|
||||
break;
|
||||
|
||||
case CMD_TYPE_INDICATION:
|
||||
/* Event handling */
|
||||
event = le32_to_cpu(pkt[1]);
|
||||
lbs_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event);
|
||||
kfree_skb(skb);
|
||||
|
||||
/* Icky undocumented magic special case */
|
||||
if (event & 0xffff0000) {
|
||||
u32 trycount = (event & 0xffff0000) >> 16;
|
||||
|
||||
lbs_send_tx_feedback(priv, trycount);
|
||||
} else
|
||||
lbs_queue_event(priv, event & 0xFF);
|
||||
break;
|
||||
|
||||
default:
|
||||
lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
|
||||
recvtype);
|
||||
kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
|
||||
setup_for_next:
|
||||
if_usb_submit_rx_urb(cardp);
|
||||
rx_exit:
|
||||
lbs_deb_leave(LBS_DEB_USB);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function downloads data to FW
|
||||
* @param priv pointer to struct lbs_private structure
|
||||
* @param type type of data
|
||||
* @param buf pointer to data buffer
|
||||
* @param len number of bytes
|
||||
* @return 0 or -1
|
||||
*/
|
||||
static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
|
||||
uint8_t *payload, uint16_t nb)
|
||||
{
|
||||
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 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
|
||||
priv->dnld_sent = DNLD_CMD_SENT;
|
||||
} else {
|
||||
*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA);
|
||||
priv->dnld_sent = DNLD_DATA_SENT;
|
||||
}
|
||||
|
||||
memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb);
|
||||
|
||||
return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function issues Boot command to the Boot2 code
|
||||
* @param ivalue 1:Boot from FW by USB-Download
|
||||
* 2:Boot from FW in EEPROM
|
||||
* @return 0
|
||||
*/
|
||||
static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
|
||||
{
|
||||
struct bootcmd *bootcmd = cardp->ep_out_buf;
|
||||
|
||||
/* Prepare command */
|
||||
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->ep_out_buf, sizeof(*bootcmd));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function checks the validity of Boot2/FW image.
|
||||
*
|
||||
* @param data pointer to image
|
||||
* len image length
|
||||
* @return 0 or -1
|
||||
*/
|
||||
static int check_fwfile_format(uint8_t *data, uint32_t totlen)
|
||||
{
|
||||
uint32_t bincmd, exit;
|
||||
uint32_t blksize, offset, len;
|
||||
int ret;
|
||||
|
||||
ret = 1;
|
||||
exit = len = 0;
|
||||
|
||||
do {
|
||||
struct fwheader *fwh = (void *)data;
|
||||
|
||||
bincmd = le32_to_cpu(fwh->dnldcmd);
|
||||
blksize = le32_to_cpu(fwh->datalength);
|
||||
switch (bincmd) {
|
||||
case FW_HAS_DATA_TO_RECV:
|
||||
offset = sizeof(struct fwheader) + blksize;
|
||||
data += offset;
|
||||
len += offset;
|
||||
if (len >= totlen)
|
||||
exit = 1;
|
||||
break;
|
||||
case FW_HAS_LAST_BLOCK:
|
||||
exit = 1;
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
exit = 1;
|
||||
break;
|
||||
}
|
||||
} while (!exit);
|
||||
|
||||
if (ret)
|
||||
lbs_pr_err("firmware file format check FAIL\n");
|
||||
else
|
||||
lbs_deb_fw("firmware file format check PASS\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int if_usb_prog_firmware(struct if_usb_card *cardp)
|
||||
{
|
||||
int i = 0;
|
||||
static int reset_count = 10;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_USB);
|
||||
|
||||
if ((ret = request_firmware(&cardp->fw, lbs_fw_name,
|
||||
&cardp->udev->dev)) < 0) {
|
||||
lbs_pr_err("request_firmware() failed with %#x\n", ret);
|
||||
lbs_pr_err("firmware %s not found\n", lbs_fw_name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (check_fwfile_format(cardp->fw->data, cardp->fw->size))
|
||||
goto release_fw;
|
||||
|
||||
restart:
|
||||
if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
|
||||
lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
|
||||
ret = -1;
|
||||
goto release_fw;
|
||||
}
|
||||
|
||||
cardp->bootcmdresp = 0;
|
||||
do {
|
||||
int j = 0;
|
||||
i++;
|
||||
/* Issue Boot command = 1, Boot from Download-FW */
|
||||
if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
|
||||
/* wait for command response */
|
||||
do {
|
||||
j++;
|
||||
msleep_interruptible(100);
|
||||
} while (cardp->bootcmdresp == 0 && j < 10);
|
||||
} while (cardp->bootcmdresp == 0 && i < 5);
|
||||
|
||||
if (cardp->bootcmdresp <= 0) {
|
||||
if (--reset_count >= 0) {
|
||||
if_usb_reset_device(cardp);
|
||||
goto restart;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
cardp->totalbytes = 0;
|
||||
cardp->fwlastblksent = 0;
|
||||
cardp->CRC_OK = 1;
|
||||
cardp->fwdnldover = 0;
|
||||
cardp->fwseqnum = -1;
|
||||
cardp->totalbytes = 0;
|
||||
cardp->fwfinalblk = 0;
|
||||
|
||||
/* Send the first firmware packet... */
|
||||
if_usb_send_fw_pkt(cardp);
|
||||
|
||||
/* ... 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);
|
||||
|
||||
if (!cardp->fwdnldover) {
|
||||
lbs_pr_info("failed to load fw, resetting device!\n");
|
||||
if (--reset_count >= 0) {
|
||||
if_usb_reset_device(cardp);
|
||||
goto restart;
|
||||
}
|
||||
|
||||
lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
|
||||
ret = -1;
|
||||
goto release_fw;
|
||||
}
|
||||
|
||||
release_fw:
|
||||
release_firmware(cardp->fw);
|
||||
cardp->fw = NULL;
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
{
|
||||
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;
|
||||
|
||||
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 ret;
|
||||
}
|
||||
|
||||
static int if_usb_resume(struct usb_interface *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);
|
||||
|
||||
lbs_resume(priv);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_USB);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define if_usb_suspend NULL
|
||||
#define if_usb_resume NULL
|
||||
#endif
|
||||
|
||||
static struct usb_driver if_usb_driver = {
|
||||
.name = DRV_NAME,
|
||||
.probe = if_usb_probe,
|
||||
.disconnect = if_usb_disconnect,
|
||||
.id_table = if_usb_table,
|
||||
.suspend = if_usb_suspend,
|
||||
.resume = if_usb_resume,
|
||||
.reset_resume = if_usb_resume,
|
||||
};
|
||||
|
||||
static int __init if_usb_init_module(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
|
||||
ret = usb_register(&if_usb_driver);
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit if_usb_exit_module(void)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
|
||||
usb_deregister(&if_usb_driver);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_MAIN);
|
||||
}
|
||||
|
||||
module_init(if_usb_init_module);
|
||||
module_exit(if_usb_exit_module);
|
||||
|
||||
MODULE_DESCRIPTION("8388 USB WLAN Driver");
|
||||
MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
@ -1,100 +0,0 @@
|
||||
#ifndef _LBS_IF_USB_H
|
||||
#define _LBS_IF_USB_H
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
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 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 /* LVRM */
|
||||
|
||||
struct bootcmd
|
||||
{
|
||||
__le32 magic;
|
||||
uint8_t cmd;
|
||||
uint8_t pad[11];
|
||||
};
|
||||
|
||||
#define BOOT_CMD_RESP_OK 0x0001
|
||||
#define BOOT_CMD_RESP_FAIL 0x0000
|
||||
|
||||
struct bootcmdresp
|
||||
{
|
||||
__le32 magic;
|
||||
uint8_t cmd;
|
||||
uint8_t result;
|
||||
uint8_t pad[2];
|
||||
};
|
||||
|
||||
/** USB card description structure*/
|
||||
struct if_usb_card {
|
||||
struct usb_device *udev;
|
||||
struct urb *rx_urb, *tx_urb;
|
||||
struct lbs_private *priv;
|
||||
|
||||
struct sk_buff *rx_skb;
|
||||
|
||||
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;
|
||||
uint32_t fwseqnum;
|
||||
uint32_t totalbytes;
|
||||
uint32_t fwlastblksent;
|
||||
uint8_t CRC_OK;
|
||||
uint8_t fwdnldover;
|
||||
uint8_t fwfinalblk;
|
||||
uint8_t surprise_removed;
|
||||
|
||||
__le16 boot2_version;
|
||||
};
|
||||
|
||||
/** fwheader */
|
||||
struct fwheader {
|
||||
__le32 dnldcmd;
|
||||
__le32 baseaddr;
|
||||
__le32 datalength;
|
||||
__le32 CRC;
|
||||
};
|
||||
|
||||
#define FW_MAX_DATA_BLK_SIZE 600
|
||||
/** FWData */
|
||||
struct fwdata {
|
||||
struct fwheader hdr;
|
||||
__le32 seqnum;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
/** fwsyncheader */
|
||||
struct fwsyncheader {
|
||||
__le32 cmd;
|
||||
__le32 seqnum;
|
||||
};
|
||||
|
||||
#define FW_HAS_DATA_TO_RECV 0x00000001
|
||||
#define FW_HAS_LAST_BLOCK 0x00000004
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,49 +0,0 @@
|
||||
#define COSTS_LIST_SIZE 4
|
||||
|
||||
/* iwpriv places the subcmd number in the first uint32_t;
|
||||
data buffer follows that */
|
||||
#define SUBCMD_OFFSET sizeof(uint32_t)
|
||||
#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET))
|
||||
|
||||
/** Private ioctls and ioctls subcommands */
|
||||
#define LBS_SETNONE_GETNONE (SIOCIWFIRSTPRIV + 8)
|
||||
#define LBS_SUBCMD_BT_RESET 13
|
||||
#define LBS_SUBCMD_FWT_RESET 14
|
||||
|
||||
#define LBS_SETNONE_GETONEINT (SIOCIWFIRSTPRIV + 15)
|
||||
#define LBS_SUBCMD_GET_REGION 1
|
||||
#define LBS_SUBCMD_FWT_CLEANUP 15
|
||||
#define LBS_SUBCMD_FWT_TIME 16
|
||||
#define LBS_SUBCMD_MESH_GET_TTL 17
|
||||
#define LBS_SUBCMD_BT_GET_INVERT 18
|
||||
#define LBS_SUBCMD_MESH_GET_BCAST_RATE 19
|
||||
#define LBS_SUBCMD_MESH_GET_RREQ_DELAY 20
|
||||
#define LBS_SUBCMD_MESH_GET_ROUTE_EXP 21
|
||||
|
||||
#define LBS_SETONEINT_GETNONE (SIOCIWFIRSTPRIV + 24)
|
||||
#define LBS_SUBCMD_SET_REGION 8
|
||||
#define LBS_SUBCMD_MESH_SET_TTL 18
|
||||
#define LBS_SUBCMD_BT_SET_INVERT 19
|
||||
#define LBS_SUBCMD_MESH_SET_BCAST_RATE 20
|
||||
#define LBS_SUBCMD_MESH_SET_RREQ_DELAY 21
|
||||
#define LBS_SUBCMD_MESH_SET_ROUTE_EXP 22
|
||||
|
||||
#define LBS_SET128CHAR_GET128CHAR (SIOCIWFIRSTPRIV + 25)
|
||||
#define LBS_SUBCMD_BT_ADD 18
|
||||
#define LBS_SUBCMD_BT_DEL 19
|
||||
#define LBS_SUBCMD_BT_LIST 20
|
||||
#define LBS_SUBCMD_FWT_ADD 21
|
||||
#define LBS_SUBCMD_FWT_DEL 22
|
||||
#define LBS_SUBCMD_FWT_LOOKUP 23
|
||||
#define LBS_SUBCMD_FWT_LIST_NEIGHBOR 24
|
||||
#define LBS_SUBCMD_FWT_LIST 25
|
||||
#define LBS_SUBCMD_FWT_LIST_ROUTE 26
|
||||
#define LBS_SUBCMD_MESH_SET_LINK_COSTS 27
|
||||
#define LBS_SUBCMD_MESH_GET_LINK_COSTS 28
|
||||
|
||||
#define LBS_SET_GET_SIXTEEN_INT (SIOCIWFIRSTPRIV + 29)
|
||||
#define LBS_LED_GPIO_CTRL 5
|
||||
#define LBS_BCN_CTRL 6
|
||||
#define LBS_LED_BEHAVIOR_CTRL 7
|
||||
|
||||
int lbs_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
|
@ -1,895 +0,0 @@
|
||||
/**
|
||||
* Functions implementing wlan infrastructure and adhoc join routines,
|
||||
* IOCTL handlers as well as command preperation and response routines
|
||||
* for sending adhoc start, adhoc join, and association commands
|
||||
* to the firmware.
|
||||
*/
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include "host.h"
|
||||
#include "decl.h"
|
||||
#include "join.h"
|
||||
#include "dev.h"
|
||||
#include "assoc.h"
|
||||
|
||||
/* The firmware needs certain bits masked out of the beacon-derviced capability
|
||||
* field when associating/joining to BSSs.
|
||||
*/
|
||||
#define CAPINFO_MASK (~(0xda00))
|
||||
|
||||
/**
|
||||
* @brief This function finds common rates between rate1 and card rates.
|
||||
*
|
||||
* It will fill common rates in rate1 as output if found.
|
||||
*
|
||||
* NOTE: Setting the MSB of the basic rates need to be taken
|
||||
* care, either before or after calling this function
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @param rate1 the buffer which keeps input and output
|
||||
* @param rate1_size the size of rate1 buffer; new size of buffer on return
|
||||
*
|
||||
* @return 0 or -1
|
||||
*/
|
||||
static int get_common_rates(struct lbs_private *priv,
|
||||
u8 *rates,
|
||||
u16 *rates_size)
|
||||
{
|
||||
u8 *card_rates = lbs_bg_rates;
|
||||
size_t num_card_rates = sizeof(lbs_bg_rates);
|
||||
int ret = 0, i, j;
|
||||
u8 tmp[30];
|
||||
size_t tmp_size = 0;
|
||||
|
||||
/* For each rate in card_rates that exists in rate1, copy to tmp */
|
||||
for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
|
||||
for (j = 0; rates[j] && (j < *rates_size); j++) {
|
||||
if (rates[j] == card_rates[i])
|
||||
tmp[tmp_size++] = card_rates[i];
|
||||
}
|
||||
}
|
||||
|
||||
lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
|
||||
lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
|
||||
lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
|
||||
lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
|
||||
|
||||
if (!priv->auto_rate) {
|
||||
for (i = 0; i < tmp_size; i++) {
|
||||
if (tmp[i] == priv->cur_rate)
|
||||
goto done;
|
||||
}
|
||||
lbs_pr_alert("Previously set fixed data rate %#x isn't "
|
||||
"compatible with the network.\n", priv->cur_rate);
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
memset(rates, 0, *rates_size);
|
||||
*rates_size = min_t(int, tmp_size, *rates_size);
|
||||
memcpy(rates, tmp, *rates_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the MSB on basic rates as the firmware requires
|
||||
*
|
||||
* Scan through an array and set the MSB for basic data rates.
|
||||
*
|
||||
* @param rates buffer of data rates
|
||||
* @param len size of buffer
|
||||
*/
|
||||
static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (rates[i] == 0x02 || rates[i] == 0x04 ||
|
||||
rates[i] == 0x0b || rates[i] == 0x16)
|
||||
rates[i] |= 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unsets the MSB on basic rates
|
||||
*
|
||||
* Scan through an array and unset the MSB for basic data rates.
|
||||
*
|
||||
* @param rates buffer of data rates
|
||||
* @param len size of buffer
|
||||
*/
|
||||
void lbs_unset_basic_rate_flags(u8 *rates, size_t len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
rates[i] &= 0x7f;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Associate to a specific BSS discovered in a scan
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @param pbssdesc Pointer to the BSS descriptor to associate with.
|
||||
*
|
||||
* @return 0-success, otherwise fail
|
||||
*/
|
||||
int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ASSOC);
|
||||
|
||||
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
|
||||
0, CMD_OPTION_WAITFORRSP,
|
||||
0, assoc_req->bss.bssid);
|
||||
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
/* set preamble to firmware */
|
||||
if ( (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
|
||||
&& (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
|
||||
priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
|
||||
else
|
||||
priv->preamble = CMD_TYPE_LONG_PREAMBLE;
|
||||
|
||||
lbs_set_radio_control(priv);
|
||||
|
||||
ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
|
||||
0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start an Adhoc Network
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @param adhocssid The ssid of the Adhoc Network
|
||||
* @return 0--success, -1--fail
|
||||
*/
|
||||
int lbs_start_adhoc_network(struct lbs_private *priv,
|
||||
struct assoc_request *assoc_req)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
priv->adhoccreate = 1;
|
||||
|
||||
if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
|
||||
lbs_deb_join("AdhocStart: Short preamble\n");
|
||||
priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
|
||||
} else {
|
||||
lbs_deb_join("AdhocStart: Long preamble\n");
|
||||
priv->preamble = CMD_TYPE_LONG_PREAMBLE;
|
||||
}
|
||||
|
||||
lbs_set_radio_control(priv);
|
||||
|
||||
lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
|
||||
lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
|
||||
|
||||
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
|
||||
0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Join an adhoc network found in a previous scan
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @param pbssdesc Pointer to a BSS descriptor found in a previous scan
|
||||
* to attempt to join
|
||||
*
|
||||
* @return 0--success, -1--fail
|
||||
*/
|
||||
int lbs_join_adhoc_network(struct lbs_private *priv,
|
||||
struct assoc_request *assoc_req)
|
||||
{
|
||||
struct bss_descriptor * bss = &assoc_req->bss;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_join("%s: Current SSID '%s', ssid length %u\n",
|
||||
__func__,
|
||||
escape_essid(priv->curbssparams.ssid,
|
||||
priv->curbssparams.ssid_len),
|
||||
priv->curbssparams.ssid_len);
|
||||
lbs_deb_join("%s: requested ssid '%s', ssid length %u\n",
|
||||
__func__, escape_essid(bss->ssid, bss->ssid_len),
|
||||
bss->ssid_len);
|
||||
|
||||
/* check if the requested SSID is already joined */
|
||||
if ( priv->curbssparams.ssid_len
|
||||
&& !lbs_ssid_cmp(priv->curbssparams.ssid,
|
||||
priv->curbssparams.ssid_len,
|
||||
bss->ssid, bss->ssid_len)
|
||||
&& (priv->mode == IW_MODE_ADHOC)
|
||||
&& (priv->connect_status == LBS_CONNECTED)) {
|
||||
union iwreq_data wrqu;
|
||||
|
||||
lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
|
||||
"current, not attempting to re-join");
|
||||
|
||||
/* Send the re-association event though, because the association
|
||||
* request really was successful, even if just a null-op.
|
||||
*/
|
||||
memset(&wrqu, 0, sizeof(wrqu));
|
||||
memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid,
|
||||
ETH_ALEN);
|
||||
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Use shortpreamble only when both creator and card supports
|
||||
short preamble */
|
||||
if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
|
||||
|| !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
|
||||
lbs_deb_join("AdhocJoin: Long preamble\n");
|
||||
priv->preamble = CMD_TYPE_LONG_PREAMBLE;
|
||||
} else {
|
||||
lbs_deb_join("AdhocJoin: Short preamble\n");
|
||||
priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
|
||||
}
|
||||
|
||||
lbs_set_radio_control(priv);
|
||||
|
||||
lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
|
||||
lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
|
||||
|
||||
priv->adhoccreate = 0;
|
||||
|
||||
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
|
||||
0, CMD_OPTION_WAITFORRSP,
|
||||
OID_802_11_SSID, assoc_req);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lbs_stop_adhoc_network(struct lbs_private *priv)
|
||||
{
|
||||
return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
|
||||
0, CMD_OPTION_WAITFORRSP, 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send Deauthentication Request
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @return 0--success, -1--fail
|
||||
*/
|
||||
int lbs_send_deauthentication(struct lbs_private *priv)
|
||||
{
|
||||
return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
|
||||
0, CMD_OPTION_WAITFORRSP, 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function prepares command of authenticate.
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @param cmd A pointer to cmd_ds_command structure
|
||||
* @param pdata_buf Void cast of pointer to a BSSID to authenticate with
|
||||
*
|
||||
* @return 0 or -1
|
||||
*/
|
||||
int lbs_cmd_80211_authenticate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd,
|
||||
void *pdata_buf)
|
||||
{
|
||||
struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
|
||||
int ret = -1;
|
||||
u8 *bssid = pdata_buf;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
lbs_deb_enter(LBS_DEB_JOIN);
|
||||
|
||||
cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE);
|
||||
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
|
||||
+ S_DS_GEN);
|
||||
|
||||
/* translate auth mode to 802.11 defined wire value */
|
||||
switch (priv->secinfo.auth_mode) {
|
||||
case IW_AUTH_ALG_OPEN_SYSTEM:
|
||||
pauthenticate->authtype = 0x00;
|
||||
break;
|
||||
case IW_AUTH_ALG_SHARED_KEY:
|
||||
pauthenticate->authtype = 0x01;
|
||||
break;
|
||||
case IW_AUTH_ALG_LEAP:
|
||||
pauthenticate->authtype = 0x80;
|
||||
break;
|
||||
default:
|
||||
lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
|
||||
priv->secinfo.auth_mode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
|
||||
|
||||
lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
|
||||
print_mac(mac, bssid), pauthenticate->authtype);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd)
|
||||
{
|
||||
struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_JOIN);
|
||||
|
||||
cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE);
|
||||
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
|
||||
S_DS_GEN);
|
||||
|
||||
/* set AP MAC address */
|
||||
memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN);
|
||||
|
||||
/* Reason code 3 = Station is leaving */
|
||||
#define REASON_CODE_STA_LEAVING 3
|
||||
dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_JOIN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lbs_cmd_80211_associate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd, void *pdata_buf)
|
||||
{
|
||||
struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
|
||||
int ret = 0;
|
||||
struct assoc_request * assoc_req = pdata_buf;
|
||||
struct bss_descriptor * bss = &assoc_req->bss;
|
||||
u8 *pos;
|
||||
u16 tmpcap, tmplen;
|
||||
struct mrvlietypes_ssidparamset *ssid;
|
||||
struct mrvlietypes_phyparamset *phy;
|
||||
struct mrvlietypes_ssparamset *ss;
|
||||
struct mrvlietypes_ratesparamset *rates;
|
||||
struct mrvlietypes_rsnparamset *rsn;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ASSOC);
|
||||
|
||||
pos = (u8 *) passo;
|
||||
|
||||
if (!priv) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE);
|
||||
|
||||
memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
|
||||
pos += sizeof(passo->peerstaaddr);
|
||||
|
||||
/* set the listen interval */
|
||||
passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
|
||||
|
||||
pos += sizeof(passo->capability);
|
||||
pos += sizeof(passo->listeninterval);
|
||||
pos += sizeof(passo->bcnperiod);
|
||||
pos += sizeof(passo->dtimperiod);
|
||||
|
||||
ssid = (struct mrvlietypes_ssidparamset *) pos;
|
||||
ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
|
||||
tmplen = bss->ssid_len;
|
||||
ssid->header.len = cpu_to_le16(tmplen);
|
||||
memcpy(ssid->ssid, bss->ssid, tmplen);
|
||||
pos += sizeof(ssid->header) + tmplen;
|
||||
|
||||
phy = (struct mrvlietypes_phyparamset *) pos;
|
||||
phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
|
||||
tmplen = sizeof(phy->fh_ds.dsparamset);
|
||||
phy->header.len = cpu_to_le16(tmplen);
|
||||
memcpy(&phy->fh_ds.dsparamset,
|
||||
&bss->phyparamset.dsparamset.currentchan,
|
||||
tmplen);
|
||||
pos += sizeof(phy->header) + tmplen;
|
||||
|
||||
ss = (struct mrvlietypes_ssparamset *) pos;
|
||||
ss->header.type = cpu_to_le16(TLV_TYPE_CF);
|
||||
tmplen = sizeof(ss->cf_ibss.cfparamset);
|
||||
ss->header.len = cpu_to_le16(tmplen);
|
||||
pos += sizeof(ss->header) + tmplen;
|
||||
|
||||
rates = (struct mrvlietypes_ratesparamset *) pos;
|
||||
rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
|
||||
memcpy(&rates->rates, &bss->rates, MAX_RATES);
|
||||
tmplen = MAX_RATES;
|
||||
if (get_common_rates(priv, rates->rates, &tmplen)) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
pos += sizeof(rates->header) + tmplen;
|
||||
rates->header.len = cpu_to_le16(tmplen);
|
||||
lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
|
||||
|
||||
/* Copy the infra. association rates into Current BSS state structure */
|
||||
memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
|
||||
memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
|
||||
|
||||
/* Set MSB on basic rates as the firmware requires, but _after_
|
||||
* copying to current bss rates.
|
||||
*/
|
||||
lbs_set_basic_rate_flags(rates->rates, tmplen);
|
||||
|
||||
if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
|
||||
rsn = (struct mrvlietypes_rsnparamset *) pos;
|
||||
/* WPA_IE or WPA2_IE */
|
||||
rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
|
||||
tmplen = (u16) assoc_req->wpa_ie[1];
|
||||
rsn->header.len = cpu_to_le16(tmplen);
|
||||
memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
|
||||
lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn,
|
||||
sizeof(rsn->header) + tmplen);
|
||||
pos += sizeof(rsn->header) + tmplen;
|
||||
}
|
||||
|
||||
/* update curbssparams */
|
||||
priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
|
||||
|
||||
if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
|
||||
|
||||
/* set the capability info */
|
||||
tmpcap = (bss->capability & CAPINFO_MASK);
|
||||
if (bss->mode == IW_MODE_INFRA)
|
||||
tmpcap |= WLAN_CAPABILITY_ESS;
|
||||
passo->capability = cpu_to_le16(tmpcap);
|
||||
lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd, void *pdata_buf)
|
||||
{
|
||||
struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
|
||||
int ret = 0;
|
||||
int cmdappendsize = 0;
|
||||
struct assoc_request * assoc_req = pdata_buf;
|
||||
u16 tmpcap = 0;
|
||||
size_t ratesize = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_JOIN);
|
||||
|
||||
if (!priv) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START);
|
||||
|
||||
/*
|
||||
* Fill in the parameters for 2 data structures:
|
||||
* 1. cmd_ds_802_11_ad_hoc_start command
|
||||
* 2. priv->scantable[i]
|
||||
*
|
||||
* Driver will fill up SSID, bsstype,IBSS param, Physical Param,
|
||||
* probe delay, and cap info.
|
||||
*
|
||||
* Firmware will fill up beacon period, DTIM, Basic rates
|
||||
* and operational rates.
|
||||
*/
|
||||
|
||||
memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE);
|
||||
memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len);
|
||||
|
||||
lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
|
||||
escape_essid(assoc_req->ssid, assoc_req->ssid_len),
|
||||
assoc_req->ssid_len);
|
||||
|
||||
/* set the BSS type */
|
||||
adhs->bsstype = CMD_BSS_TYPE_IBSS;
|
||||
priv->mode = IW_MODE_ADHOC;
|
||||
if (priv->beacon_period == 0)
|
||||
priv->beacon_period = MRVDRV_BEACON_INTERVAL;
|
||||
adhs->beaconperiod = cpu_to_le16(priv->beacon_period);
|
||||
|
||||
/* set Physical param set */
|
||||
#define DS_PARA_IE_ID 3
|
||||
#define DS_PARA_IE_LEN 1
|
||||
|
||||
adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
|
||||
adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
|
||||
|
||||
WARN_ON(!assoc_req->channel);
|
||||
|
||||
lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n",
|
||||
assoc_req->channel);
|
||||
|
||||
adhs->phyparamset.dsparamset.currentchan = assoc_req->channel;
|
||||
|
||||
/* set IBSS param set */
|
||||
#define IBSS_PARA_IE_ID 6
|
||||
#define IBSS_PARA_IE_LEN 2
|
||||
|
||||
adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
|
||||
adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
|
||||
adhs->ssparamset.ibssparamset.atimwindow = 0;
|
||||
|
||||
/* set capability info */
|
||||
tmpcap = WLAN_CAPABILITY_IBSS;
|
||||
if (assoc_req->secinfo.wep_enabled) {
|
||||
lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n");
|
||||
tmpcap |= WLAN_CAPABILITY_PRIVACY;
|
||||
} else {
|
||||
lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n");
|
||||
}
|
||||
adhs->capability = cpu_to_le16(tmpcap);
|
||||
|
||||
/* probedelay */
|
||||
adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
|
||||
|
||||
memset(adhs->rates, 0, sizeof(adhs->rates));
|
||||
ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates));
|
||||
memcpy(adhs->rates, lbs_bg_rates, ratesize);
|
||||
|
||||
/* Copy the ad-hoc creating rates into Current BSS state structure */
|
||||
memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
|
||||
memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize);
|
||||
|
||||
/* Set MSB on basic rates as the firmware requires, but _after_
|
||||
* copying to current bss rates.
|
||||
*/
|
||||
lbs_set_basic_rate_flags(adhs->rates, ratesize);
|
||||
|
||||
lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
|
||||
adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]);
|
||||
|
||||
lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
|
||||
|
||||
if (lbs_create_dnld_countryinfo_11d(priv)) {
|
||||
lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) +
|
||||
S_DS_GEN + cmdappendsize);
|
||||
|
||||
ret = 0;
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd)
|
||||
{
|
||||
cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP);
|
||||
cmd->size = cpu_to_le16(S_DS_GEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd, void *pdata_buf)
|
||||
{
|
||||
struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj;
|
||||
struct assoc_request * assoc_req = pdata_buf;
|
||||
struct bss_descriptor *bss = &assoc_req->bss;
|
||||
int cmdappendsize = 0;
|
||||
int ret = 0;
|
||||
u16 ratesize = 0;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
lbs_deb_enter(LBS_DEB_JOIN);
|
||||
|
||||
cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN);
|
||||
|
||||
join_cmd->bss.type = CMD_BSS_TYPE_IBSS;
|
||||
join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
|
||||
|
||||
memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN);
|
||||
memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len);
|
||||
|
||||
memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset,
|
||||
sizeof(union ieeetypes_phyparamset));
|
||||
|
||||
memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset,
|
||||
sizeof(union IEEEtypes_ssparamset));
|
||||
|
||||
join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
|
||||
lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
|
||||
bss->capability, CAPINFO_MASK);
|
||||
|
||||
/* information on BSSID descriptor passed to FW */
|
||||
lbs_deb_join(
|
||||
"ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
|
||||
print_mac(mac, join_cmd->bss.bssid),
|
||||
join_cmd->bss.ssid);
|
||||
|
||||
/* failtimeout */
|
||||
join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
|
||||
|
||||
/* probedelay */
|
||||
join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
|
||||
|
||||
priv->curbssparams.channel = bss->channel;
|
||||
|
||||
/* Copy Data rates from the rates recorded in scan response */
|
||||
memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates));
|
||||
ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES);
|
||||
memcpy(join_cmd->bss.rates, bss->rates, ratesize);
|
||||
if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) {
|
||||
lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Copy the ad-hoc creating rates into Current BSS state structure */
|
||||
memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
|
||||
memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize);
|
||||
|
||||
/* Set MSB on basic rates as the firmware requires, but _after_
|
||||
* copying to current bss rates.
|
||||
*/
|
||||
lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
|
||||
|
||||
join_cmd->bss.ssparamset.ibssparamset.atimwindow =
|
||||
cpu_to_le16(bss->atimwindow);
|
||||
|
||||
if (assoc_req->secinfo.wep_enabled) {
|
||||
u16 tmp = le16_to_cpu(join_cmd->bss.capability);
|
||||
tmp |= WLAN_CAPABILITY_PRIVACY;
|
||||
join_cmd->bss.capability = cpu_to_le16(tmp);
|
||||
}
|
||||
|
||||
if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
|
||||
/* wake up first */
|
||||
__le32 Localpsmode;
|
||||
|
||||
Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
|
||||
ret = lbs_prepare_and_send_command(priv,
|
||||
CMD_802_11_PS_MODE,
|
||||
CMD_ACT_SET,
|
||||
0, 0, &Localpsmode);
|
||||
|
||||
if (ret) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) +
|
||||
S_DS_GEN + cmdappendsize);
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lbs_ret_80211_associate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp)
|
||||
{
|
||||
int ret = 0;
|
||||
union iwreq_data wrqu;
|
||||
struct ieeetypes_assocrsp *passocrsp;
|
||||
struct bss_descriptor * bss;
|
||||
u16 status_code;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ASSOC);
|
||||
|
||||
if (!priv->in_progress_assoc_req) {
|
||||
lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
bss = &priv->in_progress_assoc_req->bss;
|
||||
|
||||
passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
|
||||
|
||||
/*
|
||||
* Older FW versions map the IEEE 802.11 Status Code in the association
|
||||
* response to the following values returned in passocrsp->statuscode:
|
||||
*
|
||||
* IEEE Status Code Marvell Status Code
|
||||
* 0 -> 0x0000 ASSOC_RESULT_SUCCESS
|
||||
* 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
||||
* 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
||||
* 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
||||
* 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
||||
* others -> 0x0003 ASSOC_RESULT_REFUSED
|
||||
*
|
||||
* Other response codes:
|
||||
* 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
|
||||
* 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
|
||||
* association response from the AP)
|
||||
*/
|
||||
|
||||
status_code = le16_to_cpu(passocrsp->statuscode);
|
||||
switch (status_code) {
|
||||
case 0x00:
|
||||
break;
|
||||
case 0x01:
|
||||
lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
|
||||
break;
|
||||
case 0x02:
|
||||
lbs_deb_assoc("ASSOC_RESP: internal timer "
|
||||
"expired while waiting for the AP\n");
|
||||
break;
|
||||
case 0x03:
|
||||
lbs_deb_assoc("ASSOC_RESP: association "
|
||||
"refused by AP\n");
|
||||
break;
|
||||
case 0x04:
|
||||
lbs_deb_assoc("ASSOC_RESP: authentication "
|
||||
"refused by AP\n");
|
||||
break;
|
||||
default:
|
||||
lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
|
||||
" unknown\n", status_code);
|
||||
break;
|
||||
}
|
||||
|
||||
if (status_code) {
|
||||
lbs_mac_event_disconnected(priv);
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params,
|
||||
le16_to_cpu(resp->size) - S_DS_GEN);
|
||||
|
||||
/* Send a Media Connected event, according to the Spec */
|
||||
priv->connect_status = LBS_CONNECTED;
|
||||
|
||||
/* Update current SSID and BSSID */
|
||||
memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
|
||||
priv->curbssparams.ssid_len = bss->ssid_len;
|
||||
memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
|
||||
|
||||
lbs_deb_assoc("ASSOC_RESP: currentpacketfilter is 0x%x\n",
|
||||
priv->currentpacketfilter);
|
||||
|
||||
priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
|
||||
priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
|
||||
|
||||
memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
|
||||
memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
|
||||
priv->nextSNRNF = 0;
|
||||
priv->numSNRNF = 0;
|
||||
|
||||
netif_carrier_on(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;
|
||||
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lbs_ret_80211_disassociate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_JOIN);
|
||||
|
||||
lbs_mac_event_disconnected(priv);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_JOIN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp)
|
||||
{
|
||||
int ret = 0;
|
||||
u16 command = le16_to_cpu(resp->command);
|
||||
u16 result = le16_to_cpu(resp->result);
|
||||
struct cmd_ds_802_11_ad_hoc_result *padhocresult;
|
||||
union iwreq_data wrqu;
|
||||
struct bss_descriptor *bss;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
lbs_deb_enter(LBS_DEB_JOIN);
|
||||
|
||||
padhocresult = &resp->params.result;
|
||||
|
||||
lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size));
|
||||
lbs_deb_join("ADHOC_RESP: command = %x\n", command);
|
||||
lbs_deb_join("ADHOC_RESP: result = %x\n", result);
|
||||
|
||||
if (!priv->in_progress_assoc_req) {
|
||||
lbs_deb_join("ADHOC_RESP: no in-progress association request\n");
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
bss = &priv->in_progress_assoc_req->bss;
|
||||
|
||||
/*
|
||||
* Join result code 0 --> SUCCESS
|
||||
*/
|
||||
if (result) {
|
||||
lbs_deb_join("ADHOC_RESP: failed\n");
|
||||
if (priv->connect_status == LBS_CONNECTED) {
|
||||
lbs_mac_event_disconnected(priv);
|
||||
}
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now the join cmd should be successful
|
||||
* If BSSID has changed use SSID to compare instead of BSSID
|
||||
*/
|
||||
lbs_deb_join("ADHOC_RESP: associated to '%s'\n",
|
||||
escape_essid(bss->ssid, bss->ssid_len));
|
||||
|
||||
/* Send a Media Connected event, according to the Spec */
|
||||
priv->connect_status = LBS_CONNECTED;
|
||||
|
||||
if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
|
||||
/* Update the created network descriptor with the new BSSID */
|
||||
memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN);
|
||||
}
|
||||
|
||||
/* Set the BSSID from the joined/started descriptor */
|
||||
memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
|
||||
|
||||
/* Set the new SSID to current SSID */
|
||||
memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
|
||||
priv->curbssparams.ssid_len = bss->ssid_len;
|
||||
|
||||
netif_carrier_on(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);
|
||||
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
|
||||
|
||||
lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
|
||||
lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel);
|
||||
lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
|
||||
print_mac(mac, padhocresult->bssid));
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_JOIN);
|
||||
|
||||
lbs_mac_event_disconnected(priv);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_JOIN);
|
||||
return 0;
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/**
|
||||
* Interface for the wlan infrastructure and adhoc join routines
|
||||
*
|
||||
* Driver interface functions and type declarations for the join module
|
||||
* implemented in join.c. Process all start/join requests for
|
||||
* both adhoc and infrastructure networks
|
||||
*/
|
||||
#ifndef _LBS_JOIN_H
|
||||
#define _LBS_JOIN_H
|
||||
|
||||
#include "defs.h"
|
||||
#include "dev.h"
|
||||
|
||||
struct cmd_ds_command;
|
||||
int lbs_cmd_80211_authenticate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd,
|
||||
void *pdata_buf);
|
||||
int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd,
|
||||
void *pdata_buf);
|
||||
int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd);
|
||||
int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd,
|
||||
void *pdata_buf);
|
||||
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd);
|
||||
int lbs_cmd_80211_associate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *cmd,
|
||||
void *pdata_buf);
|
||||
|
||||
int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp);
|
||||
int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp);
|
||||
int lbs_ret_80211_disassociate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp);
|
||||
int lbs_ret_80211_associate(struct lbs_private *priv,
|
||||
struct cmd_ds_command *resp);
|
||||
|
||||
int lbs_start_adhoc_network(struct lbs_private *priv,
|
||||
struct assoc_request * assoc_req);
|
||||
int lbs_join_adhoc_network(struct lbs_private *priv,
|
||||
struct assoc_request * assoc_req);
|
||||
int lbs_stop_adhoc_network(struct lbs_private *priv);
|
||||
|
||||
int lbs_send_deauthentication(struct lbs_private *priv);
|
||||
|
||||
int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req);
|
||||
|
||||
void lbs_unset_basic_rate_flags(u8 *rates, size_t len);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,57 +0,0 @@
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
|
||||
struct tx_radiotap_hdr {
|
||||
struct ieee80211_radiotap_header hdr;
|
||||
u8 rate;
|
||||
u8 txpower;
|
||||
u8 rts_retries;
|
||||
u8 data_retries;
|
||||
#if 0
|
||||
u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12];
|
||||
#endif
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define TX_RADIOTAP_PRESENT ( \
|
||||
(1 << IEEE80211_RADIOTAP_RATE) | \
|
||||
(1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \
|
||||
(1 << IEEE80211_RADIOTAP_RTS_RETRIES) | \
|
||||
(1 << IEEE80211_RADIOTAP_DATA_RETRIES) | \
|
||||
0)
|
||||
|
||||
#define IEEE80211_FC_VERSION_MASK 0x0003
|
||||
#define IEEE80211_FC_TYPE_MASK 0x000c
|
||||
#define IEEE80211_FC_TYPE_MGT 0x0000
|
||||
#define IEEE80211_FC_TYPE_CTL 0x0004
|
||||
#define IEEE80211_FC_TYPE_DATA 0x0008
|
||||
#define IEEE80211_FC_SUBTYPE_MASK 0x00f0
|
||||
#define IEEE80211_FC_TOFROMDS_MASK 0x0300
|
||||
#define IEEE80211_FC_TODS_MASK 0x0100
|
||||
#define IEEE80211_FC_FROMDS_MASK 0x0200
|
||||
#define IEEE80211_FC_NODS 0x0000
|
||||
#define IEEE80211_FC_TODS 0x0100
|
||||
#define IEEE80211_FC_FROMDS 0x0200
|
||||
#define IEEE80211_FC_DSTODS 0x0300
|
||||
|
||||
struct rx_radiotap_hdr {
|
||||
struct ieee80211_radiotap_header hdr;
|
||||
u8 flags;
|
||||
u8 rate;
|
||||
u16 chan_freq;
|
||||
u16 chan_flags;
|
||||
u8 antenna;
|
||||
u8 antsignal;
|
||||
u16 rx_flags;
|
||||
#if 0
|
||||
u8 pad[IEEE80211_RADIOTAP_HDRLEN - 18];
|
||||
#endif
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define RX_RADIOTAP_PRESENT ( \
|
||||
(1 << IEEE80211_RADIOTAP_FLAGS) | \
|
||||
(1 << IEEE80211_RADIOTAP_RATE) | \
|
||||
(1 << IEEE80211_RADIOTAP_CHANNEL) | \
|
||||
(1 << IEEE80211_RADIOTAP_ANTENNA) | \
|
||||
(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\
|
||||
(1 << IEEE80211_RADIOTAP_RX_FLAGS) | \
|
||||
0)
|
||||
|
@ -1,403 +0,0 @@
|
||||
/**
|
||||
* This file contains the handling of RX in wlan driver.
|
||||
*/
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "hostcmd.h"
|
||||
#include "radiotap.h"
|
||||
#include "decl.h"
|
||||
#include "dev.h"
|
||||
#include "wext.h"
|
||||
|
||||
struct eth803hdr {
|
||||
u8 dest_addr[6];
|
||||
u8 src_addr[6];
|
||||
u16 h803_len;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rfc1042hdr {
|
||||
u8 llc_dsap;
|
||||
u8 llc_ssap;
|
||||
u8 llc_ctrl;
|
||||
u8 snap_oui[3];
|
||||
u16 snap_type;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rxpackethdr {
|
||||
struct rxpd rx_pd;
|
||||
struct eth803hdr eth803_hdr;
|
||||
struct rfc1042hdr rfc1042_hdr;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rx80211packethdr {
|
||||
struct rxpd rx_pd;
|
||||
void *eth80211_hdr;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static int process_rxed_802_11_packet(struct lbs_private *priv,
|
||||
struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* @brief This function computes the avgSNR .
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @return avgSNR
|
||||
*/
|
||||
static u8 lbs_getavgsnr(struct lbs_private *priv)
|
||||
{
|
||||
u8 i;
|
||||
u16 temp = 0;
|
||||
if (priv->numSNRNF == 0)
|
||||
return 0;
|
||||
for (i = 0; i < priv->numSNRNF; i++)
|
||||
temp += priv->rawSNR[i];
|
||||
return (u8) (temp / priv->numSNRNF);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function computes the AvgNF
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @return AvgNF
|
||||
*/
|
||||
static u8 lbs_getavgnf(struct lbs_private *priv)
|
||||
{
|
||||
u8 i;
|
||||
u16 temp = 0;
|
||||
if (priv->numSNRNF == 0)
|
||||
return 0;
|
||||
for (i = 0; i < priv->numSNRNF; i++)
|
||||
temp += priv->rawNF[i];
|
||||
return (u8) (temp / priv->numSNRNF);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function save the raw SNR/NF to our internel buffer
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @param prxpd A pointer to rxpd structure of received packet
|
||||
* @return n/a
|
||||
*/
|
||||
static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd)
|
||||
{
|
||||
if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
|
||||
priv->numSNRNF++;
|
||||
priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr;
|
||||
priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf;
|
||||
priv->nextSNRNF++;
|
||||
if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
|
||||
priv->nextSNRNF = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function computes the RSSI in received packet.
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @param prxpd A pointer to rxpd structure of received packet
|
||||
* @return n/a
|
||||
*/
|
||||
static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd)
|
||||
{
|
||||
|
||||
lbs_deb_enter(LBS_DEB_RX);
|
||||
|
||||
lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf);
|
||||
lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n",
|
||||
priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
|
||||
priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
|
||||
|
||||
priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
|
||||
priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
|
||||
lbs_save_rawSNRNF(priv, p_rx_pd);
|
||||
|
||||
priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE;
|
||||
priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE;
|
||||
lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",
|
||||
priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
|
||||
priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
|
||||
|
||||
priv->RSSI[TYPE_RXPD][TYPE_NOAVG] =
|
||||
CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG],
|
||||
priv->NF[TYPE_RXPD][TYPE_NOAVG]);
|
||||
|
||||
priv->RSSI[TYPE_RXPD][TYPE_AVG] =
|
||||
CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
|
||||
priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_RX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function processes received packet and forwards it
|
||||
* to kernel/upper layer
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private
|
||||
* @param skb A pointer to skb which includes the received packet
|
||||
* @return 0 or -1
|
||||
*/
|
||||
int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
|
||||
{
|
||||
int ret = 0;
|
||||
struct net_device *dev = priv->dev;
|
||||
struct rxpackethdr *p_rx_pkt;
|
||||
struct rxpd *p_rx_pd;
|
||||
int hdrchop;
|
||||
struct ethhdr *p_ethhdr;
|
||||
const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
|
||||
|
||||
lbs_deb_enter(LBS_DEB_RX);
|
||||
|
||||
BUG_ON(!skb);
|
||||
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
|
||||
if (priv->monitormode)
|
||||
return process_rxed_802_11_packet(priv, skb);
|
||||
|
||||
p_rx_pkt = (struct rxpackethdr *) skb->data;
|
||||
p_rx_pd = &p_rx_pkt->rx_pd;
|
||||
if (priv->mesh_dev && (p_rx_pd->rx_control & RxPD_MESH_FRAME))
|
||||
dev = priv->mesh_dev;
|
||||
|
||||
lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
|
||||
min_t(unsigned int, skb->len, 100));
|
||||
|
||||
if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
|
||||
lbs_deb_rx("rx err: frame received with bad length\n");
|
||||
priv->stats.rx_length_errors++;
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check rxpd status and update 802.3 stat,
|
||||
*/
|
||||
if (!(p_rx_pd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) {
|
||||
lbs_deb_rx("rx err: frame received with bad status\n");
|
||||
lbs_pr_alert("rxpd not ok\n");
|
||||
priv->stats.rx_errors++;
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
|
||||
skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
|
||||
|
||||
lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
|
||||
sizeof(p_rx_pkt->eth803_hdr.dest_addr));
|
||||
lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
|
||||
sizeof(p_rx_pkt->eth803_hdr.src_addr));
|
||||
|
||||
if (memcmp(&p_rx_pkt->rfc1042_hdr,
|
||||
rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
|
||||
/*
|
||||
* Replace the 803 header and rfc1042 header (llc/snap) with an
|
||||
* EthernetII header, keep the src/dst and snap_type (ethertype)
|
||||
*
|
||||
* The firmware only passes up SNAP frames converting
|
||||
* all RX Data from 802.11 to 802.2/LLC/SNAP frames.
|
||||
*
|
||||
* To create the Ethernet II, just move the src, dst address right
|
||||
* before the snap_type.
|
||||
*/
|
||||
p_ethhdr = (struct ethhdr *)
|
||||
((u8 *) & p_rx_pkt->eth803_hdr
|
||||
+ sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr)
|
||||
- sizeof(p_rx_pkt->eth803_hdr.dest_addr)
|
||||
- sizeof(p_rx_pkt->eth803_hdr.src_addr)
|
||||
- sizeof(p_rx_pkt->rfc1042_hdr.snap_type));
|
||||
|
||||
memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr,
|
||||
sizeof(p_ethhdr->h_source));
|
||||
memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr,
|
||||
sizeof(p_ethhdr->h_dest));
|
||||
|
||||
/* Chop off the rxpd + the excess memory from the 802.2/llc/snap header
|
||||
* that was removed
|
||||
*/
|
||||
hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
|
||||
} else {
|
||||
lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP",
|
||||
(u8 *) & p_rx_pkt->rfc1042_hdr,
|
||||
sizeof(p_rx_pkt->rfc1042_hdr));
|
||||
|
||||
/* Chop off the rxpd */
|
||||
hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt;
|
||||
}
|
||||
|
||||
/* Chop off the leading header bytes so the skb points to the start of
|
||||
* either the reconstructed EthII frame or the 802.2/llc/snap frame
|
||||
*/
|
||||
skb_pull(skb, hdrchop);
|
||||
|
||||
/* Take the data rate from the rxpd structure
|
||||
* only if the rate is auto
|
||||
*/
|
||||
if (priv->auto_rate)
|
||||
priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
|
||||
|
||||
lbs_compute_rssi(priv, p_rx_pd);
|
||||
|
||||
lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
|
||||
priv->stats.rx_bytes += skb->len;
|
||||
priv->stats.rx_packets++;
|
||||
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
if (in_interrupt())
|
||||
netif_rx(skb);
|
||||
else
|
||||
netif_rx_ni(skb);
|
||||
|
||||
ret = 0;
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_process_rxed_packet);
|
||||
|
||||
/**
|
||||
* @brief This function converts Tx/Rx rates from the Marvell WLAN format
|
||||
* (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
|
||||
*
|
||||
* @param rate Input rate
|
||||
* @return Output Rate (0 if invalid)
|
||||
*/
|
||||
static u8 convert_mv_rate_to_radiotap(u8 rate)
|
||||
{
|
||||
switch (rate) {
|
||||
case 0: /* 1 Mbps */
|
||||
return 2;
|
||||
case 1: /* 2 Mbps */
|
||||
return 4;
|
||||
case 2: /* 5.5 Mbps */
|
||||
return 11;
|
||||
case 3: /* 11 Mbps */
|
||||
return 22;
|
||||
/* case 4: reserved */
|
||||
case 5: /* 6 Mbps */
|
||||
return 12;
|
||||
case 6: /* 9 Mbps */
|
||||
return 18;
|
||||
case 7: /* 12 Mbps */
|
||||
return 24;
|
||||
case 8: /* 18 Mbps */
|
||||
return 36;
|
||||
case 9: /* 24 Mbps */
|
||||
return 48;
|
||||
case 10: /* 36 Mbps */
|
||||
return 72;
|
||||
case 11: /* 48 Mbps */
|
||||
return 96;
|
||||
case 12: /* 54 Mbps */
|
||||
return 108;
|
||||
}
|
||||
lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function processes a received 802.11 packet and forwards it
|
||||
* to kernel/upper layer
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private
|
||||
* @param skb A pointer to skb which includes the received packet
|
||||
* @return 0 or -1
|
||||
*/
|
||||
static int process_rxed_802_11_packet(struct lbs_private *priv,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct rx80211packethdr *p_rx_pkt;
|
||||
struct rxpd *prxpd;
|
||||
struct rx_radiotap_hdr radiotap_hdr;
|
||||
struct rx_radiotap_hdr *pradiotap_hdr;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_RX);
|
||||
|
||||
p_rx_pkt = (struct rx80211packethdr *) skb->data;
|
||||
prxpd = &p_rx_pkt->rx_pd;
|
||||
|
||||
// lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
|
||||
|
||||
if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
|
||||
lbs_deb_rx("rx err: frame received with bad length\n");
|
||||
priv->stats.rx_length_errors++;
|
||||
ret = -EINVAL;
|
||||
kfree(skb);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check rxpd status and update 802.3 stat,
|
||||
*/
|
||||
if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) {
|
||||
//lbs_deb_rx("rx err: frame received with bad status\n");
|
||||
priv->stats.rx_errors++;
|
||||
}
|
||||
|
||||
lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
|
||||
skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
|
||||
|
||||
/* create the exported radio header */
|
||||
|
||||
/* radiotap header */
|
||||
radiotap_hdr.hdr.it_version = 0;
|
||||
/* XXX must check this value for pad */
|
||||
radiotap_hdr.hdr.it_pad = 0;
|
||||
radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
|
||||
radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
|
||||
/* unknown values */
|
||||
radiotap_hdr.flags = 0;
|
||||
radiotap_hdr.chan_freq = 0;
|
||||
radiotap_hdr.chan_flags = 0;
|
||||
radiotap_hdr.antenna = 0;
|
||||
/* known values */
|
||||
radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
|
||||
/* XXX must check no carryout */
|
||||
radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
|
||||
radiotap_hdr.rx_flags = 0;
|
||||
if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK)))
|
||||
radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
|
||||
//memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
|
||||
|
||||
/* chop the rxpd */
|
||||
skb_pull(skb, sizeof(struct rxpd));
|
||||
|
||||
/* add space for the new radio header */
|
||||
if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
|
||||
pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) {
|
||||
lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
kfree_skb(skb);
|
||||
goto done;
|
||||
}
|
||||
|
||||
pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr));
|
||||
memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr));
|
||||
|
||||
/* Take the data rate from the rxpd structure
|
||||
* only if the rate is auto
|
||||
*/
|
||||
if (priv->auto_rate)
|
||||
priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
|
||||
|
||||
lbs_compute_rssi(priv, prxpd);
|
||||
|
||||
lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
|
||||
priv->stats.rx_bytes += skb->len;
|
||||
priv->stats.rx_packets++;
|
||||
|
||||
skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
|
||||
netif_rx(skb);
|
||||
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Interface for the wlan network scan routines
|
||||
*
|
||||
* Driver interface functions and type declarations for the scan module
|
||||
* implemented in scan.c.
|
||||
*/
|
||||
#ifndef _LBS_SCAN_H
|
||||
#define _LBS_SCAN_H
|
||||
|
||||
/**
|
||||
* @brief Maximum number of channels that can be sent in a setuserscan ioctl
|
||||
*/
|
||||
#define LBS_IOCTL_USER_SCAN_CHAN_MAX 50
|
||||
|
||||
int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
|
||||
|
||||
int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
|
||||
u8 ssid_len);
|
||||
|
||||
int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
|
||||
struct iw_point *dwrq, char *extra);
|
||||
int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
|
||||
union iwreq_data *wrqu, char *extra);
|
||||
|
||||
int lbs_scan_networks(struct lbs_private *priv, int full_scan);
|
||||
|
||||
void lbs_scan_worker(struct work_struct *work);
|
||||
|
||||
#endif
|
@ -1,206 +0,0 @@
|
||||
/**
|
||||
* This file contains the handling of TX in wlan driver.
|
||||
*/
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "hostcmd.h"
|
||||
#include "radiotap.h"
|
||||
#include "decl.h"
|
||||
#include "defs.h"
|
||||
#include "dev.h"
|
||||
#include "wext.h"
|
||||
|
||||
/**
|
||||
* @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
|
||||
* units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
|
||||
*
|
||||
* @param rate Input rate
|
||||
* @return Output Rate (0 if invalid)
|
||||
*/
|
||||
static u32 convert_radiotap_rate_to_mv(u8 rate)
|
||||
{
|
||||
switch (rate) {
|
||||
case 2: /* 1 Mbps */
|
||||
return 0 | (1 << 4);
|
||||
case 4: /* 2 Mbps */
|
||||
return 1 | (1 << 4);
|
||||
case 11: /* 5.5 Mbps */
|
||||
return 2 | (1 << 4);
|
||||
case 22: /* 11 Mbps */
|
||||
return 3 | (1 << 4);
|
||||
case 12: /* 6 Mbps */
|
||||
return 4 | (1 << 4);
|
||||
case 18: /* 9 Mbps */
|
||||
return 5 | (1 << 4);
|
||||
case 24: /* 12 Mbps */
|
||||
return 6 | (1 << 4);
|
||||
case 36: /* 18 Mbps */
|
||||
return 7 | (1 << 4);
|
||||
case 48: /* 24 Mbps */
|
||||
return 8 | (1 << 4);
|
||||
case 72: /* 36 Mbps */
|
||||
return 9 | (1 << 4);
|
||||
case 96: /* 48 Mbps */
|
||||
return 10 | (1 << 4);
|
||||
case 108: /* 54 Mbps */
|
||||
return 11 | (1 << 4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function checks the conditions and sends packet to IF
|
||||
* layer if everything is ok.
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @param skb A pointer to skb which includes TX packet
|
||||
* @return 0 or -1
|
||||
*/
|
||||
int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct lbs_private *priv = dev->priv;
|
||||
struct txpd *txpd;
|
||||
char *p802x_hdr;
|
||||
uint16_t pkt_len;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_TX);
|
||||
|
||||
ret = NETDEV_TX_OK;
|
||||
|
||||
/* We need to protect against the queues being restarted before
|
||||
we get round to stopping them */
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
|
||||
if (priv->surpriseremoved)
|
||||
goto free;
|
||||
|
||||
if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
|
||||
lbs_deb_tx("tx err: skb length %d 0 or > %zd\n",
|
||||
skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
|
||||
/* We'll never manage to send this one; drop it and return 'OK' */
|
||||
|
||||
priv->stats.tx_dropped++;
|
||||
priv->stats.tx_errors++;
|
||||
goto free;
|
||||
}
|
||||
|
||||
|
||||
netif_stop_queue(priv->dev);
|
||||
if (priv->mesh_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
|
||||
hard_start_xmit() calls between devices. */
|
||||
lbs_deb_tx("Packet on %s while busy\n", dev->name);
|
||||
ret = NETDEV_TX_BUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
priv->tx_pending_len = -1;
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
|
||||
|
||||
txpd = (void *)priv->tx_pending_buf;
|
||||
memset(txpd, 0, sizeof(struct txpd));
|
||||
|
||||
p802x_hdr = skb->data;
|
||||
pkt_len = skb->len;
|
||||
|
||||
if (dev == priv->rtap_net_dev) {
|
||||
struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
|
||||
|
||||
/* set txpd fields from the radiotap header */
|
||||
txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate));
|
||||
|
||||
/* skip the radiotap header */
|
||||
p802x_hdr += sizeof(*rtap_hdr);
|
||||
pkt_len -= sizeof(*rtap_hdr);
|
||||
|
||||
/* copy destination address from 802.11 header */
|
||||
memcpy(txpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
|
||||
} else {
|
||||
/* copy destination address from 802.3 header */
|
||||
memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
|
||||
}
|
||||
|
||||
txpd->tx_packet_length = cpu_to_le16(pkt_len);
|
||||
txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
|
||||
|
||||
if (dev == priv->mesh_dev)
|
||||
txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
|
||||
|
||||
lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd));
|
||||
|
||||
lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(txpd->tx_packet_length));
|
||||
|
||||
memcpy(&txpd[1], p802x_hdr, le16_to_cpu(txpd->tx_packet_length));
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
priv->tx_pending_len = pkt_len + sizeof(struct txpd);
|
||||
|
||||
lbs_deb_tx("%s lined up packet\n", __func__);
|
||||
|
||||
priv->stats.tx_packets++;
|
||||
priv->stats.tx_bytes += skb->len;
|
||||
|
||||
dev->trans_start = jiffies;
|
||||
|
||||
if (priv->monitormode) {
|
||||
/* Keep the skb to echo it back once Tx feedback is
|
||||
received from FW */
|
||||
skb_orphan(skb);
|
||||
|
||||
/* Keep the skb around for when we get feedback */
|
||||
priv->currenttxskb = skb;
|
||||
} else {
|
||||
free:
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
wake_up(&priv->waitq);
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function sends to the host the last transmitted packet,
|
||||
* filling the radiotap headers with transmission information.
|
||||
*
|
||||
* @param priv A pointer to struct lbs_private structure
|
||||
* @param status A 32 bit value containing transmission status.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
|
||||
{
|
||||
struct tx_radiotap_hdr *radiotap_hdr;
|
||||
|
||||
if (!priv->monitormode || priv->currenttxskb == NULL)
|
||||
return;
|
||||
|
||||
radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
|
||||
|
||||
radiotap_hdr->data_retries = try_count ?
|
||||
(1 + priv->txretrycount - try_count) : 0;
|
||||
|
||||
priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
|
||||
priv->rtap_net_dev);
|
||||
netif_rx(priv->currenttxskb);
|
||||
|
||||
priv->currenttxskb = NULL;
|
||||
|
||||
if (priv->connect_status == LBS_CONNECTED)
|
||||
netif_wake_queue(priv->dev);
|
||||
|
||||
if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED))
|
||||
netif_wake_queue(priv->mesh_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);
|
@ -1,255 +0,0 @@
|
||||
/**
|
||||
* This header file contains definition for global types
|
||||
*/
|
||||
#ifndef _LBS_TYPES_H_
|
||||
#define _LBS_TYPES_H_
|
||||
|
||||
#include <linux/if_ether.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
struct ieeetypes_cfparamset {
|
||||
u8 elementid;
|
||||
u8 len;
|
||||
u8 cfpcnt;
|
||||
u8 cfpperiod;
|
||||
__le16 cfpmaxduration;
|
||||
__le16 cfpdurationremaining;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
struct ieeetypes_ibssparamset {
|
||||
u8 elementid;
|
||||
u8 len;
|
||||
__le16 atimwindow;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union IEEEtypes_ssparamset {
|
||||
struct ieeetypes_cfparamset cfparamset;
|
||||
struct ieeetypes_ibssparamset ibssparamset;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieeetypes_fhparamset {
|
||||
u8 elementid;
|
||||
u8 len;
|
||||
__le16 dwelltime;
|
||||
u8 hopset;
|
||||
u8 hoppattern;
|
||||
u8 hopindex;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieeetypes_dsparamset {
|
||||
u8 elementid;
|
||||
u8 len;
|
||||
u8 currentchan;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union ieeetypes_phyparamset {
|
||||
struct ieeetypes_fhparamset fhparamset;
|
||||
struct ieeetypes_dsparamset dsparamset;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieeetypes_assocrsp {
|
||||
__le16 capability;
|
||||
__le16 statuscode;
|
||||
__le16 aid;
|
||||
u8 iebuffer[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/** TLV type ID definition */
|
||||
#define PROPRIETARY_TLV_BASE_ID 0x0100
|
||||
|
||||
/* Terminating TLV type */
|
||||
#define MRVL_TERMINATE_TLV_ID 0xffff
|
||||
|
||||
#define TLV_TYPE_SSID 0x0000
|
||||
#define TLV_TYPE_RATES 0x0001
|
||||
#define TLV_TYPE_PHY_FH 0x0002
|
||||
#define TLV_TYPE_PHY_DS 0x0003
|
||||
#define TLV_TYPE_CF 0x0004
|
||||
#define TLV_TYPE_IBSS 0x0006
|
||||
|
||||
#define TLV_TYPE_DOMAIN 0x0007
|
||||
|
||||
#define TLV_TYPE_POWER_CAPABILITY 0x0021
|
||||
|
||||
#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
|
||||
#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
|
||||
#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2)
|
||||
#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4)
|
||||
#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5)
|
||||
#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6)
|
||||
#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7)
|
||||
#define TLV_TYPE_LED_GPIO (PROPRIETARY_TLV_BASE_ID + 8)
|
||||
#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9)
|
||||
#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10)
|
||||
#define TLV_TYPE_REASSOCAP (PROPRIETARY_TLV_BASE_ID + 11)
|
||||
#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12)
|
||||
#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13)
|
||||
#define TLV_TYPE_BCASTPROBE (PROPRIETARY_TLV_BASE_ID + 14)
|
||||
#define TLV_TYPE_NUMSSID_PROBE (PROPRIETARY_TLV_BASE_ID + 15)
|
||||
#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16)
|
||||
#define TLV_TYPE_CRYPTO_DATA (PROPRIETARY_TLV_BASE_ID + 17)
|
||||
#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18)
|
||||
#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
|
||||
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
|
||||
#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
|
||||
|
||||
/** TLV related data structures*/
|
||||
struct mrvlietypesheader {
|
||||
__le16 type;
|
||||
__le16 len;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_data {
|
||||
struct mrvlietypesheader header;
|
||||
u8 Data[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_ratesparamset {
|
||||
struct mrvlietypesheader header;
|
||||
u8 rates[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_ssidparamset {
|
||||
struct mrvlietypesheader header;
|
||||
u8 ssid[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_wildcardssidparamset {
|
||||
struct mrvlietypesheader header;
|
||||
u8 MaxSsidlength;
|
||||
u8 ssid[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct chanscanmode {
|
||||
#ifdef __BIG_ENDIAN_BITFIELD
|
||||
u8 reserved_2_7:6;
|
||||
u8 disablechanfilt:1;
|
||||
u8 passivescan:1;
|
||||
#else
|
||||
u8 passivescan:1;
|
||||
u8 disablechanfilt:1;
|
||||
u8 reserved_2_7:6;
|
||||
#endif
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct chanscanparamset {
|
||||
u8 radiotype;
|
||||
u8 channumber;
|
||||
struct chanscanmode chanscanmode;
|
||||
__le16 minscantime;
|
||||
__le16 maxscantime;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_chanlistparamset {
|
||||
struct mrvlietypesheader header;
|
||||
struct chanscanparamset chanscanparam[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct cfparamset {
|
||||
u8 cfpcnt;
|
||||
u8 cfpperiod;
|
||||
__le16 cfpmaxduration;
|
||||
__le16 cfpdurationremaining;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ibssparamset {
|
||||
__le16 atimwindow;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_ssparamset {
|
||||
struct mrvlietypesheader header;
|
||||
union {
|
||||
struct cfparamset cfparamset[1];
|
||||
struct ibssparamset ibssparamset[1];
|
||||
} cf_ibss;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct fhparamset {
|
||||
__le16 dwelltime;
|
||||
u8 hopset;
|
||||
u8 hoppattern;
|
||||
u8 hopindex;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct dsparamset {
|
||||
u8 currentchan;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_phyparamset {
|
||||
struct mrvlietypesheader header;
|
||||
union {
|
||||
struct fhparamset fhparamset[1];
|
||||
struct dsparamset dsparamset[1];
|
||||
} fh_ds;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_rsnparamset {
|
||||
struct mrvlietypesheader header;
|
||||
u8 rsnie[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_tsftimestamp {
|
||||
struct mrvlietypesheader header;
|
||||
__le64 tsftable[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/** Local Power capability */
|
||||
struct mrvlietypes_powercapability {
|
||||
struct mrvlietypesheader header;
|
||||
s8 minpower;
|
||||
s8 maxpower;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
|
||||
struct mrvlietypes_thresholds {
|
||||
struct mrvlietypesheader header;
|
||||
u8 value;
|
||||
u8 freq;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_beaconsmissed {
|
||||
struct mrvlietypesheader header;
|
||||
u8 beaconmissed;
|
||||
u8 reserved;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_numprobes {
|
||||
struct mrvlietypesheader header;
|
||||
__le16 numprobes;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_bcastprobe {
|
||||
struct mrvlietypesheader header;
|
||||
__le16 bcastprobe;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_numssidprobe {
|
||||
struct mrvlietypesheader header;
|
||||
__le16 numssidprobe;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct led_pin {
|
||||
u8 led;
|
||||
u8 pin;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mrvlietypes_ledgpio {
|
||||
struct mrvlietypesheader header;
|
||||
struct led_pin ledpin[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct led_bhv {
|
||||
uint8_t firmwarestate;
|
||||
uint8_t led;
|
||||
uint8_t ledstate;
|
||||
uint8_t ledarg;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
struct mrvlietypes_ledbhv {
|
||||
struct mrvlietypesheader header;
|
||||
struct led_bhv ledbhv[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +0,0 @@
|
||||
/**
|
||||
* This file contains definition for IOCTL call.
|
||||
*/
|
||||
#ifndef _LBS_WEXT_H_
|
||||
#define _LBS_WEXT_H_
|
||||
|
||||
extern struct iw_handler_def lbs_handler_def;
|
||||
extern struct iw_handler_def mesh_handler_def;
|
||||
|
||||
#endif
|
@ -328,6 +328,28 @@ define KernelPackage/ath9k/config
|
||||
source "$(SOURCE)/Config.in.ath9k"
|
||||
endef
|
||||
|
||||
|
||||
USB8388FW_NAME:=usb8388
|
||||
USB8388FW_VERSION:=5.110.22.p23
|
||||
|
||||
define Download/usb8388
|
||||
URL:=http://dev.laptop.org/pub/firmware/libertas/
|
||||
FILE:=$(USB8388FW_NAME)-$(USB8388FW_VERSION).bin
|
||||
MD5SUM=5e38f55719df3d0c58dd3bd02575a09c
|
||||
endef
|
||||
$(eval $(call Download,usb8388))
|
||||
|
||||
define KernelPackage/libertas
|
||||
$(call KernelPackage/mac80211/Default)
|
||||
DEPENDS:= @USB_SUPPORT +kmod-mac8021 +kmod-usb-core1
|
||||
TITLE:=Marvell 88W8015 Wireless Driver
|
||||
FILES:= \
|
||||
$(PKG_BUILD_DIR)/drivers/net/wireless/libertas/libertas.$(LINUX_KMOD_SUFFIX) \
|
||||
$(PKG_BUILD_DIR)/drivers/net/wireless/libertas/usb8xxx.$(LINUX_KMOD_SUFFIX)
|
||||
AUTOLOAD:=$(call AutoLoad,27,libertas usb8xxx)
|
||||
endef
|
||||
|
||||
|
||||
define KernelPackage/ar9170
|
||||
$(call KernelPackage/mac80211/Default)
|
||||
TITLE:=Atheros AR9170 802.11n USB support
|
||||
@ -516,10 +538,11 @@ MAKE_OPTS:= \
|
||||
CONFIG_MAC80211_HWSIM=$(if $(CONFIG_PACKAGE_kmod-mac80211-hwsim),m) \
|
||||
CONFIG_PCMCIA= \
|
||||
CONFIG_LIBIPW= \
|
||||
CONFIG_LIBERTAS= \
|
||||
CONFIG_LIBERTAS=$(if $(CONFIG_PACKAGE_kmod-libertas),m) \
|
||||
CONFIG_LIBERTAS_CS= \
|
||||
CONFIG_LIBERTAS_SDIO= \
|
||||
CONFIG_LIBERTAS_THINFIRM= \
|
||||
CONFIG_LIBERTAS_USB=$(if $(CONFIG_PACKAGE_kmod-libertas),m) \
|
||||
CONFIG_IPW2100= \
|
||||
CONFIG_IPW2200= \
|
||||
CONFIG_NL80211=y \
|
||||
@ -582,6 +605,11 @@ define Build/InstallDev
|
||||
$(CP) $(PKG_BUILD_DIR)/net/mac80211/rate.h $(1)/usr/include/net/mac80211/
|
||||
endef
|
||||
|
||||
define KernelPackage/libertas/install
|
||||
$(INSTALL_DIR) $(1)/lib/firmware
|
||||
$(INSTALL_DATA) $(DL_DIR)/$(USB8388FW_NAME)-$(USB8388FW_VERSION).bin $(1)/lib/firmware/$(USB8388FW_NAME).bin
|
||||
endef
|
||||
|
||||
define KernelPackage/mac80211/install
|
||||
$(INSTALL_DIR) $(1)/lib/wifi
|
||||
$(INSTALL_DATA) ./files/lib/wifi/mac80211.sh $(1)/lib/wifi
|
||||
@ -672,6 +700,7 @@ define KernelPackage/b43legacy/install
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,ath5k))
|
||||
$(eval $(call KernelPackage,libertas))
|
||||
$(eval $(call KernelPackage,mac80211))
|
||||
$(eval $(call KernelPackage,p54-common))
|
||||
$(eval $(call KernelPackage,p54-pci))
|
||||
|
Loading…
Reference in New Issue
Block a user