aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/libertas
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-08 07:55:01 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-08 07:55:01 -0800
commitd7fc02c7bae7b1cf69269992cf880a43a350cdaa (patch)
treea43d56fa72913a1cc98a0bbebe054d08581b3a7c /drivers/net/wireless/libertas
parentee1262dbc65ce0b6234a915d8432171e8d77f518 (diff)
parent28b4d5cc17c20786848cdc07b7ea237a309776bb (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1815 commits) mac80211: fix reorder buffer release iwmc3200wifi: Enable wimax core through module parameter iwmc3200wifi: Add wifi-wimax coexistence mode as a module parameter iwmc3200wifi: Coex table command does not expect a response iwmc3200wifi: Update wiwi priority table iwlwifi: driver version track kernel version iwlwifi: indicate uCode type when fail dump error/event log iwl3945: remove duplicated event logging code b43: fix two warnings ipw2100: fix rebooting hang with driver loaded cfg80211: indent regulatory messages with spaces iwmc3200wifi: fix NULL pointer dereference in pmkid update mac80211: Fix TX status reporting for injected data frames ath9k: enable 2GHz band only if the device supports it airo: Fix integer overflow warning rt2x00: Fix padding bug on L2PAD devices. WE: Fix set events not propagated b43legacy: avoid PPC fault during resume b43: avoid PPC fault during resume tcp: fix a timewait refcnt race ... Fix up conflicts due to sysctl cleanups (dead sysctl_check code and CTL_UNNUMBERED removed) in kernel/sysctl_check.c net/ipv4/sysctl_net_ipv4.c net/ipv6/addrconf.c net/sctp/sysctl.c
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r--drivers/net/wireless/libertas/11d.c696
-rw-r--r--drivers/net/wireless/libertas/11d.h105
-rw-r--r--drivers/net/wireless/libertas/Kconfig39
-rw-r--r--drivers/net/wireless/libertas/Makefile14
-rw-r--r--drivers/net/wireless/libertas/README26
-rw-r--r--drivers/net/wireless/libertas/assoc.c445
-rw-r--r--drivers/net/wireless/libertas/assoc.h141
-rw-r--r--drivers/net/wireless/libertas/cfg.c198
-rw-r--r--drivers/net/wireless/libertas/cfg.h16
-rw-r--r--drivers/net/wireless/libertas/cmd.c695
-rw-r--r--drivers/net/wireless/libertas/cmd.h127
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c116
-rw-r--r--drivers/net/wireless/libertas/debugfs.c27
-rw-r--r--drivers/net/wireless/libertas/decl.h65
-rw-r--r--drivers/net/wireless/libertas/defs.h3
-rw-r--r--drivers/net/wireless/libertas/dev.h431
-rw-r--r--drivers/net/wireless/libertas/ethtool.c84
-rw-r--r--drivers/net/wireless/libertas/host.h959
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h800
-rw-r--r--drivers/net/wireless/libertas/if_cs.c4
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c62
-rw-r--r--drivers/net/wireless/libertas/if_sdio.h3
-rw-r--r--drivers/net/wireless/libertas/if_spi.c143
-rw-r--r--drivers/net/wireless/libertas/if_usb.c5
-rw-r--r--drivers/net/wireless/libertas/main.c720
-rw-r--r--drivers/net/wireless/libertas/mesh.c1141
-rw-r--r--drivers/net/wireless/libertas/mesh.h78
-rw-r--r--drivers/net/wireless/libertas/persistcfg.c453
-rw-r--r--drivers/net/wireless/libertas/rx.c13
-rw-r--r--drivers/net/wireless/libertas/scan.c250
-rw-r--r--drivers/net/wireless/libertas/scan.h30
-rw-r--r--drivers/net/wireless/libertas/tx.c9
-rw-r--r--drivers/net/wireless/libertas/types.h4
-rw-r--r--drivers/net/wireless/libertas/wext.c196
-rw-r--r--drivers/net/wireless/libertas/wext.h9
35 files changed, 3858 insertions, 4249 deletions
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
deleted file mode 100644
index 5c6968101f0..00000000000
--- a/drivers/net/wireless/libertas/11d.c
+++ /dev/null
@@ -1,696 +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; i < COUNTRY_CODE_LEN && region[i]; 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 ieee_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 ieee_ie_country_info_full_set *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->header.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->header.len - COUNTRY_CODE_LEN) /
- sizeof(struct ieee_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 mrvl_ie_domain_param_set *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 ieee_subbandset) +
- sizeof(domain->countrycode));
-
- if (nr_subband) {
- memcpy(domain->subband, priv->domainreg.subband,
- nr_subband * sizeof(struct ieee_subbandset));
-
- cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
- le16_to_cpu(domain->header.len) +
- sizeof(struct mrvl_ie_header) +
- 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 mrvl_ie_domain_param_set *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 ieee_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;
-}
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
deleted file mode 100644
index fb75d3e321a..00000000000
--- a/drivers/net/wireless/libertas/11d.h
+++ /dev/null
@@ -1,105 +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 ieee_subbandset {
- u8 firstchan;
- u8 nrchan;
- u8 maxtxpwr;
-} __attribute__ ((packed));
-
-struct ieee_ie_country_info_set {
- struct ieee_ie_header header;
-
- u8 countrycode[COUNTRY_CODE_LEN];
- struct ieee_subbandset subband[1];
-};
-
-struct ieee_ie_country_info_full_set {
- struct ieee_ie_header header;
-
- u8 countrycode[COUNTRY_CODE_LEN];
- struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
-} __attribute__ ((packed));
-
-struct mrvl_ie_domain_param_set {
- struct mrvl_ie_header header;
-
- u8 countrycode[COUNTRY_CODE_LEN];
- struct ieee_subbandset subband[1];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11d_domain_info {
- __le16 action;
- struct mrvl_ie_domain_param_set 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 ieee_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
diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig
new file mode 100644
index 00000000000..30aa9d48d67
--- /dev/null
+++ b/drivers/net/wireless/libertas/Kconfig
@@ -0,0 +1,39 @@
+config LIBERTAS
+ tristate "Marvell 8xxx Libertas WLAN driver support"
+ depends on CFG80211
+ select WIRELESS_EXT
+ select WEXT_SPY
+ select LIB80211
+ select FW_LOADER
+ ---help---
+ A library for Marvell Libertas 8xxx devices.
+
+config LIBERTAS_USB
+ tristate "Marvell Libertas 8388 USB 802.11b/g cards"
+ depends on LIBERTAS && USB
+ ---help---
+ A driver for Marvell Libertas 8388 USB devices.
+
+config LIBERTAS_CS
+ tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards"
+ depends on LIBERTAS && PCMCIA
+ ---help---
+ A driver for Marvell Libertas 8385 CompactFlash devices.
+
+config LIBERTAS_SDIO
+ tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards"
+ depends on LIBERTAS && MMC
+ ---help---
+ A driver for Marvell Libertas 8385/8686/8688 SDIO devices.
+
+config LIBERTAS_SPI
+ tristate "Marvell Libertas 8686 SPI 802.11b/g cards"
+ depends on LIBERTAS && SPI
+ ---help---
+ A driver for Marvell Libertas 8686 SPI devices.
+
+config LIBERTAS_DEBUG
+ bool "Enable full debugging output in the Libertas module."
+ depends on LIBERTAS
+ ---help---
+ Debugging support.
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index 0b691858450..b188cd97a05 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -1,5 +1,15 @@
-libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \
- debugfs.o persistcfg.o ethtool.o assoc.o
+libertas-y += assoc.o
+libertas-y += cfg.o
+libertas-y += cmd.o
+libertas-y += cmdresp.o
+libertas-y += debugfs.o
+libertas-y += ethtool.o
+libertas-y += main.o
+libertas-y += mesh.o
+libertas-y += rx.o
+libertas-y += scan.o
+libertas-y += tx.o
+libertas-y += wext.o
usb8xxx-objs += if_usb.o
libertas_cs-objs += if_cs.o
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index ab6a2d518af..2726c044430 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -1,5 +1,5 @@
================================================================================
- README for USB8388
+ README for Libertas
(c) Copyright © 2003-2006, Marvell International Ltd.
All Rights Reserved
@@ -226,4 +226,28 @@ 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.
+========================
+IWCONFIG COMMANDS
+========================
+power period
+
+ This command is used to configure the station in deep sleep mode /
+ auto deep sleep mode.
+
+ The timer is implemented to monitor the activities (command, event,
+ etc.). When an activity is detected station will exit from deep
+ sleep mode automatically and restart the timer. At timer expiry
+ (no activity for defined time period) the deep sleep mode is entered
+ automatically.
+
+ Note: this command is for SDIO interface only.
+
+ Usage:
+ To enable deep sleep mode do:
+ iwconfig wlan0 power period 0
+ To enable auto deep sleep mode with idle time period 5 seconds do:
+ iwconfig wlan0 power period 5
+ To disable deep sleep/auto deep sleep mode do:
+ iwconfig wlan0 power period -1
+
==============================================================================
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index dd8732611ba..751067369ba 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -23,6 +23,13 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
*/
#define CAPINFO_MASK (~(0xda00))
+/**
+ * 802.11b/g supported bitrates (in 500Kb/s units)
+ */
+u8 lbs_bg_rates[MAX_RATES] =
+ { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0x00, 0x00 };
+
/**
* @brief This function finds common rates between rates and card rates.
@@ -147,6 +154,397 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
}
+int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
+ struct assoc_request *assoc)
+{
+ struct cmd_ds_802_11_set_wep cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ cmd.action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == CMD_ACT_ADD) {
+ int i;
+
+ /* default tx key index */
+ cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
+ CMD_WEP_KEY_INDEX_MASK);
+
+ /* Copy key types and material to host command structure */
+ for (i = 0; i < 4; i++) {
+ struct enc_key *pkey = &assoc->wep_keys[i];
+
+ switch (pkey->len) {
+ case KEY_LEN_WEP_40:
+ cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
+ memmove(cmd.keymaterial[i], pkey->key, pkey->len);
+ lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
+ break;
+ case KEY_LEN_WEP_104:
+ cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
+ memmove(cmd.keymaterial[i], pkey->key, pkey->len);
+ lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
+ break;
+ case 0:
+ break;
+ default:
+ lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
+ i, pkey->len);
+ ret = -1;
+ goto done;
+ break;
+ }
+ }
+ } else if (cmd_action == CMD_ACT_REMOVE) {
+ /* ACT_REMOVE clears _all_ WEP keys */
+
+ /* default tx key index */
+ cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
+ CMD_WEP_KEY_INDEX_MASK);
+ lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
+ }
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
+done:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
+ uint16_t *enable)
+{
+ struct cmd_ds_802_11_enable_rsn cmd;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == CMD_ACT_GET)
+ cmd.enable = 0;
+ else {
+ if (*enable)
+ cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
+ else
+ cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
+ lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
+ }
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
+ if (!ret && cmd_action == CMD_ACT_GET)
+ *enable = le16_to_cpu(cmd.enable);
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
+ struct enc_key *key)
+{
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (key->flags & KEY_INFO_WPA_ENABLED)
+ keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
+ if (key->flags & KEY_INFO_WPA_UNICAST)
+ keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
+ if (key->flags & KEY_INFO_WPA_MCAST)
+ keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
+
+ keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ keyparam->keytypeid = cpu_to_le16(key->type);
+ keyparam->keylen = cpu_to_le16(key->len);
+ memcpy(keyparam->key, key->key, key->len);
+
+ /* Length field doesn't include the {type,length} header */
+ keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
+ lbs_deb_leave(LBS_DEB_CMD);
+}
+
+int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
+ struct assoc_request *assoc)
+{
+ struct cmd_ds_802_11_key_material cmd;
+ int ret = 0;
+ int index = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd.action = cpu_to_le16(cmd_action);
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ if (cmd_action == CMD_ACT_GET) {
+ cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_header) + 2);
+ } else {
+ memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
+
+ if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
+ set_one_wpa_key(&cmd.keyParamSet[index],
+ &assoc->wpa_unicast_key);
+ index++;
+ }
+
+ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
+ set_one_wpa_key(&cmd.keyParamSet[index],
+ &assoc->wpa_mcast_key);
+ index++;
+ }
+
+ /* The common header and as many keys as we included */
+ cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
+ keyParamSet[index]));
+ }
+ ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
+ /* Copy the returned key to driver private data */
+ if (!ret && cmd_action == CMD_ACT_GET) {
+ void *buf_ptr = cmd.keyParamSet;
+ void *resp_end = &(&cmd)[1];
+
+ while (buf_ptr < resp_end) {
+ struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
+ struct enc_key *key;
+ uint16_t param_set_len = le16_to_cpu(keyparam->length);
+ uint16_t key_len = le16_to_cpu(keyparam->keylen);
+ uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
+ uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
+ void *end;
+
+ end = (void *)keyparam + sizeof(keyparam->type)
+ + sizeof(keyparam->length) + param_set_len;
+
+ /* Make sure we don't access past the end of the IEs */
+ if (end > resp_end)
+ break;
+
+ if (key_flags & KEY_INFO_WPA_UNICAST)
+ key = &priv->wpa_unicast_key;
+ else if (key_flags & KEY_INFO_WPA_MCAST)
+ key = &priv->wpa_mcast_key;
+ else
+ break;
+
+ /* Copy returned key into driver */
+ memset(key, 0, sizeof(struct enc_key));
+ if (key_len > sizeof(key->key))
+ break;
+ key->type = key_type;
+ key->flags = key_flags;
+ key->len = key_len;
+ memcpy(key->key, keyparam->key, key->len);
+
+ buf_ptr = end + 1;
+ }
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
+{
+/* Bit Rate
+* 15:13 Reserved
+* 12 54 Mbps
+* 11 48 Mbps
+* 10 36 Mbps
+* 9 24 Mbps
+* 8 18 Mbps
+* 7 12 Mbps
+* 6 9 Mbps
+* 5 6 Mbps
+* 4 Reserved
+* 3 11 Mbps
+* 2 5.5 Mbps
+* 1 2 Mbps
+* 0 1 Mbps
+**/
+
+ uint16_t ratemask;
+ int i = lbs_data_rate_to_fw_index(rate);
+ if (lower_rates_ok)
+ ratemask = (0x1fef >> (12 - i));
+ else
+ ratemask = (1 << i);
+ return cpu_to_le16(ratemask);
+}
+
+int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+ uint16_t cmd_action)
+{
+ struct cmd_ds_802_11_rate_adapt_rateset cmd;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (!priv->cur_rate && !priv->enablehwauto)
+ return -EINVAL;
+
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ cmd.action = cpu_to_le16(cmd_action);
+ cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
+ cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
+ ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
+ if (!ret && cmd_action == CMD_ACT_GET) {
+ priv->ratebitmap = le16_to_cpu(cmd.bitmap);
+ priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * @brief Set the data rate
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param rate The desired data rate, or 0 to clear a locked rate
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
+{
+ struct cmd_ds_802_11_data_rate cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ if (rate > 0) {
+ cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
+ cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
+ if (cmd.rates[0] == 0) {
+ lbs_deb_cmd("DATA_RATE: invalid requested rate of"
+ " 0x%02X\n", rate);
+ ret = 0;
+ goto out;
+ }
+ lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
+ } else {
+ cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
+ lbs_deb_cmd("DATA_RATE: setting auto\n");
+ }
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
+ if (ret)
+ goto out;
+
+ lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof(cmd));
+
+ /* FIXME: get actual rates FW can do if this command actually returns
+ * all data rates supported.
+ */
+ priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
+ lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+
+int lbs_cmd_802_11_rssi(struct lbs_private *priv,
+ struct cmd_ds_command *cmd)
+{
+
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_RSSI);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) +
+ sizeof(struct cmd_header));
+ cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
+
+ /* reset Beacon SNR/NF/RSSI values */
+ priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
+ priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
+ priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
+ priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
+ priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
+ priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
+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] = get_unaligned_le16(&rssirsp->SNR);
+ priv->NF[TYPE_BEACON][TYPE_NOAVG] =
+ get_unaligned_le16(&rssirsp->noisefloor);
+
+ priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
+ priv->NF[TYPE_BEACON][TYPE_AVG] =
+ get_unaligned_le16(&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;
+}
+
+
+int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_802_11_beacon_control
+ *bcn_ctrl = &cmd->params.bcn_ctrl;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
+ + sizeof(struct cmd_header));
+ cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
+
+ bcn_ctrl->action = cpu_to_le16(cmd_action);
+ bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
+ bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
+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 int lbs_assoc_post(struct lbs_private *priv,
struct cmd_ds_802_11_associate_response *resp)
{
@@ -226,7 +624,7 @@ static int lbs_assoc_post(struct lbs_private *priv,
priv->connect_status = LBS_CONNECTED;
/* Update current SSID and BSSID */
- memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+ memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
priv->curbssparams.ssid_len = bss->ssid_len;
memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
@@ -369,12 +767,7 @@ static int lbs_associate(struct lbs_private *priv,
(u16)(pos - (u8 *) &cmd.iebuf));
/* update curbssparams */
- priv->curbssparams.channel = bss->phy.ds.channel;
-
- if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
- ret = -1;
- goto done;
- }
+ priv->channel = bss->phy.ds.channel;
ret = lbs_cmd_with_response(priv, command, &cmd);
if (ret == 0) {
@@ -472,7 +865,7 @@ static int lbs_adhoc_post(struct lbs_private *priv,
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);
+ memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
priv->curbssparams.ssid_len = bss->ssid_len;
netif_carrier_on(priv->dev);
@@ -487,7 +880,7 @@ static int lbs_adhoc_post(struct lbs_private *priv,
lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
print_ssid(ssid, bss->ssid, bss->ssid_len),
priv->curbssparams.bssid,
- priv->curbssparams.channel);
+ priv->channel);
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
@@ -560,7 +953,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
priv->adhoccreate = 0;
- priv->curbssparams.channel = bss->channel;
+ priv->channel = bss->channel;
/* Build the join command */
memset(&cmd, 0, sizeof(cmd));
@@ -633,11 +1026,6 @@ static int lbs_adhoc_join(struct lbs_private *priv,
}
}
- if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
- ret = -1;
- goto out;
- }
-
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
if (ret == 0) {
ret = lbs_adhoc_post(priv,
@@ -737,12 +1125,6 @@ static int lbs_adhoc_start(struct lbs_private *priv,
lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n",
cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]);
- if (lbs_create_dnld_countryinfo_11d(priv)) {
- lbs_deb_join("ADHOC_START: dnld_countryinfo_11d failed\n");
- ret = -1;
- goto out;
- }
-
lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n",
assoc_req->channel, assoc_req->band);
@@ -1099,7 +1481,7 @@ static int assoc_helper_essid(struct lbs_private *priv,
/* else send START command */
lbs_deb_assoc("SSID not found, creating adhoc network\n");
memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
- IW_ESSID_MAX_SIZE);
+ IEEE80211_MAX_SSID_LEN);
assoc_req->bss.ssid_len = assoc_req->ssid_len;
lbs_adhoc_start(priv, assoc_req);
}
@@ -1185,7 +1567,8 @@ static int assoc_helper_mode(struct lbs_private *priv,
}
priv->mode = assoc_req->mode;
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, assoc_req->mode);
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE,
+ assoc_req->mode == IW_MODE_ADHOC ? 2 : 1);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -1205,7 +1588,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
goto done;
}
- if (assoc_req->channel == priv->curbssparams.channel)
+ if (assoc_req->channel == priv->channel)
goto done;
if (priv->mesh_dev) {
@@ -1217,7 +1600,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
}
lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
- priv->curbssparams.channel, assoc_req->channel);
+ priv->channel, assoc_req->channel);
ret = lbs_set_channel(priv, assoc_req->channel);
if (ret < 0)
@@ -1232,7 +1615,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
goto done;
}
- if (assoc_req->channel != priv->curbssparams.channel) {
+ if (assoc_req->channel != priv->channel) {
lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
assoc_req->channel);
goto restore_mesh;
@@ -1253,7 +1636,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
restore_mesh:
if (priv->mesh_dev)
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel);
+ priv->channel);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -1475,7 +1858,7 @@ static int should_stop_adhoc(struct lbs_private *priv,
}
if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
- if (assoc_req->channel != priv->curbssparams.channel)
+ if (assoc_req->channel != priv->channel)
return 1;
}
@@ -1557,7 +1940,7 @@ static int lbs_find_best_network_ssid(struct lbs_private *priv,
found = lbs_find_best_ssid_in_list(priv, preferred_mode);
if (found && (found->ssid_len > 0)) {
- memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE);
+ memcpy(out_ssid, &found->ssid, IEEE80211_MAX_SSID_LEN);
*out_ssid_len = found->ssid_len;
*out_mode = found->mode;
ret = 0;
@@ -1775,12 +2158,12 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
assoc_req = priv->pending_assoc_req;
if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
- IW_ESSID_MAX_SIZE);
+ IEEE80211_MAX_SSID_LEN);
assoc_req->ssid_len = priv->curbssparams.ssid_len;
}
if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
- assoc_req->channel = priv->curbssparams.channel;
+ assoc_req->channel = priv->channel;
if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
assoc_req->band = priv->curbssparams.band;
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
index 6e765e9f91a..40621b789fc 100644
--- a/drivers/net/wireless/libertas/assoc.h
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -3,7 +3,126 @@
#ifndef _LBS_ASSOC_H_
#define _LBS_ASSOC_H_
-#include "dev.h"
+
+#include "defs.h"
+#include "host.h"
+
+
+struct lbs_private;
+
+/*
+ * In theory, the IE is limited to the IE length, 255,
+ * but in practice 64 bytes are enough.
+ */
+#define MAX_WPA_IE_LEN 64
+
+
+
+struct lbs_802_11_security {
+ u8 WPAenabled;
+ u8 WPA2enabled;
+ u8 wep_enabled;
+ u8 auth_mode;
+ u32 key_mgmt;
+};
+
+/** Current Basic Service Set State Structure */
+struct current_bss_params {
+ /** bssid */
+ u8 bssid[ETH_ALEN];
+ /** ssid */
+ u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 ssid_len;
+
+ /** band */
+ u8 band;
+ /** channel is directly in priv->channel */
+ /** zero-terminated array of supported data rates */
+ u8 rates[MAX_RATES + 1];
+};
+
+/**
+ * @brief Structure used to store information for each beacon/probe response
+ */
+struct bss_descriptor {
+ u8 bssid[ETH_ALEN];
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 ssid_len;
+
+ u16 capability;
+ u32 rssi;
+ u32 channel;
+ u16 beaconperiod;
+ __le16 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 ieee_phy_param_set phy;
+ union ieee_ss_param_set ss;
+
+ 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[IEEE80211_MAX_SSID_LEN + 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;
+};
+
+
+extern u8 lbs_bg_rates[MAX_RATES];
void lbs_association_worker(struct work_struct *work);
struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
@@ -13,4 +132,24 @@ int lbs_adhoc_stop(struct lbs_private *priv);
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
u8 bssid[ETH_ALEN], u16 reason);
+int lbs_cmd_802_11_rssi(struct lbs_private *priv,
+ struct cmd_ds_command *cmd);
+int lbs_ret_802_11_rssi(struct lbs_private *priv,
+ struct cmd_ds_command *resp);
+
+int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action);
+int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
+ struct cmd_ds_command *resp);
+
+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_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
new file mode 100644
index 00000000000..4396dccd12a
--- /dev/null
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -0,0 +1,198 @@
+/*
+ * Implement cfg80211 ("iw") support.
+ *
+ * Copyright (C) 2009 M&N Solutions GmbH, 61191 Rosbach, Germany
+ * Holger Schurig <hs4233@mail.mn-solutions.de>
+ *
+ */
+
+#include <net/cfg80211.h>
+
+#include "cfg.h"
+#include "cmd.h"
+
+
+#define CHAN2G(_channel, _freq, _flags) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+static struct ieee80211_channel lbs_2ghz_channels[] = {
+ CHAN2G(1, 2412, 0),
+ CHAN2G(2, 2417, 0),
+ CHAN2G(3, 2422, 0),
+ CHAN2G(4, 2427, 0),
+ CHAN2G(5, 2432, 0),
+ CHAN2G(6, 2437, 0),
+ CHAN2G(7, 2442, 0),
+ CHAN2G(8, 2447, 0),
+ CHAN2G(9, 2452, 0),
+ CHAN2G(10, 2457, 0),
+ CHAN2G(11, 2462, 0),
+ CHAN2G(12, 2467, 0),
+ CHAN2G(13, 2472, 0),
+ CHAN2G(14, 2484, 0),
+};
+
+#define RATETAB_ENT(_rate, _rateid, _flags) { \
+ .bitrate = (_rate), \
+ .hw_value = (_rateid), \
+ .flags = (_flags), \
+}
+
+
+static struct ieee80211_rate lbs_rates[] = {
+ RATETAB_ENT(10, 0x1, 0),
+ RATETAB_ENT(20, 0x2, 0),
+ RATETAB_ENT(55, 0x4, 0),
+ RATETAB_ENT(110, 0x8, 0),
+ RATETAB_ENT(60, 0x10, 0),
+ RATETAB_ENT(90, 0x20, 0),
+ RATETAB_ENT(120, 0x40, 0),
+ RATETAB_ENT(180, 0x80, 0),
+ RATETAB_ENT(240, 0x100, 0),
+ RATETAB_ENT(360, 0x200, 0),
+ RATETAB_ENT(480, 0x400, 0),
+ RATETAB_ENT(540, 0x800, 0),
+};
+
+static struct ieee80211_supported_band lbs_band_2ghz = {
+ .channels = lbs_2ghz_channels,
+ .n_channels = ARRAY_SIZE(lbs_2ghz_channels),
+ .bitrates = lbs_rates,
+ .n_bitrates = ARRAY_SIZE(lbs_rates),
+};
+
+
+static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+};
+
+
+
+static int lbs_cfg_set_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ int ret = -ENOTSUPP;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", chan->center_freq, channel_type);
+
+ if (channel_type != NL80211_CHAN_NO_HT)
+ goto out;
+
+ ret = lbs_set_channel(priv, chan->hw_value);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+
+
+static struct cfg80211_ops lbs_cfg80211_ops = {
+ .set_channel = lbs_cfg_set_channel,
+};
+
+
+/*
+ * At this time lbs_private *priv doesn't even exist, so we just allocate
+ * memory and don't initialize the wiphy further. This is postponed until we
+ * can talk to the firmware and happens at registration time in
+ * lbs_cfg_wiphy_register().
+ */
+struct wireless_dev *lbs_cfg_alloc(struct device *dev)
+{
+ int ret = 0;
+ struct wireless_dev *wdev;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!wdev) {
+ dev_err(dev, "cannot allocate wireless device\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ wdev->wiphy = wiphy_new(&lbs_cfg80211_ops, sizeof(struct lbs_private));
+ if (!wdev->wiphy) {
+ dev_err(dev, "cannot allocate wiphy\n");
+ ret = -ENOMEM;
+ goto err_wiphy_new;
+ }
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+ return wdev;
+
+ err_wiphy_new:
+ kfree(wdev);
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ERR_PTR(ret);
+}
+
+
+/*
+ * This function get's called after lbs_setup_firmware() determined the
+ * firmware capabities. So we can setup the wiphy according to our
+ * hardware/firmware.
+ */
+int lbs_cfg_register(struct lbs_private *priv)
+{
+ struct wireless_dev *wdev = priv->wdev;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ wdev->wiphy->max_scan_ssids = 1;
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ /* TODO: BIT(NL80211_IFTYPE_ADHOC); */
+ wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+ /* TODO: honor priv->regioncode */
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
+
+ /*
+ * We could check priv->fwcapinfo && FW_CAPINFO_WPA, but I have
+ * never seen a firmware without WPA
+ */
+ wdev->wiphy->cipher_suites = cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
+ ret = wiphy_register(wdev->wiphy);
+ if (ret < 0)
+ lbs_pr_err("cannot register wiphy device\n");
+
+ ret = register_netdev(priv->dev);
+ if (ret)
+ lbs_pr_err("cannot register network device\n");
+
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+void lbs_cfg_free(struct lbs_private *priv)
+{
+ struct wireless_dev *wdev = priv->wdev;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ if (!wdev)
+ return;
+
+ if (wdev->wiphy) {
+ wiphy_unregister(wdev->wiphy);
+ wiphy_free(wdev->wiphy);
+ }
+ kfree(wdev);
+}
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
new file mode 100644
index 00000000000..e09a193a34d
--- /dev/null
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -0,0 +1,16 @@
+#ifndef __LBS_CFG80211_H__
+#define __LBS_CFG80211_H__
+
+#include "dev.h"
+
+struct wireless_dev *lbs_cfg_alloc(struct device *dev);
+int lbs_cfg_register(struct lbs_private *priv);
+void lbs_cfg_free(struct lbs_private *priv);
+
+int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
+ u8 ssid_len);
+int lbs_scan_networks(struct lbs_private *priv, int full_scan);
+void lbs_cfg_scan_worker(struct work_struct *work);
+
+
+#endif
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 0a324dcd264..b9b371bfa30 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -3,21 +3,20 @@
* It prepares command and sends it to firmware when it is ready.
*/
-#include <net/iw_handler.h>
-#include <net/lib80211.h>
#include <linux/kfifo.h>
#include <linux/sched.h>
+
#include "host.h"
-#include "hostcmd.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
#include "assoc.h"
#include "wext.h"
+#include "scan.h"
#include "cmd.h"
-static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
+static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
/**
* @brief Simple callback that copies response back into command
@@ -77,6 +76,30 @@ static u8 is_command_allowed_in_ps(u16 cmd)
}
/**
+ * @brief This function checks if the command is allowed.
+ *
+ * @param priv A pointer to lbs_private structure
+ * @return allowed or not allowed.
+ */
+
+static int lbs_is_cmd_allowed(struct lbs_private *priv)
+{
+ int ret = 1;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (!priv->is_auto_deep_sleep_enabled) {
+ if (priv->is_deep_sleep) {
+ lbs_deb_cmd("command not allowed in deep sleep\n");
+ ret = 0;
+ }
+ }
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
+}
+
+/**
* @brief Updates the hardware details like MAC address and regulatory region
*
* @param priv A pointer to struct lbs_private structure
@@ -169,11 +192,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)
goto out;
}
- if (lbs_set_universaltable(priv, 0)) {
- ret = -1;
- goto out;
- }
-
out:
lbs_deb_leave(LBS_DEB_CMD);
return ret;
@@ -222,7 +240,7 @@ static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
psm->action = cpu_to_le16(cmd_action);
psm->multipledtim = 0;
switch (cmd_action) {
@@ -251,33 +269,6 @@ static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
return 0;
}
-int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
- uint16_t cmd_action, uint16_t *timeout)
-{
- struct cmd_ds_802_11_inactivity_timeout cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- cmd.hdr.command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_SET)
- cmd.timeout = cpu_to_le16(*timeout);
- else
- cmd.timeout = 0;
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_INACTIVITY_TIMEOUT, &cmd);
-
- if (!ret)
- *timeout = le16_to_cpu(cmd.timeout);
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return 0;
-}
-
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
struct sleep_params *sp)
{
@@ -320,190 +311,53 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
return 0;
}
-int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc)
+static int lbs_wait_for_ds_awake(struct lbs_private *priv)
{
- struct cmd_ds_802_11_set_wep cmd;
int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_ADD) {
- int i;
-
- /* default tx key index */
- cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
- CMD_WEP_KEY_INDEX_MASK);
-
- /* Copy key types and material to host command structure */
- for (i = 0; i < 4; i++) {
- struct enc_key *pkey = &assoc->wep_keys[i];
-
- switch (pkey->len) {
- case KEY_LEN_WEP_40:
- cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
- memmove(cmd.keymaterial[i], pkey->key, pkey->len);
- lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
- break;
- case KEY_LEN_WEP_104:
- cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
- memmove(cmd.keymaterial[i], pkey->key, pkey->len);
- lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
- break;
- case 0:
- break;
- default:
- lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
- i, pkey->len);
- ret = -1;
- goto done;
- break;
- }
+ if (priv->is_deep_sleep) {
+ if (!wait_event_interruptible_timeout(priv->ds_awake_q,
+ !priv->is_deep_sleep, (10 * HZ))) {
+ lbs_pr_err("ds_awake_q: timer expired\n");
+ ret = -1;
}
- } else if (cmd_action == CMD_ACT_REMOVE) {
- /* ACT_REMOVE clears _all_ WEP keys */
-
- /* default tx key index */
- cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
- CMD_WEP_KEY_INDEX_MASK);
- lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
- }
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
-done:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
- uint16_t *enable)
-{
- struct cmd_ds_802_11_enable_rsn cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_GET)
- cmd.enable = 0;
- else {
- if (*enable)
- cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
- else
- cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
- lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
}
- ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
- if (!ret && cmd_action == CMD_ACT_GET)
- *enable = le16_to_cpu(cmd.enable);
-
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
-static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
- struct enc_key *key)
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
{
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (key->flags & KEY_INFO_WPA_ENABLED)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
- if (key->flags & KEY_INFO_WPA_UNICAST)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
- if (key->flags & KEY_INFO_WPA_MCAST)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
-
- keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
- keyparam->keytypeid = cpu_to_le16(key->type);
- keyparam->keylen = cpu_to_le16(key->len);
- memcpy(keyparam->key, key->key, key->len);
-
- /* Length field doesn't include the {type,length} header */
- keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
- lbs_deb_leave(LBS_DEB_CMD);
-}
-
-int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc)
-{
- struct cmd_ds_802_11_key_material cmd;
- int ret = 0;
- int index = 0;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
- cmd.action = cpu_to_le16(cmd_action);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- if (cmd_action == CMD_ACT_GET) {
- cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2);
- } else {
- memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
-
- if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
- set_one_wpa_key(&cmd.keyParamSet[index],
- &assoc->wpa_unicast_key);
- index++;
- }
-
- if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
- set_one_wpa_key(&cmd.keyParamSet[index],
- &assoc->wpa_mcast_key);
- index++;
+ if (deep_sleep) {
+ if (priv->is_deep_sleep != 1) {
+ lbs_deb_cmd("deep sleep: sleep\n");
+ BUG_ON(!priv->enter_deep_sleep);
+ ret = priv->enter_deep_sleep(priv);
+ if (!ret) {
+ netif_stop_queue(priv->dev);
+ netif_carrier_off(priv->dev);
+ }
+ } else {
+ lbs_pr_err("deep sleep: already enabled\n");
}
-
- /* The common header and as many keys as we included */
- cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
- keyParamSet[index]));
- }
- ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
- /* Copy the returned key to driver private data */
- if (!ret && cmd_action == CMD_ACT_GET) {
- void *buf_ptr = cmd.keyParamSet;
- void *resp_end = &(&cmd)[1];
-
- while (buf_ptr < resp_end) {
- struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
- struct enc_key *key;
- uint16_t param_set_len = le16_to_cpu(keyparam->length);
- uint16_t key_len = le16_to_cpu(keyparam->keylen);
- uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
- uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
- void *end;
-
- end = (void *)keyparam + sizeof(keyparam->type)
- + sizeof(keyparam->length) + param_set_len;
-
- /* Make sure we don't access past the end of the IEs */
- if (end > resp_end)
- break;
-
- if (key_flags & KEY_INFO_WPA_UNICAST)
- key = &priv->wpa_unicast_key;
- else if (key_flags & KEY_INFO_WPA_MCAST)
- key = &priv->wpa_mcast_key;
- else
- break;
-
- /* Copy returned key into driver */
- memset(key, 0, sizeof(struct enc_key));
- if (key_len > sizeof(key->key))
- break;
- key->type = key_type;
- key->flags = key_flags;
- key->len = key_len;
- memcpy(key->key, keyparam->key, key->len);
-
- buf_ptr = end + 1;
+ } else {
+ if (priv->is_deep_sleep) {
+ lbs_deb_cmd("deep sleep: wakeup\n");
+ BUG_ON(!priv->exit_deep_sleep);
+ ret = priv->exit_deep_sleep(priv);
+ if (!ret) {
+ ret = lbs_wait_for_ds_awake(priv);
+ if (ret)
+ lbs_pr_err("deep sleep: wakeup"
+ "failed\n");
+ }
}
}
@@ -535,7 +389,7 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
switch (oid) {
case SNMP_MIB_OID_BSS_TYPE:
cmd.bufsize = cpu_to_le16(sizeof(u8));
- cmd.value[0] = (val == IW_MODE_ADHOC) ? 2 : 1;
+ cmd.value[0] = val;
break;
case SNMP_MIB_OID_11D_ENABLE:
case SNMP_MIB_OID_FRAG_THRESHOLD:
@@ -588,13 +442,7 @@ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
switch (le16_to_cpu(cmd.bufsize)) {
case sizeof(u8):
- if (oid == SNMP_MIB_OID_BSS_TYPE) {
- if (cmd.value[0] == 2)
- *out_val = IW_MODE_ADHOC;
- else
- *out_val = IW_MODE_INFRA;
- } else
- *out_val = cmd.value[0];
+ *out_val = cmd.value[0];
break;
case sizeof(u16):
*out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
@@ -681,7 +529,7 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
monitor->action = cpu_to_le16(cmd_action);
if (cmd_action == CMD_ACT_SET) {
@@ -692,111 +540,6 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
return 0;
}
-static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
-{
-/* Bit Rate
-* 15:13 Reserved
-* 12 54 Mbps
-* 11 48 Mbps
-* 10 36 Mbps
-* 9 24 Mbps
-* 8 18 Mbps
-* 7 12 Mbps
-* 6 9 Mbps
-* 5 6 Mbps
-* 4 Reserved
-* 3 11 Mbps
-* 2 5.5 Mbps
-* 1 2 Mbps
-* 0 1 Mbps
-**/
-
- uint16_t ratemask;
- int i = lbs_data_rate_to_fw_index(rate);
- if (lower_rates_ok)
- ratemask = (0x1fef >> (12 - i));
- else
- ratemask = (1 << i);
- return cpu_to_le16(ratemask);
-}
-
-int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
- uint16_t cmd_action)
-{
- struct cmd_ds_802_11_rate_adapt_rateset cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (!priv->cur_rate && !priv->enablehwauto)
- return -EINVAL;
-
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
- cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
- cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
- ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
- if (!ret && cmd_action == CMD_ACT_GET) {
- priv->ratebitmap = le16_to_cpu(cmd.bitmap);
- priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
- }
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset);
-
-/**
- * @brief Set the data rate
- *
- * @param priv A pointer to struct lbs_private structure
- * @param rate The desired data rate, or 0 to clear a locked rate
- *
- * @return 0 on success, error on failure
- */
-int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
-{
- struct cmd_ds_802_11_data_rate cmd;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- if (rate > 0) {
- cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
- cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
- if (cmd.rates[0] == 0) {
- lbs_deb_cmd("DATA_RATE: invalid requested rate of"
- " 0x%02X\n", rate);
- ret = 0;
- goto out;
- }
- lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
- } else {
- cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
- lbs_deb_cmd("DATA_RATE: setting auto\n");
- }
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
- if (ret)
- goto out;
-
- lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
-
- /* FIXME: get actual rates FW can do if this command actually returns
- * all data rates supported.
- */
- priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
- lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
-
-out:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
/**
* @brief Get the radio channel
*
@@ -804,7 +547,7 @@ out:
*
* @return The channel on success, error on failure
*/
-int lbs_get_channel(struct lbs_private *priv)
+static int lbs_get_channel(struct lbs_private *priv)
{
struct cmd_ds_802_11_rf_channel cmd;
int ret = 0;
@@ -836,7 +579,7 @@ int lbs_update_channel(struct lbs_private *priv)
ret = lbs_get_channel(priv);
if (ret > 0) {
- priv->curbssparams.channel = ret;
+ priv->channel = ret;
ret = 0;
}
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -855,7 +598,7 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel)
{
struct cmd_ds_802_11_rf_channel cmd;
#ifdef DEBUG
- u8 old_channel = priv->curbssparams.channel;
+ u8 old_channel = priv->channel;
#endif
int ret = 0;
@@ -870,36 +613,15 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel)
if (ret)
goto out;
- priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel);
+ priv->channel = (uint8_t) le16_to_cpu(cmd.channel);
lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
- priv->curbssparams.channel);
+ priv->channel);
out:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
-static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
- struct cmd_ds_command *cmd)
-{
-
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(CMD_802_11_RSSI);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
- cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
-
- /* reset Beacon SNR/NF/RSSI values */
- priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
- priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
- priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
- priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
- priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
- priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
u8 cmd_action, void *pdata_buf)
{
@@ -916,7 +638,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
cmdptr->size =
cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
- + S_DS_GEN);
+ + sizeof(struct cmd_header));
macreg =
(struct cmd_ds_mac_reg_access *)&cmdptr->params.
macreg;
@@ -935,7 +657,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
cmdptr->size =
cpu_to_le16(sizeof
(struct cmd_ds_bbp_reg_access)
- + S_DS_GEN);
+ + sizeof(struct cmd_header));
bbpreg =
(struct cmd_ds_bbp_reg_access *)&cmdptr->params.
bbpreg;
@@ -954,7 +676,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
cmdptr->size =
cpu_to_le16(sizeof
(struct cmd_ds_rf_reg_access) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
rfreg =
(struct cmd_ds_rf_reg_access *)&cmdptr->params.
rfreg;
@@ -974,192 +696,6 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
return 0;
}
-static int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
- u16 cmd_action, void *pdata_buf)
-{
- struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
- lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
-
- cmd->command = cpu_to_le16(CMD_BT_ACCESS);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
- cmd->result = 0;
- bt_access->action = cpu_to_le16(cmd_action);
-
- switch (cmd_action) {
- case CMD_ACT_BT_ACCESS_ADD:
- memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
- lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
- break;
- case CMD_ACT_BT_ACCESS_DEL:
- memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
- lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
- break;
- case CMD_ACT_BT_ACCESS_LIST:
- bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
- break;
- case CMD_ACT_BT_ACCESS_RESET:
- break;
- case CMD_ACT_BT_ACCESS_SET_INVERT:
- bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
- break;
- case CMD_ACT_BT_ACCESS_GET_INVERT:
- break;
- default:
- break;
- }
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
-static int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
- u16 cmd_action, void *pdata_buf)
-{
- struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
- lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
-
- cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
- cmd->result = 0;
-
- if (pdata_buf)
- memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
- else
- memset(fwt_access, 0, sizeof(*fwt_access));
-
- fwt_access->action = cpu_to_le16(cmd_action);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
-int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
- struct cmd_ds_mesh_access *cmd)
-{
- int ret;
-
- lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
-
- cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
- cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
- cmd->hdr.result = 0;
-
- cmd->action = cpu_to_le16(cmd_action);
-
- ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return ret;
-}
-
-static int __lbs_mesh_config_send(struct lbs_private *priv,
- struct cmd_ds_mesh_config *cmd,
- uint16_t action, uint16_t type)
-{
- int ret;
- u16 command = CMD_MESH_CONFIG_OLD;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- /*
- * Command id is 0xac for v10 FW along with mesh interface
- * id in bits 14-13-12.
- */
- if (priv->mesh_fw_ver == MESH_FW_NEW)
- command = CMD_MESH_CONFIG |
- (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
-
- cmd->hdr.command = cpu_to_le16(command);
- cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
- cmd->hdr.result = 0;
-
- cmd->type = cpu_to_le16(type);
- cmd->action = cpu_to_le16(action);
-
- ret = lbs_cmd_with_response(priv, command, cmd);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return ret;
-}
-
-int lbs_mesh_config_send(struct lbs_private *priv,
- struct cmd_ds_mesh_config *cmd,
- uint16_t action, uint16_t type)
-{
- int ret;
-
- if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
- return -EOPNOTSUPP;
-
- ret = __lbs_mesh_config_send(priv, cmd, action, type);
- return ret;
-}
-
-/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
- * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
- * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
- * lbs_mesh_config_send.
- */
-int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
-{
- struct cmd_ds_mesh_config cmd;
- struct mrvl_meshie *ie;
- DECLARE_SSID_BUF(ssid);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.channel = cpu_to_le16(chan);
- ie = (struct mrvl_meshie *)cmd.data;
-
- switch (action) {
- case CMD_ACT_MESH_CONFIG_START:
- ie->id = WLAN_EID_GENERIC;
- ie->val.oui[0] = 0x00;
- ie->val.oui[1] = 0x50;
- ie->val.oui[2] = 0x43;
- ie->val.type = MARVELL_MESH_IE_TYPE;
- ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
- ie->val.version = MARVELL_MESH_IE_VERSION;
- ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
- ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
- ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
- ie->val.mesh_id_len = priv->mesh_ssid_len;
- memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
- ie->len = sizeof(struct mrvl_meshie_val) -
- IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
- cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
- break;
- case CMD_ACT_MESH_CONFIG_STOP:
- break;
- default:
- return -1;
- }
- lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
- action, priv->mesh_tlv, chan,
- print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
-
- return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
-}
-
-static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
- struct cmd_ds_command *cmd,
- u16 cmd_action)
-{
- struct cmd_ds_802_11_beacon_control
- *bcn_ctrl = &cmd->params.bcn_ctrl;
-
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->size =
- cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
- + S_DS_GEN);
- cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
-
- bcn_ctrl->action = cpu_to_le16(cmd_action);
- bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
- bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
static void lbs_queue_cmd(struct lbs_private *priv,
struct cmd_ctrl_node *cmdnode)
{
@@ -1243,8 +779,17 @@ static void lbs_submit_command(struct lbs_private *priv,
timeo = HZ/4;
}
- /* Setup the timer after transmit command */
- mod_timer(&priv->command_timer, jiffies + timeo);
+ if (command == CMD_802_11_DEEP_SLEEP) {
+ if (priv->is_auto_deep_sleep_enabled) {
+ priv->wakeup_dev_required = 1;
+ priv->dnld_sent = 0;
+ }
+ priv->is_deep_sleep = 1;
+ lbs_complete_command(priv, cmdnode, 0);
+ } else {
+ /* Setup the timer after transmit command */
+ mod_timer(&priv->command_timer, jiffies + timeo);
+ }
lbs_deb_leave(LBS_DEB_HOST);
}
@@ -1391,6 +936,11 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
goto done;
}
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto done;
+ }
+
cmdnode = lbs_get_cmd_ctrl_node(priv);
if (cmdnode == NULL) {
@@ -1441,7 +991,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
cmdptr->command = cpu_to_le16(cmd_no);
cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
memmove(&cmdptr->params.afc,
pdata_buf, sizeof(struct cmd_ds_802_11_afc));
@@ -1449,45 +999,17 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = 0;
goto done;
- case CMD_802_11D_DOMAIN_INFO:
- ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
- cmd_no, cmd_action);
- break;
-
case CMD_802_11_TPC_CFG:
cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
cmdptr->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
memmove(&cmdptr->params.tpccfg,
pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
ret = 0;
break;
- case CMD_802_11_LED_GPIO_CTRL:
- {
- struct mrvl_ie_ledgpio *gpio =
- (struct mrvl_ie_ledgpio*)
- cmdptr->params.ledgpio.data;
-
- memmove(&cmdptr->params.ledgpio,
- pdata_buf,
- sizeof(struct cmd_ds_802_11_led_ctrl));
-
- cmdptr->command =
- cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
-
-#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
- cmdptr->size =
- cpu_to_le16(le16_to_cpu(gpio->header.len)
- + S_DS_GEN
- + ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
- gpio->header.len = gpio->header.len;
-
- ret = 0;
- break;
- }
case CMD_BT_ACCESS:
ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
@@ -1497,15 +1019,13 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
break;
- case CMD_GET_TSF:
- cmdptr->command = cpu_to_le16(CMD_GET_TSF);
- cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
- S_DS_GEN);
- ret = 0;
- break;
case CMD_802_11_BEACON_CTRL:
ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
break;
+ case CMD_802_11_DEEP_SLEEP:
+ cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
+ cmdptr->size = cpu_to_le16(sizeof(struct cmd_header));
+ break;
default:
lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
ret = -1;
@@ -1823,30 +1343,6 @@ done:
return ret;
}
-void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
-{
- union iwreq_data iwrq;
- u8 buf[50];
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- memset(&iwrq, 0, sizeof(union iwreq_data));
- memset(buf, 0, sizeof(buf));
-
- snprintf(buf, sizeof(buf) - 1, "%s", str);
-
- iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
-
- /* Send Event to upper layer */
- lbs_deb_wext("event indication string %s\n", (char *)buf);
- lbs_deb_wext("event indication length %d\n", iwrq.data.length);
- lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
-
- wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
-
- lbs_deb_leave(LBS_DEB_WEXT);
-}
-
static void lbs_send_confirmsleep(struct lbs_private *priv)
{
unsigned long flags;
@@ -2024,7 +1520,7 @@ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
}
-static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
+struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
unsigned long callback_arg)
@@ -2039,6 +1535,11 @@ static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
goto done;
}
+ if (!lbs_is_cmd_allowed(priv)) {
+ cmdnode = ERR_PTR(-EBUSY);
+ goto done;
+ }
+
cmdnode = lbs_get_cmd_ctrl_node(priv);
if (cmdnode == NULL) {
lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
@@ -2117,5 +1618,3 @@ done:
return ret;
}
EXPORT_SYMBOL_GPL(__lbs_cmd);
-
-
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 392e578ca09..2862748aef7 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -3,11 +3,30 @@
#ifndef _LBS_CMD_H_
#define _LBS_CMD_H_
-#include "hostcmd.h"
+#include "host.h"
#include "dev.h"
+
+/* Command & response transfer between host and card */
+
+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;
+};
+
+
/* 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
+ 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); \
@@ -18,6 +37,11 @@
#define lbs_cmd_with_response(priv, cmdnr, cmd) \
lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd))
+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);
+
void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
struct cmd_header *in_cmd, int in_cmd_size);
@@ -26,62 +50,93 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
unsigned long callback_arg);
-int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
- int8_t p1, int8_t p2);
+struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
+ uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
+ int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
+ unsigned long callback_arg);
-int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
- int8_t p2, int usesnr);
+int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
+ struct cmd_header *resp);
-int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
- int8_t p1, int8_t p2);
+int lbs_allocate_cmd_buffer(struct lbs_private *priv);
+int lbs_free_cmd_buffer(struct lbs_private *priv);
-int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
- int8_t p2, int usesnr);
+int lbs_execute_next_command(struct lbs_private *priv);
+void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+ int result);
+int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
-int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
- struct cmd_header *resp);
-int lbs_update_hw_spec(struct lbs_private *priv);
+/* From cmdresp.c */
-int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
- struct cmd_ds_mesh_access *cmd);
+void lbs_mac_event_disconnected(struct lbs_private *priv);
-int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
-int lbs_get_channel(struct lbs_private *priv);
+
+/* Events */
+
+int lbs_process_event(struct lbs_private *priv, u32 event);
+
+
+/* Actual commands */
+
+int lbs_update_hw_spec(struct lbs_private *priv);
+
int lbs_set_channel(struct lbs_private *priv, u8 channel);
-int lbs_mesh_config_send(struct lbs_private *priv,
- struct cmd_ds_mesh_config *cmd,
- uint16_t action, uint16_t type);
-int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
+int lbs_update_channel(struct lbs_private *priv);
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
struct wol_config *p_wol_config);
-int lbs_suspend(struct lbs_private *priv);
-void lbs_resume(struct lbs_private *priv);
-int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
- uint16_t cmd_action);
-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);
-int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
- s16 *maxlevel);
-int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
+void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
+
+void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
+
+void lbs_ps_confirm_sleep(struct lbs_private *priv);
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
+void lbs_set_mac_control(struct lbs_private *priv);
+
+int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
+ s16 *maxlevel);
+
int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);
int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val);
+
+/* Mesh related */
+
+int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
+ struct cmd_ds_mesh_access *cmd);
+
+int lbs_mesh_config_send(struct lbs_private *priv,
+ struct cmd_ds_mesh_config *cmd,
+ uint16_t action, uint16_t type);
+
+int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
+
+
+/* Commands only used in wext.c, assoc. and scan.c */
+
+int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
+ int8_t p1, int8_t p2);
+
+int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
+ int8_t p2, int usesnr);
+
+int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
+
+int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+ uint16_t cmd_action);
+
+int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
+
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
+
#endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 23f684337fd..21d57690c20 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -11,6 +11,7 @@
#include "host.h"
#include "decl.h"
+#include "cmd.h"
#include "defs.h"
#include "dev.h"
#include "assoc.h"
@@ -26,23 +27,17 @@
*/
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);
+ lbs_send_disconnect_notification(priv);
/* report disconnect to upper layer */
netif_stop_queue(priv->dev);
@@ -67,7 +62,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
* no longer valid.
*/
memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
- memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE);
+ memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN);
priv->curbssparams.ssid_len = 0;
if (priv->psstate != PS_STATE_FULL_POWER) {
@@ -78,32 +73,6 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
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)
{
@@ -147,53 +116,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
return ret;
}
-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] = get_unaligned_le16(&rssirsp->SNR);
- priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor);
-
- priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
- priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&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)
{
@@ -227,29 +149,13 @@ static inline int handle_cmd_response(struct lbs_private *priv,
ret = lbs_ret_802_11_rssi(priv, resp);
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)
@@ -505,9 +411,21 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
case MACREG_INT_CODE_HOST_AWAKE:
lbs_deb_cmd("EVENT: host awake\n");
+ if (priv->reset_deep_sleep_wakeup)
+ priv->reset_deep_sleep_wakeup(priv);
+ priv->is_deep_sleep = 0;
lbs_send_confirmwake(priv);
break;
+ case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
+ if (priv->reset_deep_sleep_wakeup)
+ priv->reset_deep_sleep_wakeup(priv);
+ lbs_deb_cmd("EVENT: ds awake\n");
+ priv->is_deep_sleep = 0;
+ priv->wakeup_dev_required = 0;
+ wake_up_interruptible(&priv->ds_awake_q);
+ break;
+
case MACREG_INT_CODE_PS_AWAKE:
lbs_deb_cmd("EVENT: ps awake\n");
/* handle unexpected PS AWAKE event */
@@ -533,12 +451,12 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
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);
+ lbs_send_mic_failureevent(priv, event);
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);
+ lbs_send_mic_failureevent(priv, event);
break;
case MACREG_INT_CODE_MIB_CHANGED:
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 893a55ca344..587b0cb0088 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -451,10 +451,12 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
CMD_MAC_REG_ACCESS, 0,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
+ if (!ret) {
+ 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);
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ }
free_page(addr);
return ret;
}
@@ -514,7 +516,8 @@ static ssize_t lbs_wrmac_write(struct file *file,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- res = count;
+ if (!res)
+ res = count;
out_unlock:
free_page(addr);
return res;
@@ -539,10 +542,12 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
CMD_BBP_REG_ACCESS, 0,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
+ if (!ret) {
+ 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);
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ }
free_page(addr);
return ret;
@@ -603,7 +608,8 @@ static ssize_t lbs_wrbbp_write(struct file *file,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- res = count;
+ if (!res)
+ res = count;
out_unlock:
free_page(addr);
return res;
@@ -628,10 +634,12 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
CMD_RF_REG_ACCESS, 0,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
+ if (!ret) {
+ 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);
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ }
free_page(addr);
return ret;
@@ -692,7 +700,8 @@ static ssize_t lbs_wrrf_write(struct file *file,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- res = count;
+ if (!res)
+ res = count;
out_unlock:
free_page(addr);
return res;
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 8b15380ae6e..709ffcad22a 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -8,71 +8,46 @@
#include <linux/netdevice.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);
+/* ethtool.c */
+extern const struct ethtool_ops lbs_ethtool_ops;
-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);
-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);
+/* tx.c */
+void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count);
netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev);
-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
+/* rx.c */
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);
-
-/* persistcfg.c */
-void lbs_persist_config_init(struct net_device *net);
-void lbs_persist_config_remove(struct net_device *net);
/* 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);
void lbs_remove_card(struct lbs_private *priv);
int lbs_start_card(struct lbs_private *priv);
void 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);
+int lbs_set_mac_address(struct net_device *dev, void *addr);
+void lbs_set_multicast_list(struct net_device *dev);
+
+int lbs_suspend(struct lbs_private *priv);
+void lbs_resume(struct lbs_private *priv);
+
+void lbs_queue_event(struct lbs_private *priv, u32 event);
+void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
+
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
+
+u32 lbs_fw_index_to_data_rate(u8 index);
+u8 lbs_data_rate_to_fw_index(u32 rate);
+
#endif
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 72f3479a4d7..6b6ea9f7bf5 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -42,6 +42,7 @@
#define LBS_DEB_SDIO 0x00400000
#define LBS_DEB_SYSFS 0x00800000
#define LBS_DEB_SPI 0x01000000
+#define LBS_DEB_CFG80211 0x02000000
extern unsigned int lbs_debug;
@@ -86,6 +87,7 @@ do { if ((lbs_debug & (grp)) == (grp)) \
#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
#define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args)
#define lbs_deb_spi(fmt, args...) LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args)
+#define lbs_deb_cfg80211(fmt, args...) LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args)
#define lbs_pr_info(format, args...) \
printk(KERN_INFO DRV_NAME": " format, ## args)
@@ -320,7 +322,6 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
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 */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index d3b69a4b4b5..6a8d2b291d8 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -6,75 +6,11 @@
#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 "mesh.h"
+#include "scan.h"
+#include "assoc.h"
-#include "defs.h"
-#include "hostcmd.h"
-extern const 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;
- u32 key_mgmt;
-};
-
-/** 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 {
@@ -86,109 +22,99 @@ struct sleep_params {
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 mesh_fw_ver;
- int infra_open;
- int mesh_autostart_enabled;
- char name[DEV_NAME_LEN];
-
- void *card;
+ /* Basic networking */
struct net_device *dev;
+ u32 connect_status;
+ int infra_open;
+ struct work_struct mcast_work;
+ u32 nr_of_multicastmacaddr;
+ u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+
+ /* CFG80211 */
+ struct wireless_dev *wdev;
+ /* Mesh */
struct net_device *mesh_dev; /* Virtual device */
+ u32 mesh_connect_status;
+ struct lbs_mesh_stats mstats;
+ int mesh_open;
+ int mesh_fw_ver;
+ int mesh_autostart_enabled;
+ uint16_t mesh_tlv;
+ u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 mesh_ssid_len;
+ struct work_struct sync_channel;
+
+ /* Monitor mode */
struct net_device *rtap_net_dev;
+ u32 monitormode;
- struct iw_statistics wstats;
- struct lbs_mesh_stats mstats;
+ /* Debugfs */
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];
+ /* Hardware debugging */
u32 mac_offset;
u32 bbp_offset;
u32 rf_offset;
+ struct lbs_offset_value offsetvalue;
- /* 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;
-
- struct work_struct mcast_work;
+ /* Power management */
+ u16 psmode;
+ u32 psstate;
+ u8 needtowakeup;
- /** 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;
+ /* Deep sleep */
+ int is_deep_sleep;
+ int is_auto_deep_sleep_enabled;
+ int wakeup_dev_required;
+ int is_activity_detected;
+ int auto_deep_sleep_timeout; /* in ms */
+ wait_queue_head_t ds_awake_q;
+ struct timer_list auto_deepsleep_timer;
- /** Hardware access */
+ /* Hardware access */
+ void *card;
+ u8 fw_ready;
+ u8 surpriseremoved;
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
void (*reset_card) (struct lbs_private *priv);
+ int (*enter_deep_sleep) (struct lbs_private *priv);
+ int (*exit_deep_sleep) (struct lbs_private *priv);
+ int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
- /* Wake On LAN */
- uint32_t wol_criteria;
- uint8_t wol_gpio;
- uint8_t wol_gap;
-
- /** Wlan adapter data structure*/
- /** STATUS variables */
+ /* Adapter info (from EEPROM) */
u32 fwrelease;
u32 fwcapinfo;
+ u16 regioncode;
+ u8 current_addr[ETH_ALEN];
- 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 */
+ /* Command download */
+ u8 dnld_sent;
+ /* bit0 1/0=data_sent/data_tx_done,
+ bit1 1/0=cmd_sent/cmd_tx_done,
+ all other bits reserved 0 */
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;
-
+ struct list_head cmdfreeq; /* free command buffers */
+ struct list_head cmdpendingq; /* pending command buffers */
wait_queue_head_t cmd_pending;
+ struct timer_list command_timer;
+ int nr_retries;
+ int cmd_timed_out;
/* Command responses sent from the hardware to the driver */
+ int cur_cmd_retcode;
u8 resp_idx;
u8 resp_buf[2][LBS_UPLD_SIZE];
u32 resp_len[2];
@@ -196,95 +122,76 @@ struct lbs_private {
/* 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;
+ /** thread to service interrupts */
+ struct task_struct *main_thread;
+ wait_queue_head_t waitq;
+ struct workqueue_struct *work_thread;
- /** 802.11 statistics */
-// struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
+ /** Encryption stuff */
+ struct lbs_802_11_security secinfo;
+ struct enc_key wpa_mcast_key;
+ struct enc_key wpa_unicast_key;
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ u8 wpa_ie_len;
+ u16 wep_tx_keyidx;
+ struct enc_key wep_keys[4];
- uint16_t enablehwauto;
- uint16_t ratebitmap;
+ /* Wake On LAN */
+ uint32_t wol_criteria;
+ uint8_t wol_gpio;
+ uint8_t wol_gap;
+ /* Transmitting */
+ int tx_pending_len; /* -1 while building packet */
+ u8 tx_pending_buf[LBS_UPLD_SIZE];
+ /* protected by hard_start_xmit serialization */
u8 txretrycount;
-
- /** Tx-related variables (for single packet tx) */
struct sk_buff *currenttxskb;
- /** NIC Operation characteristics */
+ /* Locks */
+ struct mutex lock;
+ spinlock_t driver_lock;
+
+ /* NIC/link operation characteristics */
u16 mac_control;
- u32 connect_status;
- u32 mesh_connect_status;
- u16 regioncode;
+ u8 radio_on;
+ u8 channel;
s16 txpower_cur;
s16 txpower_min;
s16 txpower_max;
- /** POWER MANAGEMENT AND PnP SUPPORT */
- u8 surpriseremoved;
-
- u16 psmode; /* Wlan802_11PowermodeCAM=disable
- Wlan802_11PowermodeMAX_PSP=enable */
- u32 psstate;
- u8 needtowakeup;
+ /** Scanning */
+ struct delayed_work scan_work;
+ int scan_channel;
+ /* remember which channel was scanned last, != 0 if currently scanning */
+ u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 scan_ssid_len;
+ /* Associating */
+ struct delayed_work assoc_work;
+ struct current_bss_params curbssparams;
+ u8 mode;
+ struct list_head network_list;
+ struct list_head network_free_list;
+ struct bss_descriptor *networks;
struct assoc_request * pending_assoc_req;
struct assoc_request * in_progress_assoc_req;
+ u16 capability;
+ uint16_t enablehwauto;
+ uint16_t ratebitmap;
- /** 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;
-
-/*
- * In theory, the IE is limited to the IE length, 255,
- * but in practice 64 bytes are enough.
- */
-#define MAX_WPA_IE_LEN 64
+ /* ADHOC */
+ u16 beacon_period;
+ u8 beacon_enable;
+ u8 adhoccreate;
- /** WPA Information Elements*/
- u8 wpa_ie[MAX_WPA_IE_LEN];
- u8 wpa_ie_len;
+ /* WEXT */
+ char name[DEV_NAME_LEN];
+ u8 nodename[16];
+ struct iw_statistics wstats;
+ u8 cur_rate;
+#define MAX_REGION_CHANNEL_NUM 2
+ struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
/** Requested Signal Strength*/
u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
@@ -294,116 +201,8 @@ struct lbs_private {
u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
u16 nextSNRNF;
u16 numSNRNF;
-
- u8 radio_on;
-
- /** data rate stuff */
- u8 cur_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;
- __le16 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 ieee_phy_param_set phy;
- union ieee_ss_param_set ss;
-
- struct ieee_ie_country_info_full_set 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
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 53d56ab83c0..63d020374c2 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -8,17 +8,8 @@
#include "dev.h"
#include "wext.h"
#include "cmd.h"
+#include "mesh.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)
@@ -73,73 +64,6 @@ out:
return ret;
}
-static void lbs_ethtool_get_stats(struct net_device *dev,
- struct ethtool_stats *stats, uint64_t *data)
-{
- struct lbs_private *priv = dev->ml_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->ml_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)
{
@@ -190,9 +114,9 @@ const 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_sset_count = lbs_mesh_ethtool_get_sset_count,
+ .get_ethtool_stats = lbs_mesh_ethtool_get_stats,
+ .get_strings = lbs_mesh_ethtool_get_strings,
.get_wol = lbs_ethtool_get_wol,
.set_wol = lbs_ethtool_set_wol,
};
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index fe8f0cb737b..3809c0b4946 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -1,201 +1,190 @@
/**
- * This file contains definitions of WLAN commands.
+ * This file function prototypes, data structure
+ * and definitions for all the host/station commands
*/
#ifndef _LBS_HOST_H_
#define _LBS_HOST_H_
-/** PUBLIC DEFINITIONS */
-#define DEFAULT_AD_HOC_CHANNEL 6
-#define DEFAULT_AD_HOC_CHANNEL_A 36
+#include "types.h"
+#include "defs.h"
-#define CMD_OPTION_WAITFORRSP 0x0002
+#define DEFAULT_AD_HOC_CHANNEL 6
+
+#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)
+#define CMD_RET(cmd) (0x8000 | cmd)
/* Return command convention exceptions: */
-#define CMD_RET_802_11_ASSOCIATE 0x8012
+#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_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_GSPI_BUS_CONFIG 0x005a
-#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_PA_CFG 0x0073
-#define CMD_802_11_FW_WAKE_METHOD 0x0074
-#define CMD_802_11_SUBSCRIBE_EVENT 0x0075
-#define CMD_802_11_RATE_ADAPT_RATESET 0x0076
-#define CMD_802_11_TX_RATE_QUERY 0x007f
-#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_OLD 0x00a3
-#define CMD_MESH_CONFIG 0x00ac
-#define CMD_SET_BOOT2_VER 0x00a5
-#define CMD_FUNC_INIT 0x00a9
-#define CMD_FUNC_SHUTDOWN 0x00aa
-#define CMD_802_11_BEACON_CTRL 0x00b0
+#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_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_DEEP_SLEEP 0x003e
+#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_GSPI_BUS_CONFIG 0x005a
+#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_PA_CFG 0x0073
+#define CMD_802_11_FW_WAKE_METHOD 0x0074
+#define CMD_802_11_SUBSCRIBE_EVENT 0x0075
+#define CMD_802_11_RATE_ADAPT_RATESET 0x0076
+#define CMD_802_11_TX_RATE_QUERY 0x007f
+#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_OLD 0x00a3
+#define CMD_MESH_CONFIG 0x00ac
+#define CMD_SET_BOOT2_VER 0x00a5
+#define CMD_FUNC_INIT 0x00a9
+#define CMD_FUNC_SHUTDOWN 0x00aa
+#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_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_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 CMD_ACT_GET 0x0000
+#define CMD_ACT_SET 0x0001
/* 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_ACT_ADD 0x0002
+#define CMD_ACT_REMOVE 0x0004
-#define CMD_NUM_OF_WEP_KEYS 4
+#define CMD_TYPE_WEP_40_BIT 0x01
+#define CMD_TYPE_WEP_104_BIT 0x02
-#define CMD_WEP_KEY_INDEX_MASK 0x3fff
+#define CMD_NUM_OF_WEP_KEYS 4
-/* Define action or option for CMD_802_11_RESET */
-#define CMD_ACT_HALT 0x0003
+#define CMD_WEP_KEY_INDEX_MASK 0x3fff
/* 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 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_TYPE_ACTIVE 0x0000
+#define CMD_SCAN_TYPE_PASSIVE 0x0001
-#define CMD_SCAN_RADIO_TYPE_BG 0
+#define CMD_SCAN_RADIO_TYPE_BG 0
-#define CMD_SCAN_PROBE_DELAY_TIME 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 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
/* 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 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 RADIO_PREAMBLE_LONG 0x00
-#define RADIO_PREAMBLE_SHORT 0x02
-#define RADIO_PREAMBLE_AUTO 0x04
+#define RADIO_PREAMBLE_LONG 0x00
+#define RADIO_PREAMBLE_SHORT 0x02
+#define RADIO_PREAMBLE_AUTO 0x04
/* 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 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_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 CMD_ACT_SET_TX_AUTO 0x0000
+#define CMD_ACT_SET_TX_FIX_RATE 0x0001
+#define CMD_ACT_GET_TX_RATE 0x0002
/* 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
+#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 CMD_WAKE_METHOD_UNCHANGED 0x0000
+#define CMD_WAKE_METHOD_COMMAND_INT 0x0001
+#define CMD_WAKE_METHOD_GPIO 0x0002
/* Object IDs for CMD_802_11_SNMP_MIB */
-#define SNMP_MIB_OID_BSS_TYPE 0x0000
-#define SNMP_MIB_OID_OP_RATE_SET 0x0001
-#define SNMP_MIB_OID_BEACON_PERIOD 0x0002 /* Reserved on v9+ */
-#define SNMP_MIB_OID_DTIM_PERIOD 0x0003 /* Reserved on v9+ */
-#define SNMP_MIB_OID_ASSOC_TIMEOUT 0x0004 /* Reserved on v9+ */
-#define SNMP_MIB_OID_RTS_THRESHOLD 0x0005
-#define SNMP_MIB_OID_SHORT_RETRY_LIMIT 0x0006
-#define SNMP_MIB_OID_LONG_RETRY_LIMIT 0x0007
-#define SNMP_MIB_OID_FRAG_THRESHOLD 0x0008
-#define SNMP_MIB_OID_11D_ENABLE 0x0009
-#define SNMP_MIB_OID_11H_ENABLE 0x000A
+#define SNMP_MIB_OID_BSS_TYPE 0x0000
+#define SNMP_MIB_OID_OP_RATE_SET 0x0001
+#define SNMP_MIB_OID_BEACON_PERIOD 0x0002 /* Reserved on v9+ */
+#define SNMP_MIB_OID_DTIM_PERIOD 0x0003 /* Reserved on v9+ */
+#define SNMP_MIB_OID_ASSOC_TIMEOUT 0x0004 /* Reserved on v9+ */
+#define SNMP_MIB_OID_RTS_THRESHOLD 0x0005
+#define SNMP_MIB_OID_SHORT_RETRY_LIMIT 0x0006
+#define SNMP_MIB_OID_LONG_RETRY_LIMIT 0x0007
+#define SNMP_MIB_OID_FRAG_THRESHOLD 0x0008
+#define SNMP_MIB_OID_11D_ENABLE 0x0009
+#define SNMP_MIB_OID_11H_ENABLE 0x000A
/* Define action or option for CMD_BT_ACCESS */
enum cmd_bt_access_opts {
@@ -302,4 +291,672 @@ enum cmd_mesh_config_types {
#define MACREG_INT_CODE_MESH_AUTO_STARTED 35
#define MACREG_INT_CODE_FIRMWARE_READY 48
+
+/* 802.11-related definitions */
+
+/* TxPD descriptor */
+struct txpd {
+ /* union to cope up with later FW revisions */
+ union {
+ /* Current Tx packet status */
+ __le32 tx_status;
+ struct {
+ /* BSS type: client, AP, etc. */
+ u8 bss_type;
+ /* BSS number */
+ u8 bss_num;
+ /* Reserved */
+ __le16 reserved;
+ } bss;
+ } u;
+ /* 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 (units = 2ms) */
+ u8 pktdelay_2ms;
+ /* reserved */
+ u8 reserved1;
+} __attribute__ ((packed));
+
+/* RxPD Descriptor */
+struct rxpd {
+ /* union to cope up with later FW revisions */
+ union {
+ /* Current Rx packet status */
+ __le16 status;
+ struct {
+ /* BSS type: client, AP, etc. */
+ u8 bss_type;
+ /* BSS number */
+ u8 bss_num;
+ } __attribute__ ((packed)) bss;
+ } __attribute__ ((packed)) u;
+
+ /* 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];
+} __attribute__ ((packed));
+
+struct cmd_header {
+ __le16 command;
+ __le16 size;
+ __le16 seqnum;
+ __le16 result;
+} __attribute__ ((packed));
+
+/* 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;
+} __attribute__ ((packed));
+
+/*
+ * 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_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];
+} __attribute__ ((packed));
+
+/*
+ * 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];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_scan_rsp {
+ struct cmd_header hdr;
+
+ __le16 bssdescriptsize;
+ uint8_t nr_sets;
+ uint8_t bssdesc_and_tlvbuffer[0];
+} __attribute__ ((packed));
+
+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;
+} __attribute__ ((packed));
+
+struct cmd_ds_mac_control {
+ struct cmd_header hdr;
+ __le16 action;
+ u16 reserved;
+} __attribute__ ((packed));
+
+struct cmd_ds_mac_multicast_adr {
+ struct cmd_header hdr;
+ __le16 action;
+ __le16 nr_of_adrs;
+ u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_authenticate {
+ struct cmd_header hdr;
+
+ u8 bssid[ETH_ALEN];
+ u8 authtype;
+ u8 reserved[10];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_deauthenticate {
+ struct cmd_header hdr;
+
+ u8 macaddr[ETH_ALEN];
+ __le16 reasoncode;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_associate {
+ struct cmd_header hdr;
+
+ u8 bssid[6];
+ __le16 capability;
+ __le16 listeninterval;
+ __le16 bcnperiod;
+ u8 dtimperiod;
+ u8 iebuf[512]; /* Enough for required and most optional IEs */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_associate_response {
+ struct cmd_header hdr;
+
+ __le16 capability;
+ __le16 statuscode;
+ __le16 aid;
+ u8 iebuf[512];
+} __attribute__ ((packed));
+
+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];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_snmp_mib {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 oid;
+ __le16 bufsize;
+ u8 value[128];
+} __attribute__ ((packed));
+
+struct cmd_ds_mac_reg_access {
+ __le16 action;
+ __le16 offset;
+ __le32 value;
+} __attribute__ ((packed));
+
+struct cmd_ds_bbp_reg_access {
+ __le16 action;
+ __le16 offset;
+ u8 value;
+ u8 reserved[3];
+} __attribute__ ((packed));
+
+struct cmd_ds_rf_reg_access {
+ __le16 action;
+ __le16 offset;
+ u8 value;
+ u8 reserved[3];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_radio_control {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 control;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_beacon_control {
+ __le16 action;
+ __le16 beacon_enable;
+ __le16 beacon_period;
+} __attribute__ ((packed));
+
+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;
+} __attribute__ ((packed));
+
+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 */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rssi {
+ /* weighting factor */
+ __le16 N;
+
+ __le16 reserved_0;
+ __le16 reserved_1;
+ __le16 reserved_2;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rssi_rsp {
+ __le16 SNR;
+ __le16 noisefloor;
+ __le16 avgSNR;
+ __le16 avgnoisefloor;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_mac_address {
+ struct cmd_header hdr;
+
+ __le16 action;
+ u8 macadd[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rf_tx_power {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 curlevel;
+ s8 maxlevel;
+ s8 minlevel;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_monitor_mode {
+ __le16 action;
+ __le16 mode;
+} __attribute__ ((packed));
+
+struct cmd_ds_set_boot2_ver {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 version;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_fw_wake_method {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 method;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ps_mode {
+ __le16 action;
+ __le16 nullpktinterval;
+ __le16 multipledtim;
+ __le16 reserved;
+ __le16 locallisteninterval;
+} __attribute__ ((packed));
+
+struct cmd_confirm_sleep {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 nullpktinterval;
+ __le16 multipledtim;
+ __le16 reserved;
+ __le16 locallisteninterval;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_data_rate {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 reserved;
+ u8 rates[MAX_RATES];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rate_adapt_rateset {
+ struct cmd_header hdr;
+ __le16 action;
+ __le16 enablehwauto;
+ __le16 bitmap;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_start {
+ struct cmd_header hdr;
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 bsstype;
+ __le16 beaconperiod;
+ u8 dtimperiod; /* Reserved on v9 and later */
+ struct ieee_ie_ibss_param_set ibss;
+ u8 reserved1[4];
+ struct ieee_ie_ds_param_set ds;
+ u8 reserved2[4];
+ __le16 probedelay; /* Reserved on v9 and later */
+ __le16 capability;
+ u8 rates[MAX_RATES];
+ u8 tlv_memory_size_pad[100];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_result {
+ struct cmd_header hdr;
+
+ u8 pad[3];
+ u8 bssid[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct adhoc_bssdesc {
+ u8 bssid[ETH_ALEN];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 type;
+ __le16 beaconperiod;
+ u8 dtimperiod;
+ __le64 timestamp;
+ __le64 localtime;
+ struct ieee_ie_ds_param_set ds;
+ u8 reserved1[4];
+ struct ieee_ie_ibss_param_set ibss;
+ u8 reserved2[4];
+ __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 cmd_header hdr;
+
+ struct adhoc_bssdesc bss;
+ __le16 failtimeout; /* Reserved on v9 and later */
+ __le16 probedelay; /* Reserved on v9 and later */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_stop {
+ struct cmd_header hdr;
+} __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];
+} __attribute__ ((packed));
+
+#define MAX_WOL_RULES 16
+
+struct host_wol_rule {
+ uint8_t rule_no;
+ uint8_t rule_ops;
+ __le16 sig_offset;
+ __le16 sig_length;
+ __le16 reserve;
+ __be32 sig_mask;
+ __be32 signature;
+} __attribute__ ((packed));
+
+struct wol_config {
+ uint8_t action;
+ uint8_t pattern;
+ uint8_t no_rules_in_cmd;
+ uint8_t result;
+ struct host_wol_rule rule[MAX_WOL_RULES];
+} __attribute__ ((packed));
+
+struct cmd_ds_host_sleep {
+ struct cmd_header hdr;
+ __le32 criteria;
+ uint8_t gpio;
+ uint16_t gap;
+ struct wol_config wol_conf;
+} __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 {
+ struct cmd_header hdr;
+
+ __le16 action;
+ uint8_t enable;
+ int8_t P0;
+ int8_t P1;
+ int8_t P2;
+ uint8_t usesnr;
+} __attribute__ ((packed));
+
+
+struct cmd_ds_802_11_pa_cfg {
+ struct cmd_header hdr;
+
+ __le16 action;
+ uint8_t enable;
+ int8_t P0;
+ int8_t P1;
+ int8_t P2;
+} __attribute__ ((packed));
+
+
+struct cmd_ds_802_11_led_ctrl {
+ __le16 action;
+ __le16 numled;
+ u8 data[256];
+} __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_monitor_mode monitor;
+ struct cmd_ds_802_11_rssi rssi;
+ struct cmd_ds_802_11_rssi_rsp rssirsp;
+ 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_11_tpc_cfg tpccfg;
+ struct cmd_ds_802_11_afc afc;
+ struct cmd_ds_802_11_led_ctrl ledgpio;
+
+ struct cmd_ds_bt_access bt;
+ struct cmd_ds_fwt_access fwt;
+ struct cmd_ds_802_11_beacon_control bcn_ctrl;
+ } params;
+} __attribute__ ((packed));
+
#endif
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
deleted file mode 100644
index c8a1998d474..00000000000
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ /dev/null
@@ -1,800 +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 {
- /* union to cope up with later FW revisions */
- union {
- /* Current Tx packet status */
- __le32 tx_status;
- struct {
- /* BSS type: client, AP, etc. */
- u8 bss_type;
- /* BSS number */
- u8 bss_num;
- /* Reserved */
- __le16 reserved;
- } bss;
- } u;
- /* 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;
-} __attribute__ ((packed));
-
-/* RxPD Descriptor */
-struct rxpd {
- /* union to cope up with later FW revisions */
- union {
- /* Current Rx packet status */
- __le16 status;
- struct {
- /* BSS type: client, AP, etc. */
- u8 bss_type;
- /* BSS number */
- u8 bss_num;
- } __attribute__ ((packed)) bss;
- } __attribute__ ((packed)) u;
-
- /* 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];
-} __attribute__ ((packed));
-
-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;
-} __attribute__ ((packed));
-
-/* Define general data structure */
-/* cmd_DS_GEN */
-struct cmd_ds_gen {
- __le16 command;
- __le16 size;
- __le16 seqnum;
- __le16 result;
- void *cmdresp[0];
-} __attribute__ ((packed));
-
-#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_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];
-} __attribute__ ((packed));
-
-/*
- * 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
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_scan_rsp {
- struct cmd_header hdr;
-
- __le16 bssdescriptsize;
- uint8_t nr_sets;
- uint8_t bssdesc_and_tlvbuffer[0];
-} __attribute__ ((packed));
-
-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;
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_control {
- struct cmd_header hdr;
- __le16 action;
- u16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_multicast_adr {
- struct cmd_header hdr;
- __le16 action;
- __le16 nr_of_adrs;
- u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
-} __attribute__ ((packed));
-
-struct cmd_ds_gspi_bus_config {
- struct cmd_header hdr;
- __le16 action;
- __le16 bus_delay_mode;
- __le16 host_time_delay_to_read_port;
- __le16 host_time_delay_to_read_register;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_authenticate {
- struct cmd_header hdr;
-
- u8 bssid[ETH_ALEN];
- u8 authtype;
- u8 reserved[10];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_deauthenticate {
- struct cmd_header hdr;
-
- u8 macaddr[ETH_ALEN];
- __le16 reasoncode;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_associate {
- struct cmd_header hdr;
-
- u8 bssid[6];
- __le16 capability;
- __le16 listeninterval;
- __le16 bcnperiod;
- u8 dtimperiod;
- u8 iebuf[512]; /* Enough for required and most optional IEs */
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_associate_response {
- struct cmd_header hdr;
-
- __le16 capability;
- __le16 statuscode;
- __le16 aid;
- u8 iebuf[512];
-} __attribute__ ((packed));
-
-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];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_3_get_stat {
- __le32 xmitok;
- __le32 rcvok;
- __le32 xmiterror;
- __le32 rcverror;
- __le32 rcvnobuffer;
- __le32 rcvcrcerror;
-} __attribute__ ((packed));
-
-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;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_snmp_mib {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 oid;
- __le16 bufsize;
- u8 value[128];
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_reg_map {
- __le16 buffersize;
- u8 regmap[128];
- __le16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_bbp_reg_map {
- __le16 buffersize;
- u8 regmap[128];
- __le16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_rf_reg_map {
- __le16 buffersize;
- u8 regmap[64];
- __le16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_reg_access {
- __le16 action;
- __le16 offset;
- __le32 value;
-} __attribute__ ((packed));
-
-struct cmd_ds_bbp_reg_access {
- __le16 action;
- __le16 offset;
- u8 value;
- u8 reserved[3];
-} __attribute__ ((packed));
-
-struct cmd_ds_rf_reg_access {
- __le16 action;
- __le16 offset;
- u8 value;
- u8 reserved[3];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_radio_control {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 control;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_beacon_control {
- __le16 action;
- __le16 beacon_enable;
- __le16 beacon_period;
-} __attribute__ ((packed));
-
-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;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_inactivity_timeout {
- struct cmd_header hdr;
-
- /* ACT_GET/ACT_SET */
- __le16 action;
-
- /* Inactivity timeout in msec */
- __le16 timeout;
-} __attribute__ ((packed));
-
-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 */
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rssi {
- /* weighting factor */
- __le16 N;
-
- __le16 reserved_0;
- __le16 reserved_1;
- __le16 reserved_2;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rssi_rsp {
- __le16 SNR;
- __le16 noisefloor;
- __le16 avgSNR;
- __le16 avgnoisefloor;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_mac_address {
- struct cmd_header hdr;
-
- __le16 action;
- u8 macadd[ETH_ALEN];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rf_tx_power {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 curlevel;
- s8 maxlevel;
- s8 minlevel;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rf_antenna {
- __le16 action;
-
- /* Number of antennas or 0xffff(diversity) */
- __le16 antennamode;
-
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_monitor_mode {
- __le16 action;
- __le16 mode;
-} __attribute__ ((packed));
-
-struct cmd_ds_set_boot2_ver {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 version;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_fw_wake_method {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 method;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_sleep_period {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 period;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ps_mode {
- __le16 action;
- __le16 nullpktinterval;
- __le16 multipledtim;
- __le16 reserved;
- __le16 locallisteninterval;
-} __attribute__ ((packed));
-
-struct cmd_confirm_sleep {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 nullpktinterval;
- __le16 multipledtim;
- __le16 reserved;
- __le16 locallisteninterval;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_data_rate {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 reserved;
- u8 rates[MAX_RATES];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rate_adapt_rateset {
- struct cmd_header hdr;
- __le16 action;
- __le16 enablehwauto;
- __le16 bitmap;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ad_hoc_start {
- struct cmd_header hdr;
-
- u8 ssid[IW_ESSID_MAX_SIZE];
- u8 bsstype;
- __le16 beaconperiod;
- u8 dtimperiod; /* Reserved on v9 and later */
- struct ieee_ie_ibss_param_set ibss;
- u8 reserved1[4];
- struct ieee_ie_ds_param_set ds;
- u8 reserved2[4];
- __le16 probedelay; /* Reserved on v9 and later */
- __le16 capability;
- u8 rates[MAX_RATES];
- u8 tlv_memory_size_pad[100];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ad_hoc_result {
- struct cmd_header hdr;
-
- u8 pad[3];
- u8 bssid[ETH_ALEN];
-} __attribute__ ((packed));
-
-struct adhoc_bssdesc {
- u8 bssid[ETH_ALEN];
- u8 ssid[IW_ESSID_MAX_SIZE];
- u8 type;
- __le16 beaconperiod;
- u8 dtimperiod;
- __le64 timestamp;
- __le64 localtime;
- struct ieee_ie_ds_param_set ds;
- u8 reserved1[4];
- struct ieee_ie_ibss_param_set ibss;
- u8 reserved2[4];
- __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 cmd_header hdr;
-
- struct adhoc_bssdesc bss;
- __le16 failtimeout; /* Reserved on v9 and later */
- __le16 probedelay; /* Reserved on v9 and later */
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ad_hoc_stop {
- struct cmd_header hdr;
-} __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];
-} __attribute__ ((packed));
-
-#define MAX_WOL_RULES 16
-
-struct host_wol_rule {
- uint8_t rule_no;
- uint8_t rule_ops;
- __le16 sig_offset;
- __le16 sig_length;
- __le16 reserve;
- __be32 sig_mask;
- __be32 signature;
-} __attribute__ ((packed));
-
-struct wol_config {
- uint8_t action;
- uint8_t pattern;
- uint8_t no_rules_in_cmd;
- uint8_t result;
- struct host_wol_rule rule[MAX_WOL_RULES];
-} __attribute__ ((packed));
-
-struct cmd_ds_host_sleep {
- struct cmd_header hdr;
- __le32 criteria;
- uint8_t gpio;
- uint16_t gap;
- struct wol_config wol_conf;
-} __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 {
- struct cmd_header hdr;
-
- __le16 action;
- uint8_t enable;
- int8_t P0;
- int8_t P1;
- int8_t P2;
- uint8_t usesnr;
-} __attribute__ ((packed));
-
-
-struct cmd_ds_802_11_pa_cfg {
- struct cmd_header hdr;
-
- __le16 action;
- uint8_t enable;
- int8_t P0;
- int8_t P1;
- int8_t P2;
-} __attribute__ ((packed));
-
-
-struct cmd_ds_802_11_led_ctrl {
- __le16 action;
- __le16 numled;
- u8 data[256];
-} __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_get_stat gstat;
- struct cmd_ds_802_3_get_stat gstat_8023;
- struct cmd_ds_802_11_rf_antenna rant;
- struct cmd_ds_802_11_monitor_mode monitor;
- struct cmd_ds_802_11_rssi rssi;
- struct cmd_ds_802_11_rssi_rsp rssirsp;
- 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
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index b1d84592b95..1f6cb58dd66 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -48,6 +48,7 @@
MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("libertas_cs_helper.fw");
@@ -932,6 +933,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
card->priv = priv;
priv->card = card;
priv->hw_host_to_card = if_cs_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
priv->fw_ready = 1;
/* Now actually get the IRQ */
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 485a8d40652..09fcfad742e 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -99,6 +99,12 @@ static struct if_sdio_model if_sdio_models[] = {
.firmware = "sd8688.bin",
},
};
+MODULE_FIRMWARE("sd8385_helper.bin");
+MODULE_FIRMWARE("sd8385.bin");
+MODULE_FIRMWARE("sd8686_helper.bin");
+MODULE_FIRMWARE("sd8686.bin");
+MODULE_FIRMWARE("sd8688_helper.bin");
+MODULE_FIRMWARE("sd8688.bin");
struct if_sdio_packet {
struct if_sdio_packet *next;
@@ -831,6 +837,58 @@ out:
return ret;
}
+static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
+{
+ int ret = -1;
+ struct cmd_header cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ lbs_deb_sdio("send DEEP_SLEEP command\n");
+ ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
+ lbs_cmd_copyback, (unsigned long) &cmd);
+ if (ret)
+ lbs_pr_err("DEEP_SLEEP cmd failed\n");
+
+ mdelay(200);
+ return ret;
+}
+
+static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+ sdio_claim_host(card->func);
+
+ sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
+ if (ret)
+ lbs_pr_err("sdio_writeb failed!\n");
+
+ sdio_release_host(card->func);
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+}
+
+static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+ sdio_claim_host(card->func);
+
+ sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
+ if (ret)
+ lbs_pr_err("sdio_writeb failed!\n");
+
+ sdio_release_host(card->func);
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+
+}
+
/*******************************************************************/
/* SDIO callbacks */
/*******************************************************************/
@@ -859,6 +917,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
* Ignore the define name, this really means the card has
* successfully received the command.
*/
+ card->priv->is_activity_detected = 1;
if (cause & IF_SDIO_H_INT_DNLD)
lbs_host_to_card_done(card->priv);
@@ -998,6 +1057,9 @@ static int if_sdio_probe(struct sdio_func *func,
priv->card = card;
priv->hw_host_to_card = if_sdio_host_to_card;
+ priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
+ priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
+ priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
priv->fw_ready = 1;
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
index 60c9b2fcef0..12179c1dc9c 100644
--- a/drivers/net/wireless/libertas/if_sdio.h
+++ b/drivers/net/wireless/libertas/if_sdio.h
@@ -51,5 +51,6 @@
#define IF_SDIO_EVENT 0x80fc
#define IF_SDIO_BLOCK_SIZE 256
-
+#define CONFIGURATION_REG 0x03
+#define HOST_POWER_UP (0x1U << 1)
#endif
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 5b3672c4d0c..bf4bfbae622 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -32,12 +32,6 @@
#include "dev.h"
#include "if_spi.h"
-struct if_spi_packet {
- struct list_head list;
- u16 blen;
- u8 buffer[0] __attribute__((aligned(4)));
-};
-
struct if_spi_card {
struct spi_device *spi;
struct lbs_private *priv;
@@ -66,33 +60,10 @@ struct if_spi_card {
struct semaphore spi_thread_terminated;
u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE];
-
- /* A buffer of incoming packets from libertas core.
- * Since we can't sleep in hw_host_to_card, we have to buffer
- * them. */
- struct list_head cmd_packet_list;
- struct list_head data_packet_list;
-
- /* Protects cmd_packet_list and data_packet_list */
- spinlock_t buffer_lock;
};
static void free_if_spi_card(struct if_spi_card *card)
{
- struct list_head *cursor, *next;
- struct if_spi_packet *packet;
-
- BUG_ON(card->run_thread);
- list_for_each_safe(cursor, next, &card->cmd_packet_list) {
- packet = container_of(cursor, struct if_spi_packet, list);
- list_del(&packet->list);
- kfree(packet);
- }
- list_for_each_safe(cursor, next, &card->data_packet_list) {
- packet = container_of(cursor, struct if_spi_packet, list);
- list_del(&packet->list);
- kfree(packet);
- }
spi_set_drvdata(card->spi, NULL);
kfree(card);
}
@@ -774,40 +745,6 @@ out:
return err;
}
-/* Move data or a command from the host to the card. */
-static void if_spi_h2c(struct if_spi_card *card,
- struct if_spi_packet *packet, int type)
-{
- int err = 0;
- u16 int_type, port_reg;
-
- switch (type) {
- case MVMS_DAT:
- int_type = IF_SPI_CIC_TX_DOWNLOAD_OVER;
- port_reg = IF_SPI_DATA_RDWRPORT_REG;
- break;
- case MVMS_CMD:
- int_type = IF_SPI_CIC_CMD_DOWNLOAD_OVER;
- port_reg = IF_SPI_CMD_RDWRPORT_REG;
- break;
- default:
- lbs_pr_err("can't transfer buffer of type %d\n", type);
- err = -EINVAL;
- goto out;
- }
-
- /* Write the data to the card */
- err = spu_write(card, port_reg, packet->buffer, packet->blen);
- if (err)
- goto out;
-
-out:
- kfree(packet);
-
- if (err)
- lbs_pr_err("%s: error %d\n", __func__, err);
-}
-
/* Inform the host about a card event */
static void if_spi_e2h(struct if_spi_card *card)
{
@@ -837,8 +774,6 @@ static int lbs_spi_thread(void *data)
int err;
struct if_spi_card *card = data;
u16 hiStatus;
- unsigned long flags;
- struct if_spi_packet *packet;
while (1) {
/* Wait to be woken up by one of two things. First, our ISR
@@ -877,43 +812,9 @@ static int lbs_spi_thread(void *data)
if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY ||
(card->priv->psstate != PS_STATE_FULL_POWER &&
(hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) {
- /* This means two things. First of all,
- * if there was a previous command sent, the card has
- * successfully received it.
- * Secondly, it is now ready to download another
- * command.
- */
lbs_host_to_card_done(card->priv);
-
- /* Do we have any command packets from the host to
- * send? */
- packet = NULL;
- spin_lock_irqsave(&card->buffer_lock, flags);
- if (!list_empty(&card->cmd_packet_list)) {
- packet = (struct if_spi_packet *)(card->
- cmd_packet_list.next);
- list_del(&packet->list);
- }
- spin_unlock_irqrestore(&card->buffer_lock, flags);
-
- if (packet)
- if_spi_h2c(card, packet, MVMS_CMD);
}
- if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) {
- /* Do we have any data packets from the host to
- * send? */
- packet = NULL;
- spin_lock_irqsave(&card->buffer_lock, flags);
- if (!list_empty(&card->data_packet_list)) {
- packet = (struct if_spi_packet *)(card->
- data_packet_list.next);
- list_del(&packet->list);
- }
- spin_unlock_irqrestore(&card->buffer_lock, flags);
- if (packet)
- if_spi_h2c(card, packet, MVMS_DAT);
- }
if (hiStatus & IF_SPI_HIST_CARD_EVENT)
if_spi_e2h(card);
@@ -942,40 +843,18 @@ static int if_spi_host_to_card(struct lbs_private *priv,
u8 type, u8 *buf, u16 nb)
{
int err = 0;
- unsigned long flags;
struct if_spi_card *card = priv->card;
- struct if_spi_packet *packet;
- u16 blen;
lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb);
- if (nb == 0) {
- lbs_pr_err("%s: invalid size requested: %d\n", __func__, nb);
- err = -EINVAL;
- goto out;
- }
- blen = ALIGN(nb, 4);
- packet = kzalloc(sizeof(struct if_spi_packet) + blen, GFP_ATOMIC);
- if (!packet) {
- err = -ENOMEM;
- goto out;
- }
- packet->blen = blen;
- memcpy(packet->buffer, buf, nb);
- memset(packet->buffer + nb, 0, blen - nb);
+ nb = ALIGN(nb, 4);
switch (type) {
case MVMS_CMD:
- priv->dnld_sent = DNLD_CMD_SENT;
- spin_lock_irqsave(&card->buffer_lock, flags);
- list_add_tail(&packet->list, &card->cmd_packet_list);
- spin_unlock_irqrestore(&card->buffer_lock, flags);
+ err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG, buf, nb);
break;
case MVMS_DAT:
- priv->dnld_sent = DNLD_DATA_SENT;
- spin_lock_irqsave(&card->buffer_lock, flags);
- list_add_tail(&packet->list, &card->data_packet_list);
- spin_unlock_irqrestore(&card->buffer_lock, flags);
+ err = spu_write(card, IF_SPI_DATA_RDWRPORT_REG, buf, nb);
break;
default:
lbs_pr_err("can't transfer buffer of type %d", type);
@@ -983,9 +862,6 @@ static int if_spi_host_to_card(struct lbs_private *priv,
break;
}
- /* Wake up the spi thread */
- up(&card->spi_ready);
-out:
lbs_deb_leave_args(LBS_DEB_SPI, "err=%d", err);
return err;
}
@@ -1026,6 +902,10 @@ static int if_spi_calculate_fw_names(u16 card_id,
chip_id_to_device_name[i].name);
return 0;
}
+MODULE_FIRMWARE("libertas/gspi8385_hlp.bin");
+MODULE_FIRMWARE("libertas/gspi8385.bin");
+MODULE_FIRMWARE("libertas/gspi8686_hlp.bin");
+MODULE_FIRMWARE("libertas/gspi8686.bin");
static int __devinit if_spi_probe(struct spi_device *spi)
{
@@ -1062,9 +942,6 @@ static int __devinit if_spi_probe(struct spi_device *spi)
sema_init(&card->spi_ready, 0);
sema_init(&card->spi_thread_terminated, 0);
- INIT_LIST_HEAD(&card->cmd_packet_list);
- INIT_LIST_HEAD(&card->data_packet_list);
- spin_lock_init(&card->buffer_lock);
/* Initialize the SPI Interface Unit */
err = spu_init(card, pdata->use_dummy_writes);
@@ -1117,6 +994,9 @@ static int __devinit if_spi_probe(struct spi_device *spi)
card->priv = priv;
priv->card = card;
priv->hw_host_to_card = if_spi_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
priv->fw_ready = 1;
/* Initialize interrupt handling stuff. */
@@ -1138,6 +1018,9 @@ static int __devinit if_spi_probe(struct spi_device *spi)
goto terminate_thread;
}
+ /* poke the IRQ handler so that we don't miss the first interrupt */
+ up(&card->spi_ready);
+
/* Start the card.
* This will call register_netdev, and we'll start
* getting interrupts... */
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 3fac4efa5ac..65e174595d1 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -28,6 +28,8 @@
static char *lbs_fw_name = "usb8388.bin";
module_param_named(fw_name, lbs_fw_name, charp, 0644);
+MODULE_FIRMWARE("usb8388.bin");
+
static struct usb_device_id if_usb_table[] = {
/* Enter the device signature inside */
{ USB_DEVICE(0x1286, 0x2001) },
@@ -300,6 +302,9 @@ static int if_usb_probe(struct usb_interface *intf,
cardp->priv->fw_ready = 1;
priv->hw_host_to_card = if_usb_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
#ifdef CONFIG_OLPC
if (machine_is_olpc())
priv->reset_card = if_usb_reset_olpc_card;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 87b4e497faa..db38a5a719f 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -14,11 +14,13 @@
#include <linux/stddef.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "host.h"
#include "decl.h"
#include "dev.h"
#include "wext.h"
+#include "cfg.h"
#include "debugfs.h"
#include "scan.h"
#include "assoc.h"
@@ -43,119 +45,6 @@ module_param_named(libertas_debug, lbs_debug, int, 0644);
struct cmd_confirm_sleep confirm_sleep;
-#define LBS_TX_PWR_DEFAULT 20 /*100mW */
-#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */
-#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */
-#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */
-#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */
-
-/* Format { channel, frequency (MHz), maxtxpower } */
-/* band: 'B/G', region: USA FCC/Canada IC */
-static struct chan_freq_power channel_freq_power_US_BG[] = {
- {1, 2412, LBS_TX_PWR_US_DEFAULT},
- {2, 2417, LBS_TX_PWR_US_DEFAULT},
- {3, 2422, LBS_TX_PWR_US_DEFAULT},
- {4, 2427, LBS_TX_PWR_US_DEFAULT},
- {5, 2432, LBS_TX_PWR_US_DEFAULT},
- {6, 2437, LBS_TX_PWR_US_DEFAULT},
- {7, 2442, LBS_TX_PWR_US_DEFAULT},
- {8, 2447, LBS_TX_PWR_US_DEFAULT},
- {9, 2452, LBS_TX_PWR_US_DEFAULT},
- {10, 2457, LBS_TX_PWR_US_DEFAULT},
- {11, 2462, LBS_TX_PWR_US_DEFAULT}
-};
-
-/* band: 'B/G', region: Europe ETSI */
-static struct chan_freq_power channel_freq_power_EU_BG[] = {
- {1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
- {2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
- {3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
- {4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
- {5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
- {6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
- {7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
- {8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
- {9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
- {10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
- {11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
- {12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
- {13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
-};
-
-/* band: 'B/G', region: Spain */
-static struct chan_freq_power channel_freq_power_SPN_BG[] = {
- {10, 2457, LBS_TX_PWR_DEFAULT},
- {11, 2462, LBS_TX_PWR_DEFAULT}
-};
-
-/* band: 'B/G', region: France */
-static struct chan_freq_power channel_freq_power_FR_BG[] = {
- {10, 2457, LBS_TX_PWR_FR_DEFAULT},
- {11, 2462, LBS_TX_PWR_FR_DEFAULT},
- {12, 2467, LBS_TX_PWR_FR_DEFAULT},
- {13, 2472, LBS_TX_PWR_FR_DEFAULT}
-};
-
-/* band: 'B/G', region: Japan */
-static struct chan_freq_power channel_freq_power_JPN_BG[] = {
- {1, 2412, LBS_TX_PWR_JP_DEFAULT},
- {2, 2417, LBS_TX_PWR_JP_DEFAULT},
- {3, 2422, LBS_TX_PWR_JP_DEFAULT},
- {4, 2427, LBS_TX_PWR_JP_DEFAULT},
- {5, 2432, LBS_TX_PWR_JP_DEFAULT},
- {6, 2437, LBS_TX_PWR_JP_DEFAULT},
- {7, 2442, LBS_TX_PWR_JP_DEFAULT},
- {8, 2447, LBS_TX_PWR_JP_DEFAULT},
- {9, 2452, LBS_TX_PWR_JP_DEFAULT},
- {10, 2457, LBS_TX_PWR_JP_DEFAULT},
- {11, 2462, LBS_TX_PWR_JP_DEFAULT},
- {12, 2467, LBS_TX_PWR_JP_DEFAULT},
- {13, 2472, LBS_TX_PWR_JP_DEFAULT},
- {14, 2484, LBS_TX_PWR_JP_DEFAULT}
-};
-
-/**
- * the structure for channel, frequency and power
- */
-struct region_cfp_table {
- u8 region;
- struct chan_freq_power *cfp_BG;
- int cfp_no_BG;
-};
-
-/**
- * the structure for the mapping between region and CFP
- */
-static struct region_cfp_table region_cfp_table[] = {
- {0x10, /*US FCC */
- channel_freq_power_US_BG,
- ARRAY_SIZE(channel_freq_power_US_BG),
- }
- ,
- {0x20, /*CANADA IC */
- channel_freq_power_US_BG,
- ARRAY_SIZE(channel_freq_power_US_BG),
- }
- ,
- {0x30, /*EU*/ channel_freq_power_EU_BG,
- ARRAY_SIZE(channel_freq_power_EU_BG),
- }
- ,
- {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
- ARRAY_SIZE(channel_freq_power_SPN_BG),
- }
- ,
- {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
- ARRAY_SIZE(channel_freq_power_FR_BG),
- }
- ,
- {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
- ARRAY_SIZE(channel_freq_power_JPN_BG),
- }
- ,
-/*Add new region here */
-};
-
/**
* the table to keep region code
*/
@@ -163,13 +52,6 @@ u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
{ 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
/**
- * 802.11b/g supported bitrates (in 500Kb/s units)
- */
-u8 lbs_bg_rates[MAX_RATES] =
- { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0x00, 0x00 };
-
-/**
* FW rate table. FW refers to rates by their index in this table, not by the
* rate value itself. Values of 0x00 are
* reserved positions.
@@ -212,107 +94,9 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
return 0;
}
-/**
- * Attributes exported through sysfs
- */
-
-/**
- * @brief Get function for sysfs attribute anycast_mask
- */
-static ssize_t lbs_anycast_get(struct device *dev,
- struct device_attribute *attr, char * buf)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- struct cmd_ds_mesh_access mesh_access;
- int ret;
-
- memset(&mesh_access, 0, sizeof(mesh_access));
-
- ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
- if (ret)
- return ret;
-
- return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
-}
-
-/**
- * @brief Set function for sysfs attribute anycast_mask
- */
-static ssize_t lbs_anycast_set(struct device *dev,
- struct device_attribute *attr, const char * buf, size_t count)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- struct cmd_ds_mesh_access mesh_access;
- uint32_t datum;
- int ret;
-
- memset(&mesh_access, 0, sizeof(mesh_access));
- sscanf(buf, "%x", &datum);
- mesh_access.data[0] = cpu_to_le32(datum);
-
- ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
- if (ret)
- return ret;
-
- return strlen(buf);
-}
-
-/**
- * @brief Get function for sysfs attribute prb_rsp_limit
- */
-static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- struct cmd_ds_mesh_access mesh_access;
- int ret;
- u32 retry_limit;
-
- memset(&mesh_access, 0, sizeof(mesh_access));
- mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
-
- ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
- &mesh_access);
- if (ret)
- return ret;
-
- retry_limit = le32_to_cpu(mesh_access.data[1]);
- return snprintf(buf, 10, "%d\n", retry_limit);
-}
-
-/**
- * @brief Set function for sysfs attribute prb_rsp_limit
- */
-static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- struct cmd_ds_mesh_access mesh_access;
- int ret;
- unsigned long retry_limit;
-
- memset(&mesh_access, 0, sizeof(mesh_access));
- mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
-
- if (!strict_strtoul(buf, 10, &retry_limit))
- return -ENOTSUPP;
- if (retry_limit > 15)
- return -ENOTSUPP;
-
- mesh_access.data[1] = cpu_to_le32(retry_limit);
-
- ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
- &mesh_access);
- if (ret)
- return ret;
-
- return strlen(buf);
-}
static int lbs_add_rtap(struct lbs_private *priv);
static void lbs_remove_rtap(struct lbs_private *priv);
-static int lbs_add_mesh(struct lbs_private *priv);
-static void lbs_remove_mesh(struct lbs_private *priv);
/**
@@ -378,74 +162,7 @@ static ssize_t lbs_rtap_set(struct device *dev,
static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set );
/**
- * Get function for sysfs attribute mesh
- */
-static ssize_t lbs_mesh_get(struct device *dev,
- struct device_attribute *attr, char * buf)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
-}
-
-/**
- * Set function for sysfs attribute mesh
- */
-static ssize_t lbs_mesh_set(struct device *dev,
- struct device_attribute *attr, const char * buf, size_t count)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- int enable;
- int ret, action = CMD_ACT_MESH_CONFIG_STOP;
-
- sscanf(buf, "%x", &enable);
- enable = !!enable;
- if (enable == !!priv->mesh_dev)
- return count;
- if (enable)
- action = CMD_ACT_MESH_CONFIG_START;
- ret = lbs_mesh_config(priv, action, priv->curbssparams.channel);
- if (ret)
- return ret;
-
- if (enable)
- lbs_add_mesh(priv);
- else
- lbs_remove_mesh(priv);
-
- return count;
-}
-
-/**
- * lbs_mesh attribute to be exported per ethX interface
- * through sysfs (/sys/class/net/ethX/lbs_mesh)
- */
-static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
-
-/**
- * anycast_mask attribute to be exported per mshX interface
- * through sysfs (/sys/class/net/mshX/anycast_mask)
- */
-static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
-
-/**
- * prb_rsp_limit attribute to be exported per mshX interface
- * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
- */
-static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
- lbs_prb_rsp_limit_set);
-
-static struct attribute *lbs_mesh_sysfs_entries[] = {
- &dev_attr_anycast_mask.attr,
- &dev_attr_prb_rsp_limit.attr,
- NULL,
-};
-
-static struct attribute_group lbs_mesh_attr_group = {
- .attrs = lbs_mesh_sysfs_entries,
-};
-
-/**
- * @brief This function opens the ethX or mshX interface
+ * @brief This function opens the ethX interface
*
* @param dev A pointer to net_device structure
* @return 0 or -EBUSY if monitor mode active
@@ -464,18 +181,12 @@ static int lbs_dev_open(struct net_device *dev)
goto out;
}
- if (dev == priv->mesh_dev) {
- priv->mesh_open = 1;
- priv->mesh_connect_status = LBS_CONNECTED;
- netif_carrier_on(dev);
- } else {
- priv->infra_open = 1;
+ priv->infra_open = 1;
- if (priv->connect_status == LBS_CONNECTED)
- netif_carrier_on(dev);
- else
- netif_carrier_off(dev);
- }
+ if (priv->connect_status == LBS_CONNECTED)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
if (!priv->tx_pending_len)
netif_wake_queue(dev);
@@ -487,33 +198,6 @@ static int lbs_dev_open(struct net_device *dev)
}
/**
- * @brief This function closes the mshX interface
- *
- * @param dev A pointer to net_device structure
- * @return 0
- */
-static int lbs_mesh_stop(struct net_device *dev)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_MESH);
- spin_lock_irq(&priv->driver_lock);
-
- priv->mesh_open = 0;
- priv->mesh_connect_status = LBS_DISCONNECTED;
-
- netif_stop_queue(dev);
- netif_carrier_off(dev);
-
- spin_unlock_irq(&priv->driver_lock);
-
- schedule_work(&priv->mcast_work);
-
- lbs_deb_leave(LBS_DEB_MESH);
- return 0;
-}
-
-/**
* @brief This function closes the ethX interface
*
* @param dev A pointer to net_device structure
@@ -574,15 +258,17 @@ void lbs_host_to_card_done(struct lbs_private *priv)
priv->dnld_sent = DNLD_RES_RECEIVED;
/* Wake main thread if commands are pending */
- if (!priv->cur_cmd || priv->tx_pending_len > 0)
- wake_up_interruptible(&priv->waitq);
+ if (!priv->cur_cmd || priv->tx_pending_len > 0) {
+ if (!priv->wakeup_dev_required)
+ wake_up_interruptible(&priv->waitq);
+ }
spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_leave(LBS_DEB_THREAD);
}
EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
-static int lbs_set_mac_address(struct net_device *dev, void *addr)
+int lbs_set_mac_address(struct net_device *dev, void *addr)
{
int ret = 0;
struct lbs_private *priv = dev->ml_priv;
@@ -716,7 +402,7 @@ static void lbs_set_mcast_worker(struct work_struct *work)
lbs_deb_leave(LBS_DEB_NET);
}
-static void lbs_set_multicast_list(struct net_device *dev)
+void lbs_set_multicast_list(struct net_device *dev)
{
struct lbs_private *priv = dev->ml_priv;
@@ -770,7 +456,8 @@ static int lbs_thread(void *data)
shouldsleep = 0; /* We have a command response */
else if (priv->cur_cmd)
shouldsleep = 1; /* Can't send a command; one already running */
- else if (!list_empty(&priv->cmdpendingq))
+ else if (!list_empty(&priv->cmdpendingq) &&
+ !(priv->wakeup_dev_required))
shouldsleep = 0; /* We have a command to send */
else if (__kfifo_len(priv->event_fifo))
shouldsleep = 0; /* We have an event to process */
@@ -822,6 +509,26 @@ static int lbs_thread(void *data)
}
spin_unlock_irq(&priv->driver_lock);
+ /* Process hardware events, e.g. card removed, link lost */
+ spin_lock_irq(&priv->driver_lock);
+ while (__kfifo_len(priv->event_fifo)) {
+ u32 event;
+ __kfifo_get(priv->event_fifo, (unsigned char *) &event,
+ sizeof(event));
+ spin_unlock_irq(&priv->driver_lock);
+ lbs_process_event(priv, event);
+ spin_lock_irq(&priv->driver_lock);
+ }
+ spin_unlock_irq(&priv->driver_lock);
+
+ if (priv->wakeup_dev_required) {
+ lbs_deb_thread("Waking up device...\n");
+ /* Wake up device */
+ if (priv->exit_deep_sleep(priv))
+ lbs_deb_thread("Wakeup device failed\n");
+ continue;
+ }
+
/* command timeout stuff */
if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
@@ -849,18 +556,7 @@ static int lbs_thread(void *data)
}
priv->cmd_timed_out = 0;
- /* Process hardware events, e.g. card removed, link lost */
- spin_lock_irq(&priv->driver_lock);
- while (__kfifo_len(priv->event_fifo)) {
- u32 event;
- __kfifo_get(priv->event_fifo, (unsigned char *) &event,
- sizeof(event));
- spin_unlock_irq(&priv->driver_lock);
- lbs_process_event(priv, event);
- spin_lock_irq(&priv->driver_lock);
- }
- spin_unlock_irq(&priv->driver_lock);
if (!priv->fw_ready)
continue;
@@ -894,6 +590,9 @@ static int lbs_thread(void *data)
(priv->psstate == PS_STATE_PRE_SLEEP))
continue;
+ if (priv->is_deep_sleep)
+ continue;
+
/* Execute the next command */
if (!priv->dnld_sent && !priv->cur_cmd)
lbs_execute_next_command(priv);
@@ -928,6 +627,7 @@ static int lbs_thread(void *data)
}
del_timer(&priv->command_timer);
+ del_timer(&priv->auto_deepsleep_timer);
wake_up_all(&priv->cmd_pending);
lbs_deb_leave(LBS_DEB_THREAD);
@@ -1050,6 +750,62 @@ out:
lbs_deb_leave(LBS_DEB_CMD);
}
+/**
+ * This function put the device back to deep sleep mode when timer expires
+ * and no activity (command, event, data etc.) is detected.
+ */
+static void auto_deepsleep_timer_fn(unsigned long data)
+{
+ struct lbs_private *priv = (struct lbs_private *)data;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (priv->is_activity_detected) {
+ priv->is_activity_detected = 0;
+ } else {
+ if (priv->is_auto_deep_sleep_enabled &&
+ (!priv->wakeup_dev_required) &&
+ (priv->connect_status != LBS_CONNECTED)) {
+ lbs_deb_main("Entering auto deep sleep mode...\n");
+ ret = lbs_prepare_and_send_command(priv,
+ CMD_802_11_DEEP_SLEEP, 0,
+ 0, 0, NULL);
+ if (ret)
+ lbs_pr_err("Enter Deep Sleep command failed\n");
+ }
+ }
+ mod_timer(&priv->auto_deepsleep_timer , jiffies +
+ (priv->auto_deep_sleep_timeout * HZ)/1000);
+ lbs_deb_leave(LBS_DEB_CMD);
+}
+
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ priv->is_auto_deep_sleep_enabled = 1;
+ if (priv->is_deep_sleep)
+ priv->wakeup_dev_required = 1;
+ mod_timer(&priv->auto_deepsleep_timer ,
+ jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+ return 0;
+}
+
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ priv->is_auto_deep_sleep_enabled = 0;
+ priv->auto_deep_sleep_timeout = 0;
+ del_timer(&priv->auto_deepsleep_timer);
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+ return 0;
+}
+
static void lbs_sync_channel_worker(struct work_struct *work)
{
struct lbs_private *priv = container_of(work, struct lbs_private,
@@ -1092,18 +848,24 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->mesh_connect_status = LBS_DISCONNECTED;
priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
priv->mode = IW_MODE_INFRA;
- priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
+ priv->channel = DEFAULT_AD_HOC_CHANNEL;
priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
priv->radio_on = 1;
priv->enablehwauto = 1;
priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
priv->psmode = LBS802_11POWERMODECAM;
priv->psstate = PS_STATE_FULL_POWER;
+ priv->is_deep_sleep = 0;
+ priv->is_auto_deep_sleep_enabled = 0;
+ priv->wakeup_dev_required = 0;
+ init_waitqueue_head(&priv->ds_awake_q);
mutex_init(&priv->lock);
setup_timer(&priv->command_timer, command_timer_fn,
(unsigned long)priv);
+ setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
+ (unsigned long)priv);
INIT_LIST_HEAD(&priv->cmdfreeq);
INIT_LIST_HEAD(&priv->cmdpendingq);
@@ -1142,6 +904,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
if (priv->event_fifo)
kfifo_free(priv->event_fifo);
del_timer(&priv->command_timer);
+ del_timer(&priv->auto_deepsleep_timer);
kfree(priv->networks);
priv->networks = NULL;
@@ -1168,31 +931,41 @@ static const struct net_device_ops lbs_netdev_ops = {
*/
struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
{
- struct net_device *dev = NULL;
+ struct net_device *dev;
+ struct wireless_dev *wdev;
struct lbs_private *priv = NULL;
lbs_deb_enter(LBS_DEB_MAIN);
/* Allocate an Ethernet device and register it */
- dev = alloc_etherdev(sizeof(struct lbs_private));
- if (!dev) {
- lbs_pr_err("init wlanX device failed\n");
+ wdev = lbs_cfg_alloc(dmdev);
+ if (IS_ERR(wdev)) {
+ lbs_pr_err("cfg80211 init failed\n");
goto done;
}
- priv = netdev_priv(dev);
- dev->ml_priv = priv;
+ /* TODO? */
+ wdev->iftype = NL80211_IFTYPE_STATION;
+ priv = wdev_priv(wdev);
+ priv->wdev = wdev;
if (lbs_init_adapter(priv)) {
lbs_pr_err("failed to initialize adapter structure.\n");
- goto err_init_adapter;
+ goto err_wdev;
}
+ //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
+ dev = alloc_netdev(0, "wlan%d", ether_setup);
+ if (!dev) {
+ dev_err(dmdev, "no memory for network device instance\n");
+ goto err_adapter;
+ }
+
+ dev->ieee80211_ptr = wdev;
+ dev->ml_priv = priv;
+ SET_NETDEV_DEV(dev, dmdev);
+ wdev->netdev = dev;
priv->dev = dev;
- priv->card = card;
- priv->mesh_open = 0;
- priv->infra_open = 0;
- /* Setup the OS Interface to our functions */
dev->netdev_ops = &lbs_netdev_ops;
dev->watchdog_timeo = 5 * HZ;
dev->ethtool_ops = &lbs_ethtool_ops;
@@ -1201,7 +974,13 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
#endif
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
- SET_NETDEV_DEV(dev, dmdev);
+
+ // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ??
+
+
+ priv->card = card;
+ priv->infra_open = 0;
+
priv->rtap_net_dev = NULL;
strcpy(dev->name, "wlan%d");
@@ -1211,7 +990,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main");
if (IS_ERR(priv->main_thread)) {
lbs_deb_thread("Error creating main thread.\n");
- goto err_init_adapter;
+ goto err_ndev;
}
priv->work_thread = create_singlethread_workqueue("lbs_worker");
@@ -1220,6 +999,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);
+ priv->mesh_open = 0;
sprintf(priv->mesh_ssid, "mesh");
priv->mesh_ssid_len = 4;
@@ -1228,9 +1008,15 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
goto done;
-err_init_adapter:
- lbs_free_adapter(priv);
+ err_ndev:
free_netdev(dev);
+
+ err_adapter:
+ lbs_free_adapter(priv);
+
+ err_wdev:
+ lbs_cfg_free(priv);
+
priv = NULL;
done:
@@ -1243,7 +1029,6 @@ EXPORT_SYMBOL_GPL(lbs_add_card);
void lbs_remove_card(struct lbs_private *priv)
{
struct net_device *dev = priv->dev;
- union iwreq_data wrqu;
lbs_deb_enter(LBS_DEB_MAIN);
@@ -1268,15 +1053,19 @@ void lbs_remove_card(struct lbs_private *priv)
lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
}
- memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+ lbs_send_disconnect_notification(priv);
+
+ if (priv->is_deep_sleep) {
+ priv->is_deep_sleep = 0;
+ wake_up_interruptible(&priv->ds_awake_q);
+ }
/* Stop the thread servicing the interrupts */
priv->surpriseremoved = 1;
kthread_stop(priv->main_thread);
lbs_free_adapter(priv);
+ lbs_cfg_free(priv);
priv->dev = NULL;
free_netdev(dev);
@@ -1298,60 +1087,19 @@ int lbs_start_card(struct lbs_private *priv)
if (ret)
goto done;
- /* init 802.11d */
- lbs_init_11d(priv);
-
- if (register_netdev(dev)) {
- lbs_pr_err("cannot register ethX device\n");
+ if (lbs_cfg_register(priv)) {
+ lbs_pr_err("cannot register device\n");
goto done;
}
lbs_update_channel(priv);
- /* Check mesh FW version and appropriately send the mesh start
- * command
+ /*
+ * While rtap isn't related to mesh, only mesh-enabled
+ * firmware implements the rtap functionality via
+ * CMD_802_11_MONITOR_MODE.
*/
- if (priv->mesh_fw_ver == MESH_FW_OLD) {
- /* Enable mesh, if supported, and work out which TLV it uses.
- 0x100 + 291 is an unofficial value used in 5.110.20.pXX
- 0x100 + 37 is the official value used in 5.110.21.pXX
- but we check them in that order because 20.pXX doesn't
- give an error -- it just silently fails. */
-
- /* 5.110.20.pXX firmware will fail the command if the channel
- doesn't match the existing channel. But only if the TLV
- is correct. If the channel is wrong, _BOTH_ versions will
- give an error to 0x100+291, and allow 0x100+37 to succeed.
- It's just that 5.110.20.pXX will not have done anything
- useful */
-
- priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
- if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel)) {
- priv->mesh_tlv = TLV_TYPE_MESH_ID;
- if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel))
- priv->mesh_tlv = 0;
- }
- } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
- /* 10.0.0.pXX new firmwares should succeed with TLV
- * 0x100+37; Do not invoke command with old TLV.
- */
- priv->mesh_tlv = TLV_TYPE_MESH_ID;
- if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel))
- priv->mesh_tlv = 0;
- }
- if (priv->mesh_tlv) {
- lbs_add_mesh(priv);
-
- if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
- lbs_pr_err("cannot register lbs_mesh attribute\n");
-
- /* While rtap isn't related to mesh, only mesh-enabled
- * firmware implements the rtap functionality via
- * CMD_802_11_MONITOR_MODE.
- */
+ if (lbs_init_mesh(priv)) {
if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
lbs_pr_err("cannot register lbs_rtap attribute\n");
}
@@ -1385,13 +1133,12 @@ void lbs_stop_card(struct lbs_private *priv)
netif_carrier_off(dev);
lbs_debugfs_remove_one(priv);
- if (priv->mesh_tlv) {
- device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
+ if (lbs_deinit_mesh(priv))
device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
- }
/* Delete the timeout of the currently processing command */
del_timer_sync(&priv->command_timer);
+ del_timer_sync(&priv->auto_deepsleep_timer);
/* Flush pending command nodes */
spin_lock_irqsave(&priv->driver_lock, flags);
@@ -1420,157 +1167,6 @@ out:
EXPORT_SYMBOL_GPL(lbs_stop_card);
-static const struct net_device_ops mesh_netdev_ops = {
- .ndo_open = lbs_dev_open,
- .ndo_stop = lbs_mesh_stop,
- .ndo_start_xmit = lbs_hard_start_xmit,
- .ndo_set_mac_address = lbs_set_mac_address,
- .ndo_set_multicast_list = lbs_set_multicast_list,
-};
-
-/**
- * @brief This function adds mshX interface
- *
- * @param priv A pointer to the struct lbs_private structure
- * @return 0 if successful, -X otherwise
- */
-static int lbs_add_mesh(struct lbs_private *priv)
-{
- struct net_device *mesh_dev = NULL;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_MESH);
-
- /* Allocate a virtual mesh device */
- if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) {
- lbs_deb_mesh("init mshX device failed\n");
- ret = -ENOMEM;
- goto done;
- }
- mesh_dev->ml_priv = priv;
- priv->mesh_dev = mesh_dev;
-
- mesh_dev->netdev_ops = &mesh_netdev_ops;
- mesh_dev->ethtool_ops = &lbs_ethtool_ops;
- memcpy(mesh_dev->dev_addr, priv->dev->dev_addr,
- sizeof(priv->dev->dev_addr));
-
- SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
-
-#ifdef WIRELESS_EXT
- mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def;
-#endif
- mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
- /* Register virtual mesh interface */
- ret = register_netdev(mesh_dev);
- if (ret) {
- lbs_pr_err("cannot register mshX virtual interface\n");
- goto err_free;
- }
-
- ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
- if (ret)
- goto err_unregister;
-
- lbs_persist_config_init(mesh_dev);
-
- /* Everything successful */
- ret = 0;
- goto done;
-
-err_unregister:
- unregister_netdev(mesh_dev);
-
-err_free:
- free_netdev(mesh_dev);
-
-done:
- lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
- return ret;
-}
-
-static void lbs_remove_mesh(struct lbs_private *priv)
-{
- struct net_device *mesh_dev;
-
-
- mesh_dev = priv->mesh_dev;
- if (!mesh_dev)
- return;
-
- lbs_deb_enter(LBS_DEB_MESH);
- netif_stop_queue(mesh_dev);
- netif_carrier_off(mesh_dev);
- sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
- lbs_persist_config_remove(mesh_dev);
- unregister_netdev(mesh_dev);
- priv->mesh_dev = NULL;
- free_netdev(mesh_dev);
- lbs_deb_leave(LBS_DEB_MESH);
-}
-
-/**
- * @brief This function finds the CFP in
- * region_cfp_table based on region and band parameter.
- *
- * @param region The region code
- * @param band The band
- * @param cfp_no A pointer to CFP number
- * @return A pointer to CFP
- */
-struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)
-{
- int i, end;
-
- lbs_deb_enter(LBS_DEB_MAIN);
-
- end = ARRAY_SIZE(region_cfp_table);
-
- for (i = 0; i < end ; i++) {
- lbs_deb_main("region_cfp_table[i].region=%d\n",
- region_cfp_table[i].region);
- if (region_cfp_table[i].region == region) {
- *cfp_no = region_cfp_table[i].cfp_no_BG;
- lbs_deb_leave(LBS_DEB_MAIN);
- return region_cfp_table[i].cfp_BG;
- }
- }
-
- lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");
- return NULL;
-}
-
-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
-{
- int ret = 0;
- int i = 0;
-
- struct chan_freq_power *cfp;
- int cfp_no;
-
- lbs_deb_enter(LBS_DEB_MAIN);
-
- memset(priv->region_channel, 0, sizeof(priv->region_channel));
-
- cfp = lbs_get_region_cfp_table(region, &cfp_no);
- if (cfp != NULL) {
- priv->region_channel[i].nrcfp = cfp_no;
- priv->region_channel[i].CFP = cfp;
- } else {
- lbs_deb_main("wrong region code %#x in band B/G\n",
- region);
- ret = -1;
- goto out;
- }
- priv->region_channel[i].valid = 1;
- priv->region_channel[i].region = region;
- priv->region_channel[i].band = band;
- i++;
-out:
- lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
- return ret;
-}
-
void lbs_queue_event(struct lbs_private *priv, u32 event)
{
unsigned long flags;
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
new file mode 100644
index 00000000000..2f91c9b808a
--- /dev/null
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -0,0 +1,1141 @@
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/kthread.h>
+#include <linux/kfifo.h>
+
+#include "mesh.h"
+#include "decl.h"
+#include "cmd.h"
+
+
+/***************************************************************************
+ * Mesh sysfs support
+ */
+
+/**
+ * Attributes exported through sysfs
+ */
+
+/**
+ * @brief Get function for sysfs attribute anycast_mask
+ */
+static ssize_t lbs_anycast_get(struct device *dev,
+ struct device_attribute *attr, char * buf)
+{
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ struct cmd_ds_mesh_access mesh_access;
+ int ret;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+
+ ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
+}
+
+/**
+ * @brief Set function for sysfs attribute anycast_mask
+ */
+static ssize_t lbs_anycast_set(struct device *dev,
+ struct device_attribute *attr, const char * buf, size_t count)
+{
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ struct cmd_ds_mesh_access mesh_access;
+ uint32_t datum;
+ int ret;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ sscanf(buf, "%x", &datum);
+ mesh_access.data[0] = cpu_to_le32(datum);
+
+ ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute prb_rsp_limit
+ */
+static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ struct cmd_ds_mesh_access mesh_access;
+ int ret;
+ u32 retry_limit;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
+
+ ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
+ &mesh_access);
+ if (ret)
+ return ret;
+
+ retry_limit = le32_to_cpu(mesh_access.data[1]);
+ return snprintf(buf, 10, "%d\n", retry_limit);
+}
+
+/**
+ * @brief Set function for sysfs attribute prb_rsp_limit
+ */
+static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ struct cmd_ds_mesh_access mesh_access;
+ int ret;
+ unsigned long retry_limit;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
+
+ if (!strict_strtoul(buf, 10, &retry_limit))
+ return -ENOTSUPP;
+ if (retry_limit > 15)
+ return -ENOTSUPP;
+
+ mesh_access.data[1] = cpu_to_le32(retry_limit);
+
+ ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
+ &mesh_access);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * Get function for sysfs attribute mesh
+ */
+static ssize_t lbs_mesh_get(struct device *dev,
+ struct device_attribute *attr, char * buf)
+{
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
+}
+
+/**
+ * Set function for sysfs attribute mesh
+ */
+static ssize_t lbs_mesh_set(struct device *dev,
+ struct device_attribute *attr, const char * buf, size_t count)
+{
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ int enable;
+ int ret, action = CMD_ACT_MESH_CONFIG_STOP;
+
+ sscanf(buf, "%x", &enable);
+ enable = !!enable;
+ if (enable == !!priv->mesh_dev)
+ return count;
+ if (enable)
+ action = CMD_ACT_MESH_CONFIG_START;
+ ret = lbs_mesh_config(priv, action, priv->channel);
+ if (ret)
+ return ret;
+
+ if (enable)
+ lbs_add_mesh(priv);
+ else
+ lbs_remove_mesh(priv);
+
+ return count;
+}
+
+/**
+ * lbs_mesh attribute to be exported per ethX interface
+ * through sysfs (/sys/class/net/ethX/lbs_mesh)
+ */
+static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
+
+/**
+ * anycast_mask attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/anycast_mask)
+ */
+static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
+
+/**
+ * prb_rsp_limit attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
+ */
+static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
+ lbs_prb_rsp_limit_set);
+
+static struct attribute *lbs_mesh_sysfs_entries[] = {
+ &dev_attr_anycast_mask.attr,
+ &dev_attr_prb_rsp_limit.attr,
+ NULL,
+};
+
+static struct attribute_group lbs_mesh_attr_group = {
+ .attrs = lbs_mesh_sysfs_entries,
+};
+
+
+
+/***************************************************************************
+ * Initializing and starting, stopping mesh
+ */
+
+/*
+ * Check mesh FW version and appropriately send the mesh start
+ * command
+ */
+int lbs_init_mesh(struct lbs_private *priv)
+{
+ struct net_device *dev = priv->dev;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_MESH);
+
+ if (priv->mesh_fw_ver == MESH_FW_OLD) {
+ /* Enable mesh, if supported, and work out which TLV it uses.
+ 0x100 + 291 is an unofficial value used in 5.110.20.pXX
+ 0x100 + 37 is the official value used in 5.110.21.pXX
+ but we check them in that order because 20.pXX doesn't
+ give an error -- it just silently fails. */
+
+ /* 5.110.20.pXX firmware will fail the command if the channel
+ doesn't match the existing channel. But only if the TLV
+ is correct. If the channel is wrong, _BOTH_ versions will
+ give an error to 0x100+291, and allow 0x100+37 to succeed.
+ It's just that 5.110.20.pXX will not have done anything
+ useful */
+
+ priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
+ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+ priv->channel)) {
+ priv->mesh_tlv = TLV_TYPE_MESH_ID;
+ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+ priv->channel))
+ priv->mesh_tlv = 0;
+ }
+ } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
+ /* 10.0.0.pXX new firmwares should succeed with TLV
+ * 0x100+37; Do not invoke command with old TLV.
+ */
+ priv->mesh_tlv = TLV_TYPE_MESH_ID;
+ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+ priv->channel))
+ priv->mesh_tlv = 0;
+ }
+ if (priv->mesh_tlv) {
+ lbs_add_mesh(priv);
+
+ if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
+ lbs_pr_err("cannot register lbs_mesh attribute\n");
+
+ ret = 1;
+ }
+
+ lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
+ return ret;
+}
+
+
+int lbs_deinit_mesh(struct lbs_private *priv)
+{
+ struct net_device *dev = priv->dev;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_MESH);
+
+ if (priv->mesh_tlv) {
+ device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
+ ret = 1;
+ }
+
+ lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
+ return ret;
+}
+
+
+/**
+ * @brief This function closes the mshX interface
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ */
+static int lbs_mesh_stop(struct net_device *dev)
+{
+ struct lbs_private *priv = dev->ml_priv;
+
+ lbs_deb_enter(LBS_DEB_MESH);
+ spin_lock_irq(&priv->driver_lock);
+
+ priv->mesh_open = 0;
+ priv->mesh_connect_status = LBS_DISCONNECTED;
+
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+
+ spin_unlock_irq(&priv->driver_lock);
+
+ schedule_work(&priv->mcast_work);
+
+ lbs_deb_leave(LBS_DEB_MESH);
+ return 0;
+}
+
+/**
+ * @brief This function opens the mshX interface
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0 or -EBUSY if monitor mode active
+ */
+static int lbs_mesh_dev_open(struct net_device *dev)
+{
+ struct lbs_private *priv = dev->ml_priv;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_NET);
+
+ spin_lock_irq(&priv->driver_lock);
+
+ if (priv->monitormode) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ priv->mesh_open = 1;
+ priv->mesh_connect_status = LBS_CONNECTED;
+ netif_carrier_on(dev);
+
+ if (!priv->tx_pending_len)
+ netif_wake_queue(dev);
+ out:
+
+ spin_unlock_irq(&priv->driver_lock);
+ lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+ return ret;
+}
+
+static const struct net_device_ops mesh_netdev_ops = {
+ .ndo_open = lbs_mesh_dev_open,
+ .ndo_stop = lbs_mesh_stop,
+ .ndo_start_xmit = lbs_hard_start_xmit,
+ .ndo_set_mac_address = lbs_set_mac_address,
+ .ndo_set_multicast_list = lbs_set_multicast_list,
+};
+
+/**
+ * @brief This function adds mshX interface
+ *
+ * @param priv A pointer to the struct lbs_private structure
+ * @return 0 if successful, -X otherwise
+ */
+int lbs_add_mesh(struct lbs_private *priv)
+{
+ struct net_device *mesh_dev = NULL;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_MESH);
+
+ /* Allocate a virtual mesh device */
+ mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
+ if (!mesh_dev) {
+ lbs_deb_mesh("init mshX device failed\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ mesh_dev->ml_priv = priv;
+ priv->mesh_dev = mesh_dev;
+
+ mesh_dev->netdev_ops = &mesh_netdev_ops;
+ mesh_dev->ethtool_ops = &lbs_ethtool_ops;
+ memcpy(mesh_dev->dev_addr, priv->dev->dev_addr,
+ sizeof(priv->dev->dev_addr));
+
+ SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
+
+#ifdef WIRELESS_EXT
+ mesh_dev->wireless_handlers = &mesh_handler_def;
+#endif
+ mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+ /* Register virtual mesh interface */
+ ret = register_netdev(mesh_dev);
+ if (ret) {
+ lbs_pr_err("cannot register mshX virtual interface\n");
+ goto err_free;
+ }
+
+ ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
+ if (ret)
+ goto err_unregister;
+
+ lbs_persist_config_init(mesh_dev);
+
+ /* Everything successful */
+ ret = 0;
+ goto done;
+
+err_unregister:
+ unregister_netdev(mesh_dev);
+
+err_free:
+ free_netdev(mesh_dev);
+
+done:
+ lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
+ return ret;
+}
+
+void lbs_remove_mesh(struct lbs_private *priv)
+{
+ struct net_device *mesh_dev;
+
+ mesh_dev = priv->mesh_dev;
+ if (!mesh_dev)
+ return;
+
+ lbs_deb_enter(LBS_DEB_MESH);
+ netif_stop_queue(mesh_dev);
+ netif_carrier_off(mesh_dev);
+ sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
+ lbs_persist_config_remove(mesh_dev);
+ unregister_netdev(mesh_dev);
+ priv->mesh_dev = NULL;
+ free_netdev(mesh_dev);
+ lbs_deb_leave(LBS_DEB_MESH);
+}
+
+
+
+/***************************************************************************
+ * Sending and receiving
+ */
+struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
+ struct net_device *dev, struct rxpd *rxpd)
+{
+ if (priv->mesh_dev) {
+ if (priv->mesh_fw_ver == MESH_FW_OLD) {
+ if (rxpd->rx_control & RxPD_MESH_FRAME)
+ dev = priv->mesh_dev;
+ } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
+ if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
+ dev = priv->mesh_dev;
+ }
+ }
+ return dev;
+}
+
+
+void lbs_mesh_set_txpd(struct lbs_private *priv,
+ struct net_device *dev, struct txpd *txpd)
+{
+ if (dev == priv->mesh_dev) {
+ if (priv->mesh_fw_ver == MESH_FW_OLD)
+ txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
+ else if (priv->mesh_fw_ver == MESH_FW_NEW)
+ txpd->u.bss.bss_num = MESH_IFACE_ID;
+ }
+}
+
+
+/***************************************************************************
+ * Mesh command handling
+ */
+
+int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
+ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
+
+ cmd->command = cpu_to_le16(CMD_BT_ACCESS);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) +
+ sizeof(struct cmd_header));
+ cmd->result = 0;
+ bt_access->action = cpu_to_le16(cmd_action);
+
+ switch (cmd_action) {
+ case CMD_ACT_BT_ACCESS_ADD:
+ memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
+ lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr",
+ bt_access->addr1, 6);
+ break;
+ case CMD_ACT_BT_ACCESS_DEL:
+ memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
+ lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr",
+ bt_access->addr1, 6);
+ break;
+ case CMD_ACT_BT_ACCESS_LIST:
+ bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
+ break;
+ case CMD_ACT_BT_ACCESS_RESET:
+ break;
+ case CMD_ACT_BT_ACCESS_SET_INVERT:
+ bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
+ break;
+ case CMD_ACT_BT_ACCESS_GET_INVERT:
+ break;
+ default:
+ break;
+ }
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
+int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
+ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
+
+ cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) +
+ sizeof(struct cmd_header));
+ cmd->result = 0;
+
+ if (pdata_buf)
+ memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
+ else
+ memset(fwt_access, 0, sizeof(*fwt_access));
+
+ fwt_access->action = cpu_to_le16(cmd_action);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
+int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
+ struct cmd_ds_mesh_access *cmd)
+{
+ int ret;
+
+ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
+
+ cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
+ cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
+ cmd->hdr.result = 0;
+
+ cmd->action = cpu_to_le16(cmd_action);
+
+ ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
+}
+
+static int __lbs_mesh_config_send(struct lbs_private *priv,
+ struct cmd_ds_mesh_config *cmd,
+ uint16_t action, uint16_t type)
+{
+ int ret;
+ u16 command = CMD_MESH_CONFIG_OLD;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ /*
+ * Command id is 0xac for v10 FW along with mesh interface
+ * id in bits 14-13-12.
+ */
+ if (priv->mesh_fw_ver == MESH_FW_NEW)
+ command = CMD_MESH_CONFIG |
+ (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
+
+ cmd->hdr.command = cpu_to_le16(command);
+ cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
+ cmd->hdr.result = 0;
+
+ cmd->type = cpu_to_le16(type);
+ cmd->action = cpu_to_le16(action);
+
+ ret = lbs_cmd_with_response(priv, command, cmd);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
+}
+
+int lbs_mesh_config_send(struct lbs_private *priv,
+ struct cmd_ds_mesh_config *cmd,
+ uint16_t action, uint16_t type)
+{
+ int ret;
+
+ if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
+ return -EOPNOTSUPP;
+
+ ret = __lbs_mesh_config_send(priv, cmd, action, type);
+ return ret;
+}
+
+/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
+ * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
+ * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
+ * lbs_mesh_config_send.
+ */
+int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
+{
+ struct cmd_ds_mesh_config cmd;
+ struct mrvl_meshie *ie;
+ DECLARE_SSID_BUF(ssid);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.channel = cpu_to_le16(chan);
+ ie = (struct mrvl_meshie *)cmd.data;
+
+ switch (action) {
+ case CMD_ACT_MESH_CONFIG_START:
+ ie->id = WLAN_EID_GENERIC;
+ ie->val.oui[0] = 0x00;
+ ie->val.oui[1] = 0x50;
+ ie->val.oui[2] = 0x43;
+ ie->val.type = MARVELL_MESH_IE_TYPE;
+ ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
+ ie->val.version = MARVELL_MESH_IE_VERSION;
+ ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
+ ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
+ ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
+ ie->val.mesh_id_len = priv->mesh_ssid_len;
+ memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
+ ie->len = sizeof(struct mrvl_meshie_val) -
+ IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
+ cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
+ break;
+ case CMD_ACT_MESH_CONFIG_STOP:
+ break;
+ default:
+ return -1;
+ }
+ lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
+ action, priv->mesh_tlv, chan,
+ print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
+
+ return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
+}
+
+
+
+/***************************************************************************
+ * Persistent configuration support
+ */
+
+static int mesh_get_default_parameters(struct device *dev,
+ struct mrvl_mesh_defaults *defs)
+{
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ struct cmd_ds_mesh_config cmd;
+ int ret;
+
+ memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
+ CMD_TYPE_MESH_GET_DEFAULTS);
+
+ if (ret)
+ return -EOPNOTSUPP;
+
+ memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
+
+ return 0;
+}
+
+/**
+ * @brief Get function for sysfs attribute bootflag
+ */
+static ssize_t bootflag_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
+}
+
+/**
+ * @brief Set function for sysfs attribute bootflag
+ */
+static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ struct cmd_ds_mesh_config cmd;
+ uint32_t datum;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ret = sscanf(buf, "%d", &datum);
+ if ((ret != 1) || (datum > 1))
+ return -EINVAL;
+
+ *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
+ cmd.length = cpu_to_le16(sizeof(uint32_t));
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_BOOTFLAG);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute boottime
+ */
+static ssize_t boottime_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 12, "%d\n", defs.boottime);
+}
+
+/**
+ * @brief Set function for sysfs attribute boottime
+ */
+static ssize_t boottime_set(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ struct cmd_ds_mesh_config cmd;
+ uint32_t datum;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ret = sscanf(buf, "%d", &datum);
+ if ((ret != 1) || (datum > 255))
+ return -EINVAL;
+
+ /* A too small boot time will result in the device booting into
+ * standalone (no-host) mode before the host can take control of it,
+ * so the change will be hard to revert. This may be a desired
+ * feature (e.g to configure a very fast boot time for devices that
+ * will not be attached to a host), but dangerous. So I'm enforcing a
+ * lower limit of 20 seconds: remove and recompile the driver if this
+ * does not work for you.
+ */
+ datum = (datum < 20) ? 20 : datum;
+ cmd.data[0] = datum;
+ cmd.length = cpu_to_le16(sizeof(uint8_t));
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_BOOTTIME);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute channel
+ */
+static ssize_t channel_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
+}
+
+/**
+ * @brief Set function for sysfs attribute channel
+ */
+static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ struct cmd_ds_mesh_config cmd;
+ uint32_t datum;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ret = sscanf(buf, "%d", &datum);
+ if (ret != 1 || datum < 1 || datum > 11)
+ return -EINVAL;
+
+ *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
+ cmd.length = cpu_to_le16(sizeof(uint16_t));
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_DEF_CHANNEL);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute mesh_id
+ */
+static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int maxlen;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
+ lbs_pr_err("inconsistent mesh ID length");
+ defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
+ }
+
+ /* SSID not null terminated: reserve room for \0 + \n */
+ maxlen = defs.meshie.val.mesh_id_len + 2;
+ maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
+
+ defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
+
+ return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
+}
+
+/**
+ * @brief Set function for sysfs attribute mesh_id
+ */
+static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cmd_ds_mesh_config cmd;
+ struct mrvl_mesh_defaults defs;
+ struct mrvl_meshie *ie;
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ int len;
+ int ret;
+
+ if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
+ return -EINVAL;
+
+ memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
+ ie = (struct mrvl_meshie *) &cmd.data[0];
+
+ /* fetch all other Information Element parameters */
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+ /* transfer IE elements */
+ memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+
+ len = count - 1;
+ memcpy(ie->val.mesh_id, buf, len);
+ /* SSID len */
+ ie->val.mesh_id_len = len;
+ /* IE len */
+ ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
+
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_MESH_IE);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute protocol_id
+ */
+static ssize_t protocol_id_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
+}
+
+/**
+ * @brief Set function for sysfs attribute protocol_id
+ */
+static ssize_t protocol_id_set(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct cmd_ds_mesh_config cmd;
+ struct mrvl_mesh_defaults defs;
+ struct mrvl_meshie *ie;
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ uint32_t datum;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ret = sscanf(buf, "%d", &datum);
+ if ((ret != 1) || (datum > 255))
+ return -EINVAL;
+
+ /* fetch all other Information Element parameters */
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+ /* transfer IE elements */
+ ie = (struct mrvl_meshie *) &cmd.data[0];
+ memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+ /* update protocol id */
+ ie->val.active_protocol_id = datum;
+
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_MESH_IE);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute metric_id
+ */
+static ssize_t metric_id_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
+}
+
+/**
+ * @brief Set function for sysfs attribute metric_id
+ */
+static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cmd_ds_mesh_config cmd;
+ struct mrvl_mesh_defaults defs;
+ struct mrvl_meshie *ie;
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ uint32_t datum;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ret = sscanf(buf, "%d", &datum);
+ if ((ret != 1) || (datum > 255))
+ return -EINVAL;
+
+ /* fetch all other Information Element parameters */
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+ /* transfer IE elements */
+ ie = (struct mrvl_meshie *) &cmd.data[0];
+ memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+ /* update metric id */
+ ie->val.active_metric_id = datum;
+
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_MESH_IE);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute capability
+ */
+static ssize_t capability_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
+}
+
+/**
+ * @brief Set function for sysfs attribute capability
+ */
+static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cmd_ds_mesh_config cmd;
+ struct mrvl_mesh_defaults defs;
+ struct mrvl_meshie *ie;
+ struct lbs_private *priv = to_net_dev(dev)->ml_priv;
+ uint32_t datum;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ret = sscanf(buf, "%d", &datum);
+ if ((ret != 1) || (datum > 255))
+ return -EINVAL;
+
+ /* fetch all other Information Element parameters */
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+ /* transfer IE elements */
+ ie = (struct mrvl_meshie *) &cmd.data[0];
+ memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+ /* update value */
+ ie->val.mesh_capability = datum;
+
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_MESH_IE);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+
+static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
+static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
+static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
+static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
+static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
+static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
+static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
+
+static struct attribute *boot_opts_attrs[] = {
+ &dev_attr_bootflag.attr,
+ &dev_attr_boottime.attr,
+ &dev_attr_channel.attr,
+ NULL
+};
+
+static struct attribute_group boot_opts_group = {
+ .name = "boot_options",
+ .attrs = boot_opts_attrs,
+};
+
+static struct attribute *mesh_ie_attrs[] = {
+ &dev_attr_mesh_id.attr,
+ &dev_attr_protocol_id.attr,
+ &dev_attr_metric_id.attr,
+ &dev_attr_capability.attr,
+ NULL
+};
+
+static struct attribute_group mesh_ie_group = {
+ .name = "mesh_ie",
+ .attrs = mesh_ie_attrs,
+};
+
+void lbs_persist_config_init(struct net_device *dev)
+{
+ int ret;
+ ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
+ ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
+}
+
+void lbs_persist_config_remove(struct net_device *dev)
+{
+ sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
+ sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
+}
+
+
+
+/***************************************************************************
+ * Ethtool related
+ */
+
+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"
+};
+
+void lbs_mesh_ethtool_get_stats(struct net_device *dev,
+ struct ethtool_stats *stats, uint64_t *data)
+{
+ struct lbs_private *priv = dev->ml_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);
+}
+
+int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
+{
+ struct lbs_private *priv = dev->ml_priv;
+
+ if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
+ return MESH_STATS_NUM;
+
+ return -EOPNOTSUPP;
+}
+
+void lbs_mesh_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);
+}
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
new file mode 100644
index 00000000000..fea9b5d005f
--- /dev/null
+++ b/drivers/net/wireless/libertas/mesh.h
@@ -0,0 +1,78 @@
+/**
+ * Contains all definitions needed for the Libertas' MESH implementation.
+ */
+#ifndef _LBS_MESH_H_
+#define _LBS_MESH_H_
+
+
+#include <net/iw_handler.h>
+#include <net/lib80211.h>
+
+
+/* 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 */
+};
+
+
+struct net_device;
+struct lbs_private;
+
+int lbs_init_mesh(struct lbs_private *priv);
+int lbs_deinit_mesh(struct lbs_private *priv);
+
+int lbs_add_mesh(struct lbs_private *priv);
+void lbs_remove_mesh(struct lbs_private *priv);
+
+
+/* Sending / Receiving */
+
+struct rxpd;
+struct txpd;
+
+struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
+ struct net_device *dev, struct rxpd *rxpd);
+void lbs_mesh_set_txpd(struct lbs_private *priv,
+ struct net_device *dev, struct txpd *txpd);
+
+
+/* Command handling */
+
+struct cmd_ds_command;
+
+int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf);
+int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf);
+
+
+/* Persistent configuration */
+
+void lbs_persist_config_init(struct net_device *net);
+void lbs_persist_config_remove(struct net_device *net);
+
+
+/* WEXT handler */
+
+extern struct iw_handler_def mesh_handler_def;
+
+
+/* Ethtool statistics */
+
+struct ethtool_stats;
+
+void lbs_mesh_ethtool_get_stats(struct net_device *dev,
+ struct ethtool_stats *stats, uint64_t *data);
+int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset);
+void lbs_mesh_ethtool_get_strings(struct net_device *dev,
+ uint32_t stringset, uint8_t *s);
+
+
+#endif
diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c
deleted file mode 100644
index 18fe29faf99..00000000000
--- a/drivers/net/wireless/libertas/persistcfg.c
+++ /dev/null
@@ -1,453 +0,0 @@
-#include <linux/moduleparam.h>
-#include <linux/delay.h>
-#include <linux/etherdevice.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/kthread.h>
-#include <linux/kfifo.h>
-
-#include "host.h"
-#include "decl.h"
-#include "dev.h"
-#include "wext.h"
-#include "debugfs.h"
-#include "scan.h"
-#include "assoc.h"
-#include "cmd.h"
-
-static int mesh_get_default_parameters(struct device *dev,
- struct mrvl_mesh_defaults *defs)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- struct cmd_ds_mesh_config cmd;
- int ret;
-
- memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
- ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
- CMD_TYPE_MESH_GET_DEFAULTS);
-
- if (ret)
- return -EOPNOTSUPP;
-
- memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
-
- return 0;
-}
-
-/**
- * @brief Get function for sysfs attribute bootflag
- */
-static ssize_t bootflag_get(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mrvl_mesh_defaults defs;
- int ret;
-
- ret = mesh_get_default_parameters(dev, &defs);
-
- if (ret)
- return ret;
-
- return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
-}
-
-/**
- * @brief Set function for sysfs attribute bootflag
- */
-static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- struct cmd_ds_mesh_config cmd;
- uint32_t datum;
- int ret;
-
- memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%d", &datum);
- if ((ret != 1) || (datum > 1))
- return -EINVAL;
-
- *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
- cmd.length = cpu_to_le16(sizeof(uint32_t));
- ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
- CMD_TYPE_MESH_SET_BOOTFLAG);
- if (ret)
- return ret;
-
- return strlen(buf);
-}
-
-/**
- * @brief Get function for sysfs attribute boottime
- */
-static ssize_t boottime_get(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mrvl_mesh_defaults defs;
- int ret;
-
- ret = mesh_get_default_parameters(dev, &defs);
-
- if (ret)
- return ret;
-
- return snprintf(buf, 12, "%d\n", defs.boottime);
-}
-
-/**
- * @brief Set function for sysfs attribute boottime
- */
-static ssize_t boottime_set(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- struct cmd_ds_mesh_config cmd;
- uint32_t datum;
- int ret;
-
- memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%d", &datum);
- if ((ret != 1) || (datum > 255))
- return -EINVAL;
-
- /* A too small boot time will result in the device booting into
- * standalone (no-host) mode before the host can take control of it,
- * so the change will be hard to revert. This may be a desired
- * feature (e.g to configure a very fast boot time for devices that
- * will not be attached to a host), but dangerous. So I'm enforcing a
- * lower limit of 20 seconds: remove and recompile the driver if this
- * does not work for you.
- */
- datum = (datum < 20) ? 20 : datum;
- cmd.data[0] = datum;
- cmd.length = cpu_to_le16(sizeof(uint8_t));
- ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
- CMD_TYPE_MESH_SET_BOOTTIME);
- if (ret)
- return ret;
-
- return strlen(buf);
-}
-
-/**
- * @brief Get function for sysfs attribute channel
- */
-static ssize_t channel_get(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mrvl_mesh_defaults defs;
- int ret;
-
- ret = mesh_get_default_parameters(dev, &defs);
-
- if (ret)
- return ret;
-
- return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
-}
-
-/**
- * @brief Set function for sysfs attribute channel
- */
-static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- struct cmd_ds_mesh_config cmd;
- uint32_t datum;
- int ret;
-
- memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%d", &datum);
- if (ret != 1 || datum < 1 || datum > 11)
- return -EINVAL;
-
- *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
- cmd.length = cpu_to_le16(sizeof(uint16_t));
- ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
- CMD_TYPE_MESH_SET_DEF_CHANNEL);
- if (ret)
- return ret;
-
- return strlen(buf);
-}
-
-/**
- * @brief Get function for sysfs attribute mesh_id
- */
-static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct mrvl_mesh_defaults defs;
- int maxlen;
- int ret;
-
- ret = mesh_get_default_parameters(dev, &defs);
-
- if (ret)
- return ret;
-
- if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) {
- lbs_pr_err("inconsistent mesh ID length");
- defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE;
- }
-
- /* SSID not null terminated: reserve room for \0 + \n */
- maxlen = defs.meshie.val.mesh_id_len + 2;
- maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
-
- defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
-
- return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
-}
-
-/**
- * @brief Set function for sysfs attribute mesh_id
- */
-static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct cmd_ds_mesh_config cmd;
- struct mrvl_mesh_defaults defs;
- struct mrvl_meshie *ie;
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- int len;
- int ret;
-
- if (count < 2 || count > IW_ESSID_MAX_SIZE + 1)
- return -EINVAL;
-
- memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
- ie = (struct mrvl_meshie *) &cmd.data[0];
-
- /* fetch all other Information Element parameters */
- ret = mesh_get_default_parameters(dev, &defs);
-
- cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
-
- /* transfer IE elements */
- memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
-
- len = count - 1;
- memcpy(ie->val.mesh_id, buf, len);
- /* SSID len */
- ie->val.mesh_id_len = len;
- /* IE len */
- ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
-
- ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
- CMD_TYPE_MESH_SET_MESH_IE);
- if (ret)
- return ret;
-
- return strlen(buf);
-}
-
-/**
- * @brief Get function for sysfs attribute protocol_id
- */
-static ssize_t protocol_id_get(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mrvl_mesh_defaults defs;
- int ret;
-
- ret = mesh_get_default_parameters(dev, &defs);
-
- if (ret)
- return ret;
-
- return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
-}
-
-/**
- * @brief Set function for sysfs attribute protocol_id
- */
-static ssize_t protocol_id_set(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct cmd_ds_mesh_config cmd;
- struct mrvl_mesh_defaults defs;
- struct mrvl_meshie *ie;
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- uint32_t datum;
- int ret;
-
- memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%d", &datum);
- if ((ret != 1) || (datum > 255))
- return -EINVAL;
-
- /* fetch all other Information Element parameters */
- ret = mesh_get_default_parameters(dev, &defs);
-
- cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
-
- /* transfer IE elements */
- ie = (struct mrvl_meshie *) &cmd.data[0];
- memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
- /* update protocol id */
- ie->val.active_protocol_id = datum;
-
- ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
- CMD_TYPE_MESH_SET_MESH_IE);
- if (ret)
- return ret;
-
- return strlen(buf);
-}
-
-/**
- * @brief Get function for sysfs attribute metric_id
- */
-static ssize_t metric_id_get(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mrvl_mesh_defaults defs;
- int ret;
-
- ret = mesh_get_default_parameters(dev, &defs);
-
- if (ret)
- return ret;
-
- return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
-}
-
-/**
- * @brief Set function for sysfs attribute metric_id
- */
-static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct cmd_ds_mesh_config cmd;
- struct mrvl_mesh_defaults defs;
- struct mrvl_meshie *ie;
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- uint32_t datum;
- int ret;
-
- memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%d", &datum);
- if ((ret != 1) || (datum > 255))
- return -EINVAL;
-
- /* fetch all other Information Element parameters */
- ret = mesh_get_default_parameters(dev, &defs);
-
- cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
-
- /* transfer IE elements */
- ie = (struct mrvl_meshie *) &cmd.data[0];
- memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
- /* update metric id */
- ie->val.active_metric_id = datum;
-
- ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
- CMD_TYPE_MESH_SET_MESH_IE);
- if (ret)
- return ret;
-
- return strlen(buf);
-}
-
-/**
- * @brief Get function for sysfs attribute capability
- */
-static ssize_t capability_get(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mrvl_mesh_defaults defs;
- int ret;
-
- ret = mesh_get_default_parameters(dev, &defs);
-
- if (ret)
- return ret;
-
- return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
-}
-
-/**
- * @brief Set function for sysfs attribute capability
- */
-static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct cmd_ds_mesh_config cmd;
- struct mrvl_mesh_defaults defs;
- struct mrvl_meshie *ie;
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- uint32_t datum;
- int ret;
-
- memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%d", &datum);
- if ((ret != 1) || (datum > 255))
- return -EINVAL;
-
- /* fetch all other Information Element parameters */
- ret = mesh_get_default_parameters(dev, &defs);
-
- cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
-
- /* transfer IE elements */
- ie = (struct mrvl_meshie *) &cmd.data[0];
- memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
- /* update value */
- ie->val.mesh_capability = datum;
-
- ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
- CMD_TYPE_MESH_SET_MESH_IE);
- if (ret)
- return ret;
-
- return strlen(buf);
-}
-
-
-static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
-static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
-static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
-static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
-static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
-static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
-static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
-
-static struct attribute *boot_opts_attrs[] = {
- &dev_attr_bootflag.attr,
- &dev_attr_boottime.attr,
- &dev_attr_channel.attr,
- NULL
-};
-
-static struct attribute_group boot_opts_group = {
- .name = "boot_options",
- .attrs = boot_opts_attrs,
-};
-
-static struct attribute *mesh_ie_attrs[] = {
- &dev_attr_mesh_id.attr,
- &dev_attr_protocol_id.attr,
- &dev_attr_metric_id.attr,
- &dev_attr_capability.attr,
- NULL
-};
-
-static struct attribute_group mesh_ie_group = {
- .name = "mesh_ie",
- .attrs = mesh_ie_attrs,
-};
-
-void lbs_persist_config_init(struct net_device *dev)
-{
- int ret;
- ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
- ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
-}
-
-void lbs_persist_config_remove(struct net_device *dev)
-{
- sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
- sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
-}
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 65f02cc6752..2daf8ffdb7e 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -4,7 +4,7 @@
#include <linux/etherdevice.h>
#include <linux/types.h>
-#include "hostcmd.h"
+#include "host.h"
#include "radiotap.h"
#include "decl.h"
#include "dev.h"
@@ -160,15 +160,8 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
p_rx_pd = (struct rxpd *) skb->data;
p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd +
le32_to_cpu(p_rx_pd->pkt_ptr));
- if (priv->mesh_dev) {
- if (priv->mesh_fw_ver == MESH_FW_OLD) {
- if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
- dev = priv->mesh_dev;
- } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
- if (p_rx_pd->u.bss.bss_num == MESH_IFACE_ID)
- dev = priv->mesh_dev;
- }
- }
+
+ dev = lbs_mesh_set_dev(priv, dev, p_rx_pd);
lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
min_t(unsigned int, skb->len, 100));
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 6c95af3023c..c6a6c042b82 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -12,18 +12,19 @@
#include <net/lib80211.h>
#include "host.h"
-#include "decl.h"
#include "dev.h"
#include "scan.h"
+#include "assoc.h"
+#include "wext.h"
#include "cmd.h"
//! 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 \
+ + IEEE80211_MAX_SSID_LEN \
+ IW_EV_UINT_LEN \
+ IW_EV_FREQ_LEN \
+ IW_EV_QUAL_LEN \
- + IW_ESSID_MAX_SIZE \
+ + IEEE80211_MAX_SSID_LEN \
+ IW_EV_PARAM_LEN \
+ 40) /* 40 for WPAIE */
@@ -121,6 +122,189 @@ static inline int is_same_network(struct bss_descriptor *src,
+/*********************************************************************/
+/* */
+/* Region channel support */
+/* */
+/*********************************************************************/
+
+#define LBS_TX_PWR_DEFAULT 20 /*100mW */
+#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */
+#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */
+#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */
+#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */
+
+/* Format { channel, frequency (MHz), maxtxpower } */
+/* band: 'B/G', region: USA FCC/Canada IC */
+static struct chan_freq_power channel_freq_power_US_BG[] = {
+ {1, 2412, LBS_TX_PWR_US_DEFAULT},
+ {2, 2417, LBS_TX_PWR_US_DEFAULT},
+ {3, 2422, LBS_TX_PWR_US_DEFAULT},
+ {4, 2427, LBS_TX_PWR_US_DEFAULT},
+ {5, 2432, LBS_TX_PWR_US_DEFAULT},
+ {6, 2437, LBS_TX_PWR_US_DEFAULT},
+ {7, 2442, LBS_TX_PWR_US_DEFAULT},
+ {8, 2447, LBS_TX_PWR_US_DEFAULT},
+ {9, 2452, LBS_TX_PWR_US_DEFAULT},
+ {10, 2457, LBS_TX_PWR_US_DEFAULT},
+ {11, 2462, LBS_TX_PWR_US_DEFAULT}
+};
+
+/* band: 'B/G', region: Europe ETSI */
+static struct chan_freq_power channel_freq_power_EU_BG[] = {
+ {1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
+ {2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
+ {3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
+ {4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
+ {5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
+ {6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
+ {7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
+ {8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
+ {9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
+ {10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
+ {11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
+ {12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
+ {13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
+};
+
+/* band: 'B/G', region: Spain */
+static struct chan_freq_power channel_freq_power_SPN_BG[] = {
+ {10, 2457, LBS_TX_PWR_DEFAULT},
+ {11, 2462, LBS_TX_PWR_DEFAULT}
+};
+
+/* band: 'B/G', region: France */
+static struct chan_freq_power channel_freq_power_FR_BG[] = {
+ {10, 2457, LBS_TX_PWR_FR_DEFAULT},
+ {11, 2462, LBS_TX_PWR_FR_DEFAULT},
+ {12, 2467, LBS_TX_PWR_FR_DEFAULT},
+ {13, 2472, LBS_TX_PWR_FR_DEFAULT}
+};
+
+/* band: 'B/G', region: Japan */
+static struct chan_freq_power channel_freq_power_JPN_BG[] = {
+ {1, 2412, LBS_TX_PWR_JP_DEFAULT},
+ {2, 2417, LBS_TX_PWR_JP_DEFAULT},
+ {3, 2422, LBS_TX_PWR_JP_DEFAULT},
+ {4, 2427, LBS_TX_PWR_JP_DEFAULT},
+ {5, 2432, LBS_TX_PWR_JP_DEFAULT},
+ {6, 2437, LBS_TX_PWR_JP_DEFAULT},
+ {7, 2442, LBS_TX_PWR_JP_DEFAULT},
+ {8, 2447, LBS_TX_PWR_JP_DEFAULT},
+ {9, 2452, LBS_TX_PWR_JP_DEFAULT},
+ {10, 2457, LBS_TX_PWR_JP_DEFAULT},
+ {11, 2462, LBS_TX_PWR_JP_DEFAULT},
+ {12, 2467, LBS_TX_PWR_JP_DEFAULT},
+ {13, 2472, LBS_TX_PWR_JP_DEFAULT},
+ {14, 2484, LBS_TX_PWR_JP_DEFAULT}
+};
+
+/**
+ * the structure for channel, frequency and power
+ */
+struct region_cfp_table {
+ u8 region;
+ struct chan_freq_power *cfp_BG;
+ int cfp_no_BG;
+};
+
+/**
+ * the structure for the mapping between region and CFP
+ */
+static struct region_cfp_table region_cfp_table[] = {
+ {0x10, /*US FCC */
+ channel_freq_power_US_BG,
+ ARRAY_SIZE(channel_freq_power_US_BG),
+ }
+ ,
+ {0x20, /*CANADA IC */
+ channel_freq_power_US_BG,
+ ARRAY_SIZE(channel_freq_power_US_BG),
+ }
+ ,
+ {0x30, /*EU*/ channel_freq_power_EU_BG,
+ ARRAY_SIZE(channel_freq_power_EU_BG),
+ }
+ ,
+ {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
+ ARRAY_SIZE(channel_freq_power_SPN_BG),
+ }
+ ,
+ {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
+ ARRAY_SIZE(channel_freq_power_FR_BG),
+ }
+ ,
+ {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
+ ARRAY_SIZE(channel_freq_power_JPN_BG),
+ }
+ ,
+/*Add new region here */
+};
+
+/**
+ * @brief This function finds the CFP in
+ * region_cfp_table based on region and band parameter.
+ *
+ * @param region The region code
+ * @param band The band
+ * @param cfp_no A pointer to CFP number
+ * @return A pointer to CFP
+ */
+static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)
+{
+ int i, end;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ end = ARRAY_SIZE(region_cfp_table);
+
+ for (i = 0; i < end ; i++) {
+ lbs_deb_main("region_cfp_table[i].region=%d\n",
+ region_cfp_table[i].region);
+ if (region_cfp_table[i].region == region) {
+ *cfp_no = region_cfp_table[i].cfp_no_BG;
+ lbs_deb_leave(LBS_DEB_MAIN);
+ return region_cfp_table[i].cfp_BG;
+ }
+ }
+
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");
+ return NULL;
+}
+
+int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
+{
+ int ret = 0;
+ int i = 0;
+
+ struct chan_freq_power *cfp;
+ int cfp_no;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ memset(priv->region_channel, 0, sizeof(priv->region_channel));
+
+ cfp = lbs_get_region_cfp_table(region, &cfp_no);
+ if (cfp != NULL) {
+ priv->region_channel[i].nrcfp = cfp_no;
+ priv->region_channel[i].CFP = cfp;
+ } else {
+ lbs_deb_main("wrong region code %#x in band B/G\n",
+ region);
+ ret = -1;
+ goto out;
+ }
+ priv->region_channel[i].valid = 1;
+ priv->region_channel[i].region = region;
+ priv->region_channel[i].band = band;
+ i++;
+out:
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+ return ret;
+}
+
+
+
/*********************************************************************/
/* */
@@ -161,31 +345,15 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv,
scantype = CMD_SCAN_TYPE_ACTIVE;
for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) {
- if (priv->enable11d && (priv->connect_status != LBS_CONNECTED)
- && (priv->mesh_connect_status != LBS_CONNECTED)) {
- /* Scan all the supported chan for the first scan */
- if (!priv->universal_channel[rgnidx].valid)
- continue;
- scanregion = &priv->universal_channel[rgnidx];
-
- /* clear the parsed_region_chan for the first scan */
- memset(&priv->parsed_region_chan, 0x00,
- sizeof(priv->parsed_region_chan));
- } else {
- if (!priv->region_channel[rgnidx].valid)
- continue;
- scanregion = &priv->region_channel[rgnidx];
- }
+ if (!priv->region_channel[rgnidx].valid)
+ continue;
+ scanregion = &priv->region_channel[rgnidx];
for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
struct chanscanparamset *chan = &scanchanlist[chanidx];
cfp = scanregion->CFP + nextchan;
- if (priv->enable11d)
- scantype = lbs_get_scan_type_11d(cfp->channel,
- &priv->parsed_region_chan);
-
if (scanregion->band == BAND_B || scanregion->band == BAND_G)
chan->radiotype = CMD_SCAN_RADIO_TYPE_BG;
@@ -519,7 +687,6 @@ static int lbs_process_bss(struct bss_descriptor *bss,
struct ieee_ie_cf_param_set *cf;
struct ieee_ie_ibss_param_set *ibss;
DECLARE_SSID_BUF(ssid);
- struct ieee_ie_country_info_set *pcountryinfo;
uint8_t *pos, *end, *p;
uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
uint16_t beaconsize = 0;
@@ -642,26 +809,6 @@ static int lbs_process_bss(struct bss_descriptor *bss,
lbs_deb_scan("got IBSS IE\n");
break;
- case WLAN_EID_COUNTRY:
- pcountryinfo = (struct ieee_ie_country_info_set *) pos;
- lbs_deb_scan("got COUNTRY IE\n");
- if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode)
- || pcountryinfo->header.len > 254) {
- lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n",
- __func__,
- pcountryinfo->header.len,
- sizeof(pcountryinfo->countrycode));
- ret = -1;
- goto done;
- }
-
- memcpy(&bss->countryinfo, pcountryinfo,
- pcountryinfo->header.len + 2);
- lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
- (uint8_t *) pcountryinfo,
- (int) (pcountryinfo->header.len + 2));
- break;
-
case WLAN_EID_EXT_SUPP_RATES:
/* only process extended supported rate if data rate is
* already found. Data rate IE should come before
@@ -812,7 +959,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
/* 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);
+ iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN);
start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
/* Mode */
@@ -1022,9 +1169,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
return -EAGAIN;
/* Update RSSI if current BSS is a locally created ad-hoc BSS */
- if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate)
- lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
- CMD_OPTION_WAITFORRSP, 0, NULL);
+ if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) {
+ err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
+ if (err)
+ goto out;
+ }
mutex_lock(&priv->lock);
list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
@@ -1058,7 +1208,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
dwrq->length = (ev - extra);
dwrq->flags = 0;
-
+out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
return err;
}
@@ -1141,11 +1291,11 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
/* The size of the TLV buffer is equal to the entire command response
* size (scanrespsize) minus the fixed fields (sizeof()'s), the
* BSS Descriptions (bssdescriptsize as bytesLef) and the command
- * response header (S_DS_GEN)
+ * response header (sizeof(struct cmd_header))
*/
tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize)
+ sizeof(scanresp->nr_sets)
- + S_DS_GEN);
+ + sizeof(struct cmd_header));
/*
* Process each scan response returned (scanresp->nr_sets). Save
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
index fab7d5d097f..8fb1706d752 100644
--- a/drivers/net/wireless/libertas/scan.h
+++ b/drivers/net/wireless/libertas/scan.h
@@ -9,8 +9,36 @@
#include <net/iw_handler.h>
+struct lbs_private;
+
#define MAX_NETWORK_COUNT 128
+/** 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;
+};
+
/**
* @brief Maximum number of channels that can be sent in a setuserscan ioctl
*/
@@ -18,6 +46,8 @@
int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
+int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
+
int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
u8 ssid_len);
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index 8c3766a6e8e..315d1ce286c 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -5,7 +5,7 @@
#include <linux/etherdevice.h>
#include <linux/sched.h>
-#include "hostcmd.h"
+#include "host.h"
#include "radiotap.h"
#include "decl.h"
#include "defs.h"
@@ -131,12 +131,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
txpd->tx_packet_length = cpu_to_le16(pkt_len);
txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
- if (dev == priv->mesh_dev) {
- if (priv->mesh_fw_ver == MESH_FW_OLD)
- txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
- else if (priv->mesh_fw_ver == MESH_FW_NEW)
- txpd->u.bss.bss_num = MESH_IFACE_ID;
- }
+ lbs_mesh_set_txpd(priv, dev, txpd);
lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd));
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 99905df65b2..3e72c86ceca 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -5,8 +5,8 @@
#define _LBS_TYPES_H_
#include <linux/if_ether.h>
+#include <linux/ieee80211.h>
#include <asm/byteorder.h>
-#include <linux/wireless.h>
struct ieee_ie_header {
u8 id;
@@ -247,7 +247,7 @@ struct mrvl_meshie_val {
uint8_t active_metric_id;
uint8_t mesh_capability;
uint8_t mesh_id_len;
- uint8_t mesh_id[IW_ESSID_MAX_SIZE];
+ uint8_t mesh_id[IEEE80211_MAX_SSID_LEN];
} __attribute__ ((packed));
struct mrvl_meshie {
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index be837a0d251..a8eb9e1fcf3 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -45,6 +45,63 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv)
priv->pending_assoc_req = NULL;
}
+void lbs_send_disconnect_notification(struct lbs_private *priv)
+{
+ union iwreq_data wrqu;
+
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+}
+
+static void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
+{
+ union iwreq_data iwrq;
+ u8 buf[50];
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+ memset(&iwrq, 0, sizeof(union iwreq_data));
+ memset(buf, 0, sizeof(buf));
+
+ snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+ iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
+
+ /* Send Event to upper layer */
+ lbs_deb_wext("event indication string %s\n", (char *)buf);
+ lbs_deb_wext("event indication length %d\n", iwrq.data.length);
+ lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
+
+ wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
+
+ lbs_deb_leave(LBS_DEB_WEXT);
+}
+
+/**
+ * @brief This function handles MIC failure event.
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @para event the event id
+ * @return n/a
+ */
+void lbs_send_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);
+}
/**
* @brief Find the channel frequency power info with specific channel
@@ -66,8 +123,6 @@ struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
rc = &priv->region_channel[j];
- if (priv->enable11d)
- rc = &priv->universal_channel[j];
if (!rc->valid || !rc->CFP)
continue;
if (rc->band != band)
@@ -107,8 +162,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(
for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
rc = &priv->region_channel[j];
- if (priv->enable11d)
- rc = &priv->universal_channel[j];
if (!rc->valid || !rc->CFP)
continue;
if (rc->band != band)
@@ -169,12 +222,12 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
- priv->curbssparams.channel);
+ priv->channel);
if (!cfp) {
- if (priv->curbssparams.channel)
+ if (priv->channel)
lbs_deb_wext("invalid channel %d\n",
- priv->curbssparams.channel);
+ priv->channel);
return -EINVAL;
}
@@ -547,8 +600,6 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
struct chan_freq_power *cfp;
u8 rates[MAX_RATES + 1];
- u8 flag = 0;
-
lbs_deb_enter(LBS_DEB_WEXT);
dwrq->length = sizeof(struct iw_range);
@@ -570,52 +621,21 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
range->scan_capa = IW_SCAN_CAPA_ESSID;
- if (priv->enable11d &&
- (priv->connect_status == LBS_CONNECTED ||
- priv->mesh_connect_status == LBS_CONNECTED)) {
- u8 chan_no;
- u8 band;
-
- struct parsed_region_chan_11d *parsed_region_chan =
- &priv->parsed_region_chan;
-
- if (parsed_region_chan == NULL) {
- lbs_deb_wext("11d: parsed_region_chan is NULL\n");
- goto out;
- }
- band = parsed_region_chan->band;
- lbs_deb_wext("band %d, nr_char %d\n", band,
- parsed_region_chan->nr_chan);
-
+ for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+ && (j < ARRAY_SIZE(priv->region_channel)); j++) {
+ cfp = priv->region_channel[j].CFP;
for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
- && (i < parsed_region_chan->nr_chan); i++) {
- chan_no = parsed_region_chan->chanpwr[i].chan;
- lbs_deb_wext("chan_no %d\n", chan_no);
- range->freq[range->num_frequency].i = (long)chan_no;
+ && priv->region_channel[j].valid
+ && cfp
+ && (i < priv->region_channel[j].nrcfp); i++) {
+ range->freq[range->num_frequency].i =
+ (long)cfp->channel;
range->freq[range->num_frequency].m =
- (long)lbs_chan_2_freq(chan_no) * 100000;
+ (long)cfp->freq * 100000;
range->freq[range->num_frequency].e = 1;
+ cfp++;
range->num_frequency++;
}
- flag = 1;
- }
- if (!flag) {
- for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
- && (j < ARRAY_SIZE(priv->region_channel)); j++) {
- cfp = priv->region_channel[j].CFP;
- for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
- && priv->region_channel[j].valid
- && cfp
- && (i < priv->region_channel[j].nrcfp); i++) {
- range->freq[range->num_frequency].i =
- (long)cfp->channel;
- range->freq[range->num_frequency].m =
- (long)cfp->freq * 100000;
- range->freq[range->num_frequency].e = 1;
- cfp++;
- range->num_frequency++;
- }
- }
}
lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
@@ -700,7 +720,6 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
| IW_ENC_CAPA_CIPHER_CCMP;
}
-out:
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
}
@@ -709,6 +728,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
struct lbs_private *priv = dev->ml_priv;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -737,8 +757,54 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
"setting power timeout is not supported\n");
return -EINVAL;
} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
- lbs_deb_wext("setting power period not supported\n");
- return -EINVAL;
+ vwrq->value = vwrq->value / 1000;
+ if (!priv->enter_deep_sleep) {
+ lbs_pr_err("deep sleep feature is not implemented "
+ "for this interface driver\n");
+ return -EINVAL;
+ }
+
+ if (priv->connect_status == LBS_CONNECTED) {
+ if ((priv->is_auto_deep_sleep_enabled) &&
+ (vwrq->value == -1000)) {
+ lbs_exit_auto_deep_sleep(priv);
+ return 0;
+ } else {
+ lbs_pr_err("can't use deep sleep cmd in "
+ "connected state\n");
+ return -EINVAL;
+ }
+ }
+
+ if ((vwrq->value < 0) && (vwrq->value != -1000)) {
+ lbs_pr_err("unknown option\n");
+ return -EINVAL;
+ }
+
+ if (vwrq->value > 0) {
+ if (!priv->is_auto_deep_sleep_enabled) {
+ priv->is_activity_detected = 0;
+ priv->auto_deep_sleep_timeout = vwrq->value;
+ lbs_enter_auto_deep_sleep(priv);
+ } else {
+ priv->auto_deep_sleep_timeout = vwrq->value;
+ lbs_deb_debugfs("auto deep sleep: "
+ "already enabled\n");
+ }
+ return 0;
+ } else {
+ if (priv->is_auto_deep_sleep_enabled) {
+ lbs_exit_auto_deep_sleep(priv);
+ /* Try to exit deep sleep if auto */
+ /*deep sleep disabled */
+ ret = lbs_set_deep_sleep(priv, 0);
+ }
+ if (vwrq->value == 0)
+ ret = lbs_set_deep_sleep(priv, 1);
+ else if (vwrq->value == -1000)
+ ret = lbs_set_deep_sleep(priv, 0);
+ return ret;
+ }
}
if (priv->psmode != LBS802_11POWERMODECAM) {
@@ -752,6 +818,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
}
lbs_deb_leave(LBS_DEB_WEXT);
+
return 0;
}
@@ -785,7 +852,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
u32 rssi_qual;
u32 tx_qual;
u32 quality = 0;
- int stats_valid = 0;
+ int ret, stats_valid = 0;
u8 rssi;
u32 tx_retries;
struct cmd_ds_802_11_get_log log;
@@ -834,7 +901,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
memset(&log, 0, sizeof(log));
log.hdr.size = cpu_to_le16(sizeof(log));
- lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
+ ret = lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
+ if (ret)
+ goto out;
tx_retries = le32_to_cpu(log.retry);
@@ -862,8 +931,10 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
stats_valid = 1;
/* update stats asynchronously for future calls */
- lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+ ret = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
0, 0, NULL);
+ if (ret)
+ lbs_pr_err("RSSI command failed\n");
out:
if (!stats_valid) {
priv->wstats.miss.beacon = 0;
@@ -973,7 +1044,7 @@ static int lbs_mesh_set_freq(struct net_device *dev,
goto out;
}
- if (fwrq->m != priv->curbssparams.channel) {
+ if (fwrq->m != priv->channel) {
lbs_deb_wext("mesh channel change forces eth disconnect\n");
if (priv->mode == IW_MODE_INFRA)
lbs_cmd_80211_deauthenticate(priv,
@@ -1000,6 +1071,7 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
u8 rates[MAX_RATES + 1];
lbs_deb_enter(LBS_DEB_WEXT);
+
lbs_deb_wext("vwrq->value %d\n", vwrq->value);
lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
@@ -1975,7 +2047,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
{
struct lbs_private *priv = dev->ml_priv;
int ret = 0;
- u8 ssid[IW_ESSID_MAX_SIZE];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len = 0;
struct assoc_request * assoc_req;
int in_ssid_len = dwrq->length;
@@ -1989,7 +2061,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
}
/* Check the size of the string */
- if (in_ssid_len > IW_ESSID_MAX_SIZE) {
+ if (in_ssid_len > IEEE80211_MAX_SSID_LEN) {
ret = -E2BIG;
goto out;
}
@@ -2020,7 +2092,7 @@ out:
ret = -ENOMEM;
} else {
/* Copy the SSID to the association request */
- memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE);
+ memcpy(&assoc_req->ssid, &ssid, IEEE80211_MAX_SSID_LEN);
assoc_req->ssid_len = ssid_len;
set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
lbs_postpone_association_work(priv);
@@ -2071,7 +2143,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
}
/* Check the size of the string */
- if (dwrq->length > IW_ESSID_MAX_SIZE) {
+ if (dwrq->length > IEEE80211_MAX_SSID_LEN) {
ret = -E2BIG;
goto out;
}
@@ -2086,7 +2158,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
}
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel);
+ priv->channel);
out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
index 4c08db49760..f3f19fe8c6c 100644
--- a/drivers/net/wireless/libertas/wext.h
+++ b/drivers/net/wireless/libertas/wext.h
@@ -4,7 +4,14 @@
#ifndef _LBS_WEXT_H_
#define _LBS_WEXT_H_
+void lbs_send_disconnect_notification(struct lbs_private *priv);
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
+
+struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
+ struct lbs_private *priv,
+ u8 band,
+ u16 channel);
+
extern struct iw_handler_def lbs_handler_def;
-extern struct iw_handler_def mesh_handler_def;
#endif