--- /dev/null
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/11d.c linux-2.6.22-300/drivers/net/wireless/libertas/11d.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/11d.c 2008-07-17 00:17:57.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/11d.c 2008-06-05 18:10:06.000000000 -0400
+@@ -43,16 +43,14 @@ static struct chan_freq_power channel_fr
+ {14, 2484, TX_PWR_DEFAULT}
+ };
+
+-static u8 wlan_region_2_code(u8 * region)
++static u8 lbs_region_2_code(u8 *region)
+ {
+ u8 i;
+- u8 size = sizeof(region_code_mapping)/
+- sizeof(struct region_code_mapping);
+
+ for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
+ region[i] = toupper(region[i]);
+
+- for (i = 0; i < size; 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);
+@@ -62,12 +60,11 @@ static u8 wlan_region_2_code(u8 * region
+ return (region_code_mapping[0].code);
+ }
+
+-static u8 *wlan_code_2_region(u8 code)
++static u8 *lbs_code_2_region(u8 code)
+ {
+ u8 i;
+- u8 size = sizeof(region_code_mapping)
+- / sizeof(struct region_code_mapping);
+- for (i = 0; i < size; i++) {
++
++ for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
+ if (region_code_mapping[i].code == code)
+ return (region_code_mapping[i].region);
+ }
+@@ -82,7 +79,7 @@ static u8 *wlan_code_2_region(u8 code)
+ * @param nrchan number of channels
+ * @return the nrchan-th chan number
+ */
+-static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan)
++static u8 lbs_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 *chan)
+ /*find the nrchan-th chan after the firstchan*/
+ {
+ u8 i;
+@@ -90,8 +87,7 @@ static u8 wlan_get_chan_11d(u8 band, u8
+ u8 cfp_no;
+
+ cfp = channel_freq_power_UN_BG;
+- cfp_no = sizeof(channel_freq_power_UN_BG) /
+- sizeof(struct chan_freq_power);
++ cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG);
+
+ for (i = 0; i < cfp_no; i++) {
+ if ((cfp + i)->channel == firstchan) {
+@@ -117,40 +113,36 @@ static u8 wlan_get_chan_11d(u8 band, u8
+ * @param parsed_region_chan pointer to parsed_region_chan_11d
+ * @return TRUE; FALSE
+ */
+-static u8 wlan_channel_known_11d(u8 chan,
++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_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr,
++ 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("11D: Found Chan:%d\n", chan);
++ lbs_deb_11d("found chan %d\n", chan);
+ return 1;
+ }
+ }
+
+- lbs_deb_11d("11D: Not Find Chan:%d\n", chan);
++ lbs_deb_11d("chan %d not found\n", chan);
+ return 0;
+ }
+
+-u32 libertas_chan_2_freq(u8 chan, u8 band)
++u32 lbs_chan_2_freq(u8 chan, u8 band)
+ {
+ struct chan_freq_power *cf;
+- u16 cnt;
+ u16 i;
+ u32 freq = 0;
+
+ cf = channel_freq_power_UN_BG;
+- cnt =
+- sizeof(channel_freq_power_UN_BG) /
+- sizeof(struct chan_freq_power);
+
+- for (i = 0; i < cnt; i++) {
++ for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) {
+ if (chan == cf[i].channel)
+ freq = cf[i].freq;
+ }
+@@ -160,7 +152,7 @@ u32 libertas_chan_2_freq(u8 chan, u8 ban
+
+ static int generate_domain_info_11d(struct parsed_region_chan_11d
+ *parsed_region_chan,
+- struct wlan_802_11d_domain_reg * domaininfo)
++ struct lbs_802_11d_domain_reg *domaininfo)
+ {
+ u8 nr_subband = 0;
+
+@@ -174,8 +166,8 @@ static int generate_domain_info_11d(stru
+ memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
+ COUNTRY_CODE_LEN);
+
+- lbs_deb_11d("11D:nrchan=%d\n", nr_chan);
+- lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan,
++ 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++) {
+@@ -213,7 +205,7 @@ static int generate_domain_info_11d(stru
+ domaininfo->nr_subband = nr_subband;
+
+ lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
+- lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo,
++ lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
+ COUNTRY_CODE_LEN + 1 +
+ sizeof(struct ieeetypes_subbandset) * nr_subband);
+ return 0;
+@@ -225,7 +217,7 @@ static int generate_domain_info_11d(stru
+ * @param *parsed_region_chan pointer to parsed_region_chan_11d
+ * @return N/A
+ */
+-static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan,
++static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_chan,
+ struct parsed_region_chan_11d *
+ parsed_region_chan)
+ {
+@@ -233,34 +225,34 @@ static void wlan_generate_parsed_region_
+ struct chan_freq_power *cfp;
+
+ if (region_chan == NULL) {
+- lbs_deb_11d("11D: region_chan is NULL\n");
++ lbs_deb_11d("region_chan is NULL\n");
+ return;
+ }
+
+ cfp = region_chan->CFP;
+ if (cfp == NULL) {
+- lbs_deb_11d("11D: cfp equal NULL \n");
++ 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,
+- wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
++ lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
+
+- lbs_deb_11d("11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
++ 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("11D: Chan[%d] Pwr[%d]\n",
++ 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("11D: nrchan[%d]\n", parsed_region_chan->nr_chan);
++ lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
+
+ return;
+ }
+@@ -272,7 +264,7 @@ static void wlan_generate_parsed_region_
+ * @param chan chan
+ * @return TRUE;FALSE
+ */
+-static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan)
++static u8 lbs_region_chan_supported_11d(u8 region, u8 band, u8 chan)
+ {
+ struct chan_freq_power *cfp;
+ int cfp_no;
+@@ -281,7 +273,7 @@ static u8 wlan_region_chan_supported_11d
+
+ lbs_deb_enter(LBS_DEB_11D);
+
+- cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
++ cfp = lbs_get_region_cfp_table(region, band, &cfp_no);
+ if (cfp == NULL)
+ return 0;
+
+@@ -336,7 +328,7 @@ static int parse_domain_info_11d(struct
+ 6. Others
+ */
+
+- lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30);
++ lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
+
+ if ((*(countryinfo->countrycode)) == 0
+ || (countryinfo->len <= COUNTRY_CODE_LEN)) {
+@@ -346,10 +338,10 @@ static int parse_domain_info_11d(struct
+
+ /*Step1: check region_code */
+ parsed_region_chan->region = region =
+- wlan_region_2_code(countryinfo->countrycode);
++ lbs_region_2_code(countryinfo->countrycode);
+
+ lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
+- lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode,
++ lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
+ COUNTRY_CODE_LEN);
+
+ parsed_region_chan->band = band;
+@@ -364,7 +356,7 @@ static int parse_domain_info_11d(struct
+
+ if (countryinfo->subband[j].firstchan <= lastchan) {
+ /*Step2&3. Check First Chan Num increment and no overlap */
+- lbs_deb_11d("11D: Chan[%d>%d] Overlap\n",
++ lbs_deb_11d("chan %d>%d, overlap\n",
+ countryinfo->subband[j].firstchan, lastchan);
+ continue;
+ }
+@@ -375,7 +367,7 @@ static int parse_domain_info_11d(struct
+ for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
+ /*step4: channel is supported? */
+
+- if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) {
++ if (!lbs_get_chan_11d(band, firstchan, i, &curchan)) {
+ /* Chan is not found in UN table */
+ lbs_deb_11d("chan is not supported: %d \n", i);
+ break;
+@@ -383,7 +375,7 @@ static int parse_domain_info_11d(struct
+
+ lastchan = curchan;
+
+- if (wlan_region_chan_supported_11d
++ if (lbs_region_chan_supported_11d
+ (region, band, curchan)) {
+ /*step5: Check if curchan is supported by mrvl in region */
+ parsed_region_chan->chanpwr[idx].chan = curchan;
+@@ -393,7 +385,7 @@ static int parse_domain_info_11d(struct
+ } else {
+ /*not supported and ignore the chan */
+ lbs_deb_11d(
+- "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n",
++ "i %d, chan %d unsupported in region %x, band %d\n",
+ i, curchan, region, band);
+ }
+ }
+@@ -405,7 +397,7 @@ static int parse_domain_info_11d(struct
+ parsed_region_chan->nr_chan = idx;
+
+ lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
+- lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_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:
+@@ -419,18 +411,18 @@ done:
+ * @param parsed_region_chan pointer to parsed_region_chan_11d
+ * @return PASSIVE if chan is unknown; ACTIVE if chan is known
+ */
+-u8 libertas_get_scan_type_11d(u8 chan,
++u8 lbs_get_scan_type_11d(u8 chan,
+ struct parsed_region_chan_11d * parsed_region_chan)
+ {
+- u8 scan_type = cmd_scan_type_passive;
++ u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
+
+ lbs_deb_enter(LBS_DEB_11D);
+
+- if (wlan_channel_known_11d(chan, parsed_region_chan)) {
+- lbs_deb_11d("11D: Found and do Active Scan\n");
+- scan_type = cmd_scan_type_active;
++ 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("11D: Not Find and do Passive Scan\n");
++ lbs_deb_11d("not found, do passive scan\n");
+ }
+
+ lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
+@@ -438,80 +430,60 @@ u8 libertas_get_scan_type_11d(u8 chan,
+
+ }
+
+-void libertas_init_11d(wlan_private * priv)
++void lbs_init_11d(struct lbs_private *priv)
+ {
+- priv->adapter->enable11d = 0;
+- memset(&(priv->adapter->parsed_region_chan), 0,
++ priv->enable11d = 0;
++ memset(&(priv->parsed_region_chan), 0,
+ sizeof(struct parsed_region_chan_11d));
+ return;
+ }
+
+-static int wlan_enable_11d(wlan_private * priv, u8 flag)
+-{
+- int ret;
+-
+- priv->adapter->enable11d = flag;
+-
+- /* send cmd to FW to enable/disable 11D function in FW */
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_snmp_mib,
+- cmd_act_set,
+- cmd_option_waitforrsp,
+- OID_802_11D_ENABLE,
+- &priv->adapter->enable11d);
+- if (ret)
+- lbs_deb_11d("11D: Fail to enable 11D \n");
+-
+- return 0;
+-}
+-
+ /**
+ * @brief This function sets DOMAIN INFO to FW
+- * @param priv pointer to wlan_private
++ * @param priv pointer to struct lbs_private
+ * @return 0; -1
+ */
+-static int set_domain_info_11d(wlan_private * priv)
++static int set_domain_info_11d(struct lbs_private *priv)
+ {
+ int ret;
+
+- if (!priv->adapter->enable11d) {
+- lbs_deb_11d("11D: dnld domain Info with 11d disabled\n");
++ if (!priv->enable11d) {
++ lbs_deb_11d("dnld domain Info with 11d disabled\n");
+ return 0;
+ }
+
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info,
+- cmd_act_set,
+- cmd_option_waitforrsp, 0, NULL);
++ 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("11D: Fail to dnld domain Info\n");
++ lbs_deb_11d("fail to dnld domain info\n");
+
+ return ret;
+ }
+
+ /**
+ * @brief This function setups scan channels
+- * @param priv pointer to wlan_private
++ * @param priv pointer to struct lbs_private
+ * @param band band
+ * @return 0
+ */
+-int libertas_set_universaltable(wlan_private * priv, u8 band)
++int lbs_set_universaltable(struct lbs_private *priv, u8 band)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ u16 size = sizeof(struct chan_freq_power);
+ u16 i = 0;
+
+- memset(adapter->universal_channel, 0,
+- sizeof(adapter->universal_channel));
++ memset(priv->universal_channel, 0,
++ sizeof(priv->universal_channel));
+
+- adapter->universal_channel[i].nrcfp =
++ priv->universal_channel[i].nrcfp =
+ sizeof(channel_freq_power_UN_BG) / size;
+- lbs_deb_11d("11D: BG-band nrcfp=%d\n",
+- adapter->universal_channel[i].nrcfp);
++ lbs_deb_11d("BG-band nrcfp %d\n",
++ priv->universal_channel[i].nrcfp);
+
+- adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
+- adapter->universal_channel[i].valid = 1;
+- adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+- adapter->universal_channel[i].band = band;
++ 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;
+@@ -519,21 +491,20 @@ int libertas_set_universaltable(wlan_pri
+
+ /**
+ * @brief This function implements command CMD_802_11D_DOMAIN_INFO
+- * @param priv pointer to wlan_private
++ * @param priv pointer to struct lbs_private
+ * @param cmd pointer to cmd buffer
+ * @param cmdno cmd ID
+ * @param cmdOption cmd action
+ * @return 0
+ */
+-int libertas_cmd_802_11d_domain_info(wlan_private * priv,
++int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
+ struct cmd_ds_command *cmd, u16 cmdno,
+ u16 cmdoption)
+ {
+ struct cmd_ds_802_11d_domain_info *pdomaininfo =
+ &cmd->params.domaininfo;
+ struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
+- wlan_adapter *adapter = priv->adapter;
+- u8 nr_subband = adapter->domainreg.nr_subband;
++ u8 nr_subband = priv->domainreg.nr_subband;
+
+ lbs_deb_enter(LBS_DEB_11D);
+
+@@ -541,16 +512,16 @@ int libertas_cmd_802_11d_domain_info(wla
+
+ cmd->command = cpu_to_le16(cmdno);
+ pdomaininfo->action = cpu_to_le16(cmdoption);
+- if (cmdoption == cmd_act_get) {
++ if (cmdoption == CMD_ACT_GET) {
+ cmd->size =
+ cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
+- lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd,
+- (int)(cmd->size));
++ 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, adapter->domainreg.countrycode,
++ memcpy(domain->countrycode, priv->domainreg.countrycode,
+ sizeof(domain->countrycode));
+
+ domain->header.len =
+@@ -558,7 +529,7 @@ int libertas_cmd_802_11d_domain_info(wla
+ sizeof(domain->countrycode));
+
+ if (nr_subband) {
+- memcpy(domain->subband, adapter->domainreg.subband,
++ memcpy(domain->subband, priv->domainreg.subband,
+ nr_subband * sizeof(struct ieeetypes_subbandset));
+
+ cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+@@ -570,7 +541,7 @@ int libertas_cmd_802_11d_domain_info(wla
+ cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
+ }
+
+- lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, le16_to_cpu(cmd->size));
++ lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
+
+ done:
+ lbs_deb_enter(LBS_DEB_11D);
+@@ -578,37 +549,12 @@ done:
+ }
+
+ /**
+- * @brief This function implements private cmd: enable/disable 11D
+- * @param priv pointer to wlan_private
+- * @param wrq pointer to user data
+- * @return 0 or -1
+- */
+-int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
+-{
+- int data = 0;
+- int *val;
+-
+- lbs_deb_enter(LBS_DEB_11D);
+- data = SUBCMD_DATA(wrq);
+-
+- lbs_deb_11d("enable 11D: %s\n",
+- (data == 1) ? "enable" : "Disable");
+-
+- wlan_enable_11d(priv, data);
+- val = (int *)wrq->u.name;
+- *val = priv->adapter->enable11d;
+-
+- 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 wlan_private
++ * @param priv pointer to struct lbs_private
+ * @param resp pointer to command response buffer
+ * @return 0; -1
+ */
+-int libertas_ret_802_11d_domain_info(wlan_private * priv,
++int lbs_ret_802_11d_domain_info(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+ struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
+@@ -619,13 +565,13 @@ int libertas_ret_802_11d_domain_info(wla
+
+ lbs_deb_enter(LBS_DEB_11D);
+
+- lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp,
++ lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
+ (int)le16_to_cpu(resp->size));
+
+ nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
+ sizeof(struct ieeetypes_subbandset);
+
+- lbs_deb_11d("11D Domain Info Resp: nr_subband=%d\n", nr_subband);
++ 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");
+@@ -633,10 +579,10 @@ int libertas_ret_802_11d_domain_info(wla
+ }
+
+ switch (action) {
+- case cmd_act_set: /*Proc Set action */
++ case CMD_ACT_SET: /*Proc Set action */
+ break;
+
+- case cmd_act_get:
++ case CMD_ACT_GET:
+ break;
+ default:
+ lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
+@@ -650,36 +596,35 @@ int libertas_ret_802_11d_domain_info(wla
+
+ /**
+ * @brief This function parses countryinfo from AP and download country info to FW
+- * @param priv pointer to wlan_private
++ * @param priv pointer to struct lbs_private
+ * @return 0; -1
+ */
+-int libertas_parse_dnld_countryinfo_11d(wlan_private * priv,
++int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
+ struct bss_descriptor * bss)
+ {
+ int ret;
+- wlan_adapter *adapter = priv->adapter;
+
+ lbs_deb_enter(LBS_DEB_11D);
+- if (priv->adapter->enable11d) {
+- memset(&adapter->parsed_region_chan, 0,
++ if (priv->enable11d) {
++ memset(&priv->parsed_region_chan, 0,
+ sizeof(struct parsed_region_chan_11d));
+ ret = parse_domain_info_11d(&bss->countryinfo, 0,
+- &adapter->parsed_region_chan);
++ &priv->parsed_region_chan);
+
+ if (ret == -1) {
+- lbs_deb_11d("11D: Err Parse domain_info from AP..\n");
++ lbs_deb_11d("error parsing domain_info from AP\n");
+ goto done;
+ }
+
+- memset(&adapter->domainreg, 0,
+- sizeof(struct wlan_802_11d_domain_reg));
+- generate_domain_info_11d(&adapter->parsed_region_chan,
+- &adapter->domainreg);
++ 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("11D: Err set domainInfo to FW\n");
++ lbs_deb_11d("error setting domain info\n");
+ goto done;
+ }
+ }
+@@ -692,60 +637,57 @@ done:
+
+ /**
+ * @brief This function generates 11D info from user specified regioncode and download to FW
+- * @param priv pointer to wlan_private
++ * @param priv pointer to struct lbs_private
+ * @return 0; -1
+ */
+-int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
++int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv)
+ {
+ int ret;
+- wlan_adapter *adapter = priv->adapter;
+ struct region_channel *region_chan;
+ u8 j;
+
+ lbs_deb_enter(LBS_DEB_11D);
+- lbs_deb_11d("11D:curbssparams.band[%d]\n", adapter->curbssparams.band);
++ lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band);
+
+- if (priv->adapter->enable11d) {
++ if (priv->enable11d) {
+ /* update parsed_region_chan_11; dnld domaininf to FW */
+
+- for (j = 0; j < sizeof(adapter->region_channel) /
+- sizeof(adapter->region_channel[0]); j++) {
+- region_chan = &adapter->region_channel[j];
++ for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) {
++ region_chan = &priv->region_channel[j];
+
+- lbs_deb_11d("11D:[%d] region_chan->band[%d]\n", 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 != adapter->curbssparams.band)
++ if (region_chan->band != priv->curbssparams.band)
+ continue;
+ break;
+ }
+
+- if (j >= sizeof(adapter->region_channel) /
+- sizeof(adapter->region_channel[0])) {
+- lbs_deb_11d("11D:region_chan not found. band[%d]\n",
+- adapter->curbssparams.band);
++ 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(&adapter->parsed_region_chan, 0,
++ memset(&priv->parsed_region_chan, 0,
+ sizeof(struct parsed_region_chan_11d));
+- wlan_generate_parsed_region_chan_11d(region_chan,
+- &adapter->
++ lbs_generate_parsed_region_chan_11d(region_chan,
++ &priv->
+ parsed_region_chan);
+
+- memset(&adapter->domainreg, 0,
+- sizeof(struct wlan_802_11d_domain_reg));
+- generate_domain_info_11d(&adapter->parsed_region_chan,
+- &adapter->domainreg);
++ 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("11D: Err set domainInfo to FW\n");
++ lbs_deb_11d("error setting domain info\n");
+ goto done;
+ }
+
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/11d.h linux-2.6.22-300/drivers/net/wireless/libertas/11d.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/11d.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/11d.h 2008-06-05 18:10:06.000000000 -0400
+@@ -2,8 +2,8 @@
+ * This header file contains data structures and
+ * function declarations of 802.11d
+ */
+-#ifndef _WLAN_11D_
+-#define _WLAN_11D_
++#ifndef _LBS_11D_
++#define _LBS_11D_
+
+ #include "types.h"
+ #include "defs.h"
+@@ -52,7 +52,7 @@ struct cmd_ds_802_11d_domain_info {
+ } __attribute__ ((packed));
+
+ /** domain regulatory information */
+-struct wlan_802_11d_domain_reg {
++struct lbs_802_11d_domain_reg {
+ /** country Code*/
+ u8 countrycode[COUNTRY_CODE_LEN];
+ /** No. of subband*/
+@@ -78,30 +78,28 @@ struct region_code_mapping {
+ u8 code;
+ };
+
+-u8 libertas_get_scan_type_11d(u8 chan,
+- struct parsed_region_chan_11d *parsed_region_chan);
++struct lbs_private;
+
+-u32 libertas_chan_2_freq(u8 chan, u8 band);
++u8 lbs_get_scan_type_11d(u8 chan,
++ struct parsed_region_chan_11d *parsed_region_chan);
+
+-enum state_11d libertas_get_state_11d(wlan_private * priv);
++u32 lbs_chan_2_freq(u8 chan, u8 band);
+
+-void libertas_init_11d(wlan_private * priv);
++void lbs_init_11d(struct lbs_private *priv);
+
+-int libertas_set_universaltable(wlan_private * priv, u8 band);
++int lbs_set_universaltable(struct lbs_private *priv, u8 band);
+
+-int libertas_cmd_802_11d_domain_info(wlan_private * priv,
++int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
+ struct cmd_ds_command *cmd, u16 cmdno,
+ u16 cmdOption);
+
+-int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
+-
+-int libertas_ret_802_11d_domain_info(wlan_private * priv,
++int lbs_ret_802_11d_domain_info(struct lbs_private *priv,
+ struct cmd_ds_command *resp);
+
+ struct bss_descriptor;
+-int libertas_parse_dnld_countryinfo_11d(wlan_private * priv,
++int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
+ struct bss_descriptor * bss);
+
+-int libertas_create_dnld_countryinfo_11d(wlan_private * priv);
++int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv);
+
+-#endif /* _WLAN_11D_ */
++#endif
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/assoc.c linux-2.6.22-300/drivers/net/wireless/libertas/assoc.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/assoc.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/assoc.c 2008-06-05 18:10:06.000000000 -0400
+@@ -9,38 +9,16 @@
+ #include "decl.h"
+ #include "hostcmd.h"
+ #include "host.h"
++#include "cmd.h"
+
+
+ static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+-static void print_assoc_req(const char * extra, struct assoc_request * assoc_req)
+-{
+- lbs_deb_assoc(
+- "#### Association Request: %s\n"
+- " flags: 0x%08lX\n"
+- " SSID: '%s'\n"
+- " channel: %d\n"
+- " band: %d\n"
+- " mode: %d\n"
+- " BSSID: " MAC_FMT "\n"
+- " Encryption:%s%s%s\n"
+- " auth: %d\n",
+- extra, assoc_req->flags,
+- escape_essid(assoc_req->ssid, assoc_req->ssid_len),
+- assoc_req->channel, assoc_req->band, assoc_req->mode,
+- MAC_ARG(assoc_req->bssid),
+- assoc_req->secinfo.WPAenabled ? " WPA" : "",
+- assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
+- assoc_req->secinfo.wep_enabled ? " WEP" : "",
+- assoc_req->secinfo.auth_mode);
+-}
+
+-
+-static int assoc_helper_essid(wlan_private *priv,
++static int assoc_helper_essid(struct lbs_private *priv,
+ struct assoc_request * assoc_req)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct bss_descriptor * bss;
+ int channel = -1;
+@@ -54,20 +32,17 @@ static int assoc_helper_essid(wlan_priva
+ if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
+ channel = assoc_req->channel;
+
+- lbs_deb_assoc("New SSID requested: '%s'\n",
++ lbs_deb_assoc("SSID '%s' requested\n",
+ escape_essid(assoc_req->ssid, assoc_req->ssid_len));
+ if (assoc_req->mode == IW_MODE_INFRA) {
+- if (adapter->prescan) {
+- libertas_send_specific_ssid_scan(priv, assoc_req->ssid,
+- assoc_req->ssid_len, 0);
+- }
++ lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
++ assoc_req->ssid_len, 0);
+
+- bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid,
++ bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
+ assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
+ if (bss != NULL) {
+- lbs_deb_assoc("SSID found in scan list, associating\n");
+ memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
+- ret = wlan_associate(priv, assoc_req);
++ ret = lbs_associate(priv, assoc_req);
+ } else {
+ lbs_deb_assoc("SSID not found; cannot associate\n");
+ }
+@@ -75,23 +50,23 @@ static int assoc_helper_essid(wlan_priva
+ /* Scan for the network, do not save previous results. Stale
+ * scan data will cause us to join a non-existant adhoc network
+ */
+- libertas_send_specific_ssid_scan(priv, assoc_req->ssid,
++ lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
+ assoc_req->ssid_len, 1);
+
+ /* Search for the requested SSID in the scan table */
+- bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid,
++ bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
+ assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel);
+ if (bss != NULL) {
+ lbs_deb_assoc("SSID found, will join\n");
+ memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
+- libertas_join_adhoc_network(priv, assoc_req);
++ lbs_join_adhoc_network(priv, assoc_req);
+ } else {
+ /* 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);
+ assoc_req->bss.ssid_len = assoc_req->ssid_len;
+- libertas_start_adhoc_network(priv, assoc_req);
++ lbs_start_adhoc_network(priv, assoc_req);
+ }
+ }
+
+@@ -100,31 +75,31 @@ static int assoc_helper_essid(wlan_priva
+ }
+
+
+-static int assoc_helper_bssid(wlan_private *priv,
++static int assoc_helper_bssid(struct lbs_private *priv,
+ struct assoc_request * assoc_req)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct bss_descriptor * bss;
++ DECLARE_MAC_BUF(mac);
+
+- lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID " MAC_FMT,
+- MAC_ARG(assoc_req->bssid));
++ lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s",
++ print_mac(mac, assoc_req->bssid));
+
+ /* Search for index position in list for requested MAC */
+- bss = libertas_find_bssid_in_list(adapter, assoc_req->bssid,
++ bss = lbs_find_bssid_in_list(priv, assoc_req->bssid,
+ assoc_req->mode);
+ if (bss == NULL) {
+- lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, "
+- "cannot associate.\n", MAC_ARG(assoc_req->bssid));
++ lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, "
++ "cannot associate.\n", print_mac(mac, assoc_req->bssid));
+ goto out;
+ }
+
+ memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
+ if (assoc_req->mode == IW_MODE_INFRA) {
+- ret = wlan_associate(priv, assoc_req);
+- lbs_deb_assoc("ASSOC: wlan_associate(bssid) returned %d\n", ret);
++ ret = lbs_associate(priv, assoc_req);
++ lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret);
+ } else if (assoc_req->mode == IW_MODE_ADHOC) {
+- libertas_join_adhoc_network(priv, assoc_req);
++ lbs_join_adhoc_network(priv, assoc_req);
+ }
+
+ out:
+@@ -133,11 +108,13 @@ out:
+ }
+
+
+-static int assoc_helper_associate(wlan_private *priv,
++static int assoc_helper_associate(struct lbs_private *priv,
+ struct assoc_request * assoc_req)
+ {
+ int ret = 0, done = 0;
+
++ lbs_deb_enter(LBS_DEB_ASSOC);
++
+ /* If we're given and 'any' BSSID, try associating based on SSID */
+
+ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+@@ -145,44 +122,38 @@ static int assoc_helper_associate(wlan_p
+ && compare_ether_addr(bssid_off, assoc_req->bssid)) {
+ ret = assoc_helper_bssid(priv, assoc_req);
+ done = 1;
+- if (ret) {
+- lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
+- }
+ }
+ }
+
+ if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+ ret = assoc_helper_essid(priv, assoc_req);
+- if (ret) {
+- lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
+- }
+ }
+
++ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+ return ret;
+ }
+
+
+-static int assoc_helper_mode(wlan_private *priv,
++static int assoc_helper_mode(struct lbs_private *priv,
+ struct assoc_request * assoc_req)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_ASSOC);
+
+- if (assoc_req->mode == adapter->mode)
++ if (assoc_req->mode == priv->mode)
+ goto done;
+
+ if (assoc_req->mode == IW_MODE_INFRA) {
+- if (adapter->psstate != PS_STATE_FULL_POWER)
+- libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+- adapter->psmode = wlan802_11powermodecam;
++ if (priv->psstate != PS_STATE_FULL_POWER)
++ lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
++ priv->psmode = LBS802_11POWERMODECAM;
+ }
+
+- adapter->mode = assoc_req->mode;
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_snmp_mib,
+- 0, cmd_option_waitforrsp,
++ priv->mode = assoc_req->mode;
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_SNMP_MIB,
++ 0, CMD_OPTION_WAITFORRSP,
+ OID_802_11_INFRASTRUCTURE_MODE,
+ /* Shoot me now */ (void *) (size_t) assoc_req->mode);
+
+@@ -192,57 +163,77 @@ done:
+ }
+
+
+-static int update_channel(wlan_private * priv)
++int lbs_update_channel(struct lbs_private *priv)
+ {
+- /* the channel in f/w could be out of sync, get the current channel */
+- return libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+- cmd_opt_802_11_rf_channel_get,
+- cmd_option_waitforrsp, 0, NULL);
++ int ret;
++
++ /* the channel in f/w could be out of sync; get the current channel */
++ lbs_deb_enter(LBS_DEB_ASSOC);
++
++ ret = lbs_get_channel(priv);
++ if (ret > 0) {
++ priv->curbssparams.channel = ret;
++ ret = 0;
++ }
++ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
++ return ret;
+ }
+
+-void libertas_sync_channel(struct work_struct *work)
++void lbs_sync_channel(struct work_struct *work)
+ {
+- wlan_private *priv = container_of(work, wlan_private, sync_channel);
++ struct lbs_private *priv = container_of(work, struct lbs_private,
++ sync_channel);
+
+- if (update_channel(priv) != 0)
++ lbs_deb_enter(LBS_DEB_ASSOC);
++ if (lbs_update_channel(priv))
+ lbs_pr_info("Channel synchronization failed.");
++ lbs_deb_leave(LBS_DEB_ASSOC);
+ }
+
+-static int assoc_helper_channel(wlan_private *priv,
++static int assoc_helper_channel(struct lbs_private *priv,
+ struct assoc_request * assoc_req)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_ASSOC);
+
+- ret = update_channel(priv);
+- if (ret < 0) {
+- lbs_deb_assoc("ASSOC: channel: error getting channel.");
++ ret = lbs_update_channel(priv);
++ if (ret) {
++ lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
++ goto done;
+ }
+
+- if (assoc_req->channel == adapter->curbssparams.channel)
++ if (assoc_req->channel == priv->curbssparams.channel)
+ goto done;
+
+- lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
+- adapter->curbssparams.channel, assoc_req->channel);
+-
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+- cmd_opt_802_11_rf_channel_set,
+- cmd_option_waitforrsp, 0, &assoc_req->channel);
+- if (ret < 0) {
+- lbs_deb_assoc("ASSOC: channel: error setting channel.");
++ if (priv->mesh_dev) {
++ /* Change mesh channel first; 21.p21 firmware won't let
++ you change channel otherwise (even though it'll return
++ an error to this */
++ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
++ assoc_req->channel);
+ }
+
+- ret = update_channel(priv);
+- if (ret < 0) {
+- lbs_deb_assoc("ASSOC: channel: error getting channel.");
++ lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
++ priv->curbssparams.channel, assoc_req->channel);
++
++ ret = lbs_set_channel(priv, assoc_req->channel);
++ if (ret < 0)
++ lbs_deb_assoc("ASSOC: channel: error setting channel.\n");
++
++ /* FIXME: shouldn't need to grab the channel _again_ after setting
++ * it since the firmware is supposed to return the new channel, but
++ * whatever... */
++ ret = lbs_update_channel(priv);
++ if (ret) {
++ lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
++ goto done;
+ }
+
+- if (assoc_req->channel != adapter->curbssparams.channel) {
+- lbs_deb_assoc("ASSOC: channel: failed to update channel to %d",
++ if (assoc_req->channel != priv->curbssparams.channel) {
++ lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
+ assoc_req->channel);
+- goto done;
++ goto restore_mesh;
+ }
+
+ if ( assoc_req->secinfo.wep_enabled
+@@ -255,18 +246,22 @@ static int assoc_helper_channel(wlan_pri
+ }
+
+ /* Must restart/rejoin adhoc networks after channel change */
+- set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
++ set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
+
+-done:
++ restore_mesh:
++ if (priv->mesh_dev)
++ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
++ priv->curbssparams.channel);
++
++ done:
+ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+ return ret;
+ }
+
+
+-static int assoc_helper_wep_keys(wlan_private *priv,
++static int assoc_helper_wep_keys(struct lbs_private *priv,
+ struct assoc_request * assoc_req)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int i;
+ int ret = 0;
+
+@@ -277,16 +272,16 @@ static int assoc_helper_wep_keys(wlan_pr
+ || assoc_req->wep_keys[1].len
+ || assoc_req->wep_keys[2].len
+ || assoc_req->wep_keys[3].len) {
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_set_wep,
+- cmd_act_add,
+- cmd_option_waitforrsp,
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_SET_WEP,
++ CMD_ACT_ADD,
++ CMD_OPTION_WAITFORRSP,
+ 0, assoc_req);
+ } else {
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_set_wep,
+- cmd_act_remove,
+- cmd_option_waitforrsp,
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_SET_WEP,
++ CMD_ACT_REMOVE,
++ CMD_OPTION_WAITFORRSP,
+ 0, NULL);
+ }
+
+@@ -295,45 +290,41 @@ static int assoc_helper_wep_keys(wlan_pr
+
+ /* enable/disable the MAC's WEP packet filter */
+ if (assoc_req->secinfo.wep_enabled)
+- adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
++ priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
+ else
+- adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
+- ret = libertas_set_mac_packet_filter(priv);
+- if (ret)
+- goto out;
++ priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
++
++ lbs_set_mac_control(priv);
+
+- mutex_lock(&adapter->lock);
++ mutex_lock(&priv->lock);
+
+- /* Copy WEP keys into adapter wep key fields */
++ /* Copy WEP keys into priv wep key fields */
+ for (i = 0; i < 4; i++) {
+- memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
+- sizeof(struct WLAN_802_11_KEY));
++ memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i],
++ sizeof(struct enc_key));
+ }
+- adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
++ priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
+
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+ return ret;
+ }
+
+-static int assoc_helper_secinfo(wlan_private *priv,
++static int assoc_helper_secinfo(struct lbs_private *priv,
+ struct assoc_request * assoc_req)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ u32 do_wpa;
+ u32 rsn = 0;
+
+ lbs_deb_enter(LBS_DEB_ASSOC);
+
+- memcpy(&adapter->secinfo, &assoc_req->secinfo,
+- sizeof(struct wlan_802_11_security));
++ memcpy(&priv->secinfo, &assoc_req->secinfo,
++ sizeof(struct lbs_802_11_security));
+
+- ret = libertas_set_mac_packet_filter(priv);
+- if (ret)
+- goto out;
++ lbs_set_mac_control(priv);
+
+ /* If RSN is already enabled, don't try to enable it again, since
+ * ENABLE_RSN resets internal state machines and will clobber the
+@@ -341,13 +332,13 @@ static int assoc_helper_secinfo(wlan_pri
+ */
+
+ /* Get RSN enabled/disabled */
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_enable_rsn,
+- cmd_act_set,
+- cmd_option_waitforrsp,
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_ENABLE_RSN,
++ CMD_ACT_GET,
++ CMD_OPTION_WAITFORRSP,
+ 0, &rsn);
+ if (ret) {
+- lbs_deb_assoc("Failed to get RSN status: %d", ret);
++ lbs_deb_assoc("Failed to get RSN status: %d\n", ret);
+ goto out;
+ }
+
+@@ -358,10 +349,10 @@ static int assoc_helper_secinfo(wlan_pri
+
+ /* Set RSN enabled/disabled */
+ rsn = do_wpa;
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_enable_rsn,
+- cmd_act_set,
+- cmd_option_waitforrsp,
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_ENABLE_RSN,
++ CMD_ACT_SET,
++ CMD_OPTION_WAITFORRSP,
+ 0, &rsn);
+
+ out:
+@@ -370,38 +361,62 @@ out:
+ }
+
+
+-static int assoc_helper_wpa_keys(wlan_private *priv,
++static int assoc_helper_wpa_keys(struct lbs_private *priv,
+ struct assoc_request * assoc_req)
+ {
+ int ret = 0;
++ unsigned int flags = assoc_req->flags;
+
+ lbs_deb_enter(LBS_DEB_ASSOC);
+
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_key_material,
+- cmd_act_set,
+- cmd_option_waitforrsp,
+- 0, assoc_req);
++ /* Work around older firmware bug where WPA unicast and multicast
++ * keys must be set independently. Seen in SDIO parts with firmware
++ * version 5.0.11p0.
++ */
++
++ if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
++ clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_KEY_MATERIAL,
++ CMD_ACT_SET,
++ CMD_OPTION_WAITFORRSP,
++ 0, assoc_req);
++ assoc_req->flags = flags;
++ }
++
++ if (ret)
++ goto out;
++
++ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
++ clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
++
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_KEY_MATERIAL,
++ CMD_ACT_SET,
++ CMD_OPTION_WAITFORRSP,
++ 0, assoc_req);
++ assoc_req->flags = flags;
++ }
+
++out:
+ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+ return ret;
+ }
+
+
+-static int assoc_helper_wpa_ie(wlan_private *priv,
++static int assoc_helper_wpa_ie(struct lbs_private *priv,
+ struct assoc_request * assoc_req)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_ASSOC);
+
+ if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
+- memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
+- adapter->wpa_ie_len = assoc_req->wpa_ie_len;
++ memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
++ priv->wpa_ie_len = assoc_req->wpa_ie_len;
+ } else {
+- memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
+- adapter->wpa_ie_len = 0;
++ memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN);
++ priv->wpa_ie_len = 0;
+ }
+
+ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+@@ -409,55 +424,68 @@ static int assoc_helper_wpa_ie(wlan_priv
+ }
+
+
+-static int should_deauth_infrastructure(wlan_adapter *adapter,
++static int should_deauth_infrastructure(struct lbs_private *priv,
+ struct assoc_request * assoc_req)
+ {
+- if (adapter->connect_status != libertas_connected)
++ int ret = 0;
++
++ lbs_deb_enter(LBS_DEB_ASSOC);
++
++ if (priv->connect_status != LBS_CONNECTED)
+ return 0;
+
+ if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+- lbs_deb_assoc("Deauthenticating due to new SSID in "
+- " configuration request.\n");
+- return 1;
++ lbs_deb_assoc("Deauthenticating due to new SSID\n");
++ ret = 1;
++ goto out;
+ }
+
+ if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+- if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
+- lbs_deb_assoc("Deauthenticating due to updated security "
+- "info in configuration request.\n");
+- return 1;
++ if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
++ lbs_deb_assoc("Deauthenticating due to new security\n");
++ ret = 1;
++ goto out;
+ }
+ }
+
+ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+- lbs_deb_assoc("Deauthenticating due to new BSSID in "
+- " configuration request.\n");
+- return 1;
++ lbs_deb_assoc("Deauthenticating due to new BSSID\n");
++ ret = 1;
++ goto out;
+ }
+
+ if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
+- lbs_deb_assoc("Deauthenticating due to channel switch.\n");
+- return 1;
++ lbs_deb_assoc("Deauthenticating due to channel switch\n");
++ ret = 1;
++ goto out;
+ }
+
+ /* FIXME: deal with 'auto' mode somehow */
+ if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+- if (assoc_req->mode != IW_MODE_INFRA)
+- return 1;
++ if (assoc_req->mode != IW_MODE_INFRA) {
++ lbs_deb_assoc("Deauthenticating due to leaving "
++ "infra mode\n");
++ ret = 1;
++ goto out;
++ }
+ }
+
+- return 0;
++out:
++ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
++ return ret;
+ }
+
+
+-static int should_stop_adhoc(wlan_adapter *adapter,
++static int should_stop_adhoc(struct lbs_private *priv,
+ struct assoc_request * assoc_req)
+ {
+- if (adapter->connect_status != libertas_connected)
++ lbs_deb_enter(LBS_DEB_ASSOC);
++
++ if (priv->connect_status != LBS_CONNECTED)
+ return 0;
+
+- if (libertas_ssid_cmp(adapter->curbssparams.ssid,
+- adapter->curbssparams.ssid_len,
++ if (lbs_ssid_cmp(priv->curbssparams.ssid,
++ priv->curbssparams.ssid_len,
+ assoc_req->ssid, assoc_req->ssid_len) != 0)
+ return 1;
+
+@@ -468,34 +496,53 @@ static int should_stop_adhoc(wlan_adapte
+ }
+
+ if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
+- if (assoc_req->channel != adapter->curbssparams.channel)
++ if (assoc_req->channel != priv->curbssparams.channel)
+ return 1;
+ }
+
++ lbs_deb_leave(LBS_DEB_ASSOC);
+ return 0;
+ }
+
+
+-void libertas_association_worker(struct work_struct *work)
++void lbs_association_worker(struct work_struct *work)
+ {
+- wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = container_of(work, struct lbs_private,
++ assoc_work.work);
+ struct assoc_request * assoc_req = NULL;
+ int ret = 0;
+ int find_any_ssid = 0;
++ DECLARE_MAC_BUF(mac);
+
+ lbs_deb_enter(LBS_DEB_ASSOC);
+
+- mutex_lock(&adapter->lock);
+- assoc_req = adapter->pending_assoc_req;
+- adapter->pending_assoc_req = NULL;
+- adapter->in_progress_assoc_req = assoc_req;
+- mutex_unlock(&adapter->lock);
++ mutex_lock(&priv->lock);
++ assoc_req = priv->pending_assoc_req;
++ priv->pending_assoc_req = NULL;
++ priv->in_progress_assoc_req = assoc_req;
++ mutex_unlock(&priv->lock);
+
+ if (!assoc_req)
+ goto done;
+
+- print_assoc_req(__func__, assoc_req);
++ lbs_deb_assoc(
++ "Association Request:\n"
++ " flags: 0x%08lx\n"
++ " SSID: '%s'\n"
++ " chann: %d\n"
++ " band: %d\n"
++ " mode: %d\n"
++ " BSSID: %s\n"
++ " secinfo: %s%s%s\n"
++ " auth_mode: %d\n",
++ assoc_req->flags,
++ escape_essid(assoc_req->ssid, assoc_req->ssid_len),
++ assoc_req->channel, assoc_req->band, assoc_req->mode,
++ print_mac(mac, assoc_req->bssid),
++ assoc_req->secinfo.WPAenabled ? " WPA" : "",
++ assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
++ assoc_req->secinfo.wep_enabled ? " WEP" : "",
++ assoc_req->secinfo.auth_mode);
+
+ /* If 'any' SSID was specified, find an SSID to associate with */
+ if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
+@@ -512,7 +559,7 @@ void libertas_association_worker(struct
+ if (find_any_ssid) {
+ u8 new_mode;
+
+- ret = libertas_find_best_network_ssid(priv, assoc_req->ssid,
++ ret = lbs_find_best_network_ssid(priv, assoc_req->ssid,
+ &assoc_req->ssid_len, assoc_req->mode, &new_mode);
+ if (ret) {
+ lbs_deb_assoc("Could not find best network\n");
+@@ -531,18 +578,18 @@ void libertas_association_worker(struct
+ * Check if the attributes being changing require deauthentication
+ * from the currently associated infrastructure access point.
+ */
+- if (adapter->mode == IW_MODE_INFRA) {
+- if (should_deauth_infrastructure(adapter, assoc_req)) {
+- ret = libertas_send_deauthentication(priv);
++ if (priv->mode == IW_MODE_INFRA) {
++ if (should_deauth_infrastructure(priv, assoc_req)) {
++ ret = lbs_send_deauthentication(priv);
+ if (ret) {
+ lbs_deb_assoc("Deauthentication due to new "
+ "configuration request failed: %d\n",
+ ret);
+ }
+ }
+- } else if (adapter->mode == IW_MODE_ADHOC) {
+- if (should_stop_adhoc(adapter, assoc_req)) {
+- ret = libertas_stop_adhoc_network(priv);
++ } else if (priv->mode == IW_MODE_ADHOC) {
++ if (should_stop_adhoc(priv, assoc_req)) {
++ ret = lbs_stop_adhoc_network(priv);
+ if (ret) {
+ lbs_deb_assoc("Teardown of AdHoc network due to "
+ "new configuration request failed: %d\n",
+@@ -555,53 +602,40 @@ void libertas_association_worker(struct
+ /* Send the various configuration bits to the firmware */
+ if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+ ret = assoc_helper_mode(priv, assoc_req);
+- if (ret) {
+-lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
++ if (ret)
+ goto out;
+- }
+ }
+
+ if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
+ ret = assoc_helper_channel(priv, assoc_req);
+- if (ret) {
+- lbs_deb_assoc("ASSOC(:%d) channel: ret = %d\n",
+- __LINE__, ret);
++ if (ret)
+ goto out;
+- }
+ }
+
+ if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
+ || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
+ ret = assoc_helper_wep_keys(priv, assoc_req);
+- if (ret) {
+-lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
++ if (ret)
+ goto out;
+- }
+ }
+
+ if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+ ret = assoc_helper_secinfo(priv, assoc_req);
+- if (ret) {
+-lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
++ if (ret)
+ goto out;
+- }
+ }
+
+ if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
+ ret = assoc_helper_wpa_ie(priv, assoc_req);
+- if (ret) {
+-lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
++ if (ret)
+ goto out;
+- }
+ }
+
+ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
+ || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+ ret = assoc_helper_wpa_keys(priv, assoc_req);
+- if (ret) {
+-lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
++ if (ret)
+ goto out;
+- }
+ }
+
+ /* SSID/BSSID should be the _last_ config option set, because they
+@@ -613,30 +647,29 @@ lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret
+
+ ret = assoc_helper_associate(priv, assoc_req);
+ if (ret) {
+- lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n",
++ lbs_deb_assoc("ASSOC: association unsuccessful: %d\n",
+ ret);
+ success = 0;
+ }
+
+- if (adapter->connect_status != libertas_connected) {
+- lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
+- "not connected.\n");
++ if (priv->connect_status != LBS_CONNECTED) {
++ lbs_deb_assoc("ASSOC: association unsuccessful, "
++ "not connected\n");
+ success = 0;
+ }
+
+ if (success) {
+- lbs_deb_assoc("ASSOC: association attempt successful. "
+- "Associated to '%s' (" MAC_FMT ")\n",
+- escape_essid(adapter->curbssparams.ssid,
+- adapter->curbssparams.ssid_len),
+- MAC_ARG(adapter->curbssparams.bssid));
+- libertas_prepare_and_send_command(priv,
+- cmd_802_11_rssi,
+- 0, cmd_option_waitforrsp, 0, NULL);
+-
+- libertas_prepare_and_send_command(priv,
+- cmd_802_11_get_log,
+- 0, cmd_option_waitforrsp, 0, NULL);
++ lbs_deb_assoc("ASSOC: associated to '%s', %s\n",
++ escape_essid(priv->curbssparams.ssid,
++ priv->curbssparams.ssid_len),
++ print_mac(mac, priv->curbssparams.bssid));
++ lbs_prepare_and_send_command(priv,
++ CMD_802_11_RSSI,
++ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
++
++ lbs_prepare_and_send_command(priv,
++ CMD_802_11_GET_LOG,
++ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
+ } else {
+ ret = -1;
+ }
+@@ -648,9 +681,9 @@ out:
+ ret);
+ }
+
+- mutex_lock(&adapter->lock);
+- adapter->in_progress_assoc_req = NULL;
+- mutex_unlock(&adapter->lock);
++ mutex_lock(&priv->lock);
++ priv->in_progress_assoc_req = NULL;
++ mutex_unlock(&priv->lock);
+ kfree(assoc_req);
+
+ done:
+@@ -661,14 +694,15 @@ done:
+ /*
+ * Caller MUST hold any necessary locks
+ */
+-struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
++struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
+ {
+ struct assoc_request * assoc_req;
+
+- if (!adapter->pending_assoc_req) {
+- adapter->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
++ lbs_deb_enter(LBS_DEB_ASSOC);
++ if (!priv->pending_assoc_req) {
++ priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
+ GFP_KERNEL);
+- if (!adapter->pending_assoc_req) {
++ if (!priv->pending_assoc_req) {
+ lbs_pr_info("Not enough memory to allocate association"
+ " request!\n");
+ return NULL;
+@@ -678,60 +712,59 @@ struct assoc_request * wlan_get_associat
+ /* Copy current configuration attributes to the association request,
+ * but don't overwrite any that are already set.
+ */
+- assoc_req = adapter->pending_assoc_req;
++ assoc_req = priv->pending_assoc_req;
+ if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+- memcpy(&assoc_req->ssid, &adapter->curbssparams.ssid,
++ memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
+ IW_ESSID_MAX_SIZE);
+- assoc_req->ssid_len = adapter->curbssparams.ssid_len;
++ assoc_req->ssid_len = priv->curbssparams.ssid_len;
+ }
+
+ if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
+- assoc_req->channel = adapter->curbssparams.channel;
++ assoc_req->channel = priv->curbssparams.channel;
+
+ if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
+- assoc_req->band = adapter->curbssparams.band;
++ assoc_req->band = priv->curbssparams.band;
+
+ if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
+- assoc_req->mode = adapter->mode;
++ assoc_req->mode = priv->mode;
+
+ if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+- memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
++ memcpy(&assoc_req->bssid, priv->curbssparams.bssid,
+ ETH_ALEN);
+ }
+
+ if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
+ int i;
+ for (i = 0; i < 4; i++) {
+- memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
+- sizeof(struct WLAN_802_11_KEY));
++ memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i],
++ sizeof(struct enc_key));
+ }
+ }
+
+ if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
+- assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
++ assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx;
+
+ if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
+- memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
+- sizeof(struct WLAN_802_11_KEY));
++ memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key,
++ sizeof(struct enc_key));
+ }
+
+ if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+- memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
+- sizeof(struct WLAN_802_11_KEY));
++ memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key,
++ sizeof(struct enc_key));
+ }
+
+ if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+- memcpy(&assoc_req->secinfo, &adapter->secinfo,
+- sizeof(struct wlan_802_11_security));
++ memcpy(&assoc_req->secinfo, &priv->secinfo,
++ sizeof(struct lbs_802_11_security));
+ }
+
+ if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
+- memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
++ memcpy(&assoc_req->wpa_ie, &priv->wpa_ie,
+ MAX_WPA_IE_LEN);
+- assoc_req->wpa_ie_len = adapter->wpa_ie_len;
++ assoc_req->wpa_ie_len = priv->wpa_ie_len;
+ }
+
+- print_assoc_req(__func__, assoc_req);
+-
++ lbs_deb_leave(LBS_DEB_ASSOC);
+ return assoc_req;
+ }
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/assoc.h linux-2.6.22-300/drivers/net/wireless/libertas/assoc.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/assoc.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/assoc.h 2008-06-05 18:10:06.000000000 -0400
+@@ -1,32 +1,12 @@
+ /* Copyright (C) 2006, Red Hat, Inc. */
+
+-#ifndef _WLAN_ASSOC_H_
+-#define _WLAN_ASSOC_H_
++#ifndef _LBS_ASSOC_H_
++#define _LBS_ASSOC_H_
+
+ #include "dev.h"
+
+-void libertas_association_worker(struct work_struct *work);
++void lbs_association_worker(struct work_struct *work);
++struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
++void lbs_sync_channel(struct work_struct *work);
+
+-struct assoc_request * wlan_get_association_request(wlan_adapter *adapter);
+-
+-void libertas_sync_channel(struct work_struct *work);
+-
+-#define ASSOC_DELAY (HZ / 2)
+-static inline void wlan_postpone_association_work(wlan_private *priv)
+-{
+- if (priv->adapter->surpriseremoved)
+- return;
+- cancel_delayed_work(&priv->assoc_work);
+- queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY);
+-}
+-
+-static inline void wlan_cancel_association_work(wlan_private *priv)
+-{
+- cancel_delayed_work(&priv->assoc_work);
+- if (priv->adapter->pending_assoc_req) {
+- kfree(priv->adapter->pending_assoc_req);
+- priv->adapter->pending_assoc_req = NULL;
+- }
+-}
+-
+-#endif /* _WLAN_ASSOC_H */
++#endif /* _LBS_ASSOC_H */
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/cmd.c linux-2.6.22-300/drivers/net/wireless/libertas/cmd.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/cmd.c 2008-07-17 00:17:57.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/cmd.c 2008-06-05 18:10:06.000000000 -0400
+@@ -4,6 +4,7 @@
+ */
+
+ #include <net/iw_handler.h>
++#include <net/ieee80211.h>
+ #include "host.h"
+ #include "hostcmd.h"
+ #include "decl.h"
+@@ -11,79 +12,195 @@
+ #include "dev.h"
+ #include "join.h"
+ #include "wext.h"
++#include "cmd.h"
+
+-static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
++static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
++static void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
++ struct cmd_ctrl_node *ptempnode,
++ void *pdata_buf);
+
+-static u16 commands_allowed_in_ps[] = {
+- cmd_802_11_rssi,
+-};
+
+ /**
+- * @brief This function checks if the commans is allowed
+- * in PS mode not.
++ * @brief Simple callback that copies response back into command
+ *
+- * @param command the command ID
+- * @return TRUE or FALSE
++ * @param priv A pointer to struct lbs_private structure
++ * @param extra A pointer to the original command structure for which
++ * 'resp' is a response
++ * @param resp A pointer to the command response
++ *
++ * @return 0 on success, error on failure
+ */
+-static u8 is_command_allowed_in_ps(__le16 command)
++int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
++ struct cmd_header *resp)
+ {
+- int i;
++ struct cmd_header *buf = (void *)extra;
++ uint16_t copy_len;
+
+- for (i = 0; i < ARRAY_SIZE(commands_allowed_in_ps); i++) {
+- if (command == cpu_to_le16(commands_allowed_in_ps[i]))
+- return 1;
+- }
++ copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
++ memcpy(buf, resp, copy_len);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
+
++/**
++ * @brief Simple callback that ignores the result. Use this if
++ * you just want to send a command to the hardware, but don't
++ * care for the result.
++ *
++ * @param priv ignored
++ * @param extra ignored
++ * @param resp ignored
++ *
++ * @return 0 for success
++ */
++static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
++ struct cmd_header *resp)
++{
+ return 0;
+ }
+
+-static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd)
++
++/**
++ * @brief Checks whether a command is allowed in Power Save mode
++ *
++ * @param command the command ID
++ * @return 1 if allowed, 0 if not allowed
++ */
++static u8 is_command_allowed_in_ps(u16 cmd)
+ {
+- struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec;
++ switch (cmd) {
++ case CMD_802_11_RSSI:
++ return 1;
++ default:
++ break;
++ }
++ return 0;
++}
++
++/**
++ * @brief Updates the hardware details like MAC address and regulatory region
++ *
++ * @param priv A pointer to struct lbs_private structure
++ *
++ * @return 0 on success, error on failure
++ */
++int lbs_update_hw_spec(struct lbs_private *priv)
++{
++ struct cmd_ds_get_hw_spec cmd;
++ int ret = -1;
++ u32 i;
++ DECLARE_MAC_BUF(mac);
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- cmd->command = cpu_to_le16(cmd_get_hw_spec);
+- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
+- memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN);
++ memset(&cmd, 0, sizeof(cmd));
++ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
++ memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
++ ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
++ if (ret)
++ goto out;
++
++ priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
++ memcpy(priv->fwreleasenumber, cmd.fwreleasenumber, 4);
++
++ lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n",
++ priv->fwreleasenumber[2], priv->fwreleasenumber[1],
++ priv->fwreleasenumber[0], priv->fwreleasenumber[3]);
++ lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n",
++ print_mac(mac, cmd.permanentaddr));
++ lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
++ cmd.hwifversion, cmd.version);
++
++ /* Clamp region code to 8-bit since FW spec indicates that it should
++ * only ever be 8-bit, even though the field size is 16-bit. Some firmware
++ * returns non-zero high 8 bits here.
++ */
++ priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
+
++ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
++ /* use the region code to search for the index */
++ if (priv->regioncode == lbs_region_code_to_index[i])
++ break;
++ }
++
++ /* if it's unidentified region code, use the default (USA) */
++ if (i >= MRVDRV_MAX_REGION_CODE) {
++ priv->regioncode = 0x10;
++ lbs_pr_info("unidentified region code; using the default (USA)\n");
++ }
++
++ if (priv->current_addr[0] == 0xff)
++ memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
++
++ memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN);
++ if (priv->mesh_dev)
++ memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
++
++ if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
++ ret = -1;
++ goto out;
++ }
++
++ if (lbs_set_universaltable(priv, 0)) {
++ ret = -1;
++ goto out;
++ }
++
++out:
+ lbs_deb_leave(LBS_DEB_CMD);
+- return 0;
++ return ret;
+ }
+
+-static int wlan_cmd_802_11_ps_mode(wlan_private * priv,
++int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria)
++{
++ struct cmd_ds_host_sleep cmd_config;
++ int ret;
++
++ cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
++ cmd_config.criteria = cpu_to_le32(criteria);
++ cmd_config.gpio = priv->wol_gpio;
++ cmd_config.gap = priv->wol_gap;
++
++ ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
++ if (!ret) {
++ lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
++ priv->wol_criteria = criteria;
++ } else {
++ lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
++
++static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+ {
+ struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
+- wlan_adapter *adapter = priv->adapter;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- cmd->command = cpu_to_le16(cmd_802_11_ps_mode);
++ 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);
+ psm->action = cpu_to_le16(cmd_action);
+ psm->multipledtim = 0;
+ switch (cmd_action) {
+- case cmd_subcmd_enter_ps:
++ case CMD_SUBCMD_ENTER_PS:
+ lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
+- lbs_deb_cmd("locallisteninterval = %d\n",
+- adapter->locallisteninterval);
+
+- psm->locallisteninterval =
+- cpu_to_le16(adapter->locallisteninterval);
+- psm->nullpktinterval =
+- cpu_to_le16(adapter->nullpktinterval);
++ psm->locallisteninterval = 0;
++ psm->nullpktinterval = 0;
+ psm->multipledtim =
+- cpu_to_le16(priv->adapter->multipledtim);
++ cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
+ break;
+
+- case cmd_subcmd_exit_ps:
++ case CMD_SUBCMD_EXIT_PS:
+ lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
+ break;
+
+- case cmd_subcmd_sleep_confirmed:
++ case CMD_SUBCMD_SLEEP_CONFIRMED:
+ lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
+ break;
+
+@@ -95,13 +212,15 @@ static int wlan_cmd_802_11_ps_mode(wlan_
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
++static int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+ {
+ u16 *timeout = pdata_buf;
+
+- cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout);
++ lbs_deb_enter(LBS_DEB_CMD);
++
++ cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
+ + S_DS_GEN);
+@@ -113,104 +232,104 @@ static int wlan_cmd_802_11_inactivity_ti
+ else
+ cmd->params.inactivity_timeout.timeout = 0;
+
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_sleep_params(wlan_private * priv,
++static int lbs_cmd_802_11_sleep_params(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
+ S_DS_GEN);
+- cmd->command = cpu_to_le16(cmd_802_11_sleep_params);
++ cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS);
+
+- if (cmd_action == cmd_act_get) {
+- memset(&adapter->sp, 0, sizeof(struct sleep_params));
++ if (cmd_action == CMD_ACT_GET) {
++ memset(&priv->sp, 0, sizeof(struct sleep_params));
+ memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
+ sp->action = cpu_to_le16(cmd_action);
+- } else if (cmd_action == cmd_act_set) {
++ } else if (cmd_action == CMD_ACT_SET) {
+ sp->action = cpu_to_le16(cmd_action);
+- sp->error = cpu_to_le16(adapter->sp.sp_error);
+- sp->offset = cpu_to_le16(adapter->sp.sp_offset);
+- sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime);
+- sp->calcontrol = (u8) adapter->sp.sp_calcontrol;
+- sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk;
+- sp->reserved = cpu_to_le16(adapter->sp.sp_reserved);
++ sp->error = cpu_to_le16(priv->sp.sp_error);
++ sp->offset = cpu_to_le16(priv->sp.sp_offset);
++ sp->stabletime = cpu_to_le16(priv->sp.sp_stabletime);
++ sp->calcontrol = (u8) priv->sp.sp_calcontrol;
++ sp->externalsleepclk = (u8) priv->sp.sp_extsleepclk;
++ sp->reserved = cpu_to_le16(priv->sp.sp_reserved);
+ }
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_set_wep(wlan_private * priv,
++static int lbs_cmd_802_11_set_wep(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u32 cmd_act,
+ void * pdata_buf)
+ {
+ struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct assoc_request * assoc_req = pdata_buf;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- cmd->command = cpu_to_le16(cmd_802_11_set_wep);
++ cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
+ cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
+
+- if (cmd_act == cmd_act_add) {
++ if (cmd_act == CMD_ACT_ADD) {
+ int i;
+
+ if (!assoc_req) {
+- lbs_deb_cmd("Invalid association request!");
++ lbs_deb_cmd("Invalid association request!\n");
+ ret = -1;
+ goto done;
+ }
+
+- wep->action = cpu_to_le16(cmd_act_add);
++ wep->action = cpu_to_le16(CMD_ACT_ADD);
+
+ /* default tx key index */
+ wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
+- (u32)cmd_WEP_KEY_INDEX_MASK));
+-
+- lbs_deb_cmd("Tx key Index: %u\n", le16_to_cpu(wep->keyindex));
++ (u32)CMD_WEP_KEY_INDEX_MASK));
+
+ /* Copy key types and material to host command structure */
+ for (i = 0; i < 4; i++) {
+- struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i];
++ struct enc_key * pkey = &assoc_req->wep_keys[i];
+
+ switch (pkey->len) {
+ case KEY_LEN_WEP_40:
+- wep->keytype[i] = cmd_type_wep_40_bit;
++ wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
+ memmove(&wep->keymaterial[i], pkey->key,
+ pkey->len);
++ lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
+ break;
+ case KEY_LEN_WEP_104:
+- wep->keytype[i] = cmd_type_wep_104_bit;
++ wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
+ memmove(&wep->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("Invalid WEP key %d length of %d\n",
++ lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
+ i, pkey->len);
+ ret = -1;
+ goto done;
+ break;
+ }
+ }
+- } else if (cmd_act == cmd_act_remove) {
++ } else if (cmd_act == CMD_ACT_REMOVE) {
+ /* ACT_REMOVE clears _all_ WEP keys */
+- wep->action = cpu_to_le16(cmd_act_remove);
++ wep->action = cpu_to_le16(CMD_ACT_REMOVE);
+
+ /* default tx key index */
+- wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx &
+- (u32)cmd_WEP_KEY_INDEX_MASK));
++ wep->keyindex = cpu_to_le16((u16)(priv->wep_tx_keyidx &
++ (u32)CMD_WEP_KEY_INDEX_MASK));
++ lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
+ }
+
+ ret = 0;
+@@ -220,7 +339,7 @@ done:
+ return ret;
+ }
+
+-static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
++static int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action,
+ void * pdata_buf)
+@@ -230,15 +349,16 @@ static int wlan_cmd_802_11_enable_rsn(wl
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- cmd->command = cpu_to_le16(cmd_802_11_enable_rsn);
++ cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
+ cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
+ penableRSN->action = cpu_to_le16(cmd_action);
+
+- if (cmd_action == cmd_act_set) {
++ if (cmd_action == CMD_ACT_SET) {
+ if (*enable)
+- penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
++ penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
+ else
+- penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
++ penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
++ lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
+ }
+
+ lbs_deb_leave(LBS_DEB_CMD);
+@@ -246,10 +366,56 @@ static int wlan_cmd_802_11_enable_rsn(wl
+ }
+
+
++static ssize_t lbs_tlv_size(const u8 *tlv, u16 size)
++{
++ ssize_t pos = 0;
++ struct mrvlietypesheader *tlv_h;
++ while (pos < size) {
++ u16 length;
++ tlv_h = (struct mrvlietypesheader *) tlv;
++ if (tlv_h->len == 0)
++ return pos;
++ length = le16_to_cpu(tlv_h->len) +
++ sizeof(struct mrvlietypesheader);
++ pos += length;
++ tlv += length;
++ }
++ return pos;
++}
++
++
++static void lbs_cmd_802_11_subscribe_event(struct lbs_private *priv,
++ struct cmd_ds_command *cmd, u16 cmd_action,
++ void *pdata_buf)
++{
++ struct cmd_ds_802_11_subscribe_event *events =
++ (struct cmd_ds_802_11_subscribe_event *) pdata_buf;
++
++ /* pdata_buf points to a struct cmd_ds_802_11_subscribe_event and room
++ * for various Marvell TLVs */
++
++ lbs_deb_enter(LBS_DEB_CMD);
++
++ cmd->size = cpu_to_le16(sizeof(*events)
++ - sizeof(events->tlv)
++ + S_DS_GEN);
++ cmd->params.subscribe_event.action = cpu_to_le16(cmd_action);
++ if (cmd_action == CMD_ACT_GET) {
++ cmd->params.subscribe_event.events = 0;
++ } else {
++ ssize_t sz = lbs_tlv_size(events->tlv, sizeof(events->tlv));
++ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + sz);
++ cmd->params.subscribe_event.events = events->events;
++ memcpy(cmd->params.subscribe_event.tlv, events->tlv, sz);
++ }
++
++ lbs_deb_leave(LBS_DEB_CMD);
++}
++
+ static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
+- struct WLAN_802_11_KEY * pkey)
++ struct enc_key * pkey)
+ {
+- pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
++ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (pkey->flags & KEY_INFO_WPA_ENABLED) {
+ pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
+@@ -262,15 +428,17 @@ static void set_one_wpa_key(struct MrvlI
+ }
+
+ pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
++ pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
+ pkeyparamset->keylen = cpu_to_le16(pkey->len);
+ memcpy(pkeyparamset->key, pkey->key, pkey->len);
+ pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid)
+ + sizeof(pkeyparamset->keyinfo)
+ + sizeof(pkeyparamset->keylen)
+ + sizeof(pkeyparamset->key));
++ lbs_deb_leave(LBS_DEB_CMD);
+ }
+
+-static int wlan_cmd_802_11_key_material(wlan_private * priv,
++static int lbs_cmd_802_11_key_material(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action,
+ u32 cmd_oid, void *pdata_buf)
+@@ -283,10 +451,10 @@ static int wlan_cmd_802_11_key_material(
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- cmd->command = cpu_to_le16(cmd_802_11_key_material);
++ cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
+ pkeymaterial->action = cpu_to_le16(cmd_action);
+
+- if (cmd_action == cmd_act_get) {
++ if (cmd_action == CMD_ACT_GET) {
+ cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
+ ret = 0;
+ goto done;
+@@ -317,61 +485,67 @@ done:
+ return ret;
+ }
+
+-static int wlan_cmd_802_11_reset(wlan_private * priv,
++static int lbs_cmd_802_11_reset(struct lbs_private *priv,
+ struct cmd_ds_command *cmd, int cmd_action)
+ {
+ struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
+
+- cmd->command = cpu_to_le16(cmd_802_11_reset);
++ lbs_deb_enter(LBS_DEB_CMD);
++
++ cmd->command = cpu_to_le16(CMD_802_11_RESET);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
+ reset->action = cpu_to_le16(cmd_action);
+
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_get_log(wlan_private * priv,
++static int lbs_cmd_802_11_get_log(struct lbs_private *priv,
+ struct cmd_ds_command *cmd)
+ {
+- cmd->command = cpu_to_le16(cmd_802_11_get_log);
++ lbs_deb_enter(LBS_DEB_CMD);
++ cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
+
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_get_stat(wlan_private * priv,
++static int lbs_cmd_802_11_get_stat(struct lbs_private *priv,
+ struct cmd_ds_command *cmd)
+ {
+- cmd->command = cpu_to_le16(cmd_802_11_get_stat);
++ lbs_deb_enter(LBS_DEB_CMD);
++ cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
+
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
++static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ int cmd_action,
+ int cmd_oid, void *pdata_buf)
+ {
+ struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
+- wlan_adapter *adapter = priv->adapter;
+ u8 ucTemp;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+
+- cmd->command = cpu_to_le16(cmd_802_11_snmp_mib);
++ cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
+ cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
+
+ switch (cmd_oid) {
+ case OID_802_11_INFRASTRUCTURE_MODE:
+ {
+ u8 mode = (u8) (size_t) pdata_buf;
+- pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+- pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i);
+- pSNMPMIB->bufsize = sizeof(u8);
++ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
++ pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
++ pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8));
+ if (mode == IW_MODE_ADHOC) {
+ ucTemp = SNMP_MIB_VALUE_ADHOC;
+ } else {
+@@ -388,11 +562,11 @@ static int wlan_cmd_802_11_snmp_mib(wlan
+ {
+ u32 ulTemp;
+
+- pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i);
++ pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
+
+- if (cmd_action == cmd_act_set) {
+- pSNMPMIB->querytype = cmd_act_set;
+- pSNMPMIB->bufsize = sizeof(u16);
++ if (cmd_action == CMD_ACT_SET) {
++ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
++ pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
+ ulTemp = *(u32 *)pdata_buf;
+ *((__le16 *)(pSNMPMIB->value)) =
+ cpu_to_le16((u16) ulTemp);
+@@ -404,12 +578,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan
+ {
+ u32 ulTemp;
+
+- pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i);
++ pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
+
+- if (cmd_action == cmd_act_get) {
+- pSNMPMIB->querytype = cpu_to_le16(cmd_act_get);
+- } else if (cmd_action == cmd_act_set) {
+- pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
++ if (cmd_action == CMD_ACT_GET) {
++ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
++ } else if (cmd_action == CMD_ACT_SET) {
++ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
+ pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
+ ulTemp = *((u32 *) pdata_buf);
+ *((__le16 *)(pSNMPMIB->value)) =
+@@ -424,12 +598,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan
+ {
+
+ u32 ulTemp;
+- pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i);
++ pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I);
+
+- if (cmd_action == cmd_act_get) {
+- pSNMPMIB->querytype = cpu_to_le16(cmd_act_get);
+- } else if (cmd_action == cmd_act_set) {
+- pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
++ if (cmd_action == CMD_ACT_GET) {
++ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
++ } else if (cmd_action == CMD_ACT_SET) {
++ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
+ pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
+ ulTemp = *((u32 *)pdata_buf);
+ *(__le16 *)(pSNMPMIB->value) =
+@@ -439,15 +613,15 @@ static int wlan_cmd_802_11_snmp_mib(wlan
+ break;
+ }
+ case OID_802_11_TX_RETRYCOUNT:
+- pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i);
++ pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);
+
+- if (cmd_action == cmd_act_get) {
+- pSNMPMIB->querytype = cpu_to_le16(cmd_act_get);
+- } else if (cmd_action == cmd_act_set) {
+- pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
++ if (cmd_action == CMD_ACT_GET) {
++ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
++ } else if (cmd_action == CMD_ACT_SET) {
++ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
+ pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
+ *((__le16 *)(pSNMPMIB->value)) =
+- cpu_to_le16((u16) adapter->txretrycount);
++ cpu_to_le16((u16) priv->txretrycount);
+ }
+
+ break;
+@@ -461,7 +635,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan
+ le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
+
+ lbs_deb_cmd(
+- "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n",
++ "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
+ le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
+ le16_to_cpu(pSNMPMIB->bufsize),
+ le16_to_cpu(*(__le16 *) pSNMPMIB->value));
+@@ -470,11 +644,10 @@ static int wlan_cmd_802_11_snmp_mib(wlan
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_radio_control(wlan_private * priv,
++static int lbs_cmd_802_11_radio_control(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ int cmd_action)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_radio_control *pradiocontrol = &cmd->params.radio;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+@@ -482,26 +655,26 @@ static int wlan_cmd_802_11_radio_control
+ cmd->size =
+ cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
+ S_DS_GEN);
+- cmd->command = cpu_to_le16(cmd_802_11_radio_control);
++ cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL);
+
+ pradiocontrol->action = cpu_to_le16(cmd_action);
+
+- switch (adapter->preamble) {
+- case cmd_type_short_preamble:
++ switch (priv->preamble) {
++ case CMD_TYPE_SHORT_PREAMBLE:
+ pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
+ break;
+
+- case cmd_type_long_preamble:
++ case CMD_TYPE_LONG_PREAMBLE:
+ pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
+ break;
+
+- case cmd_type_auto_preamble:
++ case CMD_TYPE_AUTO_PREAMBLE:
+ default:
+ pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
+ break;
+ }
+
+- if (adapter->radioon)
++ if (priv->radioon)
+ pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
+ else
+ pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);
+@@ -510,7 +683,7 @@ static int wlan_cmd_802_11_radio_control
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
++static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+ {
+@@ -521,7 +694,7 @@ static int wlan_cmd_802_11_rf_tx_power(w
+
+ cmd->size =
+ cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
+- cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power);
++ cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
+ prtp->action = cpu_to_le16(cmd_action);
+
+ lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n",
+@@ -529,23 +702,23 @@ static int wlan_cmd_802_11_rf_tx_power(w
+ le16_to_cpu(prtp->action));
+
+ switch (cmd_action) {
+- case cmd_act_tx_power_opt_get:
+- prtp->action = cpu_to_le16(cmd_act_get);
++ case CMD_ACT_TX_POWER_OPT_GET:
++ prtp->action = cpu_to_le16(CMD_ACT_GET);
+ prtp->currentlevel = 0;
+ break;
+
+- case cmd_act_tx_power_opt_set_high:
+- prtp->action = cpu_to_le16(cmd_act_set);
+- prtp->currentlevel = cpu_to_le16(cmd_act_tx_power_index_high);
++ case CMD_ACT_TX_POWER_OPT_SET_HIGH:
++ prtp->action = cpu_to_le16(CMD_ACT_SET);
++ prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH);
+ break;
+
+- case cmd_act_tx_power_opt_set_mid:
+- prtp->action = cpu_to_le16(cmd_act_set);
+- prtp->currentlevel = cpu_to_le16(cmd_act_tx_power_index_mid);
++ case CMD_ACT_TX_POWER_OPT_SET_MID:
++ prtp->action = cpu_to_le16(CMD_ACT_SET);
++ prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID);
+ break;
+
+- case cmd_act_tx_power_opt_set_low:
+- prtp->action = cpu_to_le16(cmd_act_set);
++ case CMD_ACT_TX_POWER_OPT_SET_LOW:
++ prtp->action = cpu_to_le16(CMD_ACT_SET);
+ prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
+ break;
+ }
+@@ -554,148 +727,224 @@ static int wlan_cmd_802_11_rf_tx_power(w
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_rf_antenna(wlan_private * priv,
++static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+ {
+- struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant;
++ struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;
+
+- cmd->command = cpu_to_le16(cmd_802_11_rf_antenna);
+- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) +
+- S_DS_GEN);
++ 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);
+
+- rant->action = cpu_to_le16(cmd_action);
+- if ((cmd_action == cmd_act_set_rx) || (cmd_action == cmd_act_set_tx)) {
+- rant->antennamode = cpu_to_le16((u16) (*(u32 *) pdata_buf));
++ monitor->action = cpu_to_le16(cmd_action);
++ if (cmd_action == CMD_ACT_SET) {
++ monitor->mode =
++ cpu_to_le16((u16) (*(u32 *) pdata_buf));
+ }
+
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
++static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+ {
+ struct cmd_ds_802_11_rate_adapt_rateset
+ *rateadapt = &cmd->params.rateset;
+- wlan_adapter *adapter = priv->adapter;
+
++ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
+ + S_DS_GEN);
+- cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset);
+-
+- lbs_deb_enter(LBS_DEB_CMD);
++ cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
+
+ rateadapt->action = cpu_to_le16(cmd_action);
+- rateadapt->enablehwauto = cpu_to_le16(adapter->enablehwauto);
+- rateadapt->bitmap = cpu_to_le16(adapter->ratebitmap);
++ rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
++ rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_data_rate(wlan_private * priv,
+- struct cmd_ds_command *cmd,
+- u16 cmd_action)
++/**
++ * @brief Get the current data rate
++ *
++ * @param priv A pointer to struct lbs_private structure
++ *
++ * @return The data rate on success, error on failure
++ */
++int lbs_get_data_rate(struct lbs_private *priv)
+ {
+- struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;
+- wlan_adapter *adapter = priv->adapter;
++ struct cmd_ds_802_11_data_rate cmd;
++ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
+- S_DS_GEN);
++ memset(&cmd, 0, sizeof(cmd));
++ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
++ cmd.action = cpu_to_le16(CMD_ACT_GET_TX_RATE);
++
++ ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
++ if (ret)
++ goto out;
+
+- cmd->command = cpu_to_le16(cmd_802_11_data_rate);
++ lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
+
+- memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
++ ret = (int) lbs_fw_index_to_data_rate(cmd.rates[0]);
++ lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", ret);
+
+- pdatarate->action = cpu_to_le16(cmd_action);
++out:
++ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
++ return ret;
++}
+
+- if (cmd_action == cmd_act_set_tx_fix_rate) {
+- pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate);
+- lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n",
+- adapter->datarate);
+- } else if (cmd_action == cmd_act_set_tx_auto) {
+- lbs_deb_cmd("Setting FW for AUTO rate\n");
++/**
++ * @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");
+ }
+
+- lbs_deb_leave(LBS_DEB_CMD);
+- return 0;
++ 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;
+ }
+
+-static int wlan_cmd_mac_multicast_adr(wlan_private * priv,
+- struct cmd_ds_command *cmd,
+- u16 cmd_action)
++/**
++ * @brief Get the radio channel
++ *
++ * @param priv A pointer to struct lbs_private structure
++ *
++ * @return The channel on success, error on failure
++ */
++int lbs_get_channel(struct lbs_private *priv)
+ {
+- struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
+- wlan_adapter *adapter = priv->adapter;
++ struct cmd_ds_802_11_rf_channel cmd;
++ int ret = 0;
+
+- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
+- S_DS_GEN);
+- cmd->command = cpu_to_le16(cmd_mac_multicast_adr);
++ lbs_deb_enter(LBS_DEB_CMD);
+
+- pMCastAdr->action = cpu_to_le16(cmd_action);
+- pMCastAdr->nr_of_adrs =
+- cpu_to_le16((u16) adapter->nr_of_multicastmacaddr);
+- memcpy(pMCastAdr->maclist, adapter->multicastlist,
+- adapter->nr_of_multicastmacaddr * ETH_ALEN);
++ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
++ cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
+
+- return 0;
++ ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
++ if (ret)
++ goto out;
++
++ ret = le16_to_cpu(cmd.channel);
++ lbs_deb_cmd("current radio channel is %d\n", ret);
++
++out:
++ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
++ return ret;
+ }
+
+-static int wlan_cmd_802_11_rf_channel(wlan_private * priv,
+- struct cmd_ds_command *cmd,
+- int option, void *pdata_buf)
++/**
++ * @brief Set the radio channel
++ *
++ * @param priv A pointer to struct lbs_private structure
++ * @param channel The desired channel, or 0 to clear a locked channel
++ *
++ * @return 0 on success, error on failure
++ */
++int lbs_set_channel(struct lbs_private *priv, u8 channel)
+ {
+- struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
+-
+- cmd->command = cpu_to_le16(cmd_802_11_rf_channel);
+- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) +
+- S_DS_GEN);
++ struct cmd_ds_802_11_rf_channel cmd;
++ u8 old_channel = priv->curbssparams.channel;
++ int ret = 0;
+
+- if (option == cmd_opt_802_11_rf_channel_set) {
+- rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
+- }
++ lbs_deb_enter(LBS_DEB_CMD);
+
+- rfchan->action = cpu_to_le16(option);
++ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
++ cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
++ cmd.channel = cpu_to_le16(channel);
++
++ ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
++ if (ret)
++ goto out;
++
++ priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel);
++ lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
++ priv->curbssparams.channel);
+
+- return 0;
++out:
++ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
++ return ret;
+ }
+
+-static int wlan_cmd_802_11_rssi(wlan_private * priv,
++static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
+ struct cmd_ds_command *cmd)
+ {
+- wlan_adapter *adapter = priv->adapter;
+
+- cmd->command = cpu_to_le16(cmd_802_11_rssi);
++ 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(priv->adapter->bcn_avg_factor);
++ cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
+
+ /* reset Beacon SNR/NF/RSSI values */
+- adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
+- adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0;
+- adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
+- adapter->NF[TYPE_BEACON][TYPE_AVG] = 0;
+- adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
+- adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
++ 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 wlan_cmd_reg_access(wlan_private * priv,
++static int lbs_cmd_reg_access(struct lbs_private *priv,
+ struct cmd_ds_command *cmdptr,
+ u8 cmd_action, void *pdata_buf)
+ {
+- struct wlan_offset_value *offval;
++ struct lbs_offset_value *offval;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- offval = (struct wlan_offset_value *)pdata_buf;
++ offval = (struct lbs_offset_value *)pdata_buf;
+
+- switch (cmdptr->command) {
+- case cmd_mac_reg_access:
++ switch (le16_to_cpu(cmdptr->command)) {
++ case CMD_MAC_REG_ACCESS:
+ {
+ struct cmd_ds_mac_reg_access *macreg;
+
+@@ -713,7 +962,7 @@ static int wlan_cmd_reg_access(wlan_priv
+ break;
+ }
+
+- case cmd_bbp_reg_access:
++ case CMD_BBP_REG_ACCESS:
+ {
+ struct cmd_ds_bbp_reg_access *bbpreg;
+
+@@ -732,7 +981,7 @@ static int wlan_cmd_reg_access(wlan_priv
+ break;
+ }
+
+- case cmd_rf_reg_access:
++ case CMD_RF_REG_ACCESS:
+ {
+ struct cmd_ds_rf_reg_access *rfreg;
+
+@@ -759,37 +1008,38 @@ static int wlan_cmd_reg_access(wlan_priv
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_mac_address(wlan_private * priv,
++static int lbs_cmd_802_11_mac_address(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+ {
+- wlan_adapter *adapter = priv->adapter;
+
+- cmd->command = cpu_to_le16(cmd_802_11_mac_address);
++ lbs_deb_enter(LBS_DEB_CMD);
++ cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
+ S_DS_GEN);
+ cmd->result = 0;
+
+ cmd->params.macadd.action = cpu_to_le16(cmd_action);
+
+- if (cmd_action == cmd_act_set) {
++ if (cmd_action == CMD_ACT_SET) {
+ memcpy(cmd->params.macadd.macadd,
+- adapter->current_addr, ETH_ALEN);
+- lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6);
++ priv->current_addr, ETH_ALEN);
++ lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6);
+ }
+
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
++static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ int cmd_action, void *pdata_buf)
+ {
+- struct wlan_ioctl_regrdwr *ea = pdata_buf;
++ struct lbs_ioctl_regrdwr *ea = pdata_buf;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- cmd->command = cpu_to_le16(cmd_802_11_eeprom_access);
++ cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
+ S_DS_GEN);
+ cmd->result = 0;
+@@ -799,54 +1049,56 @@ static int wlan_cmd_802_11_eeprom_access
+ cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
+ cmd->params.rdeeprom.value = 0;
+
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_cmd_bt_access(wlan_private * priv,
++static int lbs_cmd_bt_access(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+ {
+ struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
+- lbs_deb_cmd("BT CMD(%d)\n", cmd_action);
++ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
+
+- cmd->command = cpu_to_le16(cmd_bt_access);
++ 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:
++ case CMD_ACT_BT_ACCESS_ADD:
+ memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
+- lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6);
++ lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
+ break;
+- case cmd_act_bt_access_del:
++ case CMD_ACT_BT_ACCESS_DEL:
+ memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
+- lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6);
++ lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
+ break;
+- case cmd_act_bt_access_list:
++ case CMD_ACT_BT_ACCESS_LIST:
+ bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
+ break;
+- case cmd_act_bt_access_reset:
++ case CMD_ACT_BT_ACCESS_RESET:
+ break;
+- case cmd_act_bt_access_set_invert:
++ case CMD_ACT_BT_ACCESS_SET_INVERT:
+ bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
+ break;
+- case cmd_act_bt_access_get_invert:
++ case CMD_ACT_BT_ACCESS_GET_INVERT:
+ break;
+ default:
+ break;
+ }
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_cmd_fwt_access(wlan_private * priv,
++static int lbs_cmd_fwt_access(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+ {
+ struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
+- lbs_deb_cmd("FWT CMD(%d)\n", cmd_action);
++ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
+
+- cmd->command = cpu_to_le16(cmd_fwt_access);
++ 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;
+
+@@ -857,244 +1109,290 @@ static int wlan_cmd_fwt_access(wlan_priv
+
+ fwt_access->action = cpu_to_le16(cmd_action);
+
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_cmd_mesh_access(wlan_private * priv,
+- struct cmd_ds_command *cmd,
+- u16 cmd_action, void *pdata_buf)
++int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
++ struct cmd_ds_mesh_access *cmd)
+ {
+- struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
+- lbs_deb_cmd("FWT CMD(%d)\n", cmd_action);
++ int ret;
+
+- cmd->command = cpu_to_le16(cmd_mesh_access);
+- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN);
+- cmd->result = 0;
++ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
+
+- if (pdata_buf)
+- memcpy(mesh_access, pdata_buf, sizeof(*mesh_access));
+- else
+- memset(mesh_access, 0, sizeof(*mesh_access));
++ cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
++ cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
++ cmd->hdr.result = 0;
+
+- mesh_access->action = cpu_to_le16(cmd_action);
++ cmd->action = cpu_to_le16(cmd_action);
+
+- return 0;
++ ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
++
++ lbs_deb_leave(LBS_DEB_CMD);
++ return ret;
+ }
++EXPORT_SYMBOL_GPL(lbs_mesh_access);
+
+-void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail)
++int lbs_mesh_config_send(struct lbs_private *priv,
++ struct cmd_ds_mesh_config *cmd,
++ uint16_t action, uint16_t type)
+ {
+- unsigned long flags;
+- struct cmd_ds_command *cmdptr;
++ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- if (!cmdnode) {
+- lbs_deb_cmd("QUEUE_CMD: cmdnode is NULL\n");
+- goto done;
+- }
++ cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG);
++ cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
++ cmd->hdr.result = 0;
+
+- cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+- if (!cmdptr) {
+- lbs_deb_cmd("QUEUE_CMD: cmdptr is NULL\n");
+- goto done;
+- }
++ cmd->type = cpu_to_le16(type);
++ cmd->action = cpu_to_le16(action);
+
+- /* Exit_PS command needs to be queued in the header always. */
+- if (cmdptr->command == cmd_802_11_ps_mode) {
+- struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
+- if (psm->action == cpu_to_le16(cmd_subcmd_exit_ps)) {
+- if (adapter->psstate != PS_STATE_FULL_POWER)
+- addtail = 0;
+- }
++ ret = lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd);
++
++ lbs_deb_leave(LBS_DEB_CMD);
++ 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;
++
++ 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->hdr.id = MFIE_TYPE_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->hdr.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,
++ escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
+
+- spin_lock_irqsave(&adapter->driver_lock, flags);
++ return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
++}
+
+- if (addtail)
+- list_add_tail((struct list_head *)cmdnode,
+- &adapter->cmdpendingq);
+- else
+- list_add((struct list_head *)cmdnode, &adapter->cmdpendingq);
++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;
+
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ 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);
+
+- lbs_deb_cmd("QUEUE_CMD: Inserted node=%p, cmd=0x%x in cmdpendingq\n",
+- cmdnode,
+- le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command));
++ 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);
+
+-done:
+ lbs_deb_leave(LBS_DEB_CMD);
++ return 0;
+ }
+
+-/*
+- * TODO: Fix the issue when DownloadcommandToStation is being called the
+- * second time when the command timesout. All the cmdptr->xxx are in little
+- * endian and therefore all the comparissions will fail.
+- * For now - we are not performing the endian conversion the second time - but
+- * for PS and DEEP_SLEEP we need to worry
+- */
+-static int DownloadcommandToStation(wlan_private * priv,
+- struct cmd_ctrl_node *cmdnode)
++static void lbs_queue_cmd(struct lbs_private *priv,
++ struct cmd_ctrl_node *cmdnode)
+ {
+ unsigned long flags;
+- struct cmd_ds_command *cmdptr;
+- wlan_adapter *adapter = priv->adapter;
+- int ret = 0;
+- u16 cmdsize;
+- u16 command;
++ int addtail = 1;
+
+- lbs_deb_enter(LBS_DEB_CMD);
++ lbs_deb_enter(LBS_DEB_HOST);
+
+- if (!adapter || !cmdnode) {
+- lbs_deb_cmd("DNLD_CMD: adapter = %p, cmdnode = %p\n",
+- adapter, cmdnode);
+- if (cmdnode) {
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- __libertas_cleanup_and_insert_cmd(priv, cmdnode);
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
+- }
+- ret = -1;
++ if (!cmdnode) {
++ lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
+ goto done;
+ }
+-
+- cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+-
+-
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- if (!cmdptr || !cmdptr->size) {
+- lbs_deb_cmd("DNLD_CMD: cmdptr is Null or cmd size is Zero, "
+- "Not sending\n");
+- __libertas_cleanup_and_insert_cmd(priv, cmdnode);
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
+- ret = -1;
++ if (!cmdnode->cmdbuf->size) {
++ lbs_deb_host("DNLD_CMD: cmd size is zero\n");
+ goto done;
+ }
++ cmdnode->result = 0;
+
+- adapter->cur_cmd = cmdnode;
+- adapter->cur_cmd_retcode = 0;
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
+- lbs_deb_cmd("DNLD_CMD:: Before download, size of cmd = %d\n",
+- le16_to_cpu(cmdptr->size));
+-
+- cmdsize = cmdptr->size;
+-
+- command = cpu_to_le16(cmdptr->command);
+-
+- cmdnode->cmdwaitqwoken = 0;
+- cmdsize = cpu_to_le16(cmdsize);
+-
+- ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
++ /* Exit_PS command needs to be queued in the header always. */
++ if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
++ struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf[1];
+
+- if (ret != 0) {
+- lbs_deb_cmd("DNLD_CMD: Host to Card failed\n");
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+- adapter->cur_cmd = NULL;
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
+- ret = -1;
+- goto done;
++ if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
++ if (priv->psstate != PS_STATE_FULL_POWER)
++ addtail = 0;
++ }
+ }
+
+- lbs_deb_cmd("DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies);
+- lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize);
++ spin_lock_irqsave(&priv->driver_lock, flags);
+
+- /* Setup the timer after transmit command */
+- if (command == cmd_802_11_scan || command == cmd_802_11_authenticate
+- || command == cmd_802_11_associate)
+- mod_timer(&adapter->command_timer, jiffies + (10*HZ));
++ if (addtail)
++ list_add_tail(&cmdnode->list, &priv->cmdpendingq);
+ else
+- mod_timer(&adapter->command_timer, jiffies + (5*HZ));
++ list_add(&cmdnode->list, &priv->cmdpendingq);
+
+- ret = 0;
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++
++ lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
++ le16_to_cpu(cmdnode->cmdbuf->command));
+
+ done:
+- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+- return ret;
++ lbs_deb_leave(LBS_DEB_HOST);
+ }
+
+-static int wlan_cmd_mac_control(wlan_private * priv,
+- struct cmd_ds_command *cmd)
++static void lbs_submit_command(struct lbs_private *priv,
++ struct cmd_ctrl_node *cmdnode)
+ {
+- struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
++ unsigned long flags;
++ struct cmd_header *cmd;
++ uint16_t cmdsize;
++ uint16_t command;
++ int timeo = 5 * HZ;
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_HOST);
++
++ cmd = cmdnode->cmdbuf;
++
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ priv->cur_cmd = cmdnode;
++ priv->cur_cmd_retcode = 0;
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++
++ cmdsize = le16_to_cpu(cmd->size);
++ command = le16_to_cpu(cmd->command);
++
++ /* These commands take longer */
++ if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
++ command == CMD_802_11_AUTHENTICATE)
++ timeo = 10 * HZ;
++
++ lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n",
++ command, le16_to_cpu(cmd->seqnum), cmdsize, jiffies);
++ lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
+
+- lbs_deb_enter(LBS_DEB_CMD);
++ ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
+
+- cmd->command = cpu_to_le16(cmd_mac_control);
+- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
+- mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);
++ if (ret) {
++ lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
++ /* Let the timer kick in and retry, and potentially reset
++ the whole thing if the condition persists */
++ timeo = HZ;
++ }
+
+- lbs_deb_cmd("wlan_cmd_mac_control(): action=0x%X size=%d\n",
+- le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
++ /* Setup the timer after transmit command */
++ mod_timer(&priv->command_timer, jiffies + timeo);
+
+- lbs_deb_leave(LBS_DEB_CMD);
+- return 0;
++ lbs_deb_leave(LBS_DEB_HOST);
+ }
+
+ /**
+ * This function inserts command node to cmdfreeq
+- * after cleans it. Requires adapter->driver_lock held.
++ * after cleans it. Requires priv->driver_lock held.
+ */
+-void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
++static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
++ struct cmd_ctrl_node *cmdnode)
+ {
+- wlan_adapter *adapter = priv->adapter;
++ lbs_deb_enter(LBS_DEB_HOST);
+
+- if (!ptempcmd)
+- goto done;
++ if (!cmdnode)
++ goto out;
+
+- cleanup_cmdnode(ptempcmd);
+- list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq);
+-done:
+- return;
++ cmdnode->callback = NULL;
++ cmdnode->callback_arg = 0;
++
++ memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
++
++ list_add_tail(&cmdnode->list, &priv->cmdfreeq);
++ out:
++ lbs_deb_leave(LBS_DEB_HOST);
+ }
+
+-void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
++static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
++ struct cmd_ctrl_node *ptempcmd)
+ {
+ unsigned long flags;
+
+- spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+- __libertas_cleanup_and_insert_cmd(priv, ptempcmd);
+- spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ __lbs_cleanup_and_insert_cmd(priv, ptempcmd);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++}
++
++void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
++ int result)
++{
++ if (cmd == priv->cur_cmd)
++ priv->cur_cmd_retcode = result;
++
++ cmd->result = result;
++ cmd->cmdwaitqwoken = 1;
++ wake_up_interruptible(&cmd->cmdwait_q);
++
++ if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
++ __lbs_cleanup_and_insert_cmd(priv, cmd);
++ priv->cur_cmd = NULL;
+ }
+
+-int libertas_set_radio_control(wlan_private * priv)
++int lbs_set_radio_control(struct lbs_private *priv)
+ {
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_radio_control,
+- cmd_act_set,
+- cmd_option_waitforrsp, 0, NULL);
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_RADIO_CONTROL,
++ CMD_ACT_SET,
++ CMD_OPTION_WAITFORRSP, 0, NULL);
+
+- lbs_deb_cmd("RADIO_SET: on or off: 0x%X, preamble = 0x%X\n",
+- priv->adapter->radioon, priv->adapter->preamble);
++ lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n",
++ priv->radioon, priv->preamble);
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+ }
+
+-int libertas_set_mac_packet_filter(wlan_private * priv)
++void lbs_set_mac_control(struct lbs_private *priv)
+ {
+- int ret = 0;
++ struct cmd_ds_mac_control cmd;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- lbs_deb_cmd("libertas_set_mac_packet_filter value = %x\n",
+- priv->adapter->currentpacketfilter);
++ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
++ cmd.action = cpu_to_le16(priv->mac_control);
++ cmd.reserved = 0;
+
+- /* Send MAC control command to station */
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_mac_control, 0, 0, 0, NULL);
++ lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
+
+- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+- return ret;
++ lbs_deb_leave(LBS_DEB_CMD);
+ }
+
+ /**
+ * @brief This function prepare the command before send to firmware.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param cmd_no command number
+ * @param cmd_action command action: GET or SET
+ * @param wait_option wait option: wait response or not
+@@ -1102,194 +1400,166 @@ int libertas_set_mac_packet_filter(wlan_
+ * @param pdata_buf A pointer to informaion buffer
+ * @return 0 or -1
+ */
+-int libertas_prepare_and_send_command(wlan_private * priv,
++int lbs_prepare_and_send_command(struct lbs_private *priv,
+ u16 cmd_no,
+ u16 cmd_action,
+ u16 wait_option, u32 cmd_oid, void *pdata_buf)
+ {
+ int ret = 0;
+- wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *cmdnode;
+ struct cmd_ds_command *cmdptr;
+ unsigned long flags;
+
+- lbs_deb_enter(LBS_DEB_CMD);
++ lbs_deb_enter(LBS_DEB_HOST);
+
+- if (!adapter) {
+- lbs_deb_cmd("PREP_CMD: adapter is Null\n");
++ if (!priv) {
++ lbs_deb_host("PREP_CMD: priv is NULL\n");
+ ret = -1;
+ goto done;
+ }
+
+- if (adapter->surpriseremoved) {
+- lbs_deb_cmd("PREP_CMD: Card is Removed\n");
++ if (priv->surpriseremoved) {
++ lbs_deb_host("PREP_CMD: card removed\n");
+ ret = -1;
+ goto done;
+ }
+
+- cmdnode = libertas_get_free_cmd_ctrl_node(priv);
++ cmdnode = lbs_get_cmd_ctrl_node(priv);
+
+ if (cmdnode == NULL) {
+- lbs_deb_cmd("PREP_CMD: No free cmdnode\n");
++ lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
+
+ /* Wake up main thread to execute next command */
+- wake_up_interruptible(&priv->mainthread.waitq);
++ wake_up_interruptible(&priv->waitq);
+ ret = -1;
+ goto done;
+ }
+
+- libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf);
++ lbs_set_cmd_ctrl_node(priv, cmdnode, pdata_buf);
+
+- cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
++ cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
+
+- lbs_deb_cmd("PREP_CMD: Val of cmd ptr=%p, command=0x%X\n",
+- cmdptr, cmd_no);
+-
+- if (!cmdptr) {
+- lbs_deb_cmd("PREP_CMD: bufvirtualaddr of cmdnode is NULL\n");
+- libertas_cleanup_and_insert_cmd(priv, cmdnode);
+- ret = -1;
+- goto done;
+- }
++ lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
+
+ /* Set sequence number, command and INT option */
+- adapter->seqnum++;
+- cmdptr->seqnum = cpu_to_le16(adapter->seqnum);
++ priv->seqnum++;
++ cmdptr->seqnum = cpu_to_le16(priv->seqnum);
+
+ cmdptr->command = cpu_to_le16(cmd_no);
+ cmdptr->result = 0;
+
+ switch (cmd_no) {
+- case cmd_get_hw_spec:
+- ret = wlan_cmd_hw_spec(priv, cmdptr);
+- break;
+- case cmd_802_11_ps_mode:
+- ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
++ case CMD_802_11_PS_MODE:
++ ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
+ break;
+
+- case cmd_802_11_scan:
+- ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf);
++ case CMD_802_11_SCAN:
++ ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
+ break;
+
+- case cmd_mac_control:
+- ret = wlan_cmd_mac_control(priv, cmdptr);
++ case CMD_802_11_ASSOCIATE:
++ case CMD_802_11_REASSOCIATE:
++ ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
+ break;
+
+- case cmd_802_11_associate:
+- case cmd_802_11_reassociate:
+- ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf);
++ case CMD_802_11_DEAUTHENTICATE:
++ ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
+ break;
+
+- case cmd_802_11_deauthenticate:
+- ret = libertas_cmd_80211_deauthenticate(priv, cmdptr);
++ case CMD_802_11_SET_WEP:
++ ret = lbs_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+- case cmd_802_11_set_wep:
+- ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
++ case CMD_802_11_AD_HOC_START:
++ ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
+ break;
+-
+- case cmd_802_11_ad_hoc_start:
+- ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
+- break;
+- case cmd_code_dnld:
++ case CMD_CODE_DNLD:
+ break;
+
+- case cmd_802_11_reset:
+- ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action);
++ case CMD_802_11_RESET:
++ ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
+ break;
+
+- case cmd_802_11_get_log:
+- ret = wlan_cmd_802_11_get_log(priv, cmdptr);
++ case CMD_802_11_GET_LOG:
++ ret = lbs_cmd_802_11_get_log(priv, cmdptr);
+ break;
+
+- case cmd_802_11_authenticate:
+- ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
++ case CMD_802_11_AUTHENTICATE:
++ ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
+ break;
+
+- case cmd_802_11_get_stat:
+- ret = wlan_cmd_802_11_get_stat(priv, cmdptr);
++ case CMD_802_11_GET_STAT:
++ ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
+ break;
+
+- case cmd_802_11_snmp_mib:
+- ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr,
++ case CMD_802_11_SNMP_MIB:
++ ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
+ cmd_action, cmd_oid, pdata_buf);
+ break;
+
+- case cmd_mac_reg_access:
+- case cmd_bbp_reg_access:
+- case cmd_rf_reg_access:
+- ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
+- break;
+-
+- case cmd_802_11_rf_channel:
+- ret = wlan_cmd_802_11_rf_channel(priv, cmdptr,
+- cmd_action, pdata_buf);
++ case CMD_MAC_REG_ACCESS:
++ case CMD_BBP_REG_ACCESS:
++ case CMD_RF_REG_ACCESS:
++ ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+- case cmd_802_11_rf_tx_power:
+- ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr,
++ case CMD_802_11_RF_TX_POWER:
++ ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
+ cmd_action, pdata_buf);
+ break;
+
+- case cmd_802_11_radio_control:
+- ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
+- break;
+-
+- case cmd_802_11_rf_antenna:
+- ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr,
+- cmd_action, pdata_buf);
++ case CMD_802_11_RADIO_CONTROL:
++ ret = lbs_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
+ break;
+
+- case cmd_802_11_data_rate:
+- ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
+- break;
+- case cmd_802_11_rate_adapt_rateset:
+- ret = wlan_cmd_802_11_rate_adapt_rateset(priv,
++ case CMD_802_11_RATE_ADAPT_RATESET:
++ ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
+ cmdptr, cmd_action);
+ break;
+
+- case cmd_mac_multicast_adr:
+- ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
++ case CMD_802_11_MONITOR_MODE:
++ ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
++ cmd_action, pdata_buf);
+ break;
+
+- case cmd_802_11_ad_hoc_join:
+- ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
++ case CMD_802_11_AD_HOC_JOIN:
++ ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
+ break;
+
+- case cmd_802_11_rssi:
+- ret = wlan_cmd_802_11_rssi(priv, cmdptr);
++ case CMD_802_11_RSSI:
++ ret = lbs_cmd_802_11_rssi(priv, cmdptr);
+ break;
+
+- case cmd_802_11_ad_hoc_stop:
+- ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr);
++ case CMD_802_11_AD_HOC_STOP:
++ ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
+ break;
+
+- case cmd_802_11_enable_rsn:
+- ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
++ case CMD_802_11_ENABLE_RSN:
++ ret = lbs_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
+ pdata_buf);
+ break;
+
+- case cmd_802_11_key_material:
+- ret = wlan_cmd_802_11_key_material(priv, cmdptr, cmd_action,
++ case CMD_802_11_KEY_MATERIAL:
++ ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
+ cmd_oid, pdata_buf);
+ break;
+
+- case cmd_802_11_pairwise_tsc:
++ case CMD_802_11_PAIRWISE_TSC:
+ break;
+- case cmd_802_11_group_tsc:
++ case CMD_802_11_GROUP_TSC:
+ break;
+
+- case cmd_802_11_mac_address:
+- ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
++ case CMD_802_11_MAC_ADDRESS:
++ ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
+ break;
+
+- case cmd_802_11_eeprom_access:
+- ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr,
++ case CMD_802_11_EEPROM_ACCESS:
++ ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
+ cmd_action, pdata_buf);
+ break;
+
+- case cmd_802_11_set_afc:
+- case cmd_802_11_get_afc:
++ case CMD_802_11_SET_AFC:
++ case CMD_802_11_GET_AFC:
+
+ cmdptr->command = cpu_to_le16(cmd_no);
+ cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
+@@ -1301,22 +1571,22 @@ int libertas_prepare_and_send_command(wl
+ ret = 0;
+ goto done;
+
+- case cmd_802_11d_domain_info:
+- ret = libertas_cmd_802_11d_domain_info(priv, cmdptr,
++ case CMD_802_11D_DOMAIN_INFO:
++ ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
+ cmd_no, cmd_action);
+ break;
+
+- case cmd_802_11_sleep_params:
+- ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
++ case CMD_802_11_SLEEP_PARAMS:
++ ret = lbs_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
+ break;
+- case cmd_802_11_inactivity_timeout:
+- ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr,
++ case CMD_802_11_INACTIVITY_TIMEOUT:
++ ret = lbs_cmd_802_11_inactivity_timeout(priv, cmdptr,
+ cmd_action, pdata_buf);
+- libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf);
++ lbs_set_cmd_ctrl_node(priv, cmdnode, pdata_buf);
+ break;
+
+- case cmd_802_11_tpc_cfg:
+- cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg);
++ 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);
+@@ -1326,7 +1596,7 @@ int libertas_prepare_and_send_command(wl
+
+ ret = 0;
+ break;
+- case cmd_802_11_led_gpio_ctrl:
++ case CMD_802_11_LED_GPIO_CTRL:
+ {
+ struct mrvlietypes_ledgpio *gpio =
+ (struct mrvlietypes_ledgpio*)
+@@ -1337,19 +1607,24 @@ int libertas_prepare_and_send_command(wl
+ sizeof(struct cmd_ds_802_11_led_ctrl));
+
+ cmdptr->command =
+- cpu_to_le16(cmd_802_11_led_gpio_ctrl);
++ cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
+
+ #define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
+ cmdptr->size =
+- cpu_to_le16(gpio->header.len + S_DS_GEN +
+- ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
+- gpio->header.len = cpu_to_le16(gpio->header.len);
++ 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_802_11_pwr_cfg:
+- cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg);
++ case CMD_802_11_SUBSCRIBE_EVENT:
++ lbs_cmd_802_11_subscribe_event(priv, cmdptr,
++ cmd_action, pdata_buf);
++ break;
++ case CMD_802_11_PWR_CFG:
++ cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
+ cmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
+ S_DS_GEN);
+@@ -1358,170 +1633,147 @@ int libertas_prepare_and_send_command(wl
+
+ ret = 0;
+ break;
+- case cmd_bt_access:
+- ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
++ case CMD_BT_ACCESS:
++ ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+- case cmd_fwt_access:
+- ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
++ case CMD_FWT_ACCESS:
++ ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+- case cmd_mesh_access:
+- ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
+- break;
+-
+- case cmd_get_tsf:
+- cmdptr->command = cpu_to_le16(cmd_get_tsf);
++ 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_tx_rate_query:
+- cmdptr->command = cpu_to_le16(cmd_802_11_tx_rate_query);
+- cmdptr->size = cpu_to_le16(sizeof(struct cmd_tx_rate_query) +
+- S_DS_GEN);
+- adapter->txrate = 0;
+- ret = 0;
++ case CMD_802_11_BEACON_CTRL:
++ ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
+ break;
+ default:
+- lbs_deb_cmd("PREP_CMD: unknown command- %#x\n", cmd_no);
++ lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
+ ret = -1;
+ break;
+ }
+
+ /* return error, since the command preparation failed */
+ if (ret != 0) {
+- lbs_deb_cmd("PREP_CMD: command preparation failed\n");
+- libertas_cleanup_and_insert_cmd(priv, cmdnode);
++ lbs_deb_host("PREP_CMD: command preparation failed\n");
++ lbs_cleanup_and_insert_cmd(priv, cmdnode);
+ ret = -1;
+ goto done;
+ }
+
+ cmdnode->cmdwaitqwoken = 0;
+
+- libertas_queue_cmd(adapter, cmdnode, 1);
+- adapter->nr_cmd_pending++;
+- wake_up_interruptible(&priv->mainthread.waitq);
++ lbs_queue_cmd(priv, cmdnode);
++ wake_up_interruptible(&priv->waitq);
+
+- if (wait_option & cmd_option_waitforrsp) {
+- lbs_deb_cmd("PREP_CMD: Wait for CMD response\n");
++ if (wait_option & CMD_OPTION_WAITFORRSP) {
++ lbs_deb_host("PREP_CMD: wait for response\n");
+ might_sleep();
+ wait_event_interruptible(cmdnode->cmdwait_q,
+ cmdnode->cmdwaitqwoken);
+ }
+
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- if (adapter->cur_cmd_retcode) {
+- lbs_deb_cmd("PREP_CMD: command failed with return code=%d\n",
+- adapter->cur_cmd_retcode);
+- adapter->cur_cmd_retcode = 0;
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ if (priv->cur_cmd_retcode) {
++ lbs_deb_host("PREP_CMD: command failed with return code %d\n",
++ priv->cur_cmd_retcode);
++ priv->cur_cmd_retcode = 0;
+ ret = -1;
+ }
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ done:
+- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
++ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
+ return ret;
+ }
+-EXPORT_SYMBOL_GPL(libertas_prepare_and_send_command);
++EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
+
+ /**
+ * @brief This function allocates the command buffer and link
+ * it to command free queue.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @return 0 or -1
+ */
+-int libertas_allocate_cmd_buffer(wlan_private * priv)
++int lbs_allocate_cmd_buffer(struct lbs_private *priv)
+ {
+ int ret = 0;
+- u32 ulbufsize;
++ u32 bufsize;
+ u32 i;
+- struct cmd_ctrl_node *tempcmd_array;
+- u8 *ptempvirtualaddr;
+- wlan_adapter *adapter = priv->adapter;
++ struct cmd_ctrl_node *cmdarray;
+
+- lbs_deb_enter(LBS_DEB_CMD);
++ lbs_deb_enter(LBS_DEB_HOST);
+
+- /* Allocate and initialize cmdCtrlNode */
+- ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
+-
+- if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) {
+- lbs_deb_cmd(
+- "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n");
++ /* Allocate and initialize the command array */
++ bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
++ if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
++ lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
+ ret = -1;
+ goto done;
+ }
+- adapter->cmd_array = tempcmd_array;
++ priv->cmd_array = cmdarray;
+
+- /* Allocate and initialize command buffers */
+- ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
+- for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+- if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) {
+- lbs_deb_cmd(
+- "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n");
++ /* Allocate and initialize each command buffer in the command array */
++ for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
++ cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
++ if (!cmdarray[i].cmdbuf) {
++ lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
+ ret = -1;
+ goto done;
+ }
+-
+- /* Update command buffer virtual */
+- tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr;
+ }
+
+- for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+- init_waitqueue_head(&tempcmd_array[i].cmdwait_q);
+- libertas_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
++ for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
++ init_waitqueue_head(&cmdarray[i].cmdwait_q);
++ lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
+ }
+-
+ ret = 0;
+
+ done:
+- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
++ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
+ return ret;
+ }
+
+ /**
+ * @brief This function frees the command buffer.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @return 0 or -1
+ */
+-int libertas_free_cmd_buffer(wlan_private * priv)
++int lbs_free_cmd_buffer(struct lbs_private *priv)
+ {
+- u32 ulbufsize; /* Someone needs to die for this. Slowly and painfully */
++ struct cmd_ctrl_node *cmdarray;
+ unsigned int i;
+- struct cmd_ctrl_node *tempcmd_array;
+- wlan_adapter *adapter = priv->adapter;
+
+- lbs_deb_enter(LBS_DEB_CMD);
++ lbs_deb_enter(LBS_DEB_HOST);
+
+ /* need to check if cmd array is allocated or not */
+- if (adapter->cmd_array == NULL) {
+- lbs_deb_cmd("FREE_CMD_BUF: cmd_array is Null\n");
++ if (priv->cmd_array == NULL) {
++ lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
+ goto done;
+ }
+
+- tempcmd_array = adapter->cmd_array;
++ cmdarray = priv->cmd_array;
+
+ /* Release shared memory buffers */
+- ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
+- for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+- if (tempcmd_array[i].bufvirtualaddr) {
+- lbs_deb_cmd("Free all the array\n");
+- kfree(tempcmd_array[i].bufvirtualaddr);
+- tempcmd_array[i].bufvirtualaddr = NULL;
++ for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
++ if (cmdarray[i].cmdbuf) {
++ kfree(cmdarray[i].cmdbuf);
++ cmdarray[i].cmdbuf = NULL;
+ }
+ }
+
+ /* Release cmd_ctrl_node */
+- if (adapter->cmd_array) {
+- lbs_deb_cmd("Free cmd_array\n");
+- kfree(adapter->cmd_array);
+- adapter->cmd_array = NULL;
++ if (priv->cmd_array) {
++ kfree(priv->cmd_array);
++ priv->cmd_array = NULL;
+ }
+
+ done:
+- lbs_deb_leave(LBS_DEB_CMD);
++ lbs_deb_leave(LBS_DEB_HOST);
+ return 0;
+ }
+
+@@ -1529,39 +1781,33 @@ done:
+ * @brief This function gets a free command node if available in
+ * command free queue.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
+ */
+-struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
++static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
+ {
+ struct cmd_ctrl_node *tempnode;
+- wlan_adapter *adapter = priv->adapter;
+ unsigned long flags;
+
+- if (!adapter)
++ lbs_deb_enter(LBS_DEB_HOST);
++
++ if (!priv)
+ return NULL;
+
+- spin_lock_irqsave(&adapter->driver_lock, flags);
++ spin_lock_irqsave(&priv->driver_lock, flags);
+
+- if (!list_empty(&adapter->cmdfreeq)) {
+- tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next;
+- list_del((struct list_head *)tempnode);
++ if (!list_empty(&priv->cmdfreeq)) {
++ tempnode = list_first_entry(&priv->cmdfreeq,
++ struct cmd_ctrl_node, list);
++ list_del(&tempnode->list);
+ } else {
+- lbs_deb_cmd("GET_CMD_NODE: cmd_ctrl_node is not available\n");
++ lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
+ tempnode = NULL;
+ }
+
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
+-
+- if (tempnode) {
+- /*
+- lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n");
+- lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n",
+- tempnode);
+- */
+- cleanup_cmdnode(tempnode);
+- }
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
++ lbs_deb_leave(LBS_DEB_HOST);
+ return tempnode;
+ }
+
+@@ -1571,46 +1817,28 @@ struct cmd_ctrl_node *libertas_get_free_
+ * @param ptempnode A pointer to cmdCtrlNode structure
+ * @return n/a
+ */
+-static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
+-{
+- if (!ptempnode)
+- return;
+- ptempnode->cmdwaitqwoken = 1;
+- wake_up_interruptible(&ptempnode->cmdwait_q);
+- ptempnode->status = 0;
+- ptempnode->cmd_oid = (u32) 0;
+- ptempnode->wait_option = 0;
+- ptempnode->pdata_buf = NULL;
+-
+- if (ptempnode->bufvirtualaddr != NULL)
+- memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+- return;
+-}
+
+ /**
+ * @brief This function initializes the command node.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param ptempnode A pointer to cmd_ctrl_node structure
+- * @param cmd_oid cmd oid: treated as sub command
+- * @param wait_option wait option: wait response or not
+ * @param pdata_buf A pointer to informaion buffer
+ * @return 0 or -1
+ */
+-void libertas_set_cmd_ctrl_node(wlan_private * priv,
+- struct cmd_ctrl_node *ptempnode,
+- u32 cmd_oid, u16 wait_option, void *pdata_buf)
++static void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
++ struct cmd_ctrl_node *ptempnode,
++ void *pdata_buf)
+ {
+- lbs_deb_enter(LBS_DEB_CMD);
++ lbs_deb_enter(LBS_DEB_HOST);
+
+ if (!ptempnode)
+ return;
+
+- ptempnode->cmd_oid = cmd_oid;
+- ptempnode->wait_option = wait_option;
+- ptempnode->pdata_buf = pdata_buf;
++ ptempnode->callback = NULL;
++ ptempnode->callback_arg = (unsigned long)pdata_buf;
+
+- lbs_deb_leave(LBS_DEB_CMD);
++ lbs_deb_leave(LBS_DEB_HOST);
+ }
+
+ /**
+@@ -1618,59 +1846,58 @@ void libertas_set_cmd_ctrl_node(wlan_pri
+ * pending queue. It will put fimware back to PS mode
+ * if applicable.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @return 0 or -1
+ */
+-int libertas_execute_next_command(wlan_private * priv)
++int lbs_execute_next_command(struct lbs_private *priv)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *cmdnode = NULL;
+- struct cmd_ds_command *cmdptr;
++ struct cmd_header *cmd;
+ unsigned long flags;
+ int ret = 0;
+
+- lbs_deb_enter(LBS_DEB_CMD);
+-
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+-
+- if (adapter->cur_cmd) {
+- lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n");
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
++ * only caller to us is lbs_thread() and we get even when a
++ * data packet is received */
++ lbs_deb_enter(LBS_DEB_THREAD);
++
++ spin_lock_irqsave(&priv->driver_lock, flags);
++
++ if (priv->cur_cmd) {
++ lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ ret = -1;
+ goto done;
+ }
+
+- if (!list_empty(&adapter->cmdpendingq)) {
+- cmdnode = (struct cmd_ctrl_node *)
+- adapter->cmdpendingq.next;
++ if (!list_empty(&priv->cmdpendingq)) {
++ cmdnode = list_first_entry(&priv->cmdpendingq,
++ struct cmd_ctrl_node, list);
+ }
+
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ if (cmdnode) {
+- lbs_deb_cmd(
+- "EXEC_NEXT_CMD: Got next command from cmdpendingq\n");
+- cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+-
+- if (is_command_allowed_in_ps(cmdptr->command)) {
+- if ((adapter->psstate == PS_STATE_SLEEP) ||
+- (adapter->psstate == PS_STATE_PRE_SLEEP)) {
+- lbs_deb_cmd(
+- "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n",
+- le16_to_cpu(cmdptr->command),
+- adapter->psstate);
++ cmd = cmdnode->cmdbuf;
++
++ if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
++ if ((priv->psstate == PS_STATE_SLEEP) ||
++ (priv->psstate == PS_STATE_PRE_SLEEP)) {
++ lbs_deb_host(
++ "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
++ le16_to_cpu(cmd->command),
++ priv->psstate);
+ ret = -1;
+ goto done;
+ }
+- lbs_deb_cmd("EXEC_NEXT_CMD: OK to send command "
+- "0x%x in psstate %d\n",
+- le16_to_cpu(cmdptr->command),
+- adapter->psstate);
+- } else if (adapter->psstate != PS_STATE_FULL_POWER) {
++ lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
++ "0x%04x in psstate %d\n",
++ le16_to_cpu(cmd->command), priv->psstate);
++ } else if (priv->psstate != PS_STATE_FULL_POWER) {
+ /*
+ * 1. Non-PS command:
+ * Queue it. set needtowakeup to TRUE if current state
+- * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS.
++ * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
+ * 2. PS command but not Exit_PS:
+ * Ignore it.
+ * 3. PS command Exit_PS:
+@@ -1678,18 +1905,17 @@ int libertas_execute_next_command(wlan_p
+ * otherwise send this command down to firmware
+ * immediately.
+ */
+- if (cmdptr->command !=
+- cpu_to_le16(cmd_802_11_ps_mode)) {
++ if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
+ /* Prepare to send Exit PS,
+ * this non PS command will be sent later */
+- if ((adapter->psstate == PS_STATE_SLEEP)
+- || (adapter->psstate == PS_STATE_PRE_SLEEP)
++ if ((priv->psstate == PS_STATE_SLEEP)
++ || (priv->psstate == PS_STATE_PRE_SLEEP)
+ ) {
+ /* w/ new scheme, it will not reach here.
+ since it is blocked in main_thread. */
+- adapter->needtowakeup = 1;
++ priv->needtowakeup = 1;
+ } else
+- libertas_ps_wakeup(priv, 0);
++ lbs_ps_wakeup(priv, 0);
+
+ ret = 0;
+ goto done;
+@@ -1698,82 +1924,86 @@ int libertas_execute_next_command(wlan_p
+ * PS command. Ignore it if it is not Exit_PS.
+ * otherwise send it down immediately.
+ */
+- struct cmd_ds_802_11_ps_mode *psm =
+- &cmdptr->params.psmode;
++ struct cmd_ds_802_11_ps_mode *psm = (void *)&cmd[1];
+
+- lbs_deb_cmd(
+- "EXEC_NEXT_CMD: PS cmd- action=0x%x\n",
++ lbs_deb_host(
++ "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
+ psm->action);
+ if (psm->action !=
+- cpu_to_le16(cmd_subcmd_exit_ps)) {
+- lbs_deb_cmd(
+- "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
+- list_del((struct list_head *)cmdnode);
+- libertas_cleanup_and_insert_cmd(priv, cmdnode);
++ cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
++ lbs_deb_host(
++ "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
++ list_del(&cmdnode->list);
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ lbs_complete_command(priv, cmdnode, 0);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ ret = 0;
+ goto done;
+ }
+
+- if ((adapter->psstate == PS_STATE_SLEEP) ||
+- (adapter->psstate == PS_STATE_PRE_SLEEP)) {
+- lbs_deb_cmd(
+- "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n");
+- list_del((struct list_head *)cmdnode);
+- libertas_cleanup_and_insert_cmd(priv, cmdnode);
+- adapter->needtowakeup = 1;
++ if ((priv->psstate == PS_STATE_SLEEP) ||
++ (priv->psstate == PS_STATE_PRE_SLEEP)) {
++ lbs_deb_host(
++ "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
++ list_del(&cmdnode->list);
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ lbs_complete_command(priv, cmdnode, 0);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++ priv->needtowakeup = 1;
+
+ ret = 0;
+ goto done;
+ }
+
+- lbs_deb_cmd(
+- "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
++ lbs_deb_host(
++ "EXEC_NEXT_CMD: sending EXIT_PS\n");
+ }
+ }
+- list_del((struct list_head *)cmdnode);
+- lbs_deb_cmd("EXEC_NEXT_CMD: Sending 0x%04X command\n",
+- le16_to_cpu(cmdptr->command));
+- DownloadcommandToStation(priv, cmdnode);
++ list_del(&cmdnode->list);
++ lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
++ le16_to_cpu(cmd->command));
++ lbs_submit_command(priv, cmdnode);
+ } else {
+ /*
+ * check if in power save mode, if yes, put the device back
+ * to PS mode
+ */
+- if ((adapter->psmode != wlan802_11powermodecam) &&
+- (adapter->psstate == PS_STATE_FULL_POWER) &&
+- (adapter->connect_status == libertas_connected)) {
+- if (adapter->secinfo.WPAenabled ||
+- adapter->secinfo.WPA2enabled) {
++ if ((priv->psmode != LBS802_11POWERMODECAM) &&
++ (priv->psstate == PS_STATE_FULL_POWER) &&
++ ((priv->connect_status == LBS_CONNECTED) ||
++ (priv->mesh_connect_status == LBS_CONNECTED))) {
++ if (priv->secinfo.WPAenabled ||
++ priv->secinfo.WPA2enabled) {
+ /* check for valid WPA group keys */
+- if (adapter->wpa_mcast_key.len ||
+- adapter->wpa_unicast_key.len) {
+- lbs_deb_cmd(
++ if (priv->wpa_mcast_key.len ||
++ priv->wpa_unicast_key.len) {
++ lbs_deb_host(
+ "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
+ " go back to PS_SLEEP");
+- libertas_ps_sleep(priv, 0);
++ lbs_ps_sleep(priv, 0);
+ }
+ } else {
+- lbs_deb_cmd(
+- "EXEC_NEXT_CMD: command PendQ is empty,"
+- " go back to PS_SLEEP");
+- libertas_ps_sleep(priv, 0);
++ lbs_deb_host(
++ "EXEC_NEXT_CMD: cmdpendingq empty, "
++ "go back to PS_SLEEP");
++ lbs_ps_sleep(priv, 0);
+ }
+ }
+ }
+
+ ret = 0;
+ done:
+- lbs_deb_leave(LBS_DEB_CMD);
++ lbs_deb_leave(LBS_DEB_THREAD);
+ return ret;
+ }
+
+-void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str)
++void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
+ {
+ union iwreq_data iwrq;
+ u8 buf[50];
+
+- lbs_deb_enter(LBS_DEB_CMD);
++ lbs_deb_enter(LBS_DEB_WEXT);
+
+ memset(&iwrq, 0, sizeof(union iwreq_data));
+ memset(buf, 0, sizeof(buf));
+@@ -1783,136 +2013,227 @@ void libertas_send_iwevcustom_event(wlan
+ iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
+
+ /* Send Event to upper layer */
+- lbs_deb_cmd("Event Indication string = %s\n", (char *)buf);
+- lbs_deb_cmd("Event Indication String length = %d\n", iwrq.data.length);
++ 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);
+
+- lbs_deb_cmd("Sending wireless event IWEVCUSTOM for %s\n", str);
+ wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
+
+- lbs_deb_leave(LBS_DEB_CMD);
++ lbs_deb_leave(LBS_DEB_WEXT);
+ }
+
+-static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
++static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
+ {
+ unsigned long flags;
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+- lbs_deb_enter(LBS_DEB_CMD);
++ lbs_deb_enter(LBS_DEB_HOST);
+
+- lbs_deb_cmd("SEND_SLEEPC_CMD: Before download, size of cmd = %d\n",
++ lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
+ size);
+
+- lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size);
++ lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
+
+ ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
+- priv->dnld_sent = DNLD_RES_RECEIVED;
+
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- if (adapter->intcounter || adapter->currenttxskb)
+- lbs_deb_cmd("SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n",
+- adapter->intcounter, adapter->currenttxskb);
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ if (priv->intcounter || priv->currenttxskb)
++ lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
++ priv->intcounter, priv->currenttxskb);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ if (ret) {
+ lbs_pr_alert(
+ "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
+ } else {
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- if (!adapter->intcounter) {
+- adapter->psstate = PS_STATE_SLEEP;
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ if (!priv->intcounter) {
++ priv->psstate = PS_STATE_SLEEP;
+ } else {
+- lbs_deb_cmd("SEND_SLEEPC_CMD: After sent,IntC=%d\n",
+- adapter->intcounter);
++ lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
++ priv->intcounter);
+ }
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+- lbs_deb_cmd("SEND_SLEEPC_CMD: Sent Confirm Sleep command\n");
+- lbs_deb_cmd("+");
++ lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
+ }
+
+- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
++ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
+ return ret;
+ }
+
+-void libertas_ps_sleep(wlan_private * priv, int wait_option)
++void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
+ {
+- lbs_deb_enter(LBS_DEB_CMD);
++ lbs_deb_enter(LBS_DEB_HOST);
+
+ /*
+ * PS is currently supported only in Infrastructure mode
+ * Remove this check if it is to be supported in IBSS mode also
+ */
+
+- libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
+- cmd_subcmd_enter_ps, wait_option, 0, NULL);
++ lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
++ CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
+
+- lbs_deb_leave(LBS_DEB_CMD);
++ lbs_deb_leave(LBS_DEB_HOST);
+ }
+
+ /**
+- * @brief This function sends Eixt_PS command to firmware.
++ * @brief This function sends Exit_PS command to firmware.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param wait_option wait response or not
+ * @return n/a
+ */
+-void libertas_ps_wakeup(wlan_private * priv, int wait_option)
++void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
+ {
+ __le32 Localpsmode;
+
+- lbs_deb_enter(LBS_DEB_CMD);
+-
+- Localpsmode = cpu_to_le32(wlan802_11powermodecam);
++ lbs_deb_enter(LBS_DEB_HOST);
+
+- lbs_deb_cmd("Exit_PS: Localpsmode = %d\n", wlan802_11powermodecam);
++ Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
+
+- libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
+- cmd_subcmd_exit_ps,
++ lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
++ CMD_SUBCMD_EXIT_PS,
+ wait_option, 0, &Localpsmode);
+
+- lbs_deb_leave(LBS_DEB_CMD);
++ lbs_deb_leave(LBS_DEB_HOST);
+ }
+
+ /**
+ * @brief This function checks condition and prepares to
+ * send sleep confirm command to firmware if ok.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param psmode Power Saving mode
+ * @return n/a
+ */
+-void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode)
++void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode)
+ {
+ unsigned long flags =0;
+- wlan_adapter *adapter = priv->adapter;
+ u8 allowed = 1;
+
+- lbs_deb_enter(LBS_DEB_CMD);
++ lbs_deb_enter(LBS_DEB_HOST);
+
+ if (priv->dnld_sent) {
+ allowed = 0;
+- lbs_deb_cmd("D");
++ lbs_deb_host("dnld_sent was set\n");
+ }
+
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- if (adapter->cur_cmd) {
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ if (priv->cur_cmd) {
+ allowed = 0;
+- lbs_deb_cmd("C");
++ lbs_deb_host("cur_cmd was set\n");
+ }
+- if (adapter->intcounter > 0) {
++ if (priv->intcounter > 0) {
+ allowed = 0;
+- lbs_deb_cmd("I%d", adapter->intcounter);
++ lbs_deb_host("intcounter %d\n", priv->intcounter);
+ }
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ if (allowed) {
+- lbs_deb_cmd("Sending libertas_ps_confirm_sleep\n");
+- sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep,
++ lbs_deb_host("sending lbs_ps_confirm_sleep\n");
++ sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep,
+ sizeof(struct PS_CMD_ConfirmSleep));
+ } else {
+- lbs_deb_cmd("Sleep Confirm has been delayed\n");
++ lbs_deb_host("sleep confirm has been delayed\n");
+ }
+
++ lbs_deb_leave(LBS_DEB_HOST);
++}
++
++
++static 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)
++{
++ struct cmd_ctrl_node *cmdnode;
++
++ lbs_deb_enter(LBS_DEB_HOST);
++
++ if (priv->surpriseremoved) {
++ lbs_deb_host("PREP_CMD: card removed\n");
++ cmdnode = ERR_PTR(-ENOENT);
++ goto done;
++ }
++
++ cmdnode = lbs_get_cmd_ctrl_node(priv);
++ if (cmdnode == NULL) {
++ lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
++
++ /* Wake up main thread to execute next command */
++ wake_up_interruptible(&priv->waitq);
++ cmdnode = ERR_PTR(-ENOBUFS);
++ goto done;
++ }
++
++ cmdnode->callback = callback;
++ cmdnode->callback_arg = callback_arg;
++
++ /* Copy the incoming command to the buffer */
++ memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
++
++ /* Set sequence number, clean result, move to buffer */
++ priv->seqnum++;
++ cmdnode->cmdbuf->command = cpu_to_le16(command);
++ cmdnode->cmdbuf->size = cpu_to_le16(in_cmd_size);
++ cmdnode->cmdbuf->seqnum = cpu_to_le16(priv->seqnum);
++ cmdnode->cmdbuf->result = 0;
++
++ lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
++
++ cmdnode->cmdwaitqwoken = 0;
++ lbs_queue_cmd(priv, cmdnode);
++ wake_up_interruptible(&priv->waitq);
++
++ done:
++ lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
++ return cmdnode;
++}
++
++void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
++ struct cmd_header *in_cmd, int in_cmd_size)
++{
++ lbs_deb_enter(LBS_DEB_CMD);
++ __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
++ lbs_cmd_async_callback, 0);
+ lbs_deb_leave(LBS_DEB_CMD);
+ }
++
++int __lbs_cmd(struct lbs_private *priv, uint16_t command,
++ struct cmd_header *in_cmd, int in_cmd_size,
++ int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
++ unsigned long callback_arg)
++{
++ struct cmd_ctrl_node *cmdnode;
++ unsigned long flags;
++ int ret = 0;
++
++ lbs_deb_enter(LBS_DEB_HOST);
++
++ cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
++ callback, callback_arg);
++ if (IS_ERR(cmdnode)) {
++ ret = PTR_ERR(cmdnode);
++ goto done;
++ }
++
++ might_sleep();
++ wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
++
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ ret = cmdnode->result;
++ if (ret)
++ lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
++ command, ret);
++
++ __lbs_cleanup_and_insert_cmd(priv, cmdnode);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++
++done:
++ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(__lbs_cmd);
++
++
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/cmd.h linux-2.6.22-300/drivers/net/wireless/libertas/cmd.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/cmd.h 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.22-300/drivers/net/wireless/libertas/cmd.h 2008-06-05 18:10:06.000000000 -0400
+@@ -0,0 +1,50 @@
++/* Copyright (C) 2007, Red Hat, Inc. */
++
++#ifndef _LBS_CMD_H_
++#define _LBS_CMD_H_
++
++#include "hostcmd.h"
++#include "dev.h"
++
++#define lbs_cmd(priv, cmdnr, cmd, cb, cb_arg) \
++ __lbs_cmd(priv, cmdnr, &(cmd)->hdr, sizeof(*(cmd)), cb, cb_arg)
++
++
++/* lbs_cmd_with_response() infers the size of the command to be _sent_
++ and requires that the caller sets cmd->size to the (LE) size of
++ the _response_ buffer. */
++#define lbs_cmd_with_response(priv, cmdnr, cmd) \
++ lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd))
++
++void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
++ struct cmd_header *in_cmd, int in_cmd_size);
++
++int __lbs_cmd(struct lbs_private *priv, uint16_t command,
++ struct cmd_header *in_cmd, int in_cmd_size,
++ int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
++ unsigned long callback_arg);
++
++int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
++ struct cmd_header *resp);
++
++int lbs_update_hw_spec(struct lbs_private *priv);
++
++int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
++ struct cmd_ds_mesh_access *cmd);
++
++int lbs_get_data_rate(struct lbs_private *priv);
++int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
++
++int lbs_get_channel(struct lbs_private *priv);
++int lbs_set_channel(struct lbs_private *priv, u8 channel);
++
++int lbs_mesh_config_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_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria);
++int lbs_suspend(struct lbs_private *priv);
++int lbs_resume(struct lbs_private *priv);
++
++#endif /* _LBS_CMD_H */
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/cmdresp.c linux-2.6.22-300/drivers/net/wireless/libertas/cmdresp.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/cmdresp.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/cmdresp.c 2008-06-05 18:10:06.000000000 -0400
+@@ -20,18 +20,17 @@
+ * reports disconnect to upper layer, clean tx/rx packets,
+ * reset link state etc.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @return n/a
+ */
+-void libertas_mac_event_disconnected(wlan_private * priv)
++void lbs_mac_event_disconnected(struct lbs_private *priv)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ union iwreq_data wrqu;
+
+- if (adapter->connect_status != libertas_connected)
++ if (priv->connect_status != LBS_CONNECTED)
+ return;
+
+- lbs_deb_cmd("Handles disconnect event.\n");
++ lbs_deb_enter(LBS_DEB_ASSOC);
+
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+@@ -44,64 +43,52 @@ void libertas_mac_event_disconnected(wla
+ msleep_interruptible(1000);
+ wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
+- /* Free Tx and Rx packets */
+- kfree_skb(priv->adapter->currenttxskb);
+- priv->adapter->currenttxskb = NULL;
+-
+ /* report disconnect to upper layer */
+ netif_stop_queue(priv->dev);
+ netif_carrier_off(priv->dev);
+
++ /* Free Tx and Rx packets */
++ kfree_skb(priv->currenttxskb);
++ priv->currenttxskb = NULL;
++ priv->tx_pending_len = 0;
++
+ /* reset SNR/NF/RSSI values */
+- memset(adapter->SNR, 0x00, sizeof(adapter->SNR));
+- memset(adapter->NF, 0x00, sizeof(adapter->NF));
+- memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI));
+- memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
+- memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
+- adapter->nextSNRNF = 0;
+- adapter->numSNRNF = 0;
+- adapter->rxpd_rate = 0;
+- lbs_deb_cmd("Current SSID='%s', ssid length=%u\n",
+- escape_essid(adapter->curbssparams.ssid,
+- adapter->curbssparams.ssid_len),
+- adapter->curbssparams.ssid_len);
+- lbs_deb_cmd("Previous SSID='%s', ssid length=%u\n",
+- escape_essid(adapter->prev_ssid, adapter->prev_ssid_len),
+- adapter->prev_ssid_len);
+-
+- adapter->connect_status = libertas_disconnected;
+-
+- /* Save previous SSID and BSSID for possible reassociation */
+- memcpy(&adapter->prev_ssid, &adapter->curbssparams.ssid,
+- IW_ESSID_MAX_SIZE);
+- adapter->prev_ssid_len = adapter->curbssparams.ssid_len;
+- memcpy(adapter->prev_bssid, adapter->curbssparams.bssid, ETH_ALEN);
++ memset(priv->SNR, 0x00, sizeof(priv->SNR));
++ memset(priv->NF, 0x00, sizeof(priv->NF));
++ memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
++ memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
++ memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
++ priv->nextSNRNF = 0;
++ priv->numSNRNF = 0;
++ priv->connect_status = LBS_DISCONNECTED;
+
+ /* Clear out associated SSID and BSSID since connection is
+ * no longer valid.
+ */
+- memset(&adapter->curbssparams.bssid, 0, ETH_ALEN);
+- memset(&adapter->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE);
+- adapter->curbssparams.ssid_len = 0;
++ memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
++ memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE);
++ priv->curbssparams.ssid_len = 0;
+
+- if (adapter->psstate != PS_STATE_FULL_POWER) {
++ if (priv->psstate != PS_STATE_FULL_POWER) {
+ /* make firmware to exit PS mode */
+- lbs_deb_cmd("Disconnected, so exit PS mode.\n");
+- libertas_ps_wakeup(priv, 0);
++ lbs_deb_cmd("disconnected, so exit PS mode\n");
++ lbs_ps_wakeup(priv, 0);
+ }
++ lbs_deb_leave(LBS_DEB_CMD);
+ }
+
+ /**
+ * @brief This function handles MIC failure event.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @para event the event id
+ * @return n/a
+ */
+-static void handle_mic_failureevent(wlan_private * priv, u32 event)
++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 ");
+@@ -112,42 +99,42 @@ static void handle_mic_failureevent(wlan
+ strcat(buf, "multicast ");
+ }
+
+- libertas_send_iwevcustom_event(priv, buf);
++ lbs_send_iwevcustom_event(priv, buf);
++ lbs_deb_leave(LBS_DEB_CMD);
+ }
+
+-static int wlan_ret_reg_access(wlan_private * priv,
++static int lbs_ret_reg_access(struct lbs_private *priv,
+ u16 type, struct cmd_ds_command *resp)
+ {
+ int ret = 0;
+- wlan_adapter *adapter = priv->adapter;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ switch (type) {
+- case cmd_ret_mac_reg_access:
++ case CMD_RET(CMD_MAC_REG_ACCESS):
+ {
+ struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
+
+- adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
+- adapter->offsetvalue.value = le32_to_cpu(reg->value);
++ priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
++ priv->offsetvalue.value = le32_to_cpu(reg->value);
+ break;
+ }
+
+- case cmd_ret_bbp_reg_access:
++ case CMD_RET(CMD_BBP_REG_ACCESS):
+ {
+ struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
+
+- adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
+- adapter->offsetvalue.value = reg->value;
++ priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
++ priv->offsetvalue.value = reg->value;
+ break;
+ }
+
+- case cmd_ret_rf_reg_access:
++ case CMD_RET(CMD_RF_REG_ACCESS):
+ {
+ struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
+
+- adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
+- adapter->offsetvalue.value = reg->value;
++ priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
++ priv->offsetvalue.value = reg->value;
+ break;
+ }
+
+@@ -155,113 +142,50 @@ static int wlan_ret_reg_access(wlan_priv
+ ret = -1;
+ }
+
+- lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
+- return ret;
+-}
+-
+-static int wlan_ret_get_hw_spec(wlan_private * priv,
+- struct cmd_ds_command *resp)
+-{
+- u32 i;
+- struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
+- wlan_adapter *adapter = priv->adapter;
+- int ret = 0;
+-
+- lbs_deb_enter(LBS_DEB_CMD);
+-
+- adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo);
+-
+- memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4);
+-
+- lbs_deb_cmd("GET_HW_SPEC: FWReleaseVersion- %u.%u.%u.p%u\n",
+- adapter->fwreleasenumber[2], adapter->fwreleasenumber[1],
+- adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]);
+- lbs_deb_cmd("GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
+- hwspec->permanentaddr[0], hwspec->permanentaddr[1],
+- hwspec->permanentaddr[2], hwspec->permanentaddr[3],
+- hwspec->permanentaddr[4], hwspec->permanentaddr[5]);
+- lbs_deb_cmd("GET_HW_SPEC: hwifversion=0x%X version=0x%X\n",
+- hwspec->hwifversion, hwspec->version);
+-
+- adapter->regioncode = le16_to_cpu(hwspec->regioncode);
+-
+- for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+- /* use the region code to search for the index */
+- if (adapter->regioncode == libertas_region_code_to_index[i]) {
+- adapter->regiontableindex = (u16) i;
+- break;
+- }
+- }
+-
+- /* if it's unidentified region code, use the default (USA) */
+- if (i >= MRVDRV_MAX_REGION_CODE) {
+- adapter->regioncode = 0x10;
+- adapter->regiontableindex = 0;
+- lbs_pr_info("unidentified region code; using the default (USA)\n");
+- }
+-
+- if (adapter->current_addr[0] == 0xff)
+- memmove(adapter->current_addr, hwspec->permanentaddr, ETH_ALEN);
+-
+- memcpy(priv->dev->dev_addr, adapter->current_addr, ETH_ALEN);
+- if (priv->mesh_dev)
+- memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
+-
+- if (libertas_set_regiontable(priv, adapter->regioncode, 0)) {
+- ret = -1;
+- goto done;
+- }
+-
+- if (libertas_set_universaltable(priv, 0)) {
+- ret = -1;
+- goto done;
+- }
+-
+-done:
+- lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
++ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+ }
+
+-static int wlan_ret_802_11_sleep_params(wlan_private * priv,
++static int lbs_ret_802_11_sleep_params(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+ struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
+- wlan_adapter *adapter = priv->adapter;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- lbs_deb_cmd("error=%x offset=%x stabletime=%x calcontrol=%x\n"
+- " extsleepclk=%x\n", le16_to_cpu(sp->error),
++ lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x "
++ "extsleepclk 0x%x\n", le16_to_cpu(sp->error),
+ le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime),
+ sp->calcontrol, sp->externalsleepclk);
+
+- adapter->sp.sp_error = le16_to_cpu(sp->error);
+- adapter->sp.sp_offset = le16_to_cpu(sp->offset);
+- adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
+- adapter->sp.sp_calcontrol = sp->calcontrol;
+- adapter->sp.sp_extsleepclk = sp->externalsleepclk;
+- adapter->sp.sp_reserved = le16_to_cpu(sp->reserved);
++ priv->sp.sp_error = le16_to_cpu(sp->error);
++ priv->sp.sp_offset = le16_to_cpu(sp->offset);
++ priv->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
++ priv->sp.sp_calcontrol = sp->calcontrol;
++ priv->sp.sp_extsleepclk = sp->externalsleepclk;
++ priv->sp.sp_reserved = le16_to_cpu(sp->reserved);
+
+ lbs_deb_enter(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_ret_802_11_stat(wlan_private * priv,
++static int lbs_ret_802_11_stat(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+-/* currently adapter->wlan802_11Stat is unused
++ lbs_deb_enter(LBS_DEB_CMD);
++/* currently priv->wlan802_11Stat is unused
+
+ struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
+- wlan_adapter *adapter = priv->adapter;
+
+ // TODO Convert it to Big endian befor copy
+- memcpy(&adapter->wlan802_11Stat,
++ memcpy(&priv->wlan802_11Stat,
+ p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
+ */
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
++static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+ struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
+@@ -270,29 +194,29 @@ static int wlan_ret_802_11_snmp_mib(wlan
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- lbs_deb_cmd("SNMP_RESP: value of the oid = %x, querytype=%x\n", oid,
++ lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
+ querytype);
+- lbs_deb_cmd("SNMP_RESP: Buf size = %x\n", le16_to_cpu(smib->bufsize));
++ lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
+
+- if (querytype == cmd_act_get) {
++ if (querytype == CMD_ACT_GET) {
+ switch (oid) {
+- case fragthresh_i:
+- priv->adapter->fragthsd =
++ case FRAGTHRESH_I:
++ priv->fragthsd =
+ le16_to_cpu(*((__le16 *)(smib->value)));
+- lbs_deb_cmd("SNMP_RESP: fragthsd =%u\n",
+- priv->adapter->fragthsd);
++ lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
++ priv->fragthsd);
+ break;
+- case rtsthresh_i:
+- priv->adapter->rtsthsd =
++ case RTSTHRESH_I:
++ priv->rtsthsd =
+ le16_to_cpu(*((__le16 *)(smib->value)));
+- lbs_deb_cmd("SNMP_RESP: rtsthsd =%u\n",
+- priv->adapter->rtsthsd);
++ lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
++ priv->rtsthsd);
+ break;
+- case short_retrylim_i:
+- priv->adapter->txretrycount =
++ case SHORT_RETRYLIM_I:
++ priv->txretrycount =
+ le16_to_cpu(*((__le16 *)(smib->value)));
+- lbs_deb_cmd("SNMP_RESP: txretrycount =%u\n",
+- priv->adapter->rtsthsd);
++ lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
++ priv->rtsthsd);
+ break;
+ default:
+ break;
+@@ -303,29 +227,29 @@ static int wlan_ret_802_11_snmp_mib(wlan
+ return 0;
+ }
+
+-static int wlan_ret_802_11_key_material(wlan_private * priv,
++static int lbs_ret_802_11_key_material(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+ struct cmd_ds_802_11_key_material *pkeymaterial =
+ &resp->params.keymaterial;
+- wlan_adapter *adapter = priv->adapter;
+ u16 action = le16_to_cpu(pkeymaterial->action);
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ /* Copy the returned key to driver private data */
+- if (action == cmd_act_get) {
++ if (action == CMD_ACT_GET) {
+ u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
+ u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
+
+ while (buf_ptr < resp_end) {
+ struct MrvlIEtype_keyParamSet * pkeyparamset =
+ (struct MrvlIEtype_keyParamSet *) buf_ptr;
+- struct WLAN_802_11_KEY * pkey;
+- u16 key_info = le16_to_cpu(pkeyparamset->keyinfo);
++ struct enc_key * pkey;
+ u16 param_set_len = le16_to_cpu(pkeyparamset->length);
+- u8 * end;
+ u16 key_len = le16_to_cpu(pkeyparamset->keylen);
++ u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo);
++ u16 key_type = le16_to_cpu(pkeyparamset->keytypeid);
++ u8 * end;
+
+ end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
+ + sizeof (pkeyparamset->length)
+@@ -334,20 +258,20 @@ static int wlan_ret_802_11_key_material(
+ if (end > resp_end)
+ break;
+
+- if (key_info & KEY_INFO_WPA_UNICAST)
+- pkey = &adapter->wpa_unicast_key;
+- else if (key_info & KEY_INFO_WPA_MCAST)
+- pkey = &adapter->wpa_mcast_key;
++ if (key_flags & KEY_INFO_WPA_UNICAST)
++ pkey = &priv->wpa_unicast_key;
++ else if (key_flags & KEY_INFO_WPA_MCAST)
++ pkey = &priv->wpa_mcast_key;
+ else
+ break;
+
+ /* Copy returned key into driver */
+- memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
++ memset(pkey, 0, sizeof(struct enc_key));
+ if (key_len > sizeof(pkey->key))
+ break;
+- pkey->type = le16_to_cpu(pkeyparamset->keytypeid);
+- pkey->flags = le16_to_cpu(pkeyparamset->keyinfo);
+- pkey->len = le16_to_cpu(pkeyparamset->keylen);
++ pkey->type = key_type;
++ pkey->flags = key_flags;
++ pkey->len = key_len;
+ memcpy(pkey->key, pkeyparamset->key, pkey->len);
+
+ buf_ptr = end + 1;
+@@ -358,157 +282,91 @@ static int wlan_ret_802_11_key_material(
+ return 0;
+ }
+
+-static int wlan_ret_802_11_mac_address(wlan_private * priv,
++static int lbs_ret_802_11_mac_address(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+ struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
+- wlan_adapter *adapter = priv->adapter;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN);
++ memcpy(priv->current_addr, macadd->macadd, ETH_ALEN);
+
+ lbs_deb_enter(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_ret_802_11_rf_tx_power(wlan_private * priv,
++static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+ struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
+- wlan_adapter *adapter = priv->adapter;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);
+-
+- lbs_deb_cmd("Current TxPower Level = %d\n", adapter->txpowerlevel);
+-
+- lbs_deb_enter(LBS_DEB_CMD);
+- return 0;
+-}
+-
+-static int wlan_ret_802_11_rf_antenna(wlan_private * priv,
+- struct cmd_ds_command *resp)
+-{
+- struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant;
+- wlan_adapter *adapter = priv->adapter;
+- u16 action = le16_to_cpu(pAntenna->action);
+-
+- if (action == cmd_act_get_rx)
+- adapter->rxantennamode = le16_to_cpu(pAntenna->antennamode);
+-
+- if (action == cmd_act_get_tx)
+- adapter->txantennamode = le16_to_cpu(pAntenna->antennamode);
++ priv->txpowerlevel = le16_to_cpu(rtp->currentlevel);
+
+- lbs_deb_cmd("RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n",
+- action, le16_to_cpu(pAntenna->antennamode));
++ lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel);
+
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
++static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+ struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset;
+- wlan_adapter *adapter = priv->adapter;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- if (rates->action == cmd_act_get) {
+- adapter->enablehwauto = le16_to_cpu(rates->enablehwauto);
+- adapter->ratebitmap = le16_to_cpu(rates->bitmap);
++ if (rates->action == CMD_ACT_GET) {
++ priv->enablehwauto = le16_to_cpu(rates->enablehwauto);
++ priv->ratebitmap = le16_to_cpu(rates->bitmap);
+ }
+
+- lbs_deb_enter(LBS_DEB_CMD);
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_ret_802_11_data_rate(wlan_private * priv,
+- struct cmd_ds_command *resp)
+-{
+- struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
+- wlan_adapter *adapter = priv->adapter;
+- u8 dot11datarate;
+-
+- lbs_deb_enter(LBS_DEB_CMD);
+-
+- lbs_dbg_hex("DATA_RATE_RESP: data_rate- ",
+- (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate));
+-
+- dot11datarate = pdatarate->datarate[0];
+- if (pdatarate->action == cpu_to_le16(cmd_act_get_tx_rate)) {
+- memcpy(adapter->libertas_supported_rates, pdatarate->datarate,
+- sizeof(adapter->libertas_supported_rates));
+- }
+- adapter->datarate = libertas_index_to_data_rate(dot11datarate);
+-
+- lbs_deb_enter(LBS_DEB_CMD);
+- return 0;
+-}
+-
+-static int wlan_ret_802_11_rf_channel(wlan_private * priv,
+- struct cmd_ds_command *resp)
+-{
+- struct cmd_ds_802_11_rf_channel *rfchannel = &resp->params.rfchannel;
+- wlan_adapter *adapter = priv->adapter;
+- u16 action = le16_to_cpu(rfchannel->action);
+- u16 newchannel = le16_to_cpu(rfchannel->currentchannel);
+-
+- lbs_deb_enter(LBS_DEB_CMD);
+-
+- if (action == cmd_opt_802_11_rf_channel_get
+- && adapter->curbssparams.channel != newchannel) {
+- lbs_deb_cmd("channel Switch: %d to %d\n",
+- adapter->curbssparams.channel, newchannel);
+-
+- /* Update the channel again */
+- adapter->curbssparams.channel = newchannel;
+- }
+-
+- lbs_deb_enter(LBS_DEB_CMD);
+- return 0;
+-}
+-
+-static int wlan_ret_802_11_rssi(wlan_private * priv,
++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;
+- wlan_adapter *adapter = priv->adapter;
++
++ lbs_deb_enter(LBS_DEB_CMD);
+
+ /* store the non average value */
+- adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
+- adapter->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
++ priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
++ priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
+
+- adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
+- adapter->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
++ priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
++ priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
+
+- adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] =
+- CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+- adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
++ priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
++ CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
++ priv->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+- adapter->RSSI[TYPE_BEACON][TYPE_AVG] =
+- CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
+- adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
++ 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("Beacon RSSI value = 0x%x\n",
+- adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
++ 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 wlan_ret_802_11_eeprom_access(wlan_private * priv,
++static int lbs_ret_802_11_eeprom_access(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+- wlan_adapter *adapter = priv->adapter;
+- struct wlan_ioctl_regrdwr *pbuf;
+- pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;
++ struct lbs_ioctl_regrdwr *pbuf;
++ pbuf = (struct lbs_ioctl_regrdwr *) priv->prdeeprom;
+
+- lbs_deb_cmd("eeprom read len=%x\n",
++ lbs_deb_enter_args(LBS_DEB_CMD, "len %d",
+ le16_to_cpu(resp->params.rdeeprom.bytecount));
+ if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
+ pbuf->NOB = 0;
+- lbs_deb_cmd("eeprom read return length is too big\n");
++ lbs_deb_cmd("EEPROM read length too big\n");
+ return -1;
+ }
+ pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
+@@ -516,454 +374,510 @@ static int wlan_ret_802_11_eeprom_access
+
+ memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
+ le16_to_cpu(resp->params.rdeeprom.bytecount));
+- lbs_dbg_hex("adapter", (char *)&pbuf->value,
++ lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value,
+ le16_to_cpu(resp->params.rdeeprom.bytecount));
+ }
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int wlan_ret_get_log(wlan_private * priv,
++static int lbs_ret_get_log(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+ struct cmd_ds_802_11_get_log *logmessage = &resp->params.glog;
+- wlan_adapter *adapter = priv->adapter;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ /* Stored little-endian */
+- memcpy(&adapter->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
++ memcpy(&priv->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
+
+- lbs_deb_enter(LBS_DEB_CMD);
++ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+ }
+
+-static int libertas_ret_802_11_enable_rsn(wlan_private * priv,
++static int lbs_ret_802_11_enable_rsn(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+ struct cmd_ds_802_11_enable_rsn *enable_rsn = &resp->params.enbrsn;
+- wlan_adapter *adapter = priv->adapter;
+- u32 * pdata_buf = adapter->cur_cmd->pdata_buf;
++ uint32_t * pdata_buf = (uint32_t *)priv->cur_cmd->callback_arg;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- if (enable_rsn->action == cpu_to_le16(cmd_act_get)) {
++ if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) {
+ if (pdata_buf)
+- *pdata_buf = (u32) le16_to_cpu(enable_rsn->enable);
++ *pdata_buf = (uint32_t) le16_to_cpu(enable_rsn->enable);
++ }
++
++ lbs_deb_leave(LBS_DEB_CMD);
++ return 0;
++}
++
++static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
++ struct cmd_ds_command *resp)
++{
++ 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(u16 respcmd,
+- struct cmd_ds_command *resp,
+- wlan_private *priv)
++static int lbs_ret_802_11_subscribe_event(struct lbs_private *priv,
++ struct cmd_ds_command *resp)
+ {
++ struct cmd_ds_802_11_subscribe_event *cmd_event =
++ &resp->params.subscribe_event;
++ struct cmd_ds_802_11_subscribe_event *dst_event =
++ (void *)priv->cur_cmd->callback_arg;
++
++ lbs_deb_enter(LBS_DEB_CMD);
++
++ if (dst_event->action == cpu_to_le16(CMD_ACT_GET)) {
++ dst_event->events = cmd_event->events;
++ memcpy(dst_event->tlv, cmd_event->tlv, sizeof(dst_event->tlv));
++ }
++
++ lbs_deb_leave(LBS_DEB_CMD);
++ return 0;
++}
++
++static inline int handle_cmd_response(struct lbs_private *priv,
++ unsigned long dummy,
++ struct cmd_header *cmd_response)
++{
++ struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
+ int ret = 0;
+ unsigned long flags;
+- wlan_adapter *adapter = priv->adapter;
++ uint16_t respcmd = le16_to_cpu(resp->command);
+
+- switch (respcmd) {
+- case cmd_ret_mac_reg_access:
+- case cmd_ret_bbp_reg_access:
+- case cmd_ret_rf_reg_access:
+- ret = wlan_ret_reg_access(priv, respcmd, resp);
+- break;
++ lbs_deb_enter(LBS_DEB_HOST);
+
+- case cmd_ret_hw_spec_info:
+- ret = wlan_ret_get_hw_spec(priv, resp);
++ switch (respcmd) {
++ case CMD_RET(CMD_MAC_REG_ACCESS):
++ case CMD_RET(CMD_BBP_REG_ACCESS):
++ case CMD_RET(CMD_RF_REG_ACCESS):
++ ret = lbs_ret_reg_access(priv, respcmd, resp);
+ break;
+
+- case cmd_ret_802_11_scan:
+- ret = libertas_ret_80211_scan(priv, resp);
++ case CMD_RET(CMD_802_11_SCAN):
++ ret = lbs_ret_80211_scan(priv, resp);
+ break;
+
+- case cmd_ret_802_11_get_log:
+- ret = wlan_ret_get_log(priv, resp);
++ case CMD_RET(CMD_802_11_GET_LOG):
++ ret = lbs_ret_get_log(priv, resp);
+ break;
+
+- case cmd_ret_802_11_associate:
+- case cmd_ret_802_11_reassociate:
+- ret = libertas_ret_80211_associate(priv, resp);
++ case CMD_RET_802_11_ASSOCIATE:
++ case CMD_RET(CMD_802_11_ASSOCIATE):
++ case CMD_RET(CMD_802_11_REASSOCIATE):
++ ret = lbs_ret_80211_associate(priv, resp);
+ break;
+
+- case cmd_ret_802_11_disassociate:
+- case cmd_ret_802_11_deauthenticate:
+- ret = libertas_ret_80211_disassociate(priv, resp);
++ case CMD_RET(CMD_802_11_DISASSOCIATE):
++ case CMD_RET(CMD_802_11_DEAUTHENTICATE):
++ ret = lbs_ret_80211_disassociate(priv, resp);
+ break;
+
+- case cmd_ret_802_11_ad_hoc_start:
+- case cmd_ret_802_11_ad_hoc_join:
+- ret = libertas_ret_80211_ad_hoc_start(priv, resp);
++ case CMD_RET(CMD_802_11_AD_HOC_START):
++ case CMD_RET(CMD_802_11_AD_HOC_JOIN):
++ ret = lbs_ret_80211_ad_hoc_start(priv, resp);
+ break;
+
+- case cmd_ret_802_11_stat:
+- ret = wlan_ret_802_11_stat(priv, resp);
++ case CMD_RET(CMD_802_11_GET_STAT):
++ ret = lbs_ret_802_11_stat(priv, resp);
+ break;
+
+- case cmd_ret_802_11_snmp_mib:
+- ret = wlan_ret_802_11_snmp_mib(priv, resp);
++ case CMD_RET(CMD_802_11_SNMP_MIB):
++ ret = lbs_ret_802_11_snmp_mib(priv, resp);
+ break;
+
+- case cmd_ret_802_11_rf_tx_power:
+- ret = wlan_ret_802_11_rf_tx_power(priv, resp);
++ case CMD_RET(CMD_802_11_RF_TX_POWER):
++ ret = lbs_ret_802_11_rf_tx_power(priv, resp);
+ break;
+
+- case cmd_ret_802_11_set_afc:
+- case cmd_ret_802_11_get_afc:
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- memmove(adapter->cur_cmd->pdata_buf, &resp->params.afc,
++ case CMD_RET(CMD_802_11_SET_AFC):
++ case CMD_RET(CMD_802_11_GET_AFC):
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
+ sizeof(struct cmd_ds_802_11_afc));
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ break;
+- case cmd_ret_802_11_rf_antenna:
+- ret = wlan_ret_802_11_rf_antenna(priv, resp);
+- break;
+
+- case cmd_ret_mac_multicast_adr:
+- case cmd_ret_mac_control:
+- case cmd_ret_802_11_set_wep:
+- case cmd_ret_802_11_reset:
+- case cmd_ret_802_11_authenticate:
+- case cmd_ret_802_11_radio_control:
+- case cmd_ret_802_11_beacon_stop:
++ case CMD_RET(CMD_802_11_SET_WEP):
++ case CMD_RET(CMD_802_11_RESET):
++ case CMD_RET(CMD_802_11_AUTHENTICATE):
++ case CMD_RET(CMD_802_11_RADIO_CONTROL):
++ case CMD_RET(CMD_802_11_BEACON_STOP):
+ break;
+
+- case cmd_ret_802_11_enable_rsn:
+- ret = libertas_ret_802_11_enable_rsn(priv, resp);
++ case CMD_RET(CMD_802_11_ENABLE_RSN):
++ ret = lbs_ret_802_11_enable_rsn(priv, resp);
+ break;
+
+- case cmd_ret_802_11_data_rate:
+- ret = wlan_ret_802_11_data_rate(priv, resp);
+- break;
+- case cmd_ret_802_11_rate_adapt_rateset:
+- ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
+- break;
+- case cmd_ret_802_11_rf_channel:
+- ret = wlan_ret_802_11_rf_channel(priv, resp);
++ case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
++ ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
+ break;
+
+- case cmd_ret_802_11_rssi:
+- ret = wlan_ret_802_11_rssi(priv, resp);
++ case CMD_RET(CMD_802_11_RSSI):
++ ret = lbs_ret_802_11_rssi(priv, resp);
+ break;
+
+- case cmd_ret_802_11_mac_address:
+- ret = wlan_ret_802_11_mac_address(priv, resp);
++ case CMD_RET(CMD_802_11_MAC_ADDRESS):
++ ret = lbs_ret_802_11_mac_address(priv, resp);
+ break;
+
+- case cmd_ret_802_11_ad_hoc_stop:
+- ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
++ case CMD_RET(CMD_802_11_AD_HOC_STOP):
++ ret = lbs_ret_80211_ad_hoc_stop(priv, resp);
+ break;
+
+- case cmd_ret_802_11_key_material:
+- lbs_deb_cmd("CMD_RESP: KEY_MATERIAL command response\n");
+- ret = wlan_ret_802_11_key_material(priv, resp);
++ case CMD_RET(CMD_802_11_KEY_MATERIAL):
++ ret = lbs_ret_802_11_key_material(priv, resp);
+ break;
+
+- case cmd_ret_802_11_eeprom_access:
+- ret = wlan_ret_802_11_eeprom_access(priv, resp);
++ case CMD_RET(CMD_802_11_EEPROM_ACCESS):
++ ret = lbs_ret_802_11_eeprom_access(priv, resp);
+ break;
+
+- case cmd_ret_802_11d_domain_info:
+- ret = libertas_ret_802_11d_domain_info(priv, resp);
++ case CMD_RET(CMD_802_11D_DOMAIN_INFO):
++ ret = lbs_ret_802_11d_domain_info(priv, resp);
+ break;
+
+- case cmd_ret_802_11_sleep_params:
+- ret = wlan_ret_802_11_sleep_params(priv, resp);
++ case CMD_RET(CMD_802_11_SLEEP_PARAMS):
++ ret = lbs_ret_802_11_sleep_params(priv, resp);
+ break;
+- case cmd_ret_802_11_inactivity_timeout:
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- *((u16 *) adapter->cur_cmd->pdata_buf) =
++ case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT):
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ *((uint16_t *) priv->cur_cmd->callback_arg) =
+ le16_to_cpu(resp->params.inactivity_timeout.timeout);
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ break;
+
+- case cmd_ret_802_11_tpc_cfg:
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- memmove(adapter->cur_cmd->pdata_buf, &resp->params.tpccfg,
++ 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(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ break;
+- case cmd_ret_802_11_led_gpio_ctrl:
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- memmove(adapter->cur_cmd->pdata_buf, &resp->params.ledgpio,
++ 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(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ break;
+- case cmd_ret_802_11_pwr_cfg:
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg,
++ case CMD_RET(CMD_802_11_SUBSCRIBE_EVENT):
++ ret = lbs_ret_802_11_subscribe_event(priv, resp);
++ break;
++
++ case CMD_RET(CMD_802_11_PWR_CFG):
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ memmove((void *)priv->cur_cmd->callback_arg, &resp->params.pwrcfg,
+ sizeof(struct cmd_ds_802_11_pwr_cfg));
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ break;
+
+- case cmd_ret_get_tsf:
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- memcpy(priv->adapter->cur_cmd->pdata_buf,
++ 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(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ break;
+- case cmd_ret_bt_access:
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- if (adapter->cur_cmd->pdata_buf)
+- memcpy(adapter->cur_cmd->pdata_buf,
++ case CMD_RET(CMD_BT_ACCESS):
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ if (priv->cur_cmd->callback_arg)
++ memcpy((void *)priv->cur_cmd->callback_arg,
+ &resp->params.bt.addr1, 2 * ETH_ALEN);
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ break;
+- case cmd_ret_fwt_access:
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- if (adapter->cur_cmd->pdata_buf)
+- memcpy(adapter->cur_cmd->pdata_buf, &resp->params.fwt,
++ case CMD_RET(CMD_FWT_ACCESS):
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ if (priv->cur_cmd->callback_arg)
++ memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
+ sizeof(resp->params.fwt));
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ break;
+- case cmd_ret_mesh_access:
+- if (adapter->cur_cmd->pdata_buf)
+- memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh,
+- sizeof(resp->params.mesh));
+- break;
+- case cmd_rte_802_11_tx_rate_query:
+- priv->adapter->txrate = resp->params.txrate.txrate;
++ case CMD_RET(CMD_802_11_BEACON_CTRL):
++ ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
+ break;
++
+ default:
+- lbs_deb_cmd("CMD_RESP: Unknown command response %#x\n",
+- resp->command);
++ lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
++ le16_to_cpu(resp->command));
+ break;
+ }
++ lbs_deb_leave(LBS_DEB_HOST);
+ return ret;
+ }
+
+-int libertas_process_rx_command(wlan_private * priv)
++int lbs_process_rx_command(struct lbs_private *priv)
+ {
+- u16 respcmd;
+- struct cmd_ds_command *resp;
+- wlan_adapter *adapter = priv->adapter;
++ uint16_t respcmd, curcmd;
++ struct cmd_header *resp;
+ int ret = 0;
+- ulong flags;
+- u16 result;
+-
+- lbs_deb_enter(LBS_DEB_CMD);
+-
+- lbs_deb_cmd("CMD_RESP: @ %lu\n", jiffies);
++ unsigned long flags;
++ uint16_t result;
+
+- /* Now we got response from FW, cancel the command timer */
+- del_timer(&adapter->command_timer);
++ lbs_deb_enter(LBS_DEB_HOST);
+
+- mutex_lock(&adapter->lock);
+- spin_lock_irqsave(&adapter->driver_lock, flags);
++ mutex_lock(&priv->lock);
++ spin_lock_irqsave(&priv->driver_lock, flags);
+
+- if (!adapter->cur_cmd) {
+- lbs_deb_cmd("CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd);
++ if (!priv->cur_cmd) {
++ lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
+ ret = -1;
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ goto done;
+ }
+- resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);
+
+- lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr,
+- priv->upld_len);
++ resp = (void *)priv->upld_buf;
+
+- respcmd = le16_to_cpu(resp->command);
++ curcmd = le16_to_cpu(resp->command);
+
++ respcmd = le16_to_cpu(resp->command);
+ result = le16_to_cpu(resp->result);
+
+- lbs_deb_cmd("CMD_RESP: %x result: %d length: %d\n", respcmd,
+- result, priv->upld_len);
++ lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n",
++ respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies);
++ lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, priv->upld_len);
++
++ if (resp->seqnum != resp->seqnum) {
++ lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
++ le16_to_cpu(resp->seqnum), le16_to_cpu(resp->seqnum));
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++ ret = -1;
++ goto done;
++ }
++ if (respcmd != CMD_RET(curcmd) &&
++ respcmd != CMD_802_11_ASSOCIATE && curcmd != CMD_RET_802_11_ASSOCIATE) {
++ lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++ ret = -1;
++ goto done;
++ }
+
+- if (!(respcmd & 0x8000)) {
+- lbs_deb_cmd("Invalid response to command!");
+- adapter->cur_cmd_retcode = -1;
+- __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+- adapter->nr_cmd_pending--;
+- adapter->cur_cmd = NULL;
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ if (resp->result == cpu_to_le16(0x0004)) {
++ /* 0x0004 means -EAGAIN. Drop the response, let it time out
++ and be resubmitted */
++ lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
++ le16_to_cpu(resp->command));
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ ret = -1;
+ goto done;
+ }
+
++ /* Now we got response from FW, cancel the command timer */
++ del_timer(&priv->command_timer);
++ priv->cmd_timed_out = 0;
++ if (priv->nr_retries) {
++ lbs_pr_info("Received result %x to command %x after %d retries\n",
++ result, curcmd, priv->nr_retries);
++ priv->nr_retries = 0;
++ }
++
+ /* Store the response code to cur_cmd_retcode. */
+- adapter->cur_cmd_retcode = result;;
++ priv->cur_cmd_retcode = result;
+
+- if (respcmd == cmd_ret_802_11_ps_mode) {
+- struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode;
++ if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
++ struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
+ u16 action = le16_to_cpu(psmode->action);
+
+- lbs_deb_cmd(
+- "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
++ lbs_deb_host(
++ "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
+ result, action);
+
+ if (result) {
+- lbs_deb_cmd("CMD_RESP: PS command failed- %#x \n",
++ lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
+ result);
+ /*
+ * We should not re-try enter-ps command in
+ * ad-hoc mode. It takes place in
+- * libertas_execute_next_command().
++ * lbs_execute_next_command().
+ */
+- if (adapter->mode == IW_MODE_ADHOC &&
+- action == cmd_subcmd_enter_ps)
+- adapter->psmode = wlan802_11powermodecam;
+- } else if (action == cmd_subcmd_enter_ps) {
+- adapter->needtowakeup = 0;
+- adapter->psstate = PS_STATE_AWAKE;
++ if (priv->mode == IW_MODE_ADHOC &&
++ action == CMD_SUBCMD_ENTER_PS)
++ priv->psmode = LBS802_11POWERMODECAM;
++ } else if (action == CMD_SUBCMD_ENTER_PS) {
++ priv->needtowakeup = 0;
++ priv->psstate = PS_STATE_AWAKE;
+
+- lbs_deb_cmd("CMD_RESP: Enter_PS command response\n");
+- if (adapter->connect_status != libertas_connected) {
++ lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
++ if (priv->connect_status != LBS_CONNECTED) {
+ /*
+ * When Deauth Event received before Enter_PS command
+ * response, We need to wake up the firmware.
+ */
+- lbs_deb_cmd(
+- "Disconnected, Going to invoke libertas_ps_wakeup\n");
++ lbs_deb_host(
++ "disconnected, invoking lbs_ps_wakeup\n");
+
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
+- mutex_unlock(&adapter->lock);
+- libertas_ps_wakeup(priv, 0);
+- mutex_lock(&adapter->lock);
+- spin_lock_irqsave(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++ mutex_unlock(&priv->lock);
++ lbs_ps_wakeup(priv, 0);
++ mutex_lock(&priv->lock);
++ spin_lock_irqsave(&priv->driver_lock, flags);
+ }
+- } else if (action == cmd_subcmd_exit_ps) {
+- adapter->needtowakeup = 0;
+- adapter->psstate = PS_STATE_FULL_POWER;
+- lbs_deb_cmd("CMD_RESP: Exit_PS command response\n");
++ } else if (action == CMD_SUBCMD_EXIT_PS) {
++ priv->needtowakeup = 0;
++ priv->psstate = PS_STATE_FULL_POWER;
++ lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
+ } else {
+- lbs_deb_cmd("CMD_RESP: PS- action=0x%X\n", action);
++ lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
+ }
+
+- __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+- adapter->nr_cmd_pending--;
+- adapter->cur_cmd = NULL;
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ lbs_complete_command(priv, priv->cur_cmd, result);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ ret = 0;
+ goto done;
+ }
+
+- if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
+- /* Copy the response back to response buffer */
+- memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size);
+-
+- adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
+- }
+-
+ /* If the command is not successful, cleanup and return failure */
+ if ((result != 0 || !(respcmd & 0x8000))) {
+- lbs_deb_cmd("CMD_RESP: command reply %#x result=%#x\n",
+- respcmd, result);
++ lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
++ result, respcmd);
+ /*
+ * Handling errors here
+ */
+ switch (respcmd) {
+- case cmd_ret_hw_spec_info:
+- case cmd_ret_802_11_reset:
+- lbs_deb_cmd("CMD_RESP: Reset command failed\n");
++ case CMD_RET(CMD_GET_HW_SPEC):
++ case CMD_RET(CMD_802_11_RESET):
++ lbs_deb_host("CMD_RESP: reset failed\n");
+ break;
+
+ }
+-
+- __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+- adapter->nr_cmd_pending--;
+- adapter->cur_cmd = NULL;
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ lbs_complete_command(priv, priv->cur_cmd, result);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ ret = -1;
+ goto done;
+ }
+
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+- ret = handle_cmd_response(respcmd, resp, priv);
++ if (priv->cur_cmd && priv->cur_cmd->callback) {
++ ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
++ resp);
++ } else
++ ret = handle_cmd_response(priv, 0, resp);
+
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- if (adapter->cur_cmd) {
++ spin_lock_irqsave(&priv->driver_lock, flags);
++
++ if (priv->cur_cmd) {
+ /* Clean up and Put current command back to cmdfreeq */
+- __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+- adapter->nr_cmd_pending--;
+- WARN_ON(adapter->nr_cmd_pending > 128);
+- adapter->cur_cmd = NULL;
++ lbs_complete_command(priv, priv->cur_cmd, result);
+ }
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ done:
+- mutex_unlock(&adapter->lock);
+- lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
++ mutex_unlock(&priv->lock);
++ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
+ return ret;
+ }
+
+-int libertas_process_event(wlan_private * priv)
++static int lbs_send_confirmwake(struct lbs_private *priv)
+ {
++ struct cmd_header *cmd = &priv->lbs_ps_confirm_wake;
+ int ret = 0;
+- wlan_adapter *adapter = priv->adapter;
+- u32 eventcause;
+
+- spin_lock_irq(&adapter->driver_lock);
+- eventcause = adapter->eventcause;
+- spin_unlock_irq(&adapter->driver_lock);
++ lbs_deb_enter(LBS_DEB_HOST);
++
++ cmd->command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM);
++ cmd->size = cpu_to_le16(sizeof(*cmd));
++ cmd->seqnum = cpu_to_le16(++priv->seqnum);
++ cmd->result = 0;
++
++ lbs_deb_host("SEND_WAKEC_CMD: before download\n");
++
++ lbs_deb_hex(LBS_DEB_HOST, "wake confirm command", (void *)cmd, sizeof(*cmd));
++
++ ret = priv->hw_host_to_card(priv, MVMS_CMD, (void *)cmd, sizeof(*cmd));
++ if (ret)
++ lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n");
++
++ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
++ return ret;
++}
++
++int lbs_process_event(struct lbs_private *priv)
++{
++ int ret = 0;
++ u32 eventcause;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+- lbs_deb_cmd("EVENT Cause %x\n", eventcause);
++ spin_lock_irq(&priv->driver_lock);
++ eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT;
++ spin_unlock_irq(&priv->driver_lock);
+
+- switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
++ lbs_deb_cmd("event cause %d\n", eventcause);
++
++ switch (eventcause) {
+ case MACREG_INT_CODE_LINK_SENSED:
+ lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n");
+ break;
+
+ case MACREG_INT_CODE_DEAUTHENTICATED:
+- lbs_deb_cmd("EVENT: Deauthenticated\n");
+- libertas_mac_event_disconnected(priv);
++ lbs_deb_cmd("EVENT: deauthenticated\n");
++ lbs_mac_event_disconnected(priv);
+ break;
+
+ case MACREG_INT_CODE_DISASSOCIATED:
+- lbs_deb_cmd("EVENT: Disassociated\n");
+- libertas_mac_event_disconnected(priv);
++ lbs_deb_cmd("EVENT: disassociated\n");
++ lbs_mac_event_disconnected(priv);
+ break;
+
+- case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
+- lbs_deb_cmd("EVENT: Link lost\n");
+- libertas_mac_event_disconnected(priv);
++ case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
++ lbs_deb_cmd("EVENT: link lost\n");
++ lbs_mac_event_disconnected(priv);
+ break;
+
+ case MACREG_INT_CODE_PS_SLEEP:
+- lbs_deb_cmd("EVENT: SLEEP\n");
+- lbs_deb_cmd("_");
++ lbs_deb_cmd("EVENT: sleep\n");
+
+ /* handle unexpected PS SLEEP event */
+- if (adapter->psstate == PS_STATE_FULL_POWER) {
++ if (priv->psstate == PS_STATE_FULL_POWER) {
+ lbs_deb_cmd(
+- "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
++ "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
+ break;
+ }
+- adapter->psstate = PS_STATE_PRE_SLEEP;
++ priv->psstate = PS_STATE_PRE_SLEEP;
+
+- libertas_ps_confirm_sleep(priv, (u16) adapter->psmode);
++ lbs_ps_confirm_sleep(priv, (u16) priv->psmode);
+
+ break;
+
+- case MACREG_INT_CODE_PS_AWAKE:
+- lbs_deb_cmd("EVENT: AWAKE \n");
+- lbs_deb_cmd("|");
++ case MACREG_INT_CODE_HOST_AWAKE:
++ lbs_deb_cmd("EVENT: HOST_AWAKE\n");
++ lbs_send_confirmwake(priv);
++ break;
+
++ case MACREG_INT_CODE_PS_AWAKE:
++ lbs_deb_cmd("EVENT: awake\n");
+ /* handle unexpected PS AWAKE event */
+- if (adapter->psstate == PS_STATE_FULL_POWER) {
++ if (priv->psstate == PS_STATE_FULL_POWER) {
+ lbs_deb_cmd(
+ "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
+ break;
+ }
+
+- adapter->psstate = PS_STATE_AWAKE;
++ priv->psstate = PS_STATE_AWAKE;
+
+- if (adapter->needtowakeup) {
++ if (priv->needtowakeup) {
+ /*
+ * wait for the command processing to finish
+ * before resuming sending
+- * adapter->needtowakeup will be set to FALSE
+- * in libertas_ps_wakeup()
++ * priv->needtowakeup will be set to FALSE
++ * in lbs_ps_wakeup()
+ */
+- lbs_deb_cmd("Waking up...\n");
+- libertas_ps_wakeup(priv, 0);
++ lbs_deb_cmd("waking up ...\n");
++ lbs_ps_wakeup(priv, 0);
+ }
+ break;
+
+@@ -981,46 +895,51 @@ int libertas_process_event(wlan_private
+ break;
+
+ case MACREG_INT_CODE_ADHOC_BCN_LOST:
+- lbs_deb_cmd("EVENT: HWAC - ADHOC BCN LOST\n");
++ lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
+ break;
+
+ case MACREG_INT_CODE_RSSI_LOW:
+- lbs_pr_alert( "EVENT: RSSI_LOW\n");
++ lbs_pr_alert("EVENT: rssi low\n");
+ break;
+ case MACREG_INT_CODE_SNR_LOW:
+- lbs_pr_alert( "EVENT: SNR_LOW\n");
++ lbs_pr_alert("EVENT: snr low\n");
+ break;
+ case MACREG_INT_CODE_MAX_FAIL:
+- lbs_pr_alert( "EVENT: MAX_FAIL\n");
++ lbs_pr_alert("EVENT: max fail\n");
+ break;
+ case MACREG_INT_CODE_RSSI_HIGH:
+- lbs_pr_alert( "EVENT: RSSI_HIGH\n");
++ lbs_pr_alert("EVENT: rssi high\n");
+ break;
+ case MACREG_INT_CODE_SNR_HIGH:
+- lbs_pr_alert( "EVENT: SNR_HIGH\n");
++ lbs_pr_alert("EVENT: snr high\n");
+ break;
+
+ case MACREG_INT_CODE_MESH_AUTO_STARTED:
+- lbs_pr_alert( "EVENT: MESH_AUTO_STARTED\n");
+- adapter->connect_status = libertas_connected ;
+- if (priv->mesh_open == 1) {
+- netif_wake_queue(priv->mesh_dev) ;
+- netif_carrier_on(priv->mesh_dev) ;
++ /* Ignore spurious autostart events if autostart is disabled */
++ if (!priv->mesh_autostart_enabled) {
++ lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
++ break;
++ }
++ lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
++ priv->mesh_connect_status = LBS_CONNECTED;
++ if (priv->mesh_open) {
++ netif_carrier_on(priv->mesh_dev);
++ if (!priv->tx_pending_len)
++ netif_wake_queue(priv->mesh_dev);
+ }
+- adapter->mode = IW_MODE_ADHOC ;
++ priv->mode = IW_MODE_ADHOC;
+ schedule_work(&priv->sync_channel);
+ break;
+
+ default:
+- lbs_pr_alert( "EVENT: unknown event id: %#x\n",
+- eventcause >> SBI_EVENT_CAUSE_SHIFT);
++ lbs_pr_alert("EVENT: unknown event id %d\n", eventcause);
+ break;
+ }
+
+- spin_lock_irq(&adapter->driver_lock);
+- adapter->eventcause = 0;
+- spin_unlock_irq(&adapter->driver_lock);
++ spin_lock_irq(&priv->driver_lock);
++ priv->eventcause = 0;
++ spin_unlock_irq(&priv->driver_lock);
+
+- lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
++ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+ }
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/debugfs.c linux-2.6.22-300/drivers/net/wireless/libertas/debugfs.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/debugfs.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/debugfs.c 2008-06-05 18:10:06.000000000 -0400
+@@ -3,6 +3,7 @@
+ #include <linux/debugfs.h>
+ #include <linux/delay.h>
+ #include <linux/mm.h>
++#include <linux/string.h>
+ #include <net/iw_handler.h>
+
+ #include "dev.h"
+@@ -10,14 +11,14 @@
+ #include "host.h"
+ #include "debugfs.h"
+
+-static struct dentry *libertas_dir = NULL;
++static struct dentry *lbs_dir;
+ static char *szStates[] = {
+ "Connected",
+ "Disconnected"
+ };
+
+ #ifdef PROC_DEBUG
+-static void libertas_debug_init(wlan_private * priv, struct net_device *dev);
++static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev);
+ #endif
+
+ static int open_file_generic(struct inode *inode, struct file *file)
+@@ -34,19 +35,19 @@ static ssize_t write_file_dummy(struct f
+
+ static const size_t len = PAGE_SIZE;
+
+-static ssize_t libertas_dev_info(struct file *file, char __user *userbuf,
++static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
++ struct lbs_private *priv = file->private_data;
+ size_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ ssize_t res;
+
+ pos += snprintf(buf+pos, len-pos, "state = %s\n",
+- szStates[priv->adapter->connect_status]);
++ szStates[priv->connect_status]);
+ pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
+- (u32) priv->adapter->regioncode);
++ (u32) priv->regioncode);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+@@ -55,41 +56,41 @@ static ssize_t libertas_dev_info(struct
+ }
+
+
+-static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
++static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
++ struct lbs_private *priv = file->private_data;
+ size_t pos = 0;
+ int numscansdone = 0, res;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
++ DECLARE_MAC_BUF(mac);
+ struct bss_descriptor * iter_bss;
+
+ pos += snprintf(buf+pos, len-pos,
+- "# | ch | ss | bssid | cap | TSF | Qual | SSID \n");
++ "# | ch | rssi | bssid | cap | Qual | SSID \n");
+
+- mutex_lock(&priv->adapter->lock);
+- list_for_each_entry (iter_bss, &priv->adapter->network_list, list) {
+- u16 cap;
++ mutex_lock(&priv->lock);
++ list_for_each_entry (iter_bss, &priv->network_list, list) {
++ u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
++ u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
++ u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
+
+- memcpy(&cap, &iter_bss->cap, sizeof(cap));
+ pos += snprintf(buf+pos, len-pos,
+- "%02u| %03d | %03ld | " MAC_FMT " |",
++ "%02u| %03d | %04ld | %s |",
+ numscansdone, iter_bss->channel, iter_bss->rssi,
+- MAC_ARG(iter_bss->bssid));
+- pos += snprintf(buf+pos, len-pos, " %04x-", cap);
++ print_mac(mac, iter_bss->bssid));
++ pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
+ pos += snprintf(buf+pos, len-pos, "%c%c%c |",
+- iter_bss->cap.ibss ? 'A' : 'I',
+- iter_bss->cap.privacy ? 'P' : ' ',
+- iter_bss->cap.spectrummgmt ? 'S' : ' ');
+- pos += snprintf(buf+pos, len-pos, " %08llx |", iter_bss->networktsf);
+- pos += snprintf(buf+pos, len-pos, " %d |", SCAN_RSSI(iter_bss->rssi));
++ ibss ? 'A' : 'I', privacy ? 'P' : ' ',
++ spectrum_mgmt ? 'S' : ' ');
++ pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
+ pos += snprintf(buf+pos, len-pos, " %s\n",
+ escape_essid(iter_bss->ssid, iter_bss->ssid_len));
+
+ numscansdone++;
+ }
+- mutex_unlock(&priv->adapter->lock);
++ mutex_unlock(&priv->lock);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+@@ -97,11 +98,11 @@ static ssize_t libertas_getscantable(str
+ return res;
+ }
+
+-static ssize_t libertas_sleepparams_write(struct file *file,
++static ssize_t lbs_sleepparams_write(struct file *file,
+ const char __user *user_buf, size_t count,
+ loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
++ struct lbs_private *priv = file->private_data;
+ ssize_t buf_size, res;
+ int p1, p2, p3, p4, p5, p6;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+@@ -117,17 +118,17 @@ static ssize_t libertas_sleepparams_writ
+ res = -EFAULT;
+ goto out_unlock;
+ }
+- priv->adapter->sp.sp_error = p1;
+- priv->adapter->sp.sp_offset = p2;
+- priv->adapter->sp.sp_stabletime = p3;
+- priv->adapter->sp.sp_calcontrol = p4;
+- priv->adapter->sp.sp_extsleepclk = p5;
+- priv->adapter->sp.sp_reserved = p6;
+-
+- res = libertas_prepare_and_send_command(priv,
+- cmd_802_11_sleep_params,
+- cmd_act_set,
+- cmd_option_waitforrsp, 0, NULL);
++ priv->sp.sp_error = p1;
++ priv->sp.sp_offset = p2;
++ priv->sp.sp_stabletime = p3;
++ priv->sp.sp_calcontrol = p4;
++ priv->sp.sp_extsleepclk = p5;
++ priv->sp.sp_reserved = p6;
++
++ res = lbs_prepare_and_send_command(priv,
++ CMD_802_11_SLEEP_PARAMS,
++ CMD_ACT_SET,
++ CMD_OPTION_WAITFORRSP, 0, NULL);
+
+ if (!res)
+ res = count;
+@@ -139,29 +140,28 @@ out_unlock:
+ return res;
+ }
+
+-static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf,
++static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = file->private_data;
+ ssize_t res;
+ size_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+- res = libertas_prepare_and_send_command(priv,
+- cmd_802_11_sleep_params,
+- cmd_act_get,
+- cmd_option_waitforrsp, 0, NULL);
++ res = lbs_prepare_and_send_command(priv,
++ CMD_802_11_SLEEP_PARAMS,
++ CMD_ACT_GET,
++ CMD_OPTION_WAITFORRSP, 0, NULL);
+ if (res) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+- pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
+- adapter->sp.sp_offset, adapter->sp.sp_stabletime,
+- adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
+- adapter->sp.sp_reserved);
++ pos += snprintf(buf, len, "%d %d %d %d %d %d\n", priv->sp.sp_error,
++ priv->sp.sp_offset, priv->sp.sp_stabletime,
++ priv->sp.sp_calcontrol, priv->sp.sp_extsleepclk,
++ priv->sp.sp_reserved);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+@@ -170,10 +170,10 @@ out_unlock:
+ return res;
+ }
+
+-static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
++static ssize_t lbs_extscan(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
++ struct lbs_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ union iwreq_data wrqu;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+@@ -185,7 +185,7 @@ static ssize_t libertas_extscan(struct f
+ goto out_unlock;
+ }
+
+- libertas_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0);
++ lbs_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0);
+
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+@@ -195,45 +195,8 @@ out_unlock:
+ return count;
+ }
+
+-static int libertas_parse_chan(char *buf, size_t count,
+- struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur)
+-{
+- char *start, *end, *hold, *str;
+- int i = 0;
+-
+- start = strstr(buf, "chan=");
+- if (!start)
+- return -EINVAL;
+- start += 5;
+- end = strstr(start, " ");
+- if (!end)
+- end = buf + count;
+- hold = kzalloc((end - start)+1, GFP_KERNEL);
+- if (!hold)
+- return -ENOMEM;
+- strncpy(hold, start, end - start);
+- hold[(end-start)+1] = '\0';
+- while(hold && (str = strsep(&hold, ","))) {
+- int chan;
+- char band, passive = 0;
+- sscanf(str, "%d%c%c", &chan, &band, &passive);
+- scan_cfg->chanlist[i].channumber = chan;
+- scan_cfg->chanlist[i].scantype = passive ? 1 : 0;
+- if (band == 'b' || band == 'g')
+- scan_cfg->chanlist[i].radiotype = 0;
+- else if (band == 'a')
+- scan_cfg->chanlist[i].radiotype = 1;
+-
+- scan_cfg->chanlist[i].scantime = dur;
+- i++;
+- }
+-
+- kfree(hold);
+- return i;
+-}
+-
+-static void libertas_parse_bssid(char *buf, size_t count,
+- struct wlan_ioctl_user_scan_cfg *scan_cfg)
++static void lbs_parse_bssid(char *buf, size_t count,
++ struct lbs_ioctl_user_scan_cfg *scan_cfg)
+ {
+ char *hold;
+ unsigned int mac[ETH_ALEN];
+@@ -246,8 +209,8 @@ static void libertas_parse_bssid(char *b
+ memcpy(scan_cfg->bssid, mac, ETH_ALEN);
+ }
+
+-static void libertas_parse_ssid(char *buf, size_t count,
+- struct wlan_ioctl_user_scan_cfg *scan_cfg)
++static void lbs_parse_ssid(char *buf, size_t count,
++ struct lbs_ioctl_user_scan_cfg *scan_cfg)
+ {
+ char *hold, *end;
+ ssize_t size;
+@@ -256,7 +219,7 @@ static void libertas_parse_ssid(char *bu
+ if (!hold)
+ return;
+ hold += 5;
+- end = strstr(hold, " ");
++ end = strchr(hold, ' ');
+ if (!end)
+ end = buf + count - 1;
+
+@@ -266,7 +229,7 @@ static void libertas_parse_ssid(char *bu
+ return;
+ }
+
+-static int libertas_parse_clear(char *buf, size_t count, const char *tag)
++static int lbs_parse_clear(char *buf, size_t count, const char *tag)
+ {
+ char *hold;
+ int val;
+@@ -283,8 +246,8 @@ static int libertas_parse_clear(char *bu
+ return val;
+ }
+
+-static int libertas_parse_dur(char *buf, size_t count,
+- struct wlan_ioctl_user_scan_cfg *scan_cfg)
++static int lbs_parse_dur(char *buf, size_t count,
++ struct lbs_ioctl_user_scan_cfg *scan_cfg)
+ {
+ char *hold;
+ int val;
+@@ -298,25 +261,8 @@ static int libertas_parse_dur(char *buf,
+ return val;
+ }
+
+-static void libertas_parse_probes(char *buf, size_t count,
+- struct wlan_ioctl_user_scan_cfg *scan_cfg)
+-{
+- char *hold;
+- int val;
+-
+- hold = strstr(buf, "probes=");
+- if (!hold)
+- return;
+- hold += 7;
+- sscanf(hold, "%d", &val);
+-
+- scan_cfg->numprobes = val;
+-
+- return;
+-}
+-
+-static void libertas_parse_type(char *buf, size_t count,
+- struct wlan_ioctl_user_scan_cfg *scan_cfg)
++static void lbs_parse_type(char *buf, size_t count,
++ struct lbs_ioctl_user_scan_cfg *scan_cfg)
+ {
+ char *hold;
+ int val;
+@@ -336,570 +282,217 @@ static void libertas_parse_type(char *bu
+ return;
+ }
+
+-static ssize_t libertas_setuserscan(struct file *file,
++static ssize_t lbs_setuserscan(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
++ struct lbs_private *priv = file->private_data;
+ ssize_t res, buf_size;
+- struct wlan_ioctl_user_scan_cfg *scan_cfg;
++ struct lbs_ioctl_user_scan_cfg *scan_cfg;
+ union iwreq_data wrqu;
+ int dur;
+- unsigned long addr = get_zeroed_page(GFP_KERNEL);
+- char *buf = (char *)addr;
++ char *buf = (char *)get_zeroed_page(GFP_KERNEL);
+
+- scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL);
+- if (!scan_cfg)
++ if (!buf)
+ return -ENOMEM;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+- goto out_unlock;
++ goto out_buf;
+ }
+
+- scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY;
++ scan_cfg = kzalloc(sizeof(struct lbs_ioctl_user_scan_cfg), GFP_KERNEL);
++ if (!scan_cfg) {
++ res = -ENOMEM;
++ goto out_buf;
++ }
++ res = count;
++
++ scan_cfg->bsstype = LBS_SCAN_BSS_TYPE_ANY;
+
+- dur = libertas_parse_dur(buf, count, scan_cfg);
+- libertas_parse_chan(buf, count, scan_cfg, dur);
+- libertas_parse_bssid(buf, count, scan_cfg);
+- scan_cfg->clear_bssid = libertas_parse_clear(buf, count, "clear_bssid=");
+- libertas_parse_ssid(buf, count, scan_cfg);
+- scan_cfg->clear_ssid = libertas_parse_clear(buf, count, "clear_ssid=");
+- libertas_parse_probes(buf, count, scan_cfg);
+- libertas_parse_type(buf, count, scan_cfg);
+-
+- wlan_scan_networks(priv, scan_cfg, 1);
+- wait_event_interruptible(priv->adapter->cmd_pending,
+- !priv->adapter->nr_cmd_pending);
++ dur = lbs_parse_dur(buf, count, scan_cfg);
++ lbs_parse_bssid(buf, count, scan_cfg);
++ scan_cfg->clear_bssid = lbs_parse_clear(buf, count, "clear_bssid=");
++ lbs_parse_ssid(buf, count, scan_cfg);
++ scan_cfg->clear_ssid = lbs_parse_clear(buf, count, "clear_ssid=");
++ lbs_parse_type(buf, count, scan_cfg);
++
++ lbs_scan_networks(priv, scan_cfg, 1);
++ wait_event_interruptible(priv->cmd_pending,
++ priv->surpriseremoved || !priv->last_scanned_channel);
++
++ if (priv->surpriseremoved)
++ goto out_scan_cfg;
+
+ memset(&wrqu, 0x00, sizeof(union iwreq_data));
+ wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+
+-out_unlock:
+- free_page(addr);
++ out_scan_cfg:
+ kfree(scan_cfg);
+- return count;
++ out_buf:
++ free_page((unsigned long)buf);
++ return res;
+ }
+
+-static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
+- struct cmd_ctrl_node **cmdnode,
+- struct cmd_ds_command **cmd)
+-{
+- u16 wait_option = cmd_option_waitforrsp;
+-
+- if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
+- lbs_deb_debugfs("failed libertas_get_free_cmd_ctrl_node\n");
+- return -ENOMEM;
+- }
+- if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) {
+- lbs_deb_debugfs("failed to allocate response buffer!\n");
+- return -ENOMEM;
+- }
+- libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL);
+- init_waitqueue_head(&(*cmdnode)->cmdwait_q);
+- (*cmdnode)->pdata_buf = *response_buf;
+- (*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
+- (*cmdnode)->cmdwaitqwoken = 0;
+- *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
+- (*cmd)->command = cpu_to_le16(cmd_802_11_subscribe_event);
+- (*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum);
+- (*cmd)->result = 0;
+- return 0;
+-}
+
+-static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
+- size_t count, loff_t *ppos)
++/*
++ * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
++ * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
++ * firmware. Here's an example:
++ * 04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
++ * 00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
++ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
++ *
++ * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
++ * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
++ * defined in mrvlietypes_thresholds
++ *
++ * This function searches in this TLV data chunk for a given TLV type
++ * and returns a pointer to the first data byte of the TLV, or to NULL
++ * if the TLV hasn't been found.
++ */
++static void *lbs_tlv_find(u16 tlv_type, const u8 *tlv, u16 size)
+ {
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- void *response_buf;
+- int res, cmd_len;
++ __le16 le_type = cpu_to_le16(tlv_type);
+ ssize_t pos = 0;
+- unsigned long addr = get_zeroed_page(GFP_KERNEL);
+- char *buf = (char *)addr;
+-
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0) {
+- free_page(addr);
+- return res;
+- }
+-
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_get);
+- pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = response_buf;
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+-
+- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+- lbs_pr_err("command response incorrect!\n");
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+-
+- cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+- event = (void *)(response_buf + S_DS_GEN);
+- while (cmd_len < le16_to_cpu(pcmdptr->size)) {
+- struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
+- switch (header->type) {
+- struct mrvlietypes_rssithreshold *Lowrssi;
+- case __constant_cpu_to_le16(TLV_TYPE_RSSI_LOW):
+- Lowrssi = (void *)(response_buf + cmd_len);
+- pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+- Lowrssi->rssivalue,
+- Lowrssi->rssifreq,
+- (event->events & cpu_to_le16(0x0001))?1:0);
+- default:
+- cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+- break;
+- }
+- }
+-
+- kfree(response_buf);
+- res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+- free_page(addr);
+- return res;
++ struct mrvlietypesheader *tlv_h;
++ while (pos < size) {
++ u16 length;
++ tlv_h = (struct mrvlietypesheader *) tlv;
++ if (tlv_h->type == le_type)
++ return tlv_h;
++ if (tlv_h->len == 0)
++ return NULL;
++ length = le16_to_cpu(tlv_h->len) +
++ sizeof(struct mrvlietypesheader);
++ pos += length;
++ tlv += length;
++ }
++ return NULL;
+ }
+
+-static u16 libertas_get_events_bitmap(wlan_private *priv)
+-{
+- wlan_adapter *adapter = priv->adapter;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- void *response_buf;
+- int res;
+- u16 event_bitmap;
+
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0)
+- return res;
+-
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_get);
+- pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = response_buf;
+-
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- kfree(response_buf);
+- return 0;
+- }
+-
+- if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+- lbs_pr_err("command response incorrect!\n");
+- kfree(response_buf);
+- return 0;
+- }
+-
+- event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+- event_bitmap = le16_to_cpu(event->events);
+- kfree(response_buf);
+- return event_bitmap;
+-}
+-
+-static ssize_t libertas_lowrssi_write(struct file *file,
+- const char __user *userbuf,
+- size_t count, loff_t *ppos)
++/*
++ * This just gets the bitmap of currently subscribed events. Used when
++ * adding an additonal event subscription.
++ */
++static u16 lbs_get_events_bitmap(struct lbs_private *priv)
+ {
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- ssize_t res, buf_size;
+- int value, freq, subscribed, cmd_len;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- struct mrvlietypes_rssithreshold *rssi_threshold;
+- void *response_buf;
+- u16 event_bitmap;
+- u8 *ptr;
+- unsigned long addr = get_zeroed_page(GFP_KERNEL);
+- char *buf = (char *)addr;
+-
+- buf_size = min(count, len - 1);
+- if (copy_from_user(buf, userbuf, buf_size)) {
+- res = -EFAULT;
+- goto out_unlock;
+- }
+- res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+- if (res != 3) {
+- res = -EFAULT;
+- goto out_unlock;
+- }
+-
+- event_bitmap = libertas_get_events_bitmap(priv);
++ ssize_t res;
+
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0)
+- goto out_unlock;
++ struct cmd_ds_802_11_subscribe_event *events = kzalloc(
++ sizeof(struct cmd_ds_802_11_subscribe_event),
++ GFP_KERNEL);
++
++ res = lbs_prepare_and_send_command(priv,
++ CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
++ CMD_OPTION_WAITFORRSP, 0, events);
+
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_set);
+- pcmdptr->size = cpu_to_le16(S_DS_GEN +
+- sizeof(struct cmd_ds_802_11_subscribe_event) +
+- sizeof(struct mrvlietypes_rssithreshold));
+-
+- cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+- ptr = (u8*) pcmdptr+cmd_len;
+- rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
+- rssi_threshold->header.type = cpu_to_le16(0x0104);
+- rssi_threshold->header.len = cpu_to_le16(2);
+- rssi_threshold->rssivalue = value;
+- rssi_threshold->rssifreq = freq;
+- event_bitmap |= subscribed ? 0x0001 : 0x0;
+- event->events = cpu_to_le16(event_bitmap);
+-
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = response_buf;
+-
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+-
+- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+- lbs_pr_err("command response incorrect!\n");
+- kfree(response_buf);
+- free_page(addr);
++ if (res) {
++ kfree(events);
+ return 0;
+ }
+-
+- res = count;
+-out_unlock:
+- free_page(addr);
+- return res;
++ return le16_to_cpu(events->events);
+ }
+
+-static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
+- size_t count, loff_t *ppos)
++
++static ssize_t lbs_threshold_read(
++ u16 tlv_type, u16 event_mask,
++ struct file *file, char __user *userbuf,
++ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- void *response_buf;
+- int res, cmd_len;
+- ssize_t pos = 0;
++ struct lbs_private *priv = file->private_data;
++ ssize_t res = 0;
++ size_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+-
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0) {
+- free_page(addr);
++ u8 value;
++ u8 freq;
++ int events = 0;
++
++ struct cmd_ds_802_11_subscribe_event *subscribed = kzalloc(
++ sizeof(struct cmd_ds_802_11_subscribe_event),
++ GFP_KERNEL);
++ struct mrvlietypes_thresholds *got;
++
++ res = lbs_prepare_and_send_command(priv,
++ CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
++ CMD_OPTION_WAITFORRSP, 0, subscribed);
++ if (res) {
++ kfree(subscribed);
+ return res;
+ }
+
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_get);
+- pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = response_buf;
+-
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+-
+- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+- lbs_pr_err("command response incorrect!\n");
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+-
+- cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+- event = (void *)(response_buf + S_DS_GEN);
+- while (cmd_len < le16_to_cpu(pcmdptr->size)) {
+- struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
+- switch (header->type) {
+- struct mrvlietypes_snrthreshold *LowSnr;
+- case __constant_cpu_to_le16(TLV_TYPE_SNR_LOW):
+- LowSnr = (void *)(response_buf + cmd_len);
+- pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+- LowSnr->snrvalue,
+- LowSnr->snrfreq,
+- (event->events & cpu_to_le16(0x0002))?1:0);
+- default:
+- cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+- break;
+- }
+- }
+-
+- kfree(response_buf);
++ got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
++ if (got) {
++ value = got->value;
++ freq = got->freq;
++ events = le16_to_cpu(subscribed->events);
++ }
++ kfree(subscribed);
++
++ if (got)
++ pos += snprintf(buf, len, "%d %d %d\n", value, freq,
++ !!(events & event_mask));
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+- free_page(addr);
+- return res;
+-}
+-
+-static ssize_t libertas_lowsnr_write(struct file *file,
+- const char __user *userbuf,
+- size_t count, loff_t *ppos)
+-{
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- ssize_t res, buf_size;
+- int value, freq, subscribed, cmd_len;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- struct mrvlietypes_snrthreshold *snr_threshold;
+- void *response_buf;
+- u16 event_bitmap;
+- u8 *ptr;
+- unsigned long addr = get_zeroed_page(GFP_KERNEL);
+- char *buf = (char *)addr;
+-
+- buf_size = min(count, len - 1);
+- if (copy_from_user(buf, userbuf, buf_size)) {
+- res = -EFAULT;
+- goto out_unlock;
+- }
+- res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+- if (res != 3) {
+- res = -EFAULT;
+- goto out_unlock;
+- }
+-
+- event_bitmap = libertas_get_events_bitmap(priv);
+-
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0)
+- goto out_unlock;
+-
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_set);
+- pcmdptr->size = cpu_to_le16(S_DS_GEN +
+- sizeof(struct cmd_ds_802_11_subscribe_event) +
+- sizeof(struct mrvlietypes_snrthreshold));
+- cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+- ptr = (u8*) pcmdptr+cmd_len;
+- snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
+- snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
+- snr_threshold->header.len = cpu_to_le16(2);
+- snr_threshold->snrvalue = value;
+- snr_threshold->snrfreq = freq;
+- event_bitmap |= subscribed ? 0x0002 : 0x0;
+- event->events = cpu_to_le16(event_bitmap);
+-
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = response_buf;
+-
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+-
+- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+- lbs_pr_err("command response incorrect!\n");
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+
+- res = count;
+-
+-out_unlock:
+ free_page(addr);
+ return res;
+ }
+
+-static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
+- size_t count, loff_t *ppos)
+-{
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- void *response_buf;
+- int res, cmd_len;
+- ssize_t pos = 0;
+- unsigned long addr = get_zeroed_page(GFP_KERNEL);
+- char *buf = (char *)addr;
+-
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0) {
+- free_page(addr);
+- return res;
+- }
+-
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_get);
+- pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = response_buf;
+-
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+-
+- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+- lbs_pr_err("command response incorrect!\n");
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+-
+- cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+- event = (void *)(response_buf + S_DS_GEN);
+- while (cmd_len < le16_to_cpu(pcmdptr->size)) {
+- struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
+- switch (header->type) {
+- struct mrvlietypes_failurecount *failcount;
+- case __constant_cpu_to_le16(TLV_TYPE_FAILCOUNT):
+- failcount = (void *)(response_buf + cmd_len);
+- pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+- failcount->failvalue,
+- failcount->Failfreq,
+- (event->events & cpu_to_le16(0x0004))?1:0);
+- default:
+- cmd_len += sizeof(struct mrvlietypes_failurecount);
+- break;
+- }
+- }
+-
+- kfree(response_buf);
+- res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+- free_page(addr);
+- return res;
+-}
+
+-static ssize_t libertas_failcount_write(struct file *file,
+- const char __user *userbuf,
+- size_t count, loff_t *ppos)
++static ssize_t lbs_threshold_write(
++ u16 tlv_type, u16 event_mask,
++ struct file *file,
++ const char __user *userbuf,
++ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = file->private_data;
+ ssize_t res, buf_size;
+- int value, freq, subscribed, cmd_len;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- struct mrvlietypes_failurecount *failcount;
+- void *response_buf;
+- u16 event_bitmap;
+- u8 *ptr;
++ int value, freq, curr_mask, new_mask;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
++ struct cmd_ds_802_11_subscribe_event *events;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+- res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
++ res = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
++ curr_mask = lbs_get_events_bitmap(priv);
+
+- event_bitmap = libertas_get_events_bitmap(priv);
+-
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0)
+- goto out_unlock;
+-
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_set);
+- pcmdptr->size = cpu_to_le16(S_DS_GEN +
+- sizeof(struct cmd_ds_802_11_subscribe_event) +
+- sizeof(struct mrvlietypes_failurecount));
+- cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+- ptr = (u8*) pcmdptr+cmd_len;
+- failcount = (struct mrvlietypes_failurecount *)(ptr);
+- failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT);
+- failcount->header.len = cpu_to_le16(2);
+- failcount->failvalue = value;
+- failcount->Failfreq = freq;
+- event_bitmap |= subscribed ? 0x0004 : 0x0;
+- event->events = cpu_to_le16(event_bitmap);
+-
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = (struct cmd_ds_command *)response_buf;
+-
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
++ if (new_mask)
++ new_mask = curr_mask | event_mask;
++ else
++ new_mask = curr_mask & ~event_mask;
+
+- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+- lbs_pr_err("command response incorrect!\n");
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
++ /* Now everything is set and we can send stuff down to the firmware */
++ events = kzalloc(
++ sizeof(struct cmd_ds_802_11_subscribe_event),
++ GFP_KERNEL);
++ if (events) {
++ struct mrvlietypes_thresholds *tlv =
++ (struct mrvlietypes_thresholds *) events->tlv;
++ events->action = cpu_to_le16(CMD_ACT_SET);
++ events->events = cpu_to_le16(new_mask);
++ tlv->header.type = cpu_to_le16(tlv_type);
++ tlv->header.len = cpu_to_le16(
++ sizeof(struct mrvlietypes_thresholds) -
++ sizeof(struct mrvlietypesheader));
++ tlv->value = value;
++ if (tlv_type != TLV_TYPE_BCNMISS)
++ tlv->freq = freq;
++ lbs_prepare_and_send_command(priv,
++ CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_SET,
++ CMD_OPTION_WAITFORRSP, 0, events);
++ kfree(events);
+ }
+
+ res = count;
+@@ -908,464 +501,125 @@ out_unlock:
+ return res;
+ }
+
+-static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
+- size_t count, loff_t *ppos)
+-{
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- void *response_buf;
+- int res, cmd_len;
+- ssize_t pos = 0;
+- unsigned long addr = get_zeroed_page(GFP_KERNEL);
+- char *buf = (char *)addr;
+-
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0) {
+- free_page(addr);
+- return res;
+- }
+-
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_get);
+- pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = response_buf;
+-
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- free_page(addr);
+- kfree(response_buf);
+- return 0;
+- }
+-
+- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+- lbs_pr_err("command response incorrect!\n");
+- free_page(addr);
+- kfree(response_buf);
+- return 0;
+- }
+-
+- cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+- event = (void *)(response_buf + S_DS_GEN);
+- while (cmd_len < le16_to_cpu(pcmdptr->size)) {
+- struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
+- switch (header->type) {
+- struct mrvlietypes_beaconsmissed *bcnmiss;
+- case __constant_cpu_to_le16(TLV_TYPE_BCNMISS):
+- bcnmiss = (void *)(response_buf + cmd_len);
+- pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
+- bcnmiss->beaconmissed,
+- (event->events & cpu_to_le16(0x0008))?1:0);
+- default:
+- cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
+- break;
+- }
+- }
+-
+- kfree(response_buf);
+
+- res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+- free_page(addr);
+- return res;
+-}
+-
+-static ssize_t libertas_bcnmiss_write(struct file *file,
+- const char __user *userbuf,
+- size_t count, loff_t *ppos)
++static ssize_t lbs_lowrssi_read(
++ struct file *file, char __user *userbuf,
++ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- ssize_t res, buf_size;
+- int value, freq, subscribed, cmd_len;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- struct mrvlietypes_beaconsmissed *bcnmiss;
+- void *response_buf;
+- u16 event_bitmap;
+- u8 *ptr;
+- unsigned long addr = get_zeroed_page(GFP_KERNEL);
+- char *buf = (char *)addr;
+-
+- buf_size = min(count, len - 1);
+- if (copy_from_user(buf, userbuf, buf_size)) {
+- res = -EFAULT;
+- goto out_unlock;
+- }
+- res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+- if (res != 3) {
+- res = -EFAULT;
+- goto out_unlock;
+- }
+-
+- event_bitmap = libertas_get_events_bitmap(priv);
+-
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0)
+- goto out_unlock;
+-
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_set);
+- pcmdptr->size = cpu_to_le16(S_DS_GEN +
+- sizeof(struct cmd_ds_802_11_subscribe_event) +
+- sizeof(struct mrvlietypes_beaconsmissed));
+- cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+- ptr = (u8*) pcmdptr+cmd_len;
+- bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
+- bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
+- bcnmiss->header.len = cpu_to_le16(2);
+- bcnmiss->beaconmissed = value;
+- event_bitmap |= subscribed ? 0x0008 : 0x0;
+- event->events = cpu_to_le16(event_bitmap);
+-
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = response_buf;
+-
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
++ return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
++ file, userbuf, count, ppos);
++}
+
+- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+- lbs_pr_err("command response incorrect!\n");
+- free_page(addr);
+- kfree(response_buf);
+- return 0;
+- }
+
+- res = count;
+-out_unlock:
+- free_page(addr);
+- return res;
++static ssize_t lbs_lowrssi_write(
++ struct file *file, const char __user *userbuf,
++ size_t count, loff_t *ppos)
++{
++ return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
++ file, userbuf, count, ppos);
+ }
+
+-static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
+- size_t count, loff_t *ppos)
++
++static ssize_t lbs_lowsnr_read(
++ struct file *file, char __user *userbuf,
++ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- void *response_buf;
+- int res, cmd_len;
+- ssize_t pos = 0;
+- unsigned long addr = get_zeroed_page(GFP_KERNEL);
+- char *buf = (char *)addr;
++ return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
++ file, userbuf, count, ppos);
++}
+
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0) {
+- free_page(addr);
+- return res;
+- }
+
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_get);
+- pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = response_buf;
+-
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
++static ssize_t lbs_lowsnr_write(
++ struct file *file, const char __user *userbuf,
++ size_t count, loff_t *ppos)
++{
++ return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
++ file, userbuf, count, ppos);
++}
+
+- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+- lbs_pr_err("command response incorrect!\n");
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+
+- cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+- event = (void *)(response_buf + S_DS_GEN);
+- while (cmd_len < le16_to_cpu(pcmdptr->size)) {
+- struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
+- switch (header->type) {
+- struct mrvlietypes_rssithreshold *Highrssi;
+- case __constant_cpu_to_le16(TLV_TYPE_RSSI_HIGH):
+- Highrssi = (void *)(response_buf + cmd_len);
+- pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+- Highrssi->rssivalue,
+- Highrssi->rssifreq,
+- (event->events & cpu_to_le16(0x0010))?1:0);
+- default:
+- cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+- break;
+- }
+- }
++static ssize_t lbs_failcount_read(
++ struct file *file, char __user *userbuf,
++ size_t count, loff_t *ppos)
++{
++ return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
++ file, userbuf, count, ppos);
++}
+
+- kfree(response_buf);
+
+- res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+- free_page(addr);
+- return res;
++static ssize_t lbs_failcount_write(
++ struct file *file, const char __user *userbuf,
++ size_t count, loff_t *ppos)
++{
++ return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
++ file, userbuf, count, ppos);
+ }
+
+-static ssize_t libertas_highrssi_write(struct file *file,
+- const char __user *userbuf,
+- size_t count, loff_t *ppos)
++
++static ssize_t lbs_highrssi_read(
++ struct file *file, char __user *userbuf,
++ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- ssize_t res, buf_size;
+- int value, freq, subscribed, cmd_len;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- struct mrvlietypes_rssithreshold *rssi_threshold;
+- void *response_buf;
+- u16 event_bitmap;
+- u8 *ptr;
+- unsigned long addr = get_zeroed_page(GFP_KERNEL);
+- char *buf = (char *)addr;
++ return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
++ file, userbuf, count, ppos);
++}
+
+- buf_size = min(count, len - 1);
+- if (copy_from_user(buf, userbuf, buf_size)) {
+- res = -EFAULT;
+- goto out_unlock;
+- }
+- res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+- if (res != 3) {
+- res = -EFAULT;
+- goto out_unlock;
+- }
+
+- event_bitmap = libertas_get_events_bitmap(priv);
++static ssize_t lbs_highrssi_write(
++ struct file *file, const char __user *userbuf,
++ size_t count, loff_t *ppos)
++{
++ return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
++ file, userbuf, count, ppos);
++}
+
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0)
+- goto out_unlock;
+
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_set);
+- pcmdptr->size = cpu_to_le16(S_DS_GEN +
+- sizeof(struct cmd_ds_802_11_subscribe_event) +
+- sizeof(struct mrvlietypes_rssithreshold));
+- cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+- ptr = (u8*) pcmdptr+cmd_len;
+- rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
+- rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
+- rssi_threshold->header.len = cpu_to_le16(2);
+- rssi_threshold->rssivalue = value;
+- rssi_threshold->rssifreq = freq;
+- event_bitmap |= subscribed ? 0x0010 : 0x0;
+- event->events = cpu_to_le16(event_bitmap);
+-
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = response_buf;
+-
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- kfree(response_buf);
+- return 0;
+- }
++static ssize_t lbs_highsnr_read(
++ struct file *file, char __user *userbuf,
++ size_t count, loff_t *ppos)
++{
++ return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
++ file, userbuf, count, ppos);
++}
+
+- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+- lbs_pr_err("command response incorrect!\n");
+- kfree(response_buf);
+- return 0;
+- }
+
+- res = count;
+-out_unlock:
+- free_page(addr);
+- return res;
++static ssize_t lbs_highsnr_write(
++ struct file *file, const char __user *userbuf,
++ size_t count, loff_t *ppos)
++{
++ return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
++ file, userbuf, count, ppos);
+ }
+
+-static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
+- size_t count, loff_t *ppos)
++static ssize_t lbs_bcnmiss_read(
++ struct file *file, char __user *userbuf,
++ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- void *response_buf;
+- int res, cmd_len;
+- ssize_t pos = 0;
+- unsigned long addr = get_zeroed_page(GFP_KERNEL);
+- char *buf = (char *)addr;
+-
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0) {
+- free_page(addr);
+- return res;
+- }
+-
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_get);
+- pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = response_buf;
+-
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+-
+- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+- lbs_pr_err("command response incorrect!\n");
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+-
+- cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+- event = (void *)(response_buf + S_DS_GEN);
+- while (cmd_len < le16_to_cpu(pcmdptr->size)) {
+- struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
+- switch (header->type) {
+- struct mrvlietypes_snrthreshold *HighSnr;
+- case __constant_cpu_to_le16(TLV_TYPE_SNR_HIGH):
+- HighSnr = (void *)(response_buf + cmd_len);
+- pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+- HighSnr->snrvalue,
+- HighSnr->snrfreq,
+- (event->events & cpu_to_le16(0x0020))?1:0);
+- default:
+- cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+- break;
+- }
+- }
++ return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
++ file, userbuf, count, ppos);
++}
+
+- kfree(response_buf);
+
+- res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+- free_page(addr);
+- return res;
++static ssize_t lbs_bcnmiss_write(
++ struct file *file, const char __user *userbuf,
++ size_t count, loff_t *ppos)
++{
++ return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
++ file, userbuf, count, ppos);
+ }
+
+-static ssize_t libertas_highsnr_write(struct file *file,
+- const char __user *userbuf,
+- size_t count, loff_t *ppos)
+-{
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- ssize_t res, buf_size;
+- int value, freq, subscribed, cmd_len;
+- struct cmd_ctrl_node *pcmdnode;
+- struct cmd_ds_command *pcmdptr;
+- struct cmd_ds_802_11_subscribe_event *event;
+- struct mrvlietypes_snrthreshold *snr_threshold;
+- void *response_buf;
+- u16 event_bitmap;
+- u8 *ptr;
+- unsigned long addr = get_zeroed_page(GFP_KERNEL);
+- char *buf = (char *)addr;
+
+- buf_size = min(count, len - 1);
+- if (copy_from_user(buf, userbuf, buf_size)) {
+- res = -EFAULT;
+- goto out_unlock;
+- }
+- res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+- if (res != 3) {
+- res = -EFAULT;
+- goto out_unlock;
+- }
+
+- event_bitmap = libertas_get_events_bitmap(priv);
+
+- res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+- if (res < 0)
+- goto out_unlock;
+
+- event = &pcmdptr->params.subscribe_event;
+- event->action = cpu_to_le16(cmd_act_set);
+- pcmdptr->size = cpu_to_le16(S_DS_GEN +
+- sizeof(struct cmd_ds_802_11_subscribe_event) +
+- sizeof(struct mrvlietypes_snrthreshold));
+- cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+- ptr = (u8*) pcmdptr+cmd_len;
+- snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
+- snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
+- snr_threshold->header.len = cpu_to_le16(2);
+- snr_threshold->snrvalue = value;
+- snr_threshold->snrfreq = freq;
+- event_bitmap |= subscribed ? 0x0020 : 0x0;
+- event->events = cpu_to_le16(event_bitmap);
+-
+- libertas_queue_cmd(adapter, pcmdnode, 1);
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- /* Sleep until response is generated by FW */
+- wait_event_interruptible(pcmdnode->cmdwait_q,
+- pcmdnode->cmdwaitqwoken);
+-
+- pcmdptr = response_buf;
+-
+- if (pcmdptr->result) {
+- lbs_pr_err("%s: fail, result=%d\n", __func__,
+- le16_to_cpu(pcmdptr->result));
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+
+- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+- lbs_pr_err("command response incorrect!\n");
+- kfree(response_buf);
+- free_page(addr);
+- return 0;
+- }
+
+- res = count;
+-out_unlock:
+- free_page(addr);
+- return res;
+-}
+
+-static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
++static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- struct wlan_offset_value offval;
++ struct lbs_private *priv = file->private_data;
++ struct lbs_offset_value offval;
+ ssize_t pos = 0;
+ int ret;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+@@ -1374,23 +628,23 @@ static ssize_t libertas_rdmac_read(struc
+ offval.offset = priv->mac_offset;
+ offval.value = 0;
+
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_mac_reg_access, 0,
+- cmd_option_waitforrsp, 0, &offval);
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_MAC_REG_ACCESS, 0,
++ CMD_OPTION_WAITFORRSP, 0, &offval);
+ mdelay(10);
+ pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
+- priv->mac_offset, adapter->offsetvalue.value);
++ priv->mac_offset, priv->offsetvalue.value);
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return ret;
+ }
+
+-static ssize_t libertas_rdmac_write(struct file *file,
++static ssize_t lbs_rdmac_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
++ struct lbs_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+@@ -1407,15 +661,15 @@ out_unlock:
+ return res;
+ }
+
+-static ssize_t libertas_wrmac_write(struct file *file,
++static ssize_t lbs_wrmac_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+
+- wlan_private *priv = file->private_data;
++ struct lbs_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ u32 offset, value;
+- struct wlan_offset_value offval;
++ struct lbs_offset_value offval;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+@@ -1432,9 +686,9 @@ static ssize_t libertas_wrmac_write(stru
+
+ offval.offset = offset;
+ offval.value = value;
+- res = libertas_prepare_and_send_command(priv,
+- cmd_mac_reg_access, 1,
+- cmd_option_waitforrsp, 0, &offval);
++ res = lbs_prepare_and_send_command(priv,
++ CMD_MAC_REG_ACCESS, 1,
++ CMD_OPTION_WAITFORRSP, 0, &offval);
+ mdelay(10);
+
+ res = count;
+@@ -1443,12 +697,11 @@ out_unlock:
+ return res;
+ }
+
+-static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
++static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- struct wlan_offset_value offval;
++ struct lbs_private *priv = file->private_data;
++ struct lbs_offset_value offval;
+ ssize_t pos = 0;
+ int ret;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+@@ -1457,12 +710,12 @@ static ssize_t libertas_rdbbp_read(struc
+ offval.offset = priv->bbp_offset;
+ offval.value = 0;
+
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_bbp_reg_access, 0,
+- cmd_option_waitforrsp, 0, &offval);
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_BBP_REG_ACCESS, 0,
++ CMD_OPTION_WAITFORRSP, 0, &offval);
+ mdelay(10);
+ pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
+- priv->bbp_offset, adapter->offsetvalue.value);
++ priv->bbp_offset, priv->offsetvalue.value);
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+@@ -1470,11 +723,11 @@ static ssize_t libertas_rdbbp_read(struc
+ return ret;
+ }
+
+-static ssize_t libertas_rdbbp_write(struct file *file,
++static ssize_t lbs_rdbbp_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
++ struct lbs_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+@@ -1491,15 +744,15 @@ out_unlock:
+ return res;
+ }
+
+-static ssize_t libertas_wrbbp_write(struct file *file,
++static ssize_t lbs_wrbbp_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+
+- wlan_private *priv = file->private_data;
++ struct lbs_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ u32 offset, value;
+- struct wlan_offset_value offval;
++ struct lbs_offset_value offval;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+@@ -1516,9 +769,9 @@ static ssize_t libertas_wrbbp_write(stru
+
+ offval.offset = offset;
+ offval.value = value;
+- res = libertas_prepare_and_send_command(priv,
+- cmd_bbp_reg_access, 1,
+- cmd_option_waitforrsp, 0, &offval);
++ res = lbs_prepare_and_send_command(priv,
++ CMD_BBP_REG_ACCESS, 1,
++ CMD_OPTION_WAITFORRSP, 0, &offval);
+ mdelay(10);
+
+ res = count;
+@@ -1527,12 +780,11 @@ out_unlock:
+ return res;
+ }
+
+-static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
++static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
+- wlan_adapter *adapter = priv->adapter;
+- struct wlan_offset_value offval;
++ struct lbs_private *priv = file->private_data;
++ struct lbs_offset_value offval;
+ ssize_t pos = 0;
+ int ret;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+@@ -1541,12 +793,12 @@ static ssize_t libertas_rdrf_read(struct
+ offval.offset = priv->rf_offset;
+ offval.value = 0;
+
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_rf_reg_access, 0,
+- cmd_option_waitforrsp, 0, &offval);
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_RF_REG_ACCESS, 0,
++ CMD_OPTION_WAITFORRSP, 0, &offval);
+ mdelay(10);
+ pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
+- priv->rf_offset, adapter->offsetvalue.value);
++ priv->rf_offset, priv->offsetvalue.value);
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+@@ -1554,11 +806,11 @@ static ssize_t libertas_rdrf_read(struct
+ return ret;
+ }
+
+-static ssize_t libertas_rdrf_write(struct file *file,
++static ssize_t lbs_rdrf_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+- wlan_private *priv = file->private_data;
++ struct lbs_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+@@ -1575,15 +827,15 @@ out_unlock:
+ return res;
+ }
+
+-static ssize_t libertas_wrrf_write(struct file *file,
++static ssize_t lbs_wrrf_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+
+- wlan_private *priv = file->private_data;
++ struct lbs_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ u32 offset, value;
+- struct wlan_offset_value offval;
++ struct lbs_offset_value offval;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+@@ -1600,9 +852,9 @@ static ssize_t libertas_wrrf_write(struc
+
+ offval.offset = offset;
+ offval.value = value;
+- res = libertas_prepare_and_send_command(priv,
+- cmd_rf_reg_access, 1,
+- cmd_option_waitforrsp, 0, &offval);
++ res = lbs_prepare_and_send_command(priv,
++ CMD_RF_REG_ACCESS, 1,
++ CMD_OPTION_WAITFORRSP, 0, &offval);
+ mdelay(10);
+
+ res = count;
+@@ -1618,69 +870,69 @@ out_unlock:
+ .write = (fwrite), \
+ }
+
+-struct libertas_debugfs_files {
++struct lbs_debugfs_files {
+ char *name;
+ int perm;
+ struct file_operations fops;
+ };
+
+-static struct libertas_debugfs_files debugfs_files[] = {
+- { "info", 0444, FOPS(libertas_dev_info, write_file_dummy), },
+- { "getscantable", 0444, FOPS(libertas_getscantable,
++static struct lbs_debugfs_files debugfs_files[] = {
++ { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
++ { "getscantable", 0444, FOPS(lbs_getscantable,
+ write_file_dummy), },
+- { "sleepparams", 0644, FOPS(libertas_sleepparams_read,
+- libertas_sleepparams_write), },
+- { "extscan", 0600, FOPS(NULL, libertas_extscan), },
+- { "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), },
++ { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
++ lbs_sleepparams_write), },
++ { "extscan", 0600, FOPS(NULL, lbs_extscan), },
++ { "setuserscan", 0600, FOPS(NULL, lbs_setuserscan), },
+ };
+
+-static struct libertas_debugfs_files debugfs_events_files[] = {
+- {"low_rssi", 0644, FOPS(libertas_lowrssi_read,
+- libertas_lowrssi_write), },
+- {"low_snr", 0644, FOPS(libertas_lowsnr_read,
+- libertas_lowsnr_write), },
+- {"failure_count", 0644, FOPS(libertas_failcount_read,
+- libertas_failcount_write), },
+- {"beacon_missed", 0644, FOPS(libertas_bcnmiss_read,
+- libertas_bcnmiss_write), },
+- {"high_rssi", 0644, FOPS(libertas_highrssi_read,
+- libertas_highrssi_write), },
+- {"high_snr", 0644, FOPS(libertas_highsnr_read,
+- libertas_highsnr_write), },
++static struct lbs_debugfs_files debugfs_events_files[] = {
++ {"low_rssi", 0644, FOPS(lbs_lowrssi_read,
++ lbs_lowrssi_write), },
++ {"low_snr", 0644, FOPS(lbs_lowsnr_read,
++ lbs_lowsnr_write), },
++ {"failure_count", 0644, FOPS(lbs_failcount_read,
++ lbs_failcount_write), },
++ {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
++ lbs_bcnmiss_write), },
++ {"high_rssi", 0644, FOPS(lbs_highrssi_read,
++ lbs_highrssi_write), },
++ {"high_snr", 0644, FOPS(lbs_highsnr_read,
++ lbs_highsnr_write), },
+ };
+
+-static struct libertas_debugfs_files debugfs_regs_files[] = {
+- {"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), },
+- {"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), },
+- {"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), },
+- {"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), },
+- {"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), },
+- {"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), },
++static struct lbs_debugfs_files debugfs_regs_files[] = {
++ {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
++ {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
++ {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
++ {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
++ {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
++ {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
+ };
+
+-void libertas_debugfs_init(void)
++void lbs_debugfs_init(void)
+ {
+- if (!libertas_dir)
+- libertas_dir = debugfs_create_dir("libertas_wireless", NULL);
++ if (!lbs_dir)
++ lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
+
+ return;
+ }
+
+-void libertas_debugfs_remove(void)
++void lbs_debugfs_remove(void)
+ {
+- if (libertas_dir)
+- debugfs_remove(libertas_dir);
++ if (lbs_dir)
++ debugfs_remove(lbs_dir);
+ return;
+ }
+
+-void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev)
++void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
+ {
+ int i;
+- struct libertas_debugfs_files *files;
+- if (!libertas_dir)
++ struct lbs_debugfs_files *files;
++ if (!lbs_dir)
+ goto exit;
+
+- priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir);
++ priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
+ if (!priv->debugfs_dir)
+ goto exit;
+
+@@ -1720,13 +972,13 @@ void libertas_debugfs_init_one(wlan_priv
+ }
+
+ #ifdef PROC_DEBUG
+- libertas_debug_init(priv, dev);
++ lbs_debug_init(priv, dev);
+ #endif
+ exit:
+ return;
+ }
+
+-void libertas_debugfs_remove_one(wlan_private *priv)
++void lbs_debugfs_remove_one(struct lbs_private *priv)
+ {
+ int i;
+
+@@ -1753,8 +1005,8 @@ void libertas_debugfs_remove_one(wlan_pr
+
+ #ifdef PROC_DEBUG
+
+-#define item_size(n) (FIELD_SIZEOF(wlan_adapter, n))
+-#define item_addr(n) (offsetof(wlan_adapter, n))
++#define item_size(n) (FIELD_SIZEOF(struct lbs_private, n))
++#define item_addr(n) (offsetof(struct lbs_private, n))
+
+
+ struct debug_data {
+@@ -1763,7 +1015,7 @@ struct debug_data {
+ size_t addr;
+ };
+
+-/* To debug any member of wlan_adapter, simply add one line here.
++/* To debug any member of struct lbs_private, simply add one line here.
+ */
+ static struct debug_data items[] = {
+ {"intcounter", item_size(intcounter), item_addr(intcounter)},
+@@ -1784,7 +1036,7 @@ static int num_of_items = ARRAY_SIZE(ite
+ * @param data data to output
+ * @return number of output data
+ */
+-static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf,
++static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+ {
+ int val = 0;
+@@ -1828,7 +1080,7 @@ static ssize_t wlan_debugfs_read(struct
+ * @param data data to write
+ * @return number of data
+ */
+-static ssize_t wlan_debugfs_write(struct file *f, const char __user *buf,
++static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
+ size_t cnt, loff_t *ppos)
+ {
+ int r, i;
+@@ -1839,7 +1091,7 @@ static ssize_t wlan_debugfs_write(struct
+ char *p2;
+ struct debug_data *d = (struct debug_data *)f->private_data;
+
+- pdata = (char *)kmalloc(cnt, GFP_KERNEL);
++ pdata = kmalloc(cnt, GFP_KERNEL);
+ if (pdata == NULL)
+ return 0;
+
+@@ -1880,21 +1132,21 @@ static ssize_t wlan_debugfs_write(struct
+ return (ssize_t)cnt;
+ }
+
+-static struct file_operations libertas_debug_fops = {
++static struct file_operations lbs_debug_fops = {
+ .owner = THIS_MODULE,
+ .open = open_file_generic,
+- .write = wlan_debugfs_write,
+- .read = wlan_debugfs_read,
++ .write = lbs_debugfs_write,
++ .read = lbs_debugfs_read,
+ };
+
+ /**
+ * @brief create debug proc file
+ *
+- * @param priv pointer wlan_private
++ * @param priv pointer struct lbs_private
+ * @param dev pointer net_device
+ * @return N/A
+ */
+-static void libertas_debug_init(wlan_private * priv, struct net_device *dev)
++static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev)
+ {
+ int i;
+
+@@ -1902,11 +1154,10 @@ static void libertas_debug_init(wlan_pri
+ return;
+
+ for (i = 0; i < num_of_items; i++)
+- items[i].addr += (size_t) priv->adapter;
++ items[i].addr += (size_t) priv;
+
+ priv->debugfs_debug = debugfs_create_file("debug", 0644,
+ priv->debugfs_dir, &items[0],
+- &libertas_debug_fops);
++ &lbs_debug_fops);
+ }
+ #endif
+-
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/debugfs.h linux-2.6.22-300/drivers/net/wireless/libertas/debugfs.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/debugfs.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/debugfs.h 2008-05-27 16:42:14.000000000 -0400
+@@ -1,6 +1,10 @@
+-void libertas_debugfs_init(void);
+-void libertas_debugfs_remove(void);
++#ifndef _LBS_DEBUGFS_H_
++#define _LBS_DEBUGFS_H_
+
+-void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev);
+-void libertas_debugfs_remove_one(wlan_private *priv);
++void lbs_debugfs_init(void);
++void lbs_debugfs_remove(void);
+
++void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev);
++void lbs_debugfs_remove_one(struct lbs_private *priv);
++
++#endif
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/decl.h linux-2.6.22-300/drivers/net/wireless/libertas/decl.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/decl.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/decl.h 2008-06-05 18:10:06.000000000 -0400
+@@ -3,89 +3,78 @@
+ * functions defined in other source files
+ */
+
+-#ifndef _WLAN_DECL_H_
+-#define _WLAN_DECL_H_
++#ifndef _LBS_DECL_H_
++#define _LBS_DECL_H_
+
+ #include <linux/device.h>
+
+ #include "defs.h"
+
+ /** Function Prototype Declaration */
+-struct wlan_private;
++struct lbs_private;
+ struct sk_buff;
+ struct net_device;
+-
+-extern char *libertas_fw_name;
+-
+-void libertas_free_adapter(wlan_private * priv);
+-int libertas_set_mac_packet_filter(wlan_private * priv);
+-
+-int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt);
+-void libertas_send_tx_feedback(wlan_private * priv);
+-u8 libertas_check_last_packet_indication(wlan_private * priv);
+-
+-int libertas_free_cmd_buffer(wlan_private * priv);
+ struct cmd_ctrl_node;
+-struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv);
++struct cmd_ds_command;
+
+-void libertas_set_cmd_ctrl_node(wlan_private * priv,
+- struct cmd_ctrl_node *ptempnode,
+- u32 cmd_oid, u16 wait_option, void *pdata_buf);
+-
+-int libertas_prepare_and_send_command(wlan_private * priv,
+- u16 cmd_no,
+- u16 cmd_action,
+- u16 wait_option, u32 cmd_oid, void *pdata_buf);
+-
+-void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail);
+-
+-int libertas_allocate_cmd_buffer(wlan_private * priv);
+-int libertas_execute_next_command(wlan_private * priv);
+-int libertas_process_event(wlan_private * priv);
+-void libertas_interrupt(struct net_device *);
+-int libertas_set_radio_control(wlan_private * priv);
+-u32 libertas_index_to_data_rate(u8 index);
+-u8 libertas_data_rate_to_index(u32 rate);
+-void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen);
+-
+-void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
+-
+-/** The proc fs interface */
+-int libertas_process_rx_command(wlan_private * priv);
+-int libertas_process_tx(wlan_private * priv, struct sk_buff *skb);
+-void libertas_cleanup_and_insert_cmd(wlan_private * priv,
+- struct cmd_ctrl_node *ptempcmd);
+-void __libertas_cleanup_and_insert_cmd(wlan_private * priv,
+- struct cmd_ctrl_node *ptempcmd);
++void lbs_set_mac_control(struct lbs_private *priv);
+
+-int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band);
++void lbs_send_tx_feedback(struct lbs_private *priv);
+
+-int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *);
++int lbs_free_cmd_buffer(struct lbs_private *priv);
+
+-void libertas_ps_sleep(wlan_private * priv, int wait_option);
+-void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode);
+-void libertas_ps_wakeup(wlan_private * priv, int wait_option);
++int lbs_prepare_and_send_command(struct lbs_private *priv,
++ u16 cmd_no,
++ u16 cmd_action,
++ u16 wait_option, u32 cmd_oid, void *pdata_buf);
++
++int lbs_allocate_cmd_buffer(struct lbs_private *priv);
++int lbs_execute_next_command(struct lbs_private *priv);
++int lbs_process_event(struct lbs_private *priv);
++void lbs_interrupt(struct lbs_private *priv);
++int lbs_set_radio_control(struct lbs_private *priv);
++u32 lbs_fw_index_to_data_rate(u8 index);
++u8 lbs_data_rate_to_fw_index(u32 rate);
++void lbs_get_fwversion(struct lbs_private *priv,
++ char *fwversion,
++ int maxlen);
+
+-void libertas_tx_runqueue(wlan_private *priv);
+-
+-struct chan_freq_power *libertas_find_cfp_by_band_and_channel(
+- wlan_adapter * adapter, u8 band, u16 channel);
+-
+-void libertas_mac_event_disconnected(wlan_private * priv);
+-
+-void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str);
+-
+-/* fw.c */
+-int libertas_init_fw(wlan_private * priv, char *fw_name);
++/** The proc fs interface */
++int lbs_process_rx_command(struct lbs_private *priv);
++void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
++ int result);
++int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
++int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
++
++int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *);
++
++void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
++void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode);
++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 *libertas_get_region_cfp_table(u8 region, u8 band,
+- int *cfp_no);
+-wlan_private *libertas_add_card(void *card, struct device *dmdev);
+-int libertas_activate_card(wlan_private *priv, char *fw_name);
+-int libertas_remove_card(wlan_private *priv);
+-int libertas_add_mesh(wlan_private *priv, struct device *dev);
+-void libertas_remove_mesh(wlan_private *priv);
+-
++struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
++ u8 band,
++ int *cfp_no);
++struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
++int lbs_remove_card(struct lbs_private *priv);
++int lbs_start_card(struct lbs_private *priv);
++int lbs_stop_card(struct lbs_private *priv);
++int lbs_reset_device(struct lbs_private *priv);
++void lbs_host_to_card_done(struct lbs_private *priv);
+
+-#endif /* _WLAN_DECL_H_ */
++int lbs_update_channel(struct lbs_private *priv);
++#endif
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/defs.h linux-2.6.22-300/drivers/net/wireless/libertas/defs.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/defs.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/defs.h 2008-06-05 18:10:06.000000000 -0400
+@@ -2,8 +2,8 @@
+ * This header file contains global constant/enum definitions,
+ * global variable declaration.
+ */
+-#ifndef _WLAN_DEFS_H_
+-#define _WLAN_DEFS_H_
++#ifndef _LBS_DEFS_H_
++#define _LBS_DEFS_H_
+
+ #include <linux/spinlock.h>
+
+@@ -39,47 +39,51 @@
+ #define LBS_DEB_FW 0x00080000
+ #define LBS_DEB_THREAD 0x00100000
+ #define LBS_DEB_HEX 0x00200000
++#define LBS_DEB_SDIO 0x00400000
++#define LBS_DEB_SYSFS 0x00800000
+
+-extern unsigned int libertas_debug;
++extern unsigned int lbs_debug;
+
+ #ifdef DEBUG
+-#define LBS_DEB_LL(grp, fmt, args...) \
+-do { if ((libertas_debug & (grp)) == (grp)) \
+- printk(KERN_DEBUG DRV_NAME "%s: " fmt, \
++#define LBS_DEB_LL(grp, grpnam, fmt, args...) \
++do { if ((lbs_debug & (grp)) == (grp)) \
++ printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \
+ in_interrupt() ? " (INT)" : "", ## args); } while (0)
+ #else
+-#define LBS_DEB_LL(grp, fmt, args...) do {} while (0)
++#define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0)
+ #endif
+
+ #define lbs_deb_enter(grp) \
+- LBS_DEB_LL(grp | LBS_DEB_ENTER, "%s():%d enter\n", __FUNCTION__, __LINE__);
++ LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s():%d\n", __FUNCTION__, __LINE__);
+ #define lbs_deb_enter_args(grp, fmt, args...) \
+- LBS_DEB_LL(grp | LBS_DEB_ENTER, "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__);
++ LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__);
+ #define lbs_deb_leave(grp) \
+- LBS_DEB_LL(grp | LBS_DEB_LEAVE, "%s():%d leave\n", __FUNCTION__, __LINE__);
++ LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d\n", __FUNCTION__, __LINE__);
+ #define lbs_deb_leave_args(grp, fmt, args...) \
+- LBS_DEB_LL(grp | LBS_DEB_LEAVE, "%s():%d leave, " fmt "\n", \
++ LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d, " fmt "\n", \
+ __FUNCTION__, __LINE__, ##args);
+-#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, fmt, ##args)
+-#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, fmt, ##args)
+-#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, fmt, ##args)
+-#define lbs_deb_wext(fmt, args...) LBS_DEB_LL(LBS_DEB_WEXT, fmt, ##args)
+-#define lbs_deb_ioctl(fmt, args...) LBS_DEB_LL(LBS_DEB_IOCTL, fmt, ##args)
+-#define lbs_deb_scan(fmt, args...) LBS_DEB_LL(LBS_DEB_SCAN, fmt, ##args)
+-#define lbs_deb_assoc(fmt, args...) LBS_DEB_LL(LBS_DEB_ASSOC, fmt, ##args)
+-#define lbs_deb_join(fmt, args...) LBS_DEB_LL(LBS_DEB_JOIN, fmt, ##args)
+-#define lbs_deb_11d(fmt, args...) LBS_DEB_LL(LBS_DEB_11D, fmt, ##args)
+-#define lbs_deb_debugfs(fmt, args...) LBS_DEB_LL(LBS_DEB_DEBUGFS, fmt, ##args)
+-#define lbs_deb_ethtool(fmt, args...) LBS_DEB_LL(LBS_DEB_ETHTOOL, fmt, ##args)
+-#define lbs_deb_host(fmt, args...) LBS_DEB_LL(LBS_DEB_HOST, fmt, ##args)
+-#define lbs_deb_cmd(fmt, args...) LBS_DEB_LL(LBS_DEB_CMD, fmt, ##args)
+-#define lbs_deb_rx(fmt, args...) LBS_DEB_LL(LBS_DEB_RX, fmt, ##args)
+-#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, fmt, ##args)
+-#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, fmt, ##args)
+-#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, fmt, ##args)
+-#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, "%s:" fmt, (dev)->bus_id, ##args)
+-#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, fmt, ##args)
+-#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, fmt, ##args)
++#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args)
++#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args)
++#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args)
++#define lbs_deb_wext(fmt, args...) LBS_DEB_LL(LBS_DEB_WEXT, " wext", fmt, ##args)
++#define lbs_deb_ioctl(fmt, args...) LBS_DEB_LL(LBS_DEB_IOCTL, " ioctl", fmt, ##args)
++#define lbs_deb_scan(fmt, args...) LBS_DEB_LL(LBS_DEB_SCAN, " scan", fmt, ##args)
++#define lbs_deb_assoc(fmt, args...) LBS_DEB_LL(LBS_DEB_ASSOC, " assoc", fmt, ##args)
++#define lbs_deb_join(fmt, args...) LBS_DEB_LL(LBS_DEB_JOIN, " join", fmt, ##args)
++#define lbs_deb_11d(fmt, args...) LBS_DEB_LL(LBS_DEB_11D, " 11d", fmt, ##args)
++#define lbs_deb_debugfs(fmt, args...) LBS_DEB_LL(LBS_DEB_DEBUGFS, " debugfs", fmt, ##args)
++#define lbs_deb_ethtool(fmt, args...) LBS_DEB_LL(LBS_DEB_ETHTOOL, " ethtool", fmt, ##args)
++#define lbs_deb_host(fmt, args...) LBS_DEB_LL(LBS_DEB_HOST, " host", fmt, ##args)
++#define lbs_deb_cmd(fmt, args...) LBS_DEB_LL(LBS_DEB_CMD, " cmd", fmt, ##args)
++#define lbs_deb_rx(fmt, args...) LBS_DEB_LL(LBS_DEB_RX, " rx", fmt, ##args)
++#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args)
++#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args)
++#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args)
++#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
++#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
++#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
++#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
++#define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args)
+
+ #define lbs_pr_info(format, args...) \
+ printk(KERN_INFO DRV_NAME": " format, ## args)
+@@ -89,22 +93,28 @@ do { if ((libertas_debug & (grp)) == (gr
+ printk(KERN_ALERT DRV_NAME": " format, ## args)
+
+ #ifdef DEBUG
+-static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
++static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
+ {
+ int i = 0;
+
+- if (!(libertas_debug & LBS_DEB_HEX))
+- return;
+-
+- printk(KERN_DEBUG "%s: ", prompt);
+- for (i = 1; i <= len; i++) {
+- printk("%02x ", (u8) * buf);
+- buf++;
++ if (len &&
++ (lbs_debug & LBS_DEB_HEX) &&
++ (lbs_debug & grp))
++ {
++ for (i = 1; i <= len; i++) {
++ if ((i & 0xf) == 1) {
++ if (i != 1)
++ printk("\n");
++ printk(DRV_NAME " %s: ", prompt);
++ }
++ printk("%02x ", (u8) * buf);
++ buf++;
++ }
++ printk("\n");
+ }
+- printk("\n");
+ }
+ #else
+-#define lbs_dbg_hex(x,y,z) do {} while (0)
++#define lbs_deb_hex(grp,prompt,buf,len) do {} while (0)
+ #endif
+
+
+@@ -124,15 +134,22 @@ static inline void lbs_dbg_hex(char *pro
+ */
+
+ #define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
+-#define MRVDRV_NUM_OF_CMD_BUFFER 10
+-#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
++#define LBS_NUM_CMD_BUFFERS 10
++#define LBS_CMD_BUFFER_SIZE (2 * 1024)
+ #define MRVDRV_MAX_CHANNEL_SIZE 14
+ #define MRVDRV_ASSOCIATION_TIME_OUT 255
+ #define MRVDRV_SNAP_HEADER_LEN 8
+
+-#define WLAN_UPLD_SIZE 2312
++#define LBS_UPLD_SIZE 2312
+ #define DEV_NAME_LEN 32
+
++/* Wake criteria for HOST_SLEEP_CFG command */
++#define EHS_WAKE_ON_BROADCAST_DATA 0x0001
++#define EHS_WAKE_ON_UNICAST_DATA 0x0002
++#define EHS_WAKE_ON_MAC_EVENT 0x0004
++#define EHS_WAKE_ON_MULTICAST_DATA 0x0008
++#define EHS_REMOVE_WAKEUP 0xFFFFFFFF
++
+ /** Misc constants */
+ /* This section defines 802.11 specific contants */
+
+@@ -149,17 +166,28 @@ static inline void lbs_dbg_hex(char *pro
+ #define MRVDRV_CHANNELS_PER_SCAN 4
+ #define MRVDRV_MAX_CHANNELS_PER_SCAN 14
+
+-#define MRVDRV_DEBUG_RX_PATH 0x00000001
+-#define MRVDRV_DEBUG_TX_PATH 0x00000002
+-
+ #define MRVDRV_MIN_BEACON_INTERVAL 20
+ #define MRVDRV_MAX_BEACON_INTERVAL 1000
+ #define MRVDRV_BEACON_INTERVAL 100
+
++#define MARVELL_MESH_IE_LENGTH 9
++
++/* Values used to populate the struct mrvl_mesh_ie. The only time you need this
++ * is when enabling the mesh using CMD_MESH_CONFIG.
++ */
++#define MARVELL_MESH_IE_TYPE 4
++#define MARVELL_MESH_IE_SUBTYPE 0
++#define MARVELL_MESH_IE_VERSION 0
++#define MARVELL_MESH_PROTO_ID_HWMP 0
++#define MARVELL_MESH_METRIC_ID 0
++#define MARVELL_MESH_CAPABILITY 0
++
+ /** INT status Bit Definition*/
+-#define his_cmddnldrdy 0x01
+-#define his_cardevent 0x02
+-#define his_cmdupldrdy 0x04
++#define MRVDRV_TX_DNLD_RDY 0x0001
++#define MRVDRV_RX_UPLD_RDY 0x0002
++#define MRVDRV_CMD_DNLD_RDY 0x0004
++#define MRVDRV_CMD_UPLD_RDY 0x0008
++#define MRVDRV_CARDEVENT 0x0010
+
+ #define SBI_EVENT_CAUSE_SHIFT 3
+
+@@ -218,9 +246,6 @@ static inline void lbs_dbg_hex(char *pro
+ #define CMD_F_HOSTCMD (1 << 0)
+ #define FW_CAPINFO_WPA (1 << 0)
+
+-/** WPA key LENGTH*/
+-#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32
+-
+ #define KEY_LEN_WPA_AES 16
+ #define KEY_LEN_WPA_TKIP 32
+ #define KEY_LEN_WEP_104 13
+@@ -247,28 +272,15 @@ static inline void lbs_dbg_hex(char *pro
+ ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
+ AVG_SCALE)) / N))
+
+-#define B_SUPPORTED_RATES 8
+-#define G_SUPPORTED_RATES 14
+-
+-#define WLAN_SUPPORTED_RATES 14
++#define MAX_RATES 14
+
+ #define MAX_LEDS 8
+
+-#define IS_MESH_FRAME(x) (x->cb[6])
+-#define SET_MESH_FRAME(x) (x->cb[6]=1)
+-#define UNSET_MESH_FRAME(x) (x->cb[6]=0)
+-
+ /** Global Variable Declaration */
+-typedef struct _wlan_private wlan_private;
+-typedef struct _wlan_adapter wlan_adapter;
+-extern const char libertas_driver_version[];
+-extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE];
++extern const char lbs_driver_version[];
++extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE];
+
+-extern u8 libertas_supported_rates[G_SUPPORTED_RATES];
+-
+-extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES];
+-
+-extern u8 libertas_adhoc_rates_b[4];
++extern u8 lbs_bg_rates[MAX_RATES];
+
+ /** ENUM definition*/
+ /** SNRNF_TYPE */
+@@ -285,13 +297,13 @@ enum SNRNF_DATA {
+ MAX_TYPE_AVG
+ };
+
+-/** WLAN_802_11_POWER_MODE */
+-enum WLAN_802_11_POWER_MODE {
+- wlan802_11powermodecam,
+- wlan802_11powermodemax_psp,
+- wlan802_11Powermodefast_psp,
++/** LBS_802_11_POWER_MODE */
++enum LBS_802_11_POWER_MODE {
++ LBS802_11POWERMODECAM,
++ LBS802_11POWERMODEMAX_PSP,
++ LBS802_11POWERMODEFAST_PSP,
+ /*not a real mode, defined as an upper bound */
+- wlan802_11powemodemax
++ LBS802_11POWEMODEMAX
+ };
+
+ /** PS_STATE */
+@@ -309,16 +321,16 @@ enum DNLD_STATE {
+ DNLD_CMD_SENT
+ };
+
+-/** WLAN_MEDIA_STATE */
+-enum WLAN_MEDIA_STATE {
+- libertas_connected,
+- libertas_disconnected
++/** LBS_MEDIA_STATE */
++enum LBS_MEDIA_STATE {
++ LBS_CONNECTED,
++ LBS_DISCONNECTED
+ };
+
+-/** WLAN_802_11_PRIVACY_FILTER */
+-enum WLAN_802_11_PRIVACY_FILTER {
+- wlan802_11privfilteracceptall,
+- wlan802_11privfilter8021xWEP
++/** LBS_802_11_PRIVACY_FILTER */
++enum LBS_802_11_PRIVACY_FILTER {
++ LBS802_11PRIVFILTERACCEPTALL,
++ LBS802_11PRIVFILTER8021XWEP
+ };
+
+ /** mv_ms_type */
+@@ -331,23 +343,23 @@ enum mv_ms_type {
+
+ /** SNMP_MIB_INDEX_e */
+ enum SNMP_MIB_INDEX_e {
+- desired_bsstype_i = 0,
+- op_rateset_i,
+- bcnperiod_i,
+- dtimperiod_i,
+- assocrsp_timeout_i,
+- rtsthresh_i,
+- short_retrylim_i,
+- long_retrylim_i,
+- fragthresh_i,
+- dot11d_i,
+- dot11h_i,
+- manufid_i,
+- prodID_i,
+- manuf_oui_i,
+- manuf_name_i,
+- manuf_prodname_i,
+- manuf_prodver_i,
++ DESIRED_BSSTYPE_I = 0,
++ OP_RATESET_I,
++ BCNPERIOD_I,
++ DTIMPERIOD_I,
++ ASSOCRSP_TIMEOUT_I,
++ RTSTHRESH_I,
++ SHORT_RETRYLIM_I,
++ LONG_RETRYLIM_I,
++ FRAGTHRESH_I,
++ DOT11D_I,
++ DOT11H_I,
++ MANUFID_I,
++ PRODID_I,
++ MANUF_OUI_I,
++ MANUF_NAME_I,
++ MANUF_PRODNAME_I,
++ MANUF_PRODVER_I,
+ };
+
+ /** KEY_TYPE_ID */
+@@ -383,4 +395,4 @@ enum SNMP_MIB_VALUE_e {
+ #define FWT_DEFAULT_SLEEPMODE 0
+ #define FWT_DEFAULT_SNR 0
+
+-#endif /* _WLAN_DEFS_H_ */
++#endif
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/dev.h linux-2.6.22-300/drivers/net/wireless/libertas/dev.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/dev.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/dev.h 2008-06-05 18:10:06.000000000 -0400
+@@ -1,22 +1,20 @@
+ /**
+ * This file contains definitions and data structures specific
+ * to Marvell 802.11 NIC. It contains the Device Information
+- * structure wlan_adapter.
++ * structure struct lbs_private..
+ */
+-#ifndef _WLAN_DEV_H_
+-#define _WLAN_DEV_H_
++#ifndef _LBS_DEV_H_
++#define _LBS_DEV_H_
+
+ #include <linux/netdevice.h>
+ #include <linux/wireless.h>
+ #include <linux/ethtool.h>
+ #include <linux/debugfs.h>
+-#include <net/ieee80211.h>
+
+ #include "defs.h"
+ #include "scan.h"
+-#include "thread.h"
+
+-extern struct ethtool_ops libertas_ethtool_ops;
++extern struct ethtool_ops lbs_ethtool_ops;
+
+ #define MAX_BSSID_PER_CHANNEL 16
+
+@@ -54,7 +52,7 @@ struct region_channel {
+ struct chan_freq_power *CFP;
+ };
+
+-struct wlan_802_11_security {
++struct lbs_802_11_security {
+ u8 WPAenabled;
+ u8 WPA2enabled;
+ u8 wep_enabled;
+@@ -73,10 +71,8 @@ struct current_bss_params {
+ u8 band;
+ /** channel */
+ u8 channel;
+- /** number of rates supported */
+- int numofrates;
+- /** supported rates*/
+- u8 datarates[WLAN_SUPPORTED_RATES];
++ /** zero-terminated array of supported data rates */
++ u8 rates[MAX_RATES + 1];
+ };
+
+ /** sleep_params */
+@@ -90,7 +86,7 @@ struct sleep_params {
+ };
+
+ /* Mesh statistics */
+-struct wlan_mesh_stats {
++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 */
+@@ -102,22 +98,23 @@ struct wlan_mesh_stats {
+ };
+
+ /** Private structure for the MV device */
+-struct _wlan_private {
+- int open;
++struct lbs_private {
+ int mesh_open;
+ int infra_open;
++ int mesh_autostart_enabled;
++ __le16 boot2_version;
+
+ char name[DEV_NAME_LEN];
+
+ void *card;
+- wlan_adapter *adapter;
+ struct net_device *dev;
+
+ struct net_device_stats stats;
+- struct net_device *mesh_dev ; /* Virtual device */
++ struct net_device *mesh_dev; /* Virtual device */
++ struct net_device *rtap_net_dev;
+
+ struct iw_statistics wstats;
+- struct wlan_mesh_stats mstats;
++ struct lbs_mesh_stats mstats;
+ struct dentry *debugfs_dir;
+ struct dentry *debugfs_debug;
+ struct dentry *debugfs_files[6];
+@@ -135,78 +132,37 @@ struct _wlan_private {
+ /** Upload length */
+ u32 upld_len;
+ /* Upload buffer */
+- u8 upld_buf[WLAN_UPLD_SIZE];
++ u8 upld_buf[LBS_UPLD_SIZE];
+ /* 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;
+
+- const struct firmware *firmware;
+- struct device *hotplug_device;
+-
+ /** thread to service interrupts */
+- struct wlan_thread mainthread;
++ struct task_struct *main_thread;
++ wait_queue_head_t waitq;
++ struct workqueue_struct *work_thread;
++
++ struct work_struct mcast_work;
+
++ struct delayed_work scan_work;
+ struct delayed_work assoc_work;
+- struct workqueue_struct *assoc_thread;
+ struct work_struct sync_channel;
+
+ /** Hardware access */
+- int (*hw_register_dev) (wlan_private * priv);
+- int (*hw_unregister_dev) (wlan_private *);
+- int (*hw_prog_firmware) (wlan_private *);
+- int (*hw_host_to_card) (wlan_private * priv, u8 type, u8 * payload, u16 nb);
+- int (*hw_get_int_status) (wlan_private * priv, u8 *);
+- int (*hw_read_event_cause) (wlan_private *);
+-};
+-
+-/** 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];
++ int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
++ int (*hw_get_int_status) (struct lbs_private *priv, u8 *);
++ int (*hw_read_event_cause) (struct lbs_private *);
++
++ /* Wake On LAN */
++ uint32_t wol_criteria;
++ uint8_t wol_gpio;
++ uint8_t wol_gap;
+
+- /** WEP keys */
+- struct WLAN_802_11_KEY wep_keys[4];
+- u16 wep_tx_keyidx;
+-
+- /** WPA keys */
+- struct WLAN_802_11_KEY wpa_mcast_key;
+- struct WLAN_802_11_KEY wpa_unicast_key;
+-
+- struct wlan_802_11_security secinfo;
++ /* was struct lbs_adapter from here... */
+
+- /** 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;
+-};
+-
+-/** Wlan adapter data structure*/
+-struct _wlan_adapter {
++ /** Wlan adapter data structure*/
+ /** STATUS variables */
+ u8 fwreleasenumber[4];
+ u32 fwcapinfo;
+@@ -214,7 +170,10 @@ struct _wlan_adapter {
+
+ struct mutex lock;
+
+- u8 tmptxbuf[WLAN_UPLD_SIZE];
++ /* 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 */
+@@ -232,8 +191,7 @@ struct _wlan_adapter {
+ struct list_head cmdpendingq;
+
+ wait_queue_head_t cmd_pending;
+- u8 nr_cmd_pending;
+- /* command related variables protected by adapter->driver_lock */
++ /* command related variables protected by priv->driver_lock */
+
+ /** Async and Sync Event variables */
+ u32 intcounter;
+@@ -245,37 +203,32 @@ struct _wlan_adapter {
+
+ /** Timers */
+ struct timer_list command_timer;
+-
+- /* TX queue used in PS mode */
+- spinlock_t txqueue_lock;
+- struct sk_buff *tx_queue_ps[NR_TX_QUEUE];
+- unsigned int tx_queue_idx;
++ int nr_retries;
++ int cmd_timed_out;
+
+ u8 hisregcpy;
+
+ /** current ssid/bssid related parameters*/
+ struct current_bss_params curbssparams;
+
++ uint16_t mesh_tlv;
++ u8 mesh_ssid[IW_ESSID_MAX_SIZE + 1];
++ u8 mesh_ssid_len;
++
+ /* IW_MODE_* */
+ u8 mode;
+
+- u8 prev_ssid[IW_ESSID_MAX_SIZE + 1];
+- u8 prev_ssid_len;
+- u8 prev_bssid[ETH_ALEN];
+-
+ /* Scan results list */
+ struct list_head network_list;
+ struct list_head network_free_list;
+ struct bss_descriptor *networks;
+
+- u8 scantype;
+- u32 scanmode;
+-
+- u16 beaconperiod;
++ u16 beacon_period;
++ u8 beacon_enable;
+ u8 adhoccreate;
+
+ /** capability Info used in Association, start, join */
+- struct ieeetypes_capinfo capinfo;
++ u16 capability;
+
+ /** MAC address information */
+ u8 current_addr[ETH_ALEN];
+@@ -287,71 +240,53 @@ struct _wlan_adapter {
+
+ u16 enablehwauto;
+ u16 ratebitmap;
+- /** control G rates */
+- u8 adhoc_grate_enabled;
+-
+- u32 txantenna;
+- u32 rxantenna;
+
+ u32 fragthsd;
+ u32 rtsthsd;
+
+- u32 datarate;
+- u8 is_datarate_auto;
+-
+- u16 listeninterval;
+- u16 prescan;
+ u8 txretrycount;
+
+ /** Tx-related variables (for single packet tx) */
+ struct sk_buff *currenttxskb;
+- u16 TxLockFlag;
+
+ /** NIC Operation characteristics */
+- u16 currentpacketfilter;
++ u16 mac_control;
+ u32 connect_status;
++ u32 mesh_connect_status;
+ u16 regioncode;
+- u16 regiontableindex;
+ u16 txpowerlevel;
+
+ /** POWER MANAGEMENT AND PnP SUPPORT */
+ u8 surpriseremoved;
+- u16 atimwindow;
+
+ u16 psmode; /* Wlan802_11PowermodeCAM=disable
+ Wlan802_11PowermodeMAX_PSP=enable */
+- u16 multipledtim;
+ u32 psstate;
++ char ps_supported;
+ u8 needtowakeup;
+
+- struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep;
+- u16 locallisteninterval;
+- u16 nullpktinterval;
++ struct PS_CMD_ConfirmSleep lbs_ps_confirm_sleep;
++ struct cmd_header lbs_ps_confirm_wake;
+
+ struct assoc_request * pending_assoc_req;
+ struct assoc_request * in_progress_assoc_req;
+
+ /** Encryption parameter */
+- struct wlan_802_11_security secinfo;
++ struct lbs_802_11_security secinfo;
+
+ /** WEP keys */
+- struct WLAN_802_11_KEY wep_keys[4];
++ struct enc_key wep_keys[4];
+ u16 wep_tx_keyidx;
+
+ /** WPA keys */
+- struct WLAN_802_11_KEY wpa_mcast_key;
+- struct WLAN_802_11_KEY wpa_unicast_key;
++ struct enc_key wpa_mcast_key;
++ struct enc_key wpa_unicast_key;
+
+ /** WPA Information Elements*/
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ u8 wpa_ie_len;
+
+- u16 rxantennamode;
+- u16 txantennamode;
+-
+ /** Requested Signal Strength*/
+- u16 bcn_avg_factor;
+- u16 data_avg_factor;
+ u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
+ u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
+ u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
+@@ -359,15 +294,13 @@ struct _wlan_adapter {
+ u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
+ u16 nextSNRNF;
+ u16 numSNRNF;
+- u16 rxpd_rate;
+
+ u8 radioon;
+ u32 preamble;
+
+- /** Multi bands Parameter*/
+- u8 libertas_supported_rates[G_SUPPORTED_RATES];
+-
+- /** Blue Tooth Co-existence Arbitration */
++ /** data rate stuff */
++ u8 cur_rate;
++ u8 auto_rate;
+
+ /** sleep_params */
+ struct sleep_params sp;
+@@ -381,7 +314,7 @@ struct _wlan_adapter {
+ struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM];
+
+ /** 11D and Domain Regulatory Data */
+- struct wlan_802_11d_domain_reg domainreg;
++ struct lbs_802_11d_domain_reg domainreg;
+ struct parsed_region_chan_11d parsed_region_chan;
+
+ /** FSM variable for 11d support */
+@@ -389,20 +322,57 @@ struct _wlan_adapter {
+
+ /** MISCELLANEOUS */
+ u8 *prdeeprom;
+- struct wlan_offset_value offsetvalue;
++ struct lbs_offset_value offsetvalue;
+
+ struct cmd_ds_802_11_get_log logmsg;
+- u16 scanprobes;
+-
+- u32 pkttxctrl;
+
+- u16 txrate;
+- u32 linkmode;
+- u32 radiomode;
+- u32 debugmode;
++ u32 monitormode;
++ int last_scanned_channel;
+ u8 fw_ready;
++};
+
+- u8 last_scanned_channel;
++/** 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];
++
++ /** 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 /* _WLAN_DEV_H_ */
++#endif
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/ethtool.c linux-2.6.22-300/drivers/net/wireless/libertas/ethtool.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/ethtool.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/ethtool.c 2008-06-05 18:10:06.000000000 -0400
+@@ -8,6 +8,8 @@
+ #include "dev.h"
+ #include "join.h"
+ #include "wext.h"
++#include "cmd.h"
++
+ static const char * mesh_stat_strings[]= {
+ "drop_duplicate_bcast",
+ "drop_ttl_zero",
+@@ -19,35 +21,34 @@ static const char * mesh_stat_strings[]=
+ "tx_failed_cnt"
+ };
+
+-static void libertas_ethtool_get_drvinfo(struct net_device *dev,
++static void lbs_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+ {
+- wlan_private *priv = (wlan_private *) dev->priv;
++ struct lbs_private *priv = (struct lbs_private *) dev->priv;
+ char fwver[32];
+
+- libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1);
++ lbs_get_fwversion(priv, fwver, sizeof(fwver) - 1);
+
+ strcpy(info->driver, "libertas");
+- strcpy(info->version, libertas_driver_version);
++ strcpy(info->version, lbs_driver_version);
+ strcpy(info->fw_version, fwver);
+ }
+
+ /* All 8388 parts have 16KiB EEPROM size at the time of writing.
+ * In case that changes this needs fixing.
+ */
+-#define LIBERTAS_EEPROM_LEN 16384
++#define LBS_EEPROM_LEN 16384
+
+-static int libertas_ethtool_get_eeprom_len(struct net_device *dev)
++static int lbs_ethtool_get_eeprom_len(struct net_device *dev)
+ {
+- return LIBERTAS_EEPROM_LEN;
++ return LBS_EEPROM_LEN;
+ }
+
+-static int libertas_ethtool_get_eeprom(struct net_device *dev,
++static int lbs_ethtool_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 * bytes)
+ {
+- wlan_private *priv = (wlan_private *) dev->priv;
+- wlan_adapter *adapter = priv->adapter;
+- struct wlan_ioctl_regrdwr regctrl;
++ struct lbs_private *priv = (struct lbs_private *) dev->priv;
++ struct lbs_ioctl_regrdwr regctrl;
+ char *ptr;
+ int ret;
+
+@@ -55,48 +56,47 @@ static int libertas_ethtool_get_eeprom(s
+ regctrl.offset = eeprom->offset;
+ regctrl.NOB = eeprom->len;
+
+- if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN)
++ if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN)
+ return -EINVAL;
+
+ // mutex_lock(&priv->mutex);
+
+- adapter->prdeeprom =
+- (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
+- if (!adapter->prdeeprom)
++ priv->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
++ if (!priv->prdeeprom)
+ return -ENOMEM;
+- memcpy(adapter->prdeeprom, ®ctrl, sizeof(regctrl));
++ memcpy(priv->prdeeprom, ®ctrl, sizeof(regctrl));
+
+ /* +14 is for action, offset, and NOB in
+ * response */
+ lbs_deb_ethtool("action:%d offset: %x NOB: %02x\n",
+ regctrl.action, regctrl.offset, regctrl.NOB);
+
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_eeprom_access,
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_EEPROM_ACCESS,
+ regctrl.action,
+- cmd_option_waitforrsp, 0,
++ CMD_OPTION_WAITFORRSP, 0,
+ ®ctrl);
+
+ if (ret) {
+- if (adapter->prdeeprom)
+- kfree(adapter->prdeeprom);
++ if (priv->prdeeprom)
++ kfree(priv->prdeeprom);
+ goto done;
+ }
+
+ mdelay(10);
+
+- ptr = (char *)adapter->prdeeprom;
++ ptr = (char *)priv->prdeeprom;
+
+ /* skip the command header, but include the "value" u32 variable */
+- ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4;
++ ptr = ptr + sizeof(struct lbs_ioctl_regrdwr) - 4;
+
+ /*
+ * Return the result back to the user
+ */
+ memcpy(bytes, ptr, eeprom->len);
+
+- if (adapter->prdeeprom)
+- kfree(adapter->prdeeprom);
++ if (priv->prdeeprom)
++ kfree(priv->prdeeprom);
+ // mutex_unlock(&priv->mutex);
+
+ ret = 0;
+@@ -106,65 +106,56 @@ done:
+ return ret;
+ }
+
+-static void libertas_ethtool_get_stats(struct net_device * dev,
+- struct ethtool_stats * stats, u64 * data)
++static void lbs_ethtool_get_stats(struct net_device *dev,
++ struct ethtool_stats *stats, uint64_t *data)
+ {
+- wlan_private *priv = dev->priv;
+-
+- lbs_deb_enter(LBS_DEB_ETHTOOL);
+-
+- stats->cmd = ETHTOOL_GSTATS;
+- BUG_ON(stats->n_stats != MESH_STATS_NUM);
+-
+- 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 libertas_ethtool_get_stats_count(struct net_device * dev)
+-{
+- int ret;
+- wlan_private *priv = dev->priv;
++ struct lbs_private *priv = dev->priv;
+ struct cmd_ds_mesh_access mesh_access;
++ int ret;
+
+ lbs_deb_enter(LBS_DEB_ETHTOOL);
+
+ /* Get Mesh Statistics */
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_mesh_access, cmd_act_mesh_get_stats,
+- cmd_option_waitforrsp, 0, &mesh_access);
++ ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
+
+ if (ret) {
+- ret = 0;
+- goto done;
++ 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]);
++ 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;
+
+- ret = MESH_STATS_NUM;
++ lbs_deb_enter(LBS_DEB_ETHTOOL);
++}
+
+-done:
+- lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret);
+- return ret;
++static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset)
++{
++ struct lbs_private *priv = dev->priv;
++
++ if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
++ return MESH_STATS_NUM;
++
++ return -EOPNOTSUPP;
+ }
+
+-static void libertas_ethtool_get_strings (struct net_device * dev,
+- u32 stringset,
+- u8 * s)
++static void lbs_ethtool_get_strings(struct net_device *dev,
++ uint32_t stringset, uint8_t *s)
+ {
+ int i;
+
+@@ -182,12 +173,57 @@ static void libertas_ethtool_get_strings
+ lbs_deb_enter(LBS_DEB_ETHTOOL);
+ }
+
+-struct ethtool_ops libertas_ethtool_ops = {
+- .get_drvinfo = libertas_ethtool_get_drvinfo,
+- .get_eeprom = libertas_ethtool_get_eeprom,
+- .get_eeprom_len = libertas_ethtool_get_eeprom_len,
+- .get_stats_count = libertas_ethtool_get_stats_count,
+- .get_ethtool_stats = libertas_ethtool_get_stats,
+- .get_strings = libertas_ethtool_get_strings,
++static void lbs_ethtool_get_wol(struct net_device *dev,
++ struct ethtool_wolinfo *wol)
++{
++ struct lbs_private *priv = dev->priv;
++
++ if (priv->wol_criteria == 0xffffffff) {
++ /* Interface driver didn't configure wake */
++ wol->supported = wol->wolopts = 0;
++ return;
++ }
++
++ wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY;
++
++ if (priv->wol_criteria & EHS_WAKE_ON_UNICAST_DATA)
++ wol->wolopts |= WAKE_UCAST;
++ if (priv->wol_criteria & EHS_WAKE_ON_MULTICAST_DATA)
++ wol->wolopts |= WAKE_MCAST;
++ if (priv->wol_criteria & EHS_WAKE_ON_BROADCAST_DATA)
++ wol->wolopts |= WAKE_BCAST;
++ if (priv->wol_criteria & EHS_WAKE_ON_MAC_EVENT)
++ wol->wolopts |= WAKE_PHY;
++}
++
++static int lbs_ethtool_set_wol(struct net_device *dev,
++ struct ethtool_wolinfo *wol)
++{
++ struct lbs_private *priv = dev->priv;
++ uint32_t criteria = 0;
++
++ if (priv->wol_criteria == 0xffffffff && wol->wolopts)
++ return -EOPNOTSUPP;
++
++ if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY))
++ return -EOPNOTSUPP;
++
++ if (wol->wolopts & WAKE_UCAST) criteria |= EHS_WAKE_ON_UNICAST_DATA;
++ if (wol->wolopts & WAKE_MCAST) criteria |= EHS_WAKE_ON_MULTICAST_DATA;
++ if (wol->wolopts & WAKE_BCAST) criteria |= EHS_WAKE_ON_BROADCAST_DATA;
++ if (wol->wolopts & WAKE_PHY) criteria |= EHS_WAKE_ON_MAC_EVENT;
++
++ return lbs_host_sleep_cfg(priv, criteria);
++}
++
++struct ethtool_ops lbs_ethtool_ops = {
++ .get_drvinfo = lbs_ethtool_get_drvinfo,
++ .get_eeprom = lbs_ethtool_get_eeprom,
++ .get_eeprom_len = lbs_ethtool_get_eeprom_len,
++ .get_sset_count = lbs_ethtool_get_sset_count,
++ .get_ethtool_stats = lbs_ethtool_get_stats,
++ .get_strings = lbs_ethtool_get_strings,
++ .get_wol = lbs_ethtool_get_wol,
++ .set_wol = lbs_ethtool_set_wol,
+ };
+
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/fw.c linux-2.6.22-300/drivers/net/wireless/libertas/fw.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/fw.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/fw.c 1969-12-31 19:00:00.000000000 -0500
+@@ -1,349 +0,0 @@
+-/**
+- * This file contains the initialization for FW and HW
+- */
+-#include <linux/firmware.h>
+-
+-#include "host.h"
+-#include "defs.h"
+-#include "decl.h"
+-#include "dev.h"
+-#include "wext.h"
+-#include "if_usb.h"
+-
+-/**
+- * @brief This function checks the validity of Boot2/FW image.
+- *
+- * @param data pointer to image
+- * len image length
+- * @return 0 or -1
+- */
+-static int check_fwfile_format(u8 *data, u32 totlen)
+-{
+- u32 bincmd, exit;
+- u32 blksize, offset, len;
+- int ret;
+-
+- ret = 1;
+- exit = len = 0;
+-
+- do {
+- struct fwheader *fwh = (void *)data;
+-
+- bincmd = le32_to_cpu(fwh->dnldcmd);
+- blksize = le32_to_cpu(fwh->datalength);
+- switch (bincmd) {
+- case FW_HAS_DATA_TO_RECV:
+- offset = sizeof(struct fwheader) + blksize;
+- data += offset;
+- len += offset;
+- if (len >= totlen)
+- exit = 1;
+- break;
+- case FW_HAS_LAST_BLOCK:
+- exit = 1;
+- ret = 0;
+- break;
+- default:
+- exit = 1;
+- break;
+- }
+- } while (!exit);
+-
+- if (ret)
+- lbs_pr_err("firmware file format check FAIL\n");
+- else
+- lbs_deb_fw("firmware file format check PASS\n");
+-
+- return ret;
+-}
+-
+-/**
+- * @brief This function downloads firmware image, gets
+- * HW spec from firmware and set basic parameters to
+- * firmware.
+- *
+- * @param priv A pointer to wlan_private structure
+- * @return 0 or -1
+- */
+-static int wlan_setup_station_hw(wlan_private * priv, char *fw_name)
+-{
+- int ret = -1;
+- wlan_adapter *adapter = priv->adapter;
+-
+- lbs_deb_enter(LBS_DEB_FW);
+-
+- if ((ret = request_firmware(&priv->firmware, fw_name,
+- priv->hotplug_device)) < 0) {
+- lbs_pr_err("request_firmware() failed with %#x\n", ret);
+- lbs_pr_err("firmware %s not found\n", fw_name);
+- goto done;
+- }
+-
+- if (check_fwfile_format(priv->firmware->data, priv->firmware->size)) {
+- release_firmware(priv->firmware);
+- goto done;
+- }
+-
+- ret = priv->hw_prog_firmware(priv);
+-
+- release_firmware(priv->firmware);
+-
+- if (ret) {
+- lbs_deb_fw("bootloader in invalid state\n");
+- ret = -1;
+- goto done;
+- }
+-
+- /*
+- * Read MAC address from HW
+- */
+- memset(adapter->current_addr, 0xff, ETH_ALEN);
+-
+- ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec,
+- 0, cmd_option_waitforrsp, 0, NULL);
+-
+- if (ret) {
+- ret = -1;
+- goto done;
+- }
+-
+- libertas_set_mac_packet_filter(priv);
+-
+- /* Get the supported Data rates */
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
+- cmd_act_get_tx_rate,
+- cmd_option_waitforrsp, 0, NULL);
+-
+- if (ret) {
+- ret = -1;
+- goto done;
+- }
+-
+- ret = 0;
+-done:
+- lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+- return ret;
+-}
+-
+-static int wlan_allocate_adapter(wlan_private * priv)
+-{
+- size_t bufsize;
+- wlan_adapter *adapter = priv->adapter;
+-
+- /* Allocate buffer to store the BSSID list */
+- bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
+- adapter->networks = kzalloc(bufsize, GFP_KERNEL);
+- if (!adapter->networks) {
+- lbs_pr_err("Out of memory allocating beacons\n");
+- libertas_free_adapter(priv);
+- return -ENOMEM;
+- }
+-
+- /* Allocate the command buffers */
+- libertas_allocate_cmd_buffer(priv);
+-
+- memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep));
+- adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
+- adapter->libertas_ps_confirm_sleep.command =
+- cpu_to_le16(cmd_802_11_ps_mode);
+- adapter->libertas_ps_confirm_sleep.size =
+- cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
+- adapter->libertas_ps_confirm_sleep.result = 0;
+- adapter->libertas_ps_confirm_sleep.action =
+- cpu_to_le16(cmd_subcmd_sleep_confirmed);
+-
+- return 0;
+-}
+-
+-static void wlan_init_adapter(wlan_private * priv)
+-{
+- wlan_adapter *adapter = priv->adapter;
+- int i;
+-
+- adapter->scanprobes = 0;
+-
+- adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+- adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+-
+- /* ATIM params */
+- adapter->atimwindow = 0;
+-
+- adapter->connect_status = libertas_disconnected;
+- memset(adapter->current_addr, 0xff, ETH_ALEN);
+-
+- /* scan type */
+- adapter->scantype = cmd_scan_type_active;
+-
+- /* scan mode */
+- adapter->scanmode = cmd_bss_type_any;
+-
+- /* 802.11 specific */
+- adapter->secinfo.wep_enabled = 0;
+- for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
+- i++)
+- memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY));
+- adapter->wep_tx_keyidx = 0;
+- adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
+- adapter->mode = IW_MODE_INFRA;
+-
+- adapter->pending_assoc_req = NULL;
+- adapter->in_progress_assoc_req = NULL;
+-
+- /* Initialize scan result lists */
+- INIT_LIST_HEAD(&adapter->network_free_list);
+- INIT_LIST_HEAD(&adapter->network_list);
+- for (i = 0; i < MAX_NETWORK_COUNT; i++) {
+- list_add_tail(&adapter->networks[i].list,
+- &adapter->network_free_list);
+- }
+-
+- mutex_init(&adapter->lock);
+-
+- adapter->prescan = 1;
+-
+- memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
+- adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
+-
+- /* PnP and power profile */
+- adapter->surpriseremoved = 0;
+-
+- adapter->currentpacketfilter =
+- cmd_act_mac_rx_on | cmd_act_mac_tx_on;
+-
+- adapter->radioon = RADIO_ON;
+- adapter->txantenna = RF_ANTENNA_2;
+- adapter->rxantenna = RF_ANTENNA_AUTO;
+-
+- adapter->is_datarate_auto = 1;
+- adapter->beaconperiod = MRVDRV_BEACON_INTERVAL;
+-
+- // set default value of capinfo.
+-#define SHORT_PREAMBLE_ALLOWED 1
+- memset(&adapter->capinfo, 0, sizeof(adapter->capinfo));
+- adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED;
+-
+- adapter->psmode = wlan802_11powermodecam;
+- adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
+-
+- adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
+-
+- adapter->psstate = PS_STATE_FULL_POWER;
+- adapter->needtowakeup = 0;
+- adapter->locallisteninterval = 0; /* default value in firmware will be used */
+-
+- adapter->datarate = 0; // Initially indicate the rate as auto
+-
+- adapter->adhoc_grate_enabled = 0;
+-
+- adapter->intcounter = 0;
+-
+- adapter->currenttxskb = NULL;
+- adapter->pkttxctrl = 0;
+-
+- memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
+- adapter->tx_queue_idx = 0;
+- spin_lock_init(&adapter->txqueue_lock);
+-
+- return;
+-}
+-
+-static void command_timer_fn(unsigned long data);
+-
+-int libertas_init_fw(wlan_private * priv, char *fw_name)
+-{
+- int ret = -1;
+- wlan_adapter *adapter = priv->adapter;
+-
+- lbs_deb_enter(LBS_DEB_FW);
+-
+- /* Allocate adapter structure */
+- if ((ret = wlan_allocate_adapter(priv)) != 0)
+- goto done;
+-
+- /* init adapter structure */
+- wlan_init_adapter(priv);
+-
+- /* init timer etc. */
+- setup_timer(&adapter->command_timer, command_timer_fn,
+- (unsigned long)priv);
+-
+- /* download fimrware etc. */
+- if ((ret = wlan_setup_station_hw(priv, fw_name)) != 0) {
+- del_timer_sync(&adapter->command_timer);
+- goto done;
+- }
+-
+- /* init 802.11d */
+- libertas_init_11d(priv);
+-
+- ret = 0;
+-done:
+- lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+- return ret;
+-}
+-
+-void libertas_free_adapter(wlan_private * priv)
+-{
+- wlan_adapter *adapter = priv->adapter;
+-
+- if (!adapter) {
+- lbs_deb_fw("why double free adapter?\n");
+- return;
+- }
+-
+- lbs_deb_fw("free command buffer\n");
+- libertas_free_cmd_buffer(priv);
+-
+- lbs_deb_fw("free command_timer\n");
+- del_timer(&adapter->command_timer);
+-
+- lbs_deb_fw("free scan results table\n");
+- kfree(adapter->networks);
+- adapter->networks = NULL;
+-
+- /* Free the adapter object itself */
+- lbs_deb_fw("free adapter\n");
+- kfree(adapter);
+- priv->adapter = NULL;
+-}
+-
+-/**
+- * This function handles the timeout of command sending.
+- * It will re-send the same command again.
+- */
+-static void command_timer_fn(unsigned long data)
+-{
+- wlan_private *priv = (wlan_private *)data;
+- wlan_adapter *adapter = priv->adapter;
+- struct cmd_ctrl_node *ptempnode;
+- struct cmd_ds_command *cmd;
+- unsigned long flags;
+-
+- ptempnode = adapter->cur_cmd;
+- if (ptempnode == NULL) {
+- lbs_deb_fw("ptempnode empty\n");
+- return;
+- }
+-
+- cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
+- if (!cmd) {
+- lbs_deb_fw("cmd is NULL\n");
+- return;
+- }
+-
+- lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command);
+-
+- if (!adapter->fw_ready)
+- return;
+-
+- spin_lock_irqsave(&adapter->driver_lock, flags);
+- adapter->cur_cmd = NULL;
+- spin_unlock_irqrestore(&adapter->driver_lock, flags);
+-
+- lbs_deb_fw("re-sending same command because of timeout\n");
+- libertas_queue_cmd(adapter, ptempnode, 0);
+-
+- wake_up_interruptible(&priv->mainthread.waitq);
+-
+- return;
+-}
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/hostcmd.h linux-2.6.22-300/drivers/net/wireless/libertas/hostcmd.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/hostcmd.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/hostcmd.h 2008-06-05 18:10:06.000000000 -0400
+@@ -2,8 +2,8 @@
+ * This file contains the function prototypes, data structure
+ * and defines for all the host/station commands
+ */
+-#ifndef __HOSTCMD__H
+-#define __HOSTCMD__H
++#ifndef _LBS_HOSTCMD_H
++#define _LBS_HOSTCMD_H
+
+ #include <linux/wireless.h>
+ #include "11d.h"
+@@ -65,61 +65,40 @@ struct rxpd {
+ u8 reserved[3];
+ };
+
++struct cmd_header {
++ __le16 command;
++ __le16 size;
++ __le16 seqnum;
++ __le16 result;
++} __attribute__ ((packed));
++
+ struct cmd_ctrl_node {
+- /* CMD link list */
+ struct list_head list;
+- u32 status;
+- /* CMD ID */
+- u32 cmd_oid;
+- /*CMD wait option: wait for finish or no wait */
+- u16 wait_option;
+- /* command parameter */
+- void *pdata_buf;
+- /*command data */
+- u8 *bufvirtualaddr;
+- u16 cmdflags;
++ 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;
+ };
+
+-/* WLAN_802_11_KEY
+- *
+- * Generic structure to hold all key types. key type (WEP40, WEP104, TKIP, AES)
+- * is determined from the keylength field.
+- */
+-struct WLAN_802_11_KEY {
+- __le32 len;
+- __le32 flags; /* KEY_INFO_* from wlan_defs.h */
+- u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH];
+- __le16 type; /* KEY_TYPE_* from wlan_defs.h */
+-};
+-
+-struct IE_WPA {
+- u8 elementid;
+- u8 len;
+- u8 oui[4];
+- __le16 version;
++/* 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];
+ };
+
+-/* wlan_offset_value */
+-struct wlan_offset_value {
++/* lbs_offset_value */
++struct lbs_offset_value {
+ u32 offset;
+ u32 value;
+ };
+
+-struct WLAN_802_11_FIXED_IEs {
+- __le64 timestamp;
+- __le16 beaconinterval;
+- u16 capabilities; /* Actually struct ieeetypes_capinfo */
+-};
+-
+-struct WLAN_802_11_VARIABLE_IEs {
+- u8 elementid;
+- u8 length;
+- u8 data[1];
+-};
+-
+ /* Define general data structure */
+ /* cmd_DS_GEN */
+ struct cmd_ds_gen {
+@@ -127,14 +106,19 @@ struct cmd_ds_gen {
+ __le16 size;
+ __le16 seqnum;
+ __le16 result;
++ void *cmdresp[0];
+ };
+
+ #define S_DS_GEN sizeof(struct cmd_ds_gen)
++
++
+ /*
+- * Define data structure for cmd_get_hw_spec
++ * 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 */
+@@ -174,15 +158,22 @@ struct cmd_ds_802_11_reset {
+ struct cmd_ds_802_11_subscribe_event {
+ __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.
++ */
++ u8 tlv[128];
+ };
+
+ /*
+ * This scan handle Country Information IE(802.11d compliant)
+- * Define data structure for cmd_802_11_scan
++ * Define data structure for CMD_802_11_SCAN
+ */
+ struct cmd_ds_802_11_scan {
+ u8 bsstype;
+- u8 BSSID[ETH_ALEN];
++ u8 bssid[ETH_ALEN];
+ u8 tlvbuffer[1];
+ #if 0
+ mrvlietypes_ssidparamset_t ssidParamSet;
+@@ -214,11 +205,13 @@ struct cmd_ds_802_11_get_log {
+ };
+
+ struct cmd_ds_mac_control {
++ struct cmd_header hdr;
+ __le16 action;
+- __le16 reserved;
++ u16 reserved;
+ };
+
+ 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];
+@@ -237,7 +230,7 @@ struct cmd_ds_802_11_deauthenticate {
+
+ struct cmd_ds_802_11_associate {
+ u8 peerstaaddr[6];
+- struct ieeetypes_capinfo capinfo;
++ __le16 capability;
+ __le16 listeninterval;
+ __le16 bcnperiod;
+ u8 dtimperiod;
+@@ -260,8 +253,8 @@ struct cmd_ds_802_11_associate_rsp {
+ };
+
+ struct cmd_ds_802_11_ad_hoc_result {
+- u8 PAD[3];
+- u8 BSSID[ETH_ALEN];
++ u8 pad[3];
++ u8 bssid[ETH_ALEN];
+ };
+
+ struct cmd_ds_802_11_set_wep {
+@@ -355,6 +348,12 @@ struct cmd_ds_802_11_radio_control {
+ __le16 control;
+ };
+
++struct cmd_ds_802_11_beacon_control {
++ __le16 action;
++ __le16 beacon_enable;
++ __le16 beacon_period;
++};
++
+ struct cmd_ds_802_11_sleep_params {
+ /* ACT_GET/ACT_SET */
+ __le16 action;
+@@ -387,11 +386,13 @@ struct cmd_ds_802_11_inactivity_timeout
+ };
+
+ struct cmd_ds_802_11_rf_channel {
++ struct cmd_header hdr;
++
+ __le16 action;
+- __le16 currentchannel;
+- __le16 rftype;
+- __le16 reserved;
+- u8 channellist[32];
++ __le16 channel;
++ __le16 rftype; /* unused */
++ __le16 reserved; /* unused */
++ u8 channellist[32]; /* unused */
+ };
+
+ struct cmd_ds_802_11_rssi {
+@@ -428,6 +429,32 @@ struct cmd_ds_802_11_rf_antenna {
+
+ };
+
++struct cmd_ds_802_11_monitor_mode {
++ __le16 action;
++ __le16 mode;
++};
++
++struct cmd_ds_set_boot2_ver {
++ struct cmd_header hdr;
++
++ __le16 action;
++ __le16 version;
++};
++
++struct cmd_ds_802_11_fw_wake_method {
++ struct cmd_header hdr;
++
++ __le16 action;
++ __le16 method;
++};
++
++struct cmd_ds_802_11_sleep_period {
++ struct cmd_header hdr;
++
++ __le16 action;
++ __le16 period;
++};
++
+ struct cmd_ds_802_11_ps_mode {
+ __le16 action;
+ __le16 nullpktinterval;
+@@ -450,9 +477,11 @@ struct PS_CMD_ConfirmSleep {
+ };
+
+ struct cmd_ds_802_11_data_rate {
++ struct cmd_header hdr;
++
+ __le16 action;
+- __le16 reserverd;
+- u8 datarate[G_SUPPORTED_RATES];
++ __le16 reserved;
++ u8 rates[MAX_RATES];
+ };
+
+ struct cmd_ds_802_11_rate_adapt_rateset {
+@@ -462,30 +491,30 @@ struct cmd_ds_802_11_rate_adapt_rateset
+ };
+
+ struct cmd_ds_802_11_ad_hoc_start {
+- u8 SSID[IW_ESSID_MAX_SIZE];
++ u8 ssid[IW_ESSID_MAX_SIZE];
+ u8 bsstype;
+ __le16 beaconperiod;
+ u8 dtimperiod;
+ union IEEEtypes_ssparamset ssparamset;
+ union ieeetypes_phyparamset phyparamset;
+ __le16 probedelay;
+- struct ieeetypes_capinfo cap;
+- u8 datarate[G_SUPPORTED_RATES];
++ __le16 capability;
++ u8 rates[MAX_RATES];
+ u8 tlv_memory_size_pad[100];
+ } __attribute__ ((packed));
+
+ struct adhoc_bssdesc {
+- u8 BSSID[6];
+- u8 SSID[32];
+- u8 bsstype;
++ u8 bssid[6];
++ u8 ssid[32];
++ u8 type;
+ __le16 beaconperiod;
+ u8 dtimperiod;
+ __le64 timestamp;
+ __le64 localtime;
+ union ieeetypes_phyparamset phyparamset;
+ union IEEEtypes_ssparamset ssparamset;
+- struct ieeetypes_capinfo cap;
+- u8 datarates[G_SUPPORTED_RATES];
++ __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
+@@ -494,7 +523,7 @@ struct adhoc_bssdesc {
+ } __attribute__ ((packed));
+
+ struct cmd_ds_802_11_ad_hoc_join {
+- struct adhoc_bssdesc bssdescriptor;
++ struct adhoc_bssdesc bss;
+ __le16 failtimeout;
+ __le16 probedelay;
+
+@@ -525,6 +554,13 @@ struct MrvlIEtype_keyParamSet {
+ u8 key[32];
+ };
+
++struct cmd_ds_host_sleep {
++ struct cmd_header hdr;
++ __le32 criteria;
++ uint8_t gpio;
++ uint8_t gap;
++} __attribute__ ((packed));
++
+ struct cmd_ds_802_11_key_material {
+ __le16 action;
+ struct MrvlIEtype_keyParamSet keyParamSet[2];
+@@ -611,7 +647,21 @@ struct cmd_ds_fwt_access {
+ 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));
+@@ -628,11 +678,9 @@ struct cmd_ds_command {
+
+ /* command Body */
+ union {
+- struct cmd_ds_get_hw_spec hwspec;
+ struct cmd_ds_802_11_ps_mode psmode;
+ struct cmd_ds_802_11_scan scan;
+ struct cmd_ds_802_11_scan_rsp scanresp;
+- struct cmd_ds_mac_control macctrl;
+ struct cmd_ds_802_11_associate associate;
+ struct cmd_ds_802_11_deauthenticate deauth;
+ struct cmd_ds_802_11_set_wep wep;
+@@ -646,9 +694,8 @@ struct cmd_ds_command {
+ struct cmd_ds_802_11_snmp_mib smib;
+ struct cmd_ds_802_11_rf_tx_power txp;
+ struct cmd_ds_802_11_rf_antenna rant;
+- struct cmd_ds_802_11_data_rate drate;
++ struct cmd_ds_802_11_monitor_mode monitor;
+ struct cmd_ds_802_11_rate_adapt_rateset rateset;
+- struct cmd_ds_mac_multicast_adr madr;
+ struct cmd_ds_802_11_ad_hoc_join adj;
+ struct cmd_ds_802_11_radio_control radio;
+ struct cmd_ds_802_11_rf_channel rfchannel;
+@@ -676,9 +723,9 @@ struct cmd_ds_command {
+ struct cmd_tx_rate_query txrate;
+ struct cmd_ds_bt_access bt;
+ struct cmd_ds_fwt_access fwt;
+- struct cmd_ds_mesh_access mesh;
+ struct cmd_ds_get_tsf gettsf;
+ struct cmd_ds_802_11_subscribe_event subscribe_event;
++ struct cmd_ds_802_11_beacon_control bcn_ctrl;
+ } params;
+ } __attribute__ ((packed));
+
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/host.h linux-2.6.22-300/drivers/net/wireless/libertas/host.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/host.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/host.h 2008-06-05 18:10:06.000000000 -0400
+@@ -2,340 +2,313 @@
+ * This file contains definitions of WLAN commands.
+ */
+
+-#ifndef _HOST_H_
+-#define _HOST_H_
++#ifndef _LBS_HOST_H_
++#define _LBS_HOST_H_
+
+ /** PUBLIC DEFINITIONS */
+-#define DEFAULT_AD_HOC_CHANNEL 6
+-#define DEFAULT_AD_HOC_CHANNEL_A 36
++#define DEFAULT_AD_HOC_CHANNEL 6
++#define DEFAULT_AD_HOC_CHANNEL_A 36
+
+ /** IEEE 802.11 oids */
+-#define OID_802_11_SSID 0x00008002
+-#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008
+-#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009
+-#define OID_802_11_RTS_THRESHOLD 0x0000800A
+-#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D
+-#define OID_802_11_SUPPORTED_RATES 0x0000800E
+-#define OID_802_11_STATISTICS 0x00008012
+-#define OID_802_11_TX_RETRYCOUNT 0x0000801D
+-#define OID_802_11D_ENABLE 0x00008020
+-
+-#define cmd_option_waitforrsp 0x0002
+-
+-/** Host command ID */
+-#define cmd_code_dnld 0x0002
+-#define cmd_get_hw_spec 0x0003
+-#define cmd_eeprom_update 0x0004
+-#define cmd_802_11_reset 0x0005
+-#define cmd_802_11_scan 0x0006
+-#define cmd_802_11_get_log 0x000b
+-#define cmd_mac_multicast_adr 0x0010
+-#define cmd_802_11_authenticate 0x0011
+-#define cmd_802_11_eeprom_access 0x0059
+-#define cmd_802_11_associate 0x0050
+-#define cmd_802_11_set_wep 0x0013
+-#define cmd_802_11_get_stat 0x0014
+-#define cmd_802_3_get_stat 0x0015
+-#define cmd_802_11_snmp_mib 0x0016
+-#define cmd_mac_reg_map 0x0017
+-#define cmd_bbp_reg_map 0x0018
+-#define cmd_mac_reg_access 0x0019
+-#define cmd_bbp_reg_access 0x001a
+-#define cmd_rf_reg_access 0x001b
+-#define cmd_802_11_radio_control 0x001c
+-#define cmd_802_11_rf_channel 0x001d
+-#define cmd_802_11_rf_tx_power 0x001e
+-#define cmd_802_11_rssi 0x001f
+-#define cmd_802_11_rf_antenna 0x0020
+-
+-#define cmd_802_11_ps_mode 0x0021
+-
+-#define cmd_802_11_data_rate 0x0022
+-#define cmd_rf_reg_map 0x0023
+-#define cmd_802_11_deauthenticate 0x0024
+-#define cmd_802_11_reassociate 0x0025
+-#define cmd_802_11_disassociate 0x0026
+-#define cmd_mac_control 0x0028
+-#define cmd_802_11_ad_hoc_start 0x002b
+-#define cmd_802_11_ad_hoc_join 0x002c
+-
+-#define cmd_802_11_query_tkip_reply_cntrs 0x002e
+-#define cmd_802_11_enable_rsn 0x002f
+-#define cmd_802_11_pairwise_tsc 0x0036
+-#define cmd_802_11_group_tsc 0x0037
+-#define cmd_802_11_key_material 0x005e
+-
+-#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_beacon_stop 0x0049
+-
+-#define cmd_802_11_mac_address 0x004D
+-#define cmd_802_11_eeprom_access 0x0059
+-
+-#define cmd_802_11_band_config 0x0058
+-
+-#define cmd_802_11d_domain_info 0x005b
+-
+-#define cmd_802_11_sleep_params 0x0066
+-
+-#define cmd_802_11_inactivity_timeout 0x0067
+-
+-#define cmd_802_11_tpc_cfg 0x0072
+-#define cmd_802_11_pwr_cfg 0x0073
+-
+-#define cmd_802_11_led_gpio_ctrl 0x004e
+-
+-#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_ret_bt_access 0x8087
+-
+-#define cmd_fwt_access 0x0095
+-#define cmd_ret_fwt_access 0x8095
+-
+-#define cmd_mesh_access 0x009b
+-#define cmd_ret_mesh_access 0x809b
++#define OID_802_11_SSID 0x00008002
++#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008
++#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009
++#define OID_802_11_RTS_THRESHOLD 0x0000800A
++#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D
++#define OID_802_11_SUPPORTED_RATES 0x0000800E
++#define OID_802_11_STATISTICS 0x00008012
++#define OID_802_11_TX_RETRYCOUNT 0x0000801D
++#define OID_802_11D_ENABLE 0x00008020
++
++#define CMD_OPTION_WAITFORRSP 0x0002
++
++/** Host command IDs */
++
++/* Return command are almost always the same as the host command, but with
++ * bit 15 set high. There are a few exceptions, though...
++ */
++#define CMD_RET(cmd) (0x8000 | cmd)
++
++/* Return command convention exceptions: */
++#define CMD_RET_802_11_ASSOCIATE 0x8012
++
++/* Command codes */
++#define CMD_CODE_DNLD 0x0002
++#define CMD_GET_HW_SPEC 0x0003
++#define CMD_EEPROM_UPDATE 0x0004
++#define CMD_802_11_RESET 0x0005
++#define CMD_802_11_SCAN 0x0006
++#define CMD_802_11_GET_LOG 0x000b
++#define CMD_MAC_MULTICAST_ADR 0x0010
++#define CMD_802_11_AUTHENTICATE 0x0011
++#define CMD_802_11_EEPROM_ACCESS 0x0059
++#define CMD_802_11_ASSOCIATE 0x0050
++#define CMD_802_11_SET_WEP 0x0013
++#define CMD_802_11_GET_STAT 0x0014
++#define CMD_802_3_GET_STAT 0x0015
++#define CMD_802_11_SNMP_MIB 0x0016
++#define CMD_MAC_REG_MAP 0x0017
++#define CMD_BBP_REG_MAP 0x0018
++#define CMD_MAC_REG_ACCESS 0x0019
++#define CMD_BBP_REG_ACCESS 0x001a
++#define CMD_RF_REG_ACCESS 0x001b
++#define CMD_802_11_RADIO_CONTROL 0x001c
++#define CMD_802_11_RF_CHANNEL 0x001d
++#define CMD_802_11_RF_TX_POWER 0x001e
++#define CMD_802_11_RSSI 0x001f
++#define CMD_802_11_RF_ANTENNA 0x0020
++#define CMD_802_11_PS_MODE 0x0021
++#define CMD_802_11_DATA_RATE 0x0022
++#define CMD_RF_REG_MAP 0x0023
++#define CMD_802_11_DEAUTHENTICATE 0x0024
++#define CMD_802_11_REASSOCIATE 0x0025
++#define CMD_802_11_DISASSOCIATE 0x0026
++#define CMD_MAC_CONTROL 0x0028
++#define CMD_802_11_AD_HOC_START 0x002b
++#define CMD_802_11_AD_HOC_JOIN 0x002c
++#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e
++#define CMD_802_11_ENABLE_RSN 0x002f
++#define CMD_802_11_PAIRWISE_TSC 0x0036
++#define CMD_802_11_GROUP_TSC 0x0037
++#define CMD_802_11_SET_AFC 0x003c
++#define CMD_802_11_GET_AFC 0x003d
++#define CMD_802_11_AD_HOC_STOP 0x0040
++#define CMD_802_11_HOST_SLEEP_CFG 0x0043
++#define CMD_802_11_WAKEUP_CONFIRM 0x0044
++#define CMD_802_11_HOST_SLEEP_ACTIVATE 0x0045
++#define CMD_802_11_BEACON_STOP 0x0049
++#define CMD_802_11_MAC_ADDRESS 0x004d
++#define CMD_802_11_LED_GPIO_CTRL 0x004e
++#define CMD_802_11_EEPROM_ACCESS 0x0059
++#define CMD_802_11_BAND_CONFIG 0x0058
++#define CMD_802_11D_DOMAIN_INFO 0x005b
++#define CMD_802_11_KEY_MATERIAL 0x005e
++#define CMD_802_11_SLEEP_PARAMS 0x0066
++#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067
++#define CMD_802_11_SLEEP_PERIOD 0x0068
++#define CMD_802_11_TPC_CFG 0x0072
++#define CMD_802_11_PWR_CFG 0x0073
++#define CMD_802_11_FW_WAKE_METHOD 0x0074
++#define CMD_802_11_SUBSCRIBE_EVENT 0x0075
++#define CMD_802_11_RATE_ADAPT_RATESET 0x0076
++#define CMD_802_11_TX_RATE_QUERY 0x007f
++#define CMD_GET_TSF 0x0080
++#define CMD_BT_ACCESS 0x0087
++#define CMD_FWT_ACCESS 0x0095
++#define CMD_802_11_MONITOR_MODE 0x0098
++#define CMD_MESH_ACCESS 0x009b
++#define CMD_MESH_CONFIG 0x00a3
++#define CMD_SET_BOOT2_VER 0x00a5
++#define CMD_802_11_BEACON_CTRL 0x00b0
+
+ /* For the IEEE Power Save */
+-#define cmd_subcmd_enter_ps 0x0030
+-#define cmd_subcmd_exit_ps 0x0031
+-#define cmd_subcmd_sleep_confirmed 0x0034
+-#define cmd_subcmd_full_powerdown 0x0035
+-#define cmd_subcmd_full_powerup 0x0036
+-
+-/* command RET code, MSB is set to 1 */
+-#define cmd_ret_hw_spec_info 0x8003
+-#define cmd_ret_eeprom_update 0x8004
+-#define cmd_ret_802_11_reset 0x8005
+-#define cmd_ret_802_11_scan 0x8006
+-#define cmd_ret_802_11_get_log 0x800b
+-#define cmd_ret_mac_control 0x8028
+-#define cmd_ret_mac_multicast_adr 0x8010
+-#define cmd_ret_802_11_authenticate 0x8011
+-#define cmd_ret_802_11_deauthenticate 0x8024
+-#define cmd_ret_802_11_associate 0x8012
+-#define cmd_ret_802_11_reassociate 0x8025
+-#define cmd_ret_802_11_disassociate 0x8026
+-#define cmd_ret_802_11_set_wep 0x8013
+-#define cmd_ret_802_11_stat 0x8014
+-#define cmd_ret_802_3_stat 0x8015
+-#define cmd_ret_802_11_snmp_mib 0x8016
+-#define cmd_ret_mac_reg_map 0x8017
+-#define cmd_ret_bbp_reg_map 0x8018
+-#define cmd_ret_rf_reg_map 0x8023
+-#define cmd_ret_mac_reg_access 0x8019
+-#define cmd_ret_bbp_reg_access 0x801a
+-#define cmd_ret_rf_reg_access 0x801b
+-#define cmd_ret_802_11_radio_control 0x801c
+-#define cmd_ret_802_11_rf_channel 0x801d
+-#define cmd_ret_802_11_rssi 0x801f
+-#define cmd_ret_802_11_rf_tx_power 0x801e
+-#define cmd_ret_802_11_rf_antenna 0x8020
+-#define cmd_ret_802_11_ps_mode 0x8021
+-#define cmd_ret_802_11_data_rate 0x8022
+-
+-#define cmd_ret_802_11_ad_hoc_start 0x802B
+-#define cmd_ret_802_11_ad_hoc_join 0x802C
+-
+-#define cmd_ret_802_11_query_tkip_reply_cntrs 0x802e
+-#define cmd_ret_802_11_enable_rsn 0x802f
+-#define cmd_ret_802_11_pairwise_tsc 0x8036
+-#define cmd_ret_802_11_group_tsc 0x8037
+-#define cmd_ret_802_11_key_material 0x805e
+-
+-#define cmd_enable_rsn 0x0001
+-#define cmd_disable_rsn 0x0000
+-
+-#define cmd_act_set 0x0001
+-#define cmd_act_get 0x0000
+-
+-#define cmd_act_get_AES (cmd_act_get + 2)
+-#define cmd_act_set_AES (cmd_act_set + 2)
+-#define cmd_act_remove_aes (cmd_act_set + 3)
+-
+-#define cmd_ret_802_11_set_afc 0x803c
+-#define cmd_ret_802_11_get_afc 0x803d
+-
+-#define cmd_ret_802_11_ad_hoc_stop 0x8040
+-
+-#define cmd_ret_802_11_beacon_stop 0x8049
+-
+-#define cmd_ret_802_11_mac_address 0x804D
+-#define cmd_ret_802_11_eeprom_access 0x8059
+-
+-#define cmd_ret_802_11_band_config 0x8058
+-
+-#define cmd_ret_802_11_sleep_params 0x8066
+-
+-#define cmd_ret_802_11_inactivity_timeout 0x8067
+-
+-#define cmd_ret_802_11d_domain_info (0x8000 | \
+- cmd_802_11d_domain_info)
+-
+-#define cmd_ret_802_11_tpc_cfg (cmd_802_11_tpc_cfg | 0x8000)
+-#define cmd_ret_802_11_pwr_cfg (cmd_802_11_pwr_cfg | 0x8000)
+-
+-#define cmd_ret_802_11_led_gpio_ctrl 0x804e
+-
+-#define cmd_ret_802_11_subscribe_event (cmd_802_11_subscribe_event | 0x8000)
+-
+-#define cmd_ret_802_11_rate_adapt_rateset (cmd_802_11_rate_adapt_rateset | 0x8000)
+-
+-#define cmd_rte_802_11_tx_rate_query (cmd_802_11_tx_rate_query | 0x8000)
+-
+-#define cmd_ret_get_tsf 0x8080
+-
+-/* 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 0x0001
+-#define cmd_type_wep_104_bit 0x0002
+-
+-#define cmd_NUM_OF_WEP_KEYS 4
+-
+-#define cmd_WEP_KEY_INDEX_MASK 0x3fff
+-
+-/* Define action or option for cmd_802_11_reset */
+-#define cmd_act_halt 0x0003
+-
+-/* Define action or option for cmd_802_11_scan */
+-#define cmd_bss_type_bss 0x0001
+-#define cmd_bss_type_ibss 0x0002
+-#define cmd_bss_type_any 0x0003
+-
+-/* Define action or option for cmd_802_11_scan */
+-#define cmd_scan_type_active 0x0000
+-#define cmd_scan_type_passive 0x0001
+-
+-#define cmd_scan_radio_type_bg 0
+-
+-#define cmd_scan_probe_delay_time 0
+-
+-/* Define action or option for cmd_mac_control */
+-#define cmd_act_mac_rx_on 0x0001
+-#define cmd_act_mac_tx_on 0x0002
+-#define cmd_act_mac_loopback_on 0x0004
+-#define cmd_act_mac_wep_enable 0x0008
+-#define cmd_act_mac_int_enable 0x0010
+-#define cmd_act_mac_multicast_enable 0x0020
+-#define cmd_act_mac_broadcast_enable 0x0040
+-#define cmd_act_mac_promiscuous_enable 0x0080
+-#define cmd_act_mac_all_multicast_enable 0x0100
+-#define cmd_act_mac_strict_protection_enable 0x0400
+-
+-/* Define action or option for cmd_802_11_radio_control */
+-#define cmd_type_auto_preamble 0x0001
+-#define cmd_type_short_preamble 0x0002
+-#define cmd_type_long_preamble 0x0003
+-
+-#define TURN_ON_RF 0x01
+-#define RADIO_ON 0x01
+-#define RADIO_OFF 0x00
+-
+-#define SET_AUTO_PREAMBLE 0x05
+-#define SET_SHORT_PREAMBLE 0x03
+-#define SET_LONG_PREAMBLE 0x01
++#define CMD_SUBCMD_ENTER_PS 0x0030
++#define CMD_SUBCMD_EXIT_PS 0x0031
++#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034
++#define CMD_SUBCMD_FULL_POWERDOWN 0x0035
++#define CMD_SUBCMD_FULL_POWERUP 0x0036
++
++#define CMD_ENABLE_RSN 0x0001
++#define CMD_DISABLE_RSN 0x0000
++
++#define CMD_ACT_GET 0x0000
++#define CMD_ACT_SET 0x0001
++#define CMD_ACT_GET_AES 0x0002
++#define CMD_ACT_SET_AES 0x0003
++#define CMD_ACT_REMOVE_AES 0x0004
++
++/* Define action or option for CMD_802_11_SET_WEP */
++#define CMD_ACT_ADD 0x0002
++#define CMD_ACT_REMOVE 0x0004
++#define CMD_ACT_USE_DEFAULT 0x0008
++
++#define CMD_TYPE_WEP_40_BIT 0x01
++#define CMD_TYPE_WEP_104_BIT 0x02
++
++#define CMD_NUM_OF_WEP_KEYS 4
++
++#define CMD_WEP_KEY_INDEX_MASK 0x3fff
++
++/* Define action or option for CMD_802_11_RESET */
++#define CMD_ACT_HALT 0x0003
++
++/* Define action or option for CMD_802_11_SCAN */
++#define CMD_BSS_TYPE_BSS 0x0001
++#define CMD_BSS_TYPE_IBSS 0x0002
++#define CMD_BSS_TYPE_ANY 0x0003
++
++/* Define action or option for CMD_802_11_SCAN */
++#define CMD_SCAN_TYPE_ACTIVE 0x0000
++#define CMD_SCAN_TYPE_PASSIVE 0x0001
++
++#define CMD_SCAN_RADIO_TYPE_BG 0
++
++#define CMD_SCAN_PROBE_DELAY_TIME 0
++
++/* Define action or option for CMD_MAC_CONTROL */
++#define CMD_ACT_MAC_RX_ON 0x0001
++#define CMD_ACT_MAC_TX_ON 0x0002
++#define CMD_ACT_MAC_LOOPBACK_ON 0x0004
++#define CMD_ACT_MAC_WEP_ENABLE 0x0008
++#define CMD_ACT_MAC_INT_ENABLE 0x0010
++#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020
++#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040
++#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
++#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
++#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
++
++/* Define action or option for CMD_802_11_RADIO_CONTROL */
++#define CMD_TYPE_AUTO_PREAMBLE 0x0001
++#define CMD_TYPE_SHORT_PREAMBLE 0x0002
++#define CMD_TYPE_LONG_PREAMBLE 0x0003
++
++/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
++#define CMD_SUBSCRIBE_RSSI_LOW 0x0001
++#define CMD_SUBSCRIBE_SNR_LOW 0x0002
++#define CMD_SUBSCRIBE_FAILCOUNT 0x0004
++#define CMD_SUBSCRIBE_BCNMISS 0x0008
++#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010
++#define CMD_SUBSCRIBE_SNR_HIGH 0x0020
++
++#define TURN_ON_RF 0x01
++#define RADIO_ON 0x01
++#define RADIO_OFF 0x00
++
++#define SET_AUTO_PREAMBLE 0x05
++#define SET_SHORT_PREAMBLE 0x03
++#define SET_LONG_PREAMBLE 0x01
+
+ /* Define action or option for CMD_802_11_RF_CHANNEL */
+-#define cmd_opt_802_11_rf_channel_get 0x00
+-#define cmd_opt_802_11_rf_channel_set 0x01
++#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00
++#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01
+
+-/* Define action or option for cmd_802_11_rf_tx_power */
+-#define cmd_act_tx_power_opt_get 0x0000
+-#define cmd_act_tx_power_opt_set_high 0x8007
+-#define cmd_act_tx_power_opt_set_mid 0x8004
+-#define cmd_act_tx_power_opt_set_low 0x8000
+-
+-#define cmd_act_tx_power_index_high 0x0007
+-#define cmd_act_tx_power_index_mid 0x0004
+-#define cmd_act_tx_power_index_low 0x0000
+-
+-/* Define action or option for cmd_802_11_data_rate */
+-#define cmd_act_set_tx_auto 0x0000
+-#define cmd_act_set_tx_fix_rate 0x0001
+-#define cmd_act_get_tx_rate 0x0002
+-
+-#define cmd_act_set_rx 0x0001
+-#define cmd_act_set_tx 0x0002
+-#define cmd_act_set_both 0x0003
+-#define cmd_act_get_rx 0x0004
+-#define cmd_act_get_tx 0x0008
+-#define cmd_act_get_both 0x000c
+-
+-/* Define action or option for cmd_802_11_ps_mode */
+-#define cmd_type_cam 0x0000
+-#define cmd_type_max_psp 0x0001
+-#define cmd_type_fast_psp 0x0002
++/* Define action or option for CMD_802_11_RF_TX_POWER */
++#define CMD_ACT_TX_POWER_OPT_GET 0x0000
++#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007
++#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004
++#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000
++
++#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007
++#define CMD_ACT_TX_POWER_INDEX_MID 0x0004
++#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000
++
++/* Define action or option for CMD_802_11_DATA_RATE */
++#define CMD_ACT_SET_TX_AUTO 0x0000
++#define CMD_ACT_SET_TX_FIX_RATE 0x0001
++#define CMD_ACT_GET_TX_RATE 0x0002
++
++#define CMD_ACT_SET_RX 0x0001
++#define CMD_ACT_SET_TX 0x0002
++#define CMD_ACT_SET_BOTH 0x0003
++#define CMD_ACT_GET_RX 0x0004
++#define CMD_ACT_GET_TX 0x0008
++#define CMD_ACT_GET_BOTH 0x000c
++
++/* Define action or option for CMD_802_11_PS_MODE */
++#define CMD_TYPE_CAM 0x0000
++#define CMD_TYPE_MAX_PSP 0x0001
++#define CMD_TYPE_FAST_PSP 0x0002
++
++/* Options for CMD_802_11_FW_WAKE_METHOD */
++#define CMD_WAKE_METHOD_UNCHANGED 0x0000
++#define CMD_WAKE_METHOD_COMMAND_INT 0x0001
++#define CMD_WAKE_METHOD_GPIO 0x0002
+
+-/* Define action or option for cmd_bt_access */
++/* Define action or option for CMD_BT_ACCESS */
+ enum cmd_bt_access_opts {
+ /* The bt commands start at 5 instead of 1 because the old dft commands
+ * are mapped to 1-4. These old commands are no longer maintained and
+ * should not be called.
+ */
+- cmd_act_bt_access_add = 5,
+- cmd_act_bt_access_del,
+- cmd_act_bt_access_list,
+- cmd_act_bt_access_reset,
+- cmd_act_bt_access_set_invert,
+- cmd_act_bt_access_get_invert
++ CMD_ACT_BT_ACCESS_ADD = 5,
++ CMD_ACT_BT_ACCESS_DEL,
++ CMD_ACT_BT_ACCESS_LIST,
++ CMD_ACT_BT_ACCESS_RESET,
++ CMD_ACT_BT_ACCESS_SET_INVERT,
++ CMD_ACT_BT_ACCESS_GET_INVERT
+ };
+
+-/* Define action or option for cmd_fwt_access */
++/* Define action or option for CMD_FWT_ACCESS */
+ enum cmd_fwt_access_opts {
+- cmd_act_fwt_access_add = 1,
+- cmd_act_fwt_access_del,
+- cmd_act_fwt_access_lookup,
+- cmd_act_fwt_access_list,
+- cmd_act_fwt_access_list_route,
+- cmd_act_fwt_access_list_neighbor,
+- cmd_act_fwt_access_reset,
+- cmd_act_fwt_access_cleanup,
+- cmd_act_fwt_access_time,
++ CMD_ACT_FWT_ACCESS_ADD = 1,
++ CMD_ACT_FWT_ACCESS_DEL,
++ CMD_ACT_FWT_ACCESS_LOOKUP,
++ CMD_ACT_FWT_ACCESS_LIST,
++ CMD_ACT_FWT_ACCESS_LIST_ROUTE,
++ CMD_ACT_FWT_ACCESS_LIST_NEIGHBOR,
++ CMD_ACT_FWT_ACCESS_RESET,
++ CMD_ACT_FWT_ACCESS_CLEANUP,
++ CMD_ACT_FWT_ACCESS_TIME,
+ };
+
+-/* Define action or option for cmd_mesh_access */
++/* Define action or option for CMD_MESH_ACCESS */
+ enum cmd_mesh_access_opts {
+- cmd_act_mesh_get_ttl = 1,
+- cmd_act_mesh_set_ttl,
+- cmd_act_mesh_get_stats,
+- cmd_act_mesh_get_anycast,
+- cmd_act_mesh_set_anycast,
++ CMD_ACT_MESH_GET_TTL = 1,
++ CMD_ACT_MESH_SET_TTL,
++ CMD_ACT_MESH_GET_STATS,
++ CMD_ACT_MESH_GET_ANYCAST,
++ CMD_ACT_MESH_SET_ANYCAST,
++ CMD_ACT_MESH_SET_LINK_COSTS,
++ CMD_ACT_MESH_GET_LINK_COSTS,
++ CMD_ACT_MESH_SET_BCAST_RATE,
++ CMD_ACT_MESH_GET_BCAST_RATE,
++ CMD_ACT_MESH_SET_RREQ_DELAY,
++ CMD_ACT_MESH_GET_RREQ_DELAY,
++ CMD_ACT_MESH_SET_ROUTE_EXP,
++ CMD_ACT_MESH_GET_ROUTE_EXP,
++ CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
++ CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
++ CMD_ACT_MESH_SET_PRB_RSP_RETRY_LIMIT = 17,
++};
++
++/* Define actions and types for CMD_MESH_CONFIG */
++enum cmd_mesh_config_actions {
++ CMD_ACT_MESH_CONFIG_STOP = 0,
++ CMD_ACT_MESH_CONFIG_START,
++ CMD_ACT_MESH_CONFIG_SET,
++ CMD_ACT_MESH_CONFIG_GET,
++};
++
++enum cmd_mesh_config_types {
++ CMD_TYPE_MESH_SET_BOOTFLAG = 1,
++ CMD_TYPE_MESH_SET_BOOTTIME,
++ CMD_TYPE_MESH_SET_DEF_CHANNEL,
++ CMD_TYPE_MESH_SET_MESH_IE,
++ CMD_TYPE_MESH_GET_DEFAULTS,
++ CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */
+ };
+
+ /** Card Event definition */
+-#define MACREG_INT_CODE_TX_PPA_FREE 0x00000000
+-#define MACREG_INT_CODE_TX_DMA_DONE 0x00000001
+-#define MACREG_INT_CODE_LINK_LOSE_W_SCAN 0x00000002
+-#define MACREG_INT_CODE_LINK_LOSE_NO_SCAN 0x00000003
+-#define MACREG_INT_CODE_LINK_SENSED 0x00000004
+-#define MACREG_INT_CODE_CMD_FINISHED 0x00000005
+-#define MACREG_INT_CODE_MIB_CHANGED 0x00000006
+-#define MACREG_INT_CODE_INIT_DONE 0x00000007
+-#define MACREG_INT_CODE_DEAUTHENTICATED 0x00000008
+-#define MACREG_INT_CODE_DISASSOCIATED 0x00000009
+-#define MACREG_INT_CODE_PS_AWAKE 0x0000000a
+-#define MACREG_INT_CODE_PS_SLEEP 0x0000000b
+-#define MACREG_INT_CODE_MIC_ERR_MULTICAST 0x0000000d
+-#define MACREG_INT_CODE_MIC_ERR_UNICAST 0x0000000e
+-#define MACREG_INT_CODE_WM_AWAKE 0x0000000f
+-#define MACREG_INT_CODE_ADHOC_BCN_LOST 0x00000011
+-#define MACREG_INT_CODE_RSSI_LOW 0x00000019
+-#define MACREG_INT_CODE_SNR_LOW 0x0000001a
+-#define MACREG_INT_CODE_MAX_FAIL 0x0000001b
+-#define MACREG_INT_CODE_RSSI_HIGH 0x0000001c
+-#define MACREG_INT_CODE_SNR_HIGH 0x0000001d
+-#define MACREG_INT_CODE_MESH_AUTO_STARTED 0x00000023
++#define MACREG_INT_CODE_TX_PPA_FREE 0
++#define MACREG_INT_CODE_TX_DMA_DONE 1
++#define MACREG_INT_CODE_LINK_LOST_W_SCAN 2
++#define MACREG_INT_CODE_LINK_LOST_NO_SCAN 3
++#define MACREG_INT_CODE_LINK_SENSED 4
++#define MACREG_INT_CODE_CMD_FINISHED 5
++#define MACREG_INT_CODE_MIB_CHANGED 6
++#define MACREG_INT_CODE_INIT_DONE 7
++#define MACREG_INT_CODE_DEAUTHENTICATED 8
++#define MACREG_INT_CODE_DISASSOCIATED 9
++#define MACREG_INT_CODE_PS_AWAKE 10
++#define MACREG_INT_CODE_PS_SLEEP 11
++#define MACREG_INT_CODE_MIC_ERR_MULTICAST 13
++#define MACREG_INT_CODE_MIC_ERR_UNICAST 14
++#define MACREG_INT_CODE_WM_AWAKE 15
++#define MACREG_INT_CODE_DEEP_SLEEP_AWAKE 16
++#define MACREG_INT_CODE_ADHOC_BCN_LOST 17
++#define MACREG_INT_CODE_HOST_AWAKE 18
++#define MACREG_INT_CODE_STOP_TX 19
++#define MACREG_INT_CODE_START_TX 20
++#define MACREG_INT_CODE_CHANNEL_SWITCH 21
++#define MACREG_INT_CODE_MEASUREMENT_RDY 22
++#define MACREG_INT_CODE_WMM_CHANGE 23
++#define MACREG_INT_CODE_BG_SCAN_REPORT 24
++#define MACREG_INT_CODE_RSSI_LOW 25
++#define MACREG_INT_CODE_SNR_LOW 26
++#define MACREG_INT_CODE_MAX_FAIL 27
++#define MACREG_INT_CODE_RSSI_HIGH 28
++#define MACREG_INT_CODE_SNR_HIGH 29
++#define MACREG_INT_CODE_MESH_AUTO_STARTED 35
++#define MACREG_INT_CODE_FIRMWARE_READY 48
+
+-#endif /* _HOST_H_ */
++#endif
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/if_bootcmd.c linux-2.6.22-300/drivers/net/wireless/libertas/if_bootcmd.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/if_bootcmd.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/if_bootcmd.c 1969-12-31 19:00:00.000000000 -0500
+@@ -1,40 +0,0 @@
+-/**
+- * This file contains functions used in USB Boot command
+- * and Boot2/FW update
+- */
+-
+-#include <linux/delay.h>
+-#include <linux/firmware.h>
+-#include <linux/netdevice.h>
+-#include <linux/usb.h>
+-
+-#define DRV_NAME "usb8xxx"
+-
+-#include "defs.h"
+-#include "dev.h"
+-#include "if_usb.h"
+-
+-/**
+- * @brief This function issues Boot command to the Boot2 code
+- * @param ivalue 1:Boot from FW by USB-Download
+- * 2:Boot from FW in EEPROM
+- * @return 0
+- */
+-int if_usb_issue_boot_command(wlan_private *priv, int ivalue)
+-{
+- struct usb_card_rec *cardp = priv->card;
+- struct bootcmdstr sbootcmd;
+- int i;
+-
+- /* Prepare command */
+- sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
+- sbootcmd.u8cmd_tag = ivalue;
+- for (i=0; i<11; i++)
+- sbootcmd.au8dumy[i]=0x00;
+- memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
+-
+- /* Issue command */
+- usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
+-
+- return 0;
+-}
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/if_cs.c linux-2.6.22-300/drivers/net/wireless/libertas/if_cs.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/if_cs.c 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.22-300/drivers/net/wireless/libertas/if_cs.c 2008-06-05 18:10:06.000000000 -0400
+@@ -0,0 +1,965 @@
++/*
++
++ Driver for the Marvell 8385 based compact flash WLAN cards.
++
++ (C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de>
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++
++*/
++
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/moduleparam.h>
++#include <linux/firmware.h>
++#include <linux/netdevice.h>
++
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ds.h>
++
++#include <linux/io.h>
++
++#define DRV_NAME "libertas_cs"
++
++#include "decl.h"
++#include "defs.h"
++#include "dev.h"
++
++
++/********************************************************************/
++/* Module stuff */
++/********************************************************************/
++
++MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
++MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
++MODULE_LICENSE("GPL");
++
++
++
++/********************************************************************/
++/* Data structures */
++/********************************************************************/
++
++struct if_cs_card {
++ struct pcmcia_device *p_dev;
++ struct lbs_private *priv;
++ void __iomem *iobase;
++};
++
++
++
++/********************************************************************/
++/* Hardware access */
++/********************************************************************/
++
++/* This define enables wrapper functions which allow you
++ to dump all register accesses. You normally won't this,
++ except for development */
++/* #define DEBUG_IO */
++
++#ifdef DEBUG_IO
++static int debug_output = 0;
++#else
++/* This way the compiler optimizes the printk's away */
++#define debug_output 0
++#endif
++
++static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
++{
++ unsigned int val = ioread8(card->iobase + reg);
++ if (debug_output)
++ printk(KERN_INFO "##inb %08x<%02x\n", reg, val);
++ return val;
++}
++static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
++{
++ unsigned int val = ioread16(card->iobase + reg);
++ if (debug_output)
++ printk(KERN_INFO "##inw %08x<%04x\n", reg, val);
++ return val;
++}
++static inline void if_cs_read16_rep(
++ struct if_cs_card *card,
++ uint reg,
++ void *buf,
++ unsigned long count)
++{
++ if (debug_output)
++ printk(KERN_INFO "##insw %08x<(0x%lx words)\n",
++ reg, count);
++ ioread16_rep(card->iobase + reg, buf, count);
++}
++
++static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
++{
++ if (debug_output)
++ printk(KERN_INFO "##outb %08x>%02x\n", reg, val);
++ iowrite8(val, card->iobase + reg);
++}
++
++static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
++{
++ if (debug_output)
++ printk(KERN_INFO "##outw %08x>%04x\n", reg, val);
++ iowrite16(val, card->iobase + reg);
++}
++
++static inline void if_cs_write16_rep(
++ struct if_cs_card *card,
++ uint reg,
++ void *buf,
++ unsigned long count)
++{
++ if (debug_output)
++ printk(KERN_INFO "##outsw %08x>(0x%lx words)\n",
++ reg, count);
++ iowrite16_rep(card->iobase + reg, buf, count);
++}
++
++
++/*
++ * I know that polling/delaying is frowned upon. However, this procedure
++ * with polling is needed while downloading the firmware. At this stage,
++ * the hardware does unfortunately not create any interrupts.
++ *
++ * Fortunately, this function is never used once the firmware is in
++ * the card. :-)
++ *
++ * As a reference, see the "Firmware Specification v5.1", page 18
++ * and 19. I did not follow their suggested timing to the word,
++ * but this works nice & fast anyway.
++ */
++static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg)
++{
++ int i;
++
++ for (i = 0; i < 1000; i++) {
++ u8 val = if_cs_read8(card, addr);
++ if (val == reg)
++ return i;
++ udelay(500);
++ }
++ return -ETIME;
++}
++
++
++
++/* Host control registers and their bit definitions */
++
++#define IF_CS_H_STATUS 0x00000000
++#define IF_CS_H_STATUS_TX_OVER 0x0001
++#define IF_CS_H_STATUS_RX_OVER 0x0002
++#define IF_CS_H_STATUS_DNLD_OVER 0x0004
++
++#define IF_CS_H_INT_CAUSE 0x00000002
++#define IF_CS_H_IC_TX_OVER 0x0001
++#define IF_CS_H_IC_RX_OVER 0x0002
++#define IF_CS_H_IC_DNLD_OVER 0x0004
++#define IF_CS_H_IC_POWER_DOWN 0x0008
++#define IF_CS_H_IC_HOST_EVENT 0x0010
++#define IF_CS_H_IC_MASK 0x001f
++
++#define IF_CS_H_INT_MASK 0x00000004
++#define IF_CS_H_IM_MASK 0x001f
++
++#define IF_CS_H_WRITE_LEN 0x00000014
++
++#define IF_CS_H_WRITE 0x00000016
++
++#define IF_CS_H_CMD_LEN 0x00000018
++
++#define IF_CS_H_CMD 0x0000001A
++
++#define IF_CS_C_READ_LEN 0x00000024
++
++#define IF_CS_H_READ 0x00000010
++
++/* Card control registers and their bit definitions */
++
++#define IF_CS_C_STATUS 0x00000020
++#define IF_CS_C_S_TX_DNLD_RDY 0x0001
++#define IF_CS_C_S_RX_UPLD_RDY 0x0002
++#define IF_CS_C_S_CMD_DNLD_RDY 0x0004
++#define IF_CS_C_S_CMD_UPLD_RDY 0x0008
++#define IF_CS_C_S_CARDEVENT 0x0010
++#define IF_CS_C_S_MASK 0x001f
++#define IF_CS_C_S_STATUS_MASK 0x7f00
++/* The following definitions should be the same as the MRVDRV_ ones */
++
++#if MRVDRV_CMD_DNLD_RDY != IF_CS_C_S_CMD_DNLD_RDY
++#error MRVDRV_CMD_DNLD_RDY and IF_CS_C_S_CMD_DNLD_RDY not in sync
++#endif
++#if MRVDRV_CMD_UPLD_RDY != IF_CS_C_S_CMD_UPLD_RDY
++#error MRVDRV_CMD_UPLD_RDY and IF_CS_C_S_CMD_UPLD_RDY not in sync
++#endif
++#if MRVDRV_CARDEVENT != IF_CS_C_S_CARDEVENT
++#error MRVDRV_CARDEVENT and IF_CS_C_S_CARDEVENT not in sync
++#endif
++
++#define IF_CS_C_INT_CAUSE 0x00000022
++#define IF_CS_C_IC_MASK 0x001f
++
++#define IF_CS_C_SQ_READ_LOW 0x00000028
++#define IF_CS_C_SQ_HELPER_OK 0x10
++
++#define IF_CS_C_CMD_LEN 0x00000030
++
++#define IF_CS_C_CMD 0x00000012
++
++#define IF_CS_SCRATCH 0x0000003F
++
++
++
++/********************************************************************/
++/* Interrupts */
++/********************************************************************/
++
++static inline void if_cs_enable_ints(struct if_cs_card *card)
++{
++ lbs_deb_enter(LBS_DEB_CS);
++ if_cs_write16(card, IF_CS_H_INT_MASK, 0);
++}
++
++static inline void if_cs_disable_ints(struct if_cs_card *card)
++{
++ lbs_deb_enter(LBS_DEB_CS);
++ if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
++}
++
++static irqreturn_t if_cs_interrupt(int irq, void *data)
++{
++ struct if_cs_card *card = data;
++ u16 int_cause;
++
++ lbs_deb_enter(LBS_DEB_CS);
++
++ int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
++ if(int_cause == 0x0) {
++ /* Not for us */
++ return IRQ_NONE;
++
++ } else if (int_cause == 0xffff) {
++ /* Read in junk, the card has probably been removed */
++ card->priv->surpriseremoved = 1;
++
++ } else {
++ if (int_cause & IF_CS_H_IC_TX_OVER)
++ lbs_host_to_card_done(card->priv);
++
++ /* clear interrupt */
++ if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK);
++ }
++ spin_lock(&card->priv->driver_lock);
++ lbs_interrupt(card->priv);
++ spin_unlock(&card->priv->driver_lock);
++
++ return IRQ_HANDLED;
++}
++
++
++
++
++/********************************************************************/
++/* I/O */
++/********************************************************************/
++
++/*
++ * Called from if_cs_host_to_card to send a command to the hardware
++ */
++static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
++{
++ struct if_cs_card *card = (struct if_cs_card *)priv->card;
++ int ret = -1;
++ int loops = 0;
++
++ lbs_deb_enter(LBS_DEB_CS);
++
++ /* Is hardware ready? */
++ while (1) {
++ u16 val = if_cs_read16(card, IF_CS_C_STATUS);
++ if (val & IF_CS_C_S_CMD_DNLD_RDY)
++ break;
++ if (++loops > 100) {
++ lbs_pr_err("card not ready for commands\n");
++ goto done;
++ }
++ mdelay(1);
++ }
++
++ if_cs_write16(card, IF_CS_H_CMD_LEN, nb);
++
++ if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2);
++ /* Are we supposed to transfer an odd amount of bytes? */
++ if (nb & 1)
++ if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]);
++
++ /* "Assert the download over interrupt command in the Host
++ * status register" */
++ if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
++
++ /* "Assert the download over interrupt command in the Card
++ * interrupt case register" */
++ if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
++ ret = 0;
++
++done:
++ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
++ return ret;
++}
++
++
++/*
++ * Called from if_cs_host_to_card to send a data to the hardware
++ */
++static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
++{
++ struct if_cs_card *card = (struct if_cs_card *)priv->card;
++
++ lbs_deb_enter(LBS_DEB_CS);
++
++ if_cs_write16(card, IF_CS_H_WRITE_LEN, nb);
++
++ /* write even number of bytes, then odd byte if necessary */
++ if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2);
++ if (nb & 1)
++ if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]);
++
++ if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER);
++ if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER);
++
++ lbs_deb_leave(LBS_DEB_CS);
++}
++
++
++/*
++ * Get the command result out of the card.
++ */
++static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
++{
++ int ret = -1;
++ u16 val;
++
++ lbs_deb_enter(LBS_DEB_CS);
++
++ /* is hardware ready? */
++ val = if_cs_read16(priv->card, IF_CS_C_STATUS);
++ if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) {
++ lbs_pr_err("card not ready for CMD\n");
++ goto out;
++ }
++
++ *len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN);
++ if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
++ lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
++ goto out;
++ }
++
++ /* read even number of bytes, then odd byte if necessary */
++ if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16));
++ if (*len & 1)
++ data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD);
++
++ /* This is a workaround for a firmware that reports too much
++ * bytes */
++ *len -= 8;
++ ret = 0;
++out:
++ lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
++ return ret;
++}
++
++
++static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
++{
++ struct sk_buff *skb = NULL;
++ u16 len;
++ u8 *data;
++
++ lbs_deb_enter(LBS_DEB_CS);
++
++ len = if_cs_read16(priv->card, IF_CS_C_READ_LEN);
++ if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
++ lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
++ priv->stats.rx_dropped++;
++ printk(KERN_INFO "##HS %s:%d TODO\n", __FUNCTION__, __LINE__);
++ goto dat_err;
++ }
++
++ //TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN);
++ skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
++ if (!skb)
++ goto out;
++ skb_put(skb, len);
++ skb_reserve(skb, 2);/* 16 byte align */
++ data = skb->data;
++
++ /* read even number of bytes, then odd byte if necessary */
++ if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16));
++ if (len & 1)
++ data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ);
++
++dat_err:
++ if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER);
++ if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER);
++
++out:
++ lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb);
++ return skb;
++}
++
++
++
++/********************************************************************/
++/* Firmware */
++/********************************************************************/
++
++/*
++ * Tries to program the helper firmware.
++ *
++ * Return 0 on success
++ */
++static int if_cs_prog_helper(struct if_cs_card *card)
++{
++ int ret = 0;
++ int sent = 0;
++ u8 scratch;
++ const struct firmware *fw;
++
++ lbs_deb_enter(LBS_DEB_CS);
++
++ scratch = if_cs_read8(card, IF_CS_SCRATCH);
++
++ /* "If the value is 0x5a, the firmware is already
++ * downloaded successfully"
++ */
++ if (scratch == 0x5a)
++ goto done;
++
++ /* "If the value is != 00, it is invalid value of register */
++ if (scratch != 0x00) {
++ ret = -ENODEV;
++ goto done;
++ }
++
++ /* TODO: make firmware file configurable */
++ ret = request_firmware(&fw, "libertas_cs_helper.fw",
++ &handle_to_dev(card->p_dev));
++ if (ret) {
++ lbs_pr_err("can't load helper firmware\n");
++ ret = -ENODEV;
++ goto done;
++ }
++ lbs_deb_cs("helper size %td\n", fw->size);
++
++ /* "Set the 5 bytes of the helper image to 0" */
++ /* Not needed, this contains an ARM branch instruction */
++
++ for (;;) {
++ /* "the number of bytes to send is 256" */
++ int count = 256;
++ int remain = fw->size - sent;
++
++ if (remain < count)
++ count = remain;
++ /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
++ __LINE__, sent, fw->size); */
++
++ /* "write the number of bytes to be sent to the I/O Command
++ * write length register" */
++ if_cs_write16(card, IF_CS_H_CMD_LEN, count);
++
++ /* "write this to I/O Command port register as 16 bit writes */
++ if (count)
++ if_cs_write16_rep(card, IF_CS_H_CMD,
++ &fw->data[sent],
++ count >> 1);
++
++ /* "Assert the download over interrupt command in the Host
++ * status register" */
++ if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
++
++ /* "Assert the download over interrupt command in the Card
++ * interrupt case register" */
++ if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
++
++ /* "The host polls the Card Status register ... for 50 ms before
++ declaring a failure */
++ ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
++ IF_CS_C_S_CMD_DNLD_RDY);
++ if (ret < 0) {
++ lbs_pr_err("can't download helper at 0x%x, ret %d\n",
++ sent, ret);
++ goto done;
++ }
++
++ if (count == 0)
++ break;
++
++ sent += count;
++ }
++
++ release_firmware(fw);
++ ret = 0;
++
++done:
++ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
++ return ret;
++}
++
++
++static int if_cs_prog_real(struct if_cs_card *card)
++{
++ const struct firmware *fw;
++ int ret = 0;
++ int retry = 0;
++ int len = 0;
++ int sent;
++
++ lbs_deb_enter(LBS_DEB_CS);
++
++ /* TODO: make firmware file configurable */
++ ret = request_firmware(&fw, "libertas_cs.fw",
++ &handle_to_dev(card->p_dev));
++ if (ret) {
++ lbs_pr_err("can't load firmware\n");
++ ret = -ENODEV;
++ goto done;
++ }
++ lbs_deb_cs("fw size %td\n", fw->size);
++
++ ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);
++ if (ret < 0) {
++ int i;
++ lbs_pr_err("helper firmware doesn't answer\n");
++ for (i = 0; i < 0x50; i += 2)
++ printk(KERN_INFO "## HS %02x: %04x\n",
++ i, if_cs_read16(card, i));
++ goto err_release;
++ }
++
++ for (sent = 0; sent < fw->size; sent += len) {
++ len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);
++ /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
++ __LINE__, sent, fw->size); */
++ if (len & 1) {
++ retry++;
++ lbs_pr_info("odd, need to retry this firmware block\n");
++ } else {
++ retry = 0;
++ }
++
++ if (retry > 20) {
++ lbs_pr_err("could not download firmware\n");
++ ret = -ENODEV;
++ goto err_release;
++ }
++ if (retry) {
++ sent -= len;
++ }
++
++
++ if_cs_write16(card, IF_CS_H_CMD_LEN, len);
++
++ if_cs_write16_rep(card, IF_CS_H_CMD,
++ &fw->data[sent],
++ (len+1) >> 1);
++ if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
++ if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
++
++ ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
++ IF_CS_C_S_CMD_DNLD_RDY);
++ if (ret < 0) {
++ lbs_pr_err("can't download firmware at 0x%x\n", sent);
++ goto err_release;
++ }
++ }
++
++ ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
++ if (ret < 0) {
++ lbs_pr_err("firmware download failed\n");
++ goto err_release;
++ }
++
++ ret = 0;
++ goto done;
++
++
++err_release:
++ release_firmware(fw);
++
++done:
++ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
++ return ret;
++}
++
++
++
++/********************************************************************/
++/* Callback functions for libertas.ko */
++/********************************************************************/
++
++/* Send commands or data packets to the card */
++static int if_cs_host_to_card(struct lbs_private *priv,
++ u8 type,
++ u8 *buf,
++ u16 nb)
++{
++ int ret = -1;
++
++ lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb);
++
++ switch (type) {
++ case MVMS_DAT:
++ priv->dnld_sent = DNLD_DATA_SENT;
++ if_cs_send_data(priv, buf, nb);
++ ret = 0;
++ break;
++ case MVMS_CMD:
++ priv->dnld_sent = DNLD_CMD_SENT;
++ ret = if_cs_send_cmd(priv, buf, nb);
++ break;
++ default:
++ lbs_pr_err("%s: unsupported type %d\n", __FUNCTION__, type);
++ }
++
++ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
++ return ret;
++}
++
++
++static int if_cs_get_int_status(struct lbs_private *priv, u8 *ireg)
++{
++ struct if_cs_card *card = (struct if_cs_card *)priv->card;
++ int ret = 0;
++ u16 int_cause;
++ *ireg = 0;
++
++ lbs_deb_enter(LBS_DEB_CS);
++
++ if (priv->surpriseremoved)
++ goto out;
++
++ int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK;
++ if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause);
++
++ *ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
++
++ if (!*ireg)
++ goto sbi_get_int_status_exit;
++
++sbi_get_int_status_exit:
++
++ /* is there a data packet for us? */
++ if (*ireg & IF_CS_C_S_RX_UPLD_RDY) {
++ struct sk_buff *skb = if_cs_receive_data(priv);
++ lbs_process_rxed_packet(priv, skb);
++ *ireg &= ~IF_CS_C_S_RX_UPLD_RDY;
++ }
++
++ if (*ireg & IF_CS_C_S_TX_DNLD_RDY) {
++ priv->dnld_sent = DNLD_RES_RECEIVED;
++ }
++
++ /* Card has a command result for us */
++ if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {
++ spin_lock(&priv->driver_lock);
++ ret = if_cs_receive_cmdres(priv, priv->upld_buf, &priv->upld_len);
++ spin_unlock(&priv->driver_lock);
++ if (ret < 0)
++ lbs_pr_err("could not receive cmd from card\n");
++ }
++
++out:
++ lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->hisregcpy);
++ return ret;
++}
++
++
++static int if_cs_read_event_cause(struct lbs_private *priv)
++{
++ lbs_deb_enter(LBS_DEB_CS);
++
++ priv->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5;
++ if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT);
++
++ return 0;
++}
++
++
++
++/********************************************************************/
++/* Card Services */
++/********************************************************************/
++
++/*
++ * After a card is removed, if_cs_release() will unregister the
++ * device, and release the PCMCIA configuration. If the device is
++ * still open, this will be postponed until it is closed.
++ */
++static void if_cs_release(struct pcmcia_device *p_dev)
++{
++ struct if_cs_card *card = p_dev->priv;
++
++ lbs_deb_enter(LBS_DEB_CS);
++
++ pcmcia_disable_device(p_dev);
++ free_irq(p_dev->irq.AssignedIRQ, card);
++ if (card->iobase)
++ ioport_unmap(card->iobase);
++
++ lbs_deb_leave(LBS_DEB_CS);
++}
++
++
++/*
++ * This creates an "instance" of the driver, allocating local data
++ * structures for one device. The device is registered with Card
++ * Services.
++ *
++ * The dev_link structure is initialized, but we don't actually
++ * configure the card at this point -- we wait until we receive a card
++ * insertion event.
++ */
++static int if_cs_probe(struct pcmcia_device *p_dev)
++{
++ int ret = -ENOMEM;
++ struct lbs_private *priv;
++ struct if_cs_card *card;
++ /* CIS parsing */
++ tuple_t tuple;
++ cisparse_t parse;
++ cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
++ cistpl_io_t *io = &cfg->io;
++ u_char buf[64];
++
++ lbs_deb_enter(LBS_DEB_CS);
++
++ card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
++ if (!card) {
++ lbs_pr_err("error in kzalloc\n");
++ goto out;
++ }
++ card->p_dev = p_dev;
++ p_dev->priv = card;
++
++ p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
++ p_dev->irq.Handler = NULL;
++ p_dev->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
++
++ p_dev->conf.Attributes = 0;
++ p_dev->conf.IntType = INT_MEMORY_AND_IO;
++
++ tuple.Attributes = 0;
++ tuple.TupleData = buf;
++ tuple.TupleDataMax = sizeof(buf);
++ tuple.TupleOffset = 0;
++
++ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
++ if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 ||
++ (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 ||
++ (ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0)
++ {
++ lbs_pr_err("error in pcmcia_get_first_tuple etc\n");
++ goto out1;
++ }
++
++ p_dev->conf.ConfigIndex = cfg->index;
++
++ /* Do we need to allocate an interrupt? */
++ if (cfg->irq.IRQInfo1) {
++ p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
++ }
++
++ /* IO window settings */
++ if (cfg->io.nwin != 1) {
++ lbs_pr_err("wrong CIS (check number of IO windows)\n");
++ ret = -ENODEV;
++ goto out1;
++ }
++ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
++ p_dev->io.BasePort1 = io->win[0].base;
++ p_dev->io.NumPorts1 = io->win[0].len;
++
++ /* This reserves IO space but doesn't actually enable it */
++ ret = pcmcia_request_io(p_dev, &p_dev->io);
++ if (ret) {
++ lbs_pr_err("error in pcmcia_request_io\n");
++ goto out1;
++ }
++
++ /*
++ * Allocate an interrupt line. Note that this does not assign
++ * a handler to the interrupt, unless the 'Handler' member of
++ * the irq structure is initialized.
++ */
++ if (p_dev->conf.Attributes & CONF_ENABLE_IRQ) {
++ ret = pcmcia_request_irq(p_dev, &p_dev->irq);
++ if (ret) {
++ lbs_pr_err("error in pcmcia_request_irq\n");
++ goto out1;
++ }
++ }
++
++ /* Initialize io access */
++ card->iobase = ioport_map(p_dev->io.BasePort1, p_dev->io.NumPorts1);
++ if (!card->iobase) {
++ lbs_pr_err("error in ioport_map\n");
++ ret = -EIO;
++ goto out1;
++ }
++
++ /*
++ * This actually configures the PCMCIA socket -- setting up
++ * the I/O windows and the interrupt mapping, and putting the
++ * card and host interface into "Memory and IO" mode.
++ */
++ ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
++ if (ret) {
++ lbs_pr_err("error in pcmcia_request_configuration\n");
++ goto out2;
++ }
++
++ /* Finally, report what we've done */
++ lbs_deb_cs("irq %d, io 0x%04x-0x%04x\n",
++ p_dev->irq.AssignedIRQ, p_dev->io.BasePort1,
++ p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1);
++
++
++ /* Load the firmware early, before calling into libertas.ko */
++ ret = if_cs_prog_helper(card);
++ if (ret == 0)
++ ret = if_cs_prog_real(card);
++ if (ret)
++ goto out2;
++
++ /* Make this card known to the libertas driver */
++ priv = lbs_add_card(card, &p_dev->dev);
++ if (!priv) {
++ ret = -ENOMEM;
++ goto out2;
++ }
++
++ /* Store pointers to our call-back functions */
++ card->priv = priv;
++ priv->card = card;
++ priv->hw_host_to_card = if_cs_host_to_card;
++ priv->hw_get_int_status = if_cs_get_int_status;
++ priv->hw_read_event_cause = if_cs_read_event_cause;
++
++ priv->fw_ready = 1;
++
++ /* Now actually get the IRQ */
++ ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt,
++ IRQF_SHARED, DRV_NAME, card);
++ if (ret) {
++ lbs_pr_err("error in request_irq\n");
++ goto out3;
++ }
++
++ /* Clear any interrupt cause that happend while sending
++ * firmware/initializing card */
++ if_cs_write16(card, IF_CS_C_INT_CAUSE, IF_CS_C_IC_MASK);
++ if_cs_enable_ints(card);
++
++ /* And finally bring the card up */
++ if (lbs_start_card(priv) != 0) {
++ lbs_pr_err("could not activate card\n");
++ goto out3;
++ }
++
++ ret = 0;
++ goto out;
++
++out3:
++ lbs_remove_card(priv);
++out2:
++ ioport_unmap(card->iobase);
++out1:
++ pcmcia_disable_device(p_dev);
++out:
++ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
++ return ret;
++}
++
++
++/*
++ * This deletes a driver "instance". The device is de-registered with
++ * Card Services. If it has been released, all local data structures
++ * are freed. Otherwise, the structures will be freed when the device
++ * is released.
++ */
++static void if_cs_detach(struct pcmcia_device *p_dev)
++{
++ struct if_cs_card *card = p_dev->priv;
++
++ lbs_deb_enter(LBS_DEB_CS);
++
++ lbs_stop_card(card->priv);
++ lbs_remove_card(card->priv);
++ if_cs_disable_ints(card);
++ if_cs_release(p_dev);
++ kfree(card);
++
++ lbs_deb_leave(LBS_DEB_CS);
++}
++
++
++
++/********************************************************************/
++/* Module initialization */
++/********************************************************************/
++
++static struct pcmcia_device_id if_cs_ids[] = {
++ PCMCIA_DEVICE_MANF_CARD(0x02df, 0x8103),
++ PCMCIA_DEVICE_NULL,
++};
++MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
++
++
++static struct pcmcia_driver lbs_driver = {
++ .owner = THIS_MODULE,
++ .drv = {
++ .name = DRV_NAME,
++ },
++ .probe = if_cs_probe,
++ .remove = if_cs_detach,
++ .id_table = if_cs_ids,
++};
++
++
++static int __init if_cs_init(void)
++{
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_CS);
++ ret = pcmcia_register_driver(&lbs_driver);
++ lbs_deb_leave(LBS_DEB_CS);
++ return ret;
++}
++
++
++static void __exit if_cs_exit(void)
++{
++ lbs_deb_enter(LBS_DEB_CS);
++ pcmcia_unregister_driver(&lbs_driver);
++ lbs_deb_leave(LBS_DEB_CS);
++}
++
++
++module_init(if_cs_init);
++module_exit(if_cs_exit);
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/if_sdio.c linux-2.6.22-300/drivers/net/wireless/libertas/if_sdio.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/if_sdio.c 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.22-300/drivers/net/wireless/libertas/if_sdio.c 2008-06-05 18:10:06.000000000 -0400
+@@ -0,0 +1,1073 @@
++/*
++ * linux/drivers/net/wireless/libertas/if_sdio.c
++ *
++ * Copyright 2007 Pierre Ossman
++ *
++ * Inspired by if_cs.c, Copyright 2007 Holger Schurig
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at
++ * your option) any later version.
++ *
++ * This hardware has more or less no CMD53 support, so all registers
++ * must be accessed using sdio_readb()/sdio_writeb().
++ *
++ * Transfers must be in one transaction or the firmware goes bonkers.
++ * This means that the transfer must either be small enough to do a
++ * byte based transfer or it must be padded to a multiple of the
++ * current block size.
++ *
++ * As SDIO is still new to the kernel, it is unfortunately common with
++ * bugs in the host controllers related to that. One such bug is that
++ * controllers cannot do transfers that aren't a multiple of 4 bytes.
++ * If you don't have time to fix the host controller driver, you can
++ * work around the problem by modifying if_sdio_host_to_card() and
++ * if_sdio_card_to_host() to pad the data.
++ */
++
++#include <linux/moduleparam.h>
++#include <linux/firmware.h>
++#include <linux/netdevice.h>
++#include <linux/delay.h>
++#include <linux/mmc/card.h>
++#include <linux/mmc/sdio_func.h>
++#include <linux/mmc/sdio_ids.h>
++
++#include "host.h"
++#include "decl.h"
++#include "defs.h"
++#include "dev.h"
++#include "if_sdio.h"
++
++static char *lbs_helper_name = NULL;
++module_param_named(helper_name, lbs_helper_name, charp, 0644);
++
++static char *lbs_fw_name = NULL;
++module_param_named(fw_name, lbs_fw_name, charp, 0644);
++
++static const struct sdio_device_id if_sdio_ids[] = {
++ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
++ { /* end: all zeroes */ },
++};
++
++MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
++
++struct if_sdio_model {
++ int model;
++ const char *helper;
++ const char *firmware;
++};
++
++static struct if_sdio_model if_sdio_models[] = {
++ {
++ /* 8385 */
++ .model = 0x04,
++ .helper = "sd8385_helper.bin",
++ .firmware = "sd8385.bin",
++ },
++ {
++ /* 8686 */
++ .model = 0x0B,
++ .helper = "sd8686_helper.bin",
++ .firmware = "sd8686.bin",
++ },
++};
++
++struct if_sdio_packet {
++ struct if_sdio_packet *next;
++ u16 nb;
++ u8 buffer[0] __attribute__((aligned(4)));
++};
++
++struct if_sdio_card {
++ struct sdio_func *func;
++ struct lbs_private *priv;
++
++ int model;
++ unsigned long ioport;
++
++ const char *helper;
++ const char *firmware;
++
++ u8 buffer[65536];
++ u8 int_cause;
++ u32 event;
++
++ spinlock_t lock;
++ struct if_sdio_packet *packets;
++ struct work_struct packet_worker;
++};
++
++/********************************************************************/
++/* I/O */
++/********************************************************************/
++
++static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
++{
++ int ret, reg;
++ u16 scratch;
++
++ if (card->model == 0x04)
++ reg = IF_SDIO_SCRATCH_OLD;
++ else
++ reg = IF_SDIO_SCRATCH;
++
++ scratch = sdio_readb(card->func, reg, &ret);
++ if (!ret)
++ scratch |= sdio_readb(card->func, reg + 1, &ret) << 8;
++
++ if (err)
++ *err = ret;
++
++ if (ret)
++ return 0xffff;
++
++ return scratch;
++}
++
++static int if_sdio_handle_cmd(struct if_sdio_card *card,
++ u8 *buffer, unsigned size)
++{
++ int ret;
++ unsigned long flags;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ spin_lock_irqsave(&card->priv->driver_lock, flags);
++
++ if (size > LBS_CMD_BUFFER_SIZE) {
++ lbs_deb_sdio("response packet too large (%d bytes)\n",
++ (int)size);
++ ret = -E2BIG;
++ goto out;
++ }
++
++ memcpy(card->priv->upld_buf, buffer, size);
++ card->priv->upld_len = size;
++
++ card->int_cause |= MRVDRV_CMD_UPLD_RDY;
++
++ lbs_interrupt(card->priv);
++
++ ret = 0;
++
++out:
++ spin_unlock_irqrestore(&card->priv->driver_lock, flags);
++
++ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
++
++ return ret;
++}
++
++static int if_sdio_handle_data(struct if_sdio_card *card,
++ u8 *buffer, unsigned size)
++{
++ int ret;
++ struct sk_buff *skb;
++ char *data;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ if (size > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
++ lbs_deb_sdio("response packet too large (%d bytes)\n",
++ (int)size);
++ ret = -E2BIG;
++ goto out;
++ }
++
++ skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + NET_IP_ALIGN);
++ if (!skb) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ skb_reserve(skb, NET_IP_ALIGN);
++
++ data = skb_put(skb, size);
++
++ memcpy(data, buffer, size);
++
++ lbs_process_rxed_packet(card->priv, skb);
++
++ ret = 0;
++
++out:
++ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
++
++ return ret;
++}
++
++static int if_sdio_handle_event(struct if_sdio_card *card,
++ u8 *buffer, unsigned size)
++{
++ int ret;
++ unsigned long flags;
++ u32 event;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ if (card->model == 0x04) {
++ event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
++ if (ret)
++ goto out;
++ } else {
++ if (size < 4) {
++ lbs_deb_sdio("event packet too small (%d bytes)\n",
++ (int)size);
++ ret = -EINVAL;
++ goto out;
++ }
++ event = buffer[3] << 24;
++ event |= buffer[2] << 16;
++ event |= buffer[1] << 8;
++ event |= buffer[0] << 0;
++ event <<= SBI_EVENT_CAUSE_SHIFT;
++ }
++
++ spin_lock_irqsave(&card->priv->driver_lock, flags);
++
++ card->event = event;
++ card->int_cause |= MRVDRV_CARDEVENT;
++
++ lbs_interrupt(card->priv);
++
++ spin_unlock_irqrestore(&card->priv->driver_lock, flags);
++
++ ret = 0;
++
++out:
++ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
++
++ return ret;
++}
++
++static int if_sdio_card_to_host(struct if_sdio_card *card)
++{
++ int ret;
++ u8 status;
++ u16 size, type, chunk;
++ unsigned long timeout;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ size = if_sdio_read_scratch(card, &ret);
++ if (ret)
++ goto out;
++
++ if (size < 4) {
++ lbs_deb_sdio("invalid packet size (%d bytes) from firmware\n",
++ (int)size);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ timeout = jiffies + HZ;
++ while (1) {
++ status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
++ if (ret)
++ goto out;
++ if (status & IF_SDIO_IO_RDY)
++ break;
++ if (time_after(jiffies, timeout)) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++ mdelay(1);
++ }
++
++ /*
++ * The transfer must be in one transaction or the firmware
++ * goes suicidal.
++ */
++ chunk = size;
++ if ((chunk > card->func->cur_blksize) || (chunk > 512)) {
++ chunk = (chunk + card->func->cur_blksize - 1) /
++ card->func->cur_blksize * card->func->cur_blksize;
++ }
++
++ ret = sdio_readsb(card->func, card->buffer, card->ioport, chunk);
++ if (ret)
++ goto out;
++
++ chunk = card->buffer[0] | (card->buffer[1] << 8);
++ type = card->buffer[2] | (card->buffer[3] << 8);
++
++ lbs_deb_sdio("packet of type %d and size %d bytes\n",
++ (int)type, (int)chunk);
++
++ if (chunk > size) {
++ lbs_deb_sdio("packet fragment (%d > %d)\n",
++ (int)chunk, (int)size);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (chunk < size) {
++ lbs_deb_sdio("packet fragment (%d < %d)\n",
++ (int)chunk, (int)size);
++ }
++
++ switch (type) {
++ case MVMS_CMD:
++ ret = if_sdio_handle_cmd(card, card->buffer + 4, chunk - 4);
++ if (ret)
++ goto out;
++ break;
++ case MVMS_DAT:
++ ret = if_sdio_handle_data(card, card->buffer + 4, chunk - 4);
++ if (ret)
++ goto out;
++ break;
++ case MVMS_EVENT:
++ ret = if_sdio_handle_event(card, card->buffer + 4, chunk - 4);
++ if (ret)
++ goto out;
++ break;
++ default:
++ lbs_deb_sdio("invalid type (%d) from firmware\n",
++ (int)type);
++ ret = -EINVAL;
++ goto out;
++ }
++
++out:
++ if (ret)
++ lbs_pr_err("problem fetching packet from firmware\n");
++
++ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
++
++ return ret;
++}
++
++static void if_sdio_host_to_card_worker(struct work_struct *work)
++{
++ struct if_sdio_card *card;
++ struct if_sdio_packet *packet;
++ unsigned long timeout;
++ u8 status;
++ int ret;
++ unsigned long flags;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ card = container_of(work, struct if_sdio_card, packet_worker);
++
++ while (1) {
++ spin_lock_irqsave(&card->lock, flags);
++ packet = card->packets;
++ if (packet)
++ card->packets = packet->next;
++ spin_unlock_irqrestore(&card->lock, flags);
++
++ if (!packet)
++ break;
++
++ sdio_claim_host(card->func);
++
++ timeout = jiffies + HZ;
++ while (1) {
++ status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
++ if (ret)
++ goto release;
++ if (status & IF_SDIO_IO_RDY)
++ break;
++ if (time_after(jiffies, timeout)) {
++ ret = -ETIMEDOUT;
++ goto release;
++ }
++ mdelay(1);
++ }
++
++ ret = sdio_writesb(card->func, card->ioport,
++ packet->buffer, packet->nb);
++ if (ret)
++ goto release;
++release:
++ sdio_release_host(card->func);
++
++ kfree(packet);
++ }
++
++ lbs_deb_leave(LBS_DEB_SDIO);
++}
++
++/********************************************************************/
++/* Firmware */
++/********************************************************************/
++
++static int if_sdio_prog_helper(struct if_sdio_card *card)
++{
++ int ret;
++ u8 status;
++ const struct firmware *fw;
++ unsigned long timeout;
++ u8 *chunk_buffer;
++ u32 chunk_size;
++ u8 *firmware;
++ size_t size;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ ret = request_firmware(&fw, card->helper, &card->func->dev);
++ if (ret) {
++ lbs_pr_err("can't load helper firmware\n");
++ goto out;
++ }
++
++ chunk_buffer = kzalloc(64, GFP_KERNEL);
++ if (!chunk_buffer) {
++ ret = -ENOMEM;
++ goto release_fw;
++ }
++
++ sdio_claim_host(card->func);
++
++ ret = sdio_set_block_size(card->func, 32);
++ if (ret)
++ goto release;
++
++ firmware = fw->data;
++ size = fw->size;
++
++ while (size) {
++ timeout = jiffies + HZ;
++ while (1) {
++ status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
++ if (ret)
++ goto release;
++ if ((status & IF_SDIO_IO_RDY) &&
++ (status & IF_SDIO_DL_RDY))
++ break;
++ if (time_after(jiffies, timeout)) {
++ ret = -ETIMEDOUT;
++ goto release;
++ }
++ mdelay(1);
++ }
++
++ chunk_size = min(size, (size_t)60);
++
++ *((__le32*)chunk_buffer) = cpu_to_le32(chunk_size);
++ memcpy(chunk_buffer + 4, firmware, chunk_size);
++/*
++ lbs_deb_sdio("sending %d bytes chunk\n", chunk_size);
++*/
++ ret = sdio_writesb(card->func, card->ioport,
++ chunk_buffer, 64);
++ if (ret)
++ goto release;
++
++ firmware += chunk_size;
++ size -= chunk_size;
++ }
++
++ /* an empty block marks the end of the transfer */
++ memset(chunk_buffer, 0, 4);
++ ret = sdio_writesb(card->func, card->ioport, chunk_buffer, 64);
++ if (ret)
++ goto release;
++
++ lbs_deb_sdio("waiting for helper to boot...\n");
++
++ /* wait for the helper to boot by looking at the size register */
++ timeout = jiffies + HZ;
++ while (1) {
++ u16 req_size;
++
++ req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
++ if (ret)
++ goto release;
++
++ req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
++ if (ret)
++ goto release;
++
++ if (req_size != 0)
++ break;
++
++ if (time_after(jiffies, timeout)) {
++ ret = -ETIMEDOUT;
++ goto release;
++ }
++
++ msleep(10);
++ }
++
++ ret = 0;
++
++release:
++ sdio_set_block_size(card->func, 0);
++ sdio_release_host(card->func);
++ kfree(chunk_buffer);
++release_fw:
++ release_firmware(fw);
++
++out:
++ if (ret)
++ lbs_pr_err("failed to load helper firmware\n");
++
++ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
++
++ return ret;
++}
++
++static int if_sdio_prog_real(struct if_sdio_card *card)
++{
++ int ret;
++ u8 status;
++ const struct firmware *fw;
++ unsigned long timeout;
++ u8 *chunk_buffer;
++ u32 chunk_size;
++ u8 *firmware;
++ size_t size, req_size;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ ret = request_firmware(&fw, card->firmware, &card->func->dev);
++ if (ret) {
++ lbs_pr_err("can't load firmware\n");
++ goto out;
++ }
++
++ chunk_buffer = kzalloc(512, GFP_KERNEL);
++ if (!chunk_buffer) {
++ ret = -ENOMEM;
++ goto release_fw;
++ }
++
++ sdio_claim_host(card->func);
++
++ ret = sdio_set_block_size(card->func, 32);
++ if (ret)
++ goto release;
++
++ firmware = fw->data;
++ size = fw->size;
++
++ while (size) {
++ timeout = jiffies + HZ;
++ while (1) {
++ status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
++ if (ret)
++ goto release;
++ if ((status & IF_SDIO_IO_RDY) &&
++ (status & IF_SDIO_DL_RDY))
++ break;
++ if (time_after(jiffies, timeout)) {
++ ret = -ETIMEDOUT;
++ goto release;
++ }
++ mdelay(1);
++ }
++
++ req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
++ if (ret)
++ goto release;
++
++ req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
++ if (ret)
++ goto release;
++/*
++ lbs_deb_sdio("firmware wants %d bytes\n", (int)req_size);
++*/
++ if (req_size == 0) {
++ lbs_deb_sdio("firmware helper gave up early\n");
++ ret = -EIO;
++ goto release;
++ }
++
++ if (req_size & 0x01) {
++ lbs_deb_sdio("firmware helper signalled error\n");
++ ret = -EIO;
++ goto release;
++ }
++
++ if (req_size > size)
++ req_size = size;
++
++ while (req_size) {
++ chunk_size = min(req_size, (size_t)512);
++
++ memcpy(chunk_buffer, firmware, chunk_size);
++/*
++ lbs_deb_sdio("sending %d bytes (%d bytes) chunk\n",
++ chunk_size, (chunk_size + 31) / 32 * 32);
++*/
++ ret = sdio_writesb(card->func, card->ioport,
++ chunk_buffer, (chunk_size + 31) / 32 * 32);
++ if (ret)
++ goto release;
++
++ firmware += chunk_size;
++ size -= chunk_size;
++ req_size -= chunk_size;
++ }
++ }
++
++ ret = 0;
++
++ lbs_deb_sdio("waiting for firmware to boot...\n");
++
++ /* wait for the firmware to boot */
++ timeout = jiffies + HZ;
++ while (1) {
++ u16 scratch;
++
++ scratch = if_sdio_read_scratch(card, &ret);
++ if (ret)
++ goto release;
++
++ if (scratch == IF_SDIO_FIRMWARE_OK)
++ break;
++
++ if (time_after(jiffies, timeout)) {
++ ret = -ETIMEDOUT;
++ goto release;
++ }
++
++ msleep(10);
++ }
++
++ ret = 0;
++
++release:
++ sdio_set_block_size(card->func, 0);
++ sdio_release_host(card->func);
++ kfree(chunk_buffer);
++release_fw:
++ release_firmware(fw);
++
++out:
++ if (ret)
++ lbs_pr_err("failed to load firmware\n");
++
++ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
++
++ return ret;
++}
++
++static int if_sdio_prog_firmware(struct if_sdio_card *card)
++{
++ int ret;
++ u16 scratch;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ sdio_claim_host(card->func);
++ scratch = if_sdio_read_scratch(card, &ret);
++ sdio_release_host(card->func);
++
++ if (ret)
++ goto out;
++
++ if (scratch == IF_SDIO_FIRMWARE_OK) {
++ lbs_deb_sdio("firmware already loaded\n");
++ goto success;
++ }
++
++ ret = if_sdio_prog_helper(card);
++ if (ret)
++ goto out;
++
++ ret = if_sdio_prog_real(card);
++ if (ret)
++ goto out;
++
++success:
++ ret = 0;
++
++out:
++ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
++
++ return ret;
++}
++
++/*******************************************************************/
++/* Libertas callbacks */
++/*******************************************************************/
++
++static int if_sdio_host_to_card(struct lbs_private *priv,
++ u8 type, u8 *buf, u16 nb)
++{
++ int ret;
++ struct if_sdio_card *card;
++ struct if_sdio_packet *packet, *cur;
++ u16 size;
++ unsigned long flags;
++
++ lbs_deb_enter_args(LBS_DEB_SDIO, "type %d, bytes %d", type, nb);
++
++ card = priv->card;
++
++ if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ /*
++ * The transfer must be in one transaction or the firmware
++ * goes suicidal.
++ */
++ size = nb + 4;
++ if ((size > card->func->cur_blksize) || (size > 512)) {
++ size = (size + card->func->cur_blksize - 1) /
++ card->func->cur_blksize * card->func->cur_blksize;
++ }
++
++ packet = kzalloc(sizeof(struct if_sdio_packet) + size,
++ GFP_ATOMIC);
++ if (!packet) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ packet->next = NULL;
++ packet->nb = size;
++
++ /*
++ * SDIO specific header.
++ */
++ packet->buffer[0] = (nb + 4) & 0xff;
++ packet->buffer[1] = ((nb + 4) >> 8) & 0xff;
++ packet->buffer[2] = type;
++ packet->buffer[3] = 0;
++
++ memcpy(packet->buffer + 4, buf, nb);
++
++ spin_lock_irqsave(&card->lock, flags);
++
++ if (!card->packets)
++ card->packets = packet;
++ else {
++ cur = card->packets;
++ while (cur->next)
++ cur = cur->next;
++ cur->next = packet;
++ }
++
++ switch (type) {
++ case MVMS_CMD:
++ priv->dnld_sent = DNLD_CMD_SENT;
++ break;
++ case MVMS_DAT:
++ priv->dnld_sent = DNLD_DATA_SENT;
++ break;
++ default:
++ lbs_deb_sdio("unknown packet type %d\n", (int)type);
++ }
++
++ spin_unlock_irqrestore(&card->lock, flags);
++
++ schedule_work(&card->packet_worker);
++
++ ret = 0;
++
++out:
++ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
++
++ return ret;
++}
++
++static int if_sdio_get_int_status(struct lbs_private *priv, u8 *ireg)
++{
++ struct if_sdio_card *card;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ card = priv->card;
++
++ *ireg = card->int_cause;
++ card->int_cause = 0;
++
++ lbs_deb_leave(LBS_DEB_SDIO);
++
++ return 0;
++}
++
++static int if_sdio_read_event_cause(struct lbs_private *priv)
++{
++ struct if_sdio_card *card;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ card = priv->card;
++
++ priv->eventcause = card->event;
++
++ lbs_deb_leave(LBS_DEB_SDIO);
++
++ return 0;
++}
++
++/*******************************************************************/
++/* SDIO callbacks */
++/*******************************************************************/
++
++static void if_sdio_interrupt(struct sdio_func *func)
++{
++ int ret;
++ struct if_sdio_card *card;
++ u8 cause;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ card = sdio_get_drvdata(func);
++
++ cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
++ if (ret)
++ goto out;
++
++ lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
++
++ sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
++ if (ret)
++ goto out;
++
++ /*
++ * Ignore the define name, this really means the card has
++ * successfully received the command.
++ */
++ if (cause & IF_SDIO_H_INT_DNLD)
++ lbs_host_to_card_done(card->priv);
++
++
++ if (cause & IF_SDIO_H_INT_UPLD) {
++ ret = if_sdio_card_to_host(card);
++ if (ret)
++ goto out;
++ }
++
++ ret = 0;
++
++out:
++ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
++}
++
++static int if_sdio_probe(struct sdio_func *func,
++ const struct sdio_device_id *id)
++{
++ struct if_sdio_card *card;
++ struct lbs_private *priv;
++ int ret, i;
++ unsigned int model;
++ struct if_sdio_packet *packet;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ for (i = 0;i < func->card->num_info;i++) {
++ if (sscanf(func->card->info[i],
++ "802.11 SDIO ID: %x", &model) == 1)
++ break;
++ if (sscanf(func->card->info[i],
++ "ID: %x", &model) == 1)
++ break;
++ }
++
++ if (i == func->card->num_info) {
++ lbs_pr_err("unable to identify card model\n");
++ return -ENODEV;
++ }
++
++ card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);
++ if (!card)
++ return -ENOMEM;
++
++ card->func = func;
++ card->model = model;
++ spin_lock_init(&card->lock);
++ INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
++
++ for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) {
++ if (card->model == if_sdio_models[i].model)
++ break;
++ }
++
++ if (i == ARRAY_SIZE(if_sdio_models)) {
++ lbs_pr_err("unkown card model 0x%x\n", card->model);
++ ret = -ENODEV;
++ goto free;
++ }
++
++ card->helper = if_sdio_models[i].helper;
++ card->firmware = if_sdio_models[i].firmware;
++
++ if (lbs_helper_name) {
++ lbs_deb_sdio("overriding helper firmware: %s\n",
++ lbs_helper_name);
++ card->helper = lbs_helper_name;
++ }
++
++ if (lbs_fw_name) {
++ lbs_deb_sdio("overriding firmware: %s\n", lbs_fw_name);
++ card->firmware = lbs_fw_name;
++ }
++
++ sdio_claim_host(func);
++
++ ret = sdio_enable_func(func);
++ if (ret)
++ goto release;
++
++ ret = sdio_claim_irq(func, if_sdio_interrupt);
++ if (ret)
++ goto disable;
++
++ card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
++ if (ret)
++ goto release_int;
++
++ card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
++ if (ret)
++ goto release_int;
++
++ card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
++ if (ret)
++ goto release_int;
++
++ sdio_release_host(func);
++
++ sdio_set_drvdata(func, card);
++
++ lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "
++ "device = 0x%X, model = 0x%X, ioport = 0x%X\n",
++ func->class, func->vendor, func->device,
++ model, (unsigned)card->ioport);
++
++ ret = if_sdio_prog_firmware(card);
++ if (ret)
++ goto reclaim;
++
++ priv = lbs_add_card(card, &func->dev);
++ if (!priv) {
++ ret = -ENOMEM;
++ goto reclaim;
++ }
++
++ card->priv = priv;
++
++ priv->card = card;
++ priv->hw_host_to_card = if_sdio_host_to_card;
++ priv->hw_get_int_status = if_sdio_get_int_status;
++ priv->hw_read_event_cause = if_sdio_read_event_cause;
++
++ priv->fw_ready = 1;
++
++ /*
++ * Enable interrupts now that everything is set up
++ */
++ sdio_claim_host(func);
++ sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
++ sdio_release_host(func);
++ if (ret)
++ goto reclaim;
++
++ ret = lbs_start_card(priv);
++ if (ret)
++ goto err_activate_card;
++
++out:
++ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
++
++ return ret;
++
++err_activate_card:
++ flush_scheduled_work();
++ free_netdev(priv->dev);
++ kfree(priv);
++reclaim:
++ sdio_claim_host(func);
++release_int:
++ sdio_release_irq(func);
++disable:
++ sdio_disable_func(func);
++release:
++ sdio_release_host(func);
++free:
++ while (card->packets) {
++ packet = card->packets;
++ card->packets = card->packets->next;
++ kfree(packet);
++ }
++
++ kfree(card);
++
++ goto out;
++}
++
++static void if_sdio_remove(struct sdio_func *func)
++{
++ struct if_sdio_card *card;
++ struct if_sdio_packet *packet;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ card = sdio_get_drvdata(func);
++
++ card->priv->surpriseremoved = 1;
++
++ lbs_deb_sdio("call remove card\n");
++ lbs_stop_card(card->priv);
++ lbs_remove_card(card->priv);
++
++ flush_scheduled_work();
++
++ sdio_claim_host(func);
++ sdio_release_irq(func);
++ sdio_disable_func(func);
++ sdio_release_host(func);
++
++ while (card->packets) {
++ packet = card->packets;
++ card->packets = card->packets->next;
++ kfree(packet);
++ }
++
++ kfree(card);
++
++ lbs_deb_leave(LBS_DEB_SDIO);
++}
++
++static struct sdio_driver if_sdio_driver = {
++ .name = "libertas_sdio",
++ .id_table = if_sdio_ids,
++ .probe = if_sdio_probe,
++ .remove = if_sdio_remove,
++};
++
++/*******************************************************************/
++/* Module functions */
++/*******************************************************************/
++
++static int __init if_sdio_init_module(void)
++{
++ int ret = 0;
++
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ printk(KERN_INFO "libertas_sdio: Libertas SDIO driver\n");
++ printk(KERN_INFO "libertas_sdio: Copyright Pierre Ossman\n");
++
++ ret = sdio_register_driver(&if_sdio_driver);
++
++ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
++
++ return ret;
++}
++
++static void __exit if_sdio_exit_module(void)
++{
++ lbs_deb_enter(LBS_DEB_SDIO);
++
++ sdio_unregister_driver(&if_sdio_driver);
++
++ lbs_deb_leave(LBS_DEB_SDIO);
++}
++
++module_init(if_sdio_init_module);
++module_exit(if_sdio_exit_module);
++
++MODULE_DESCRIPTION("Libertas SDIO WLAN Driver");
++MODULE_AUTHOR("Pierre Ossman");
++MODULE_LICENSE("GPL");
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/if_sdio.h linux-2.6.22-300/drivers/net/wireless/libertas/if_sdio.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/if_sdio.h 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.22-300/drivers/net/wireless/libertas/if_sdio.h 2008-05-27 16:42:14.000000000 -0400
+@@ -0,0 +1,45 @@
++/*
++ * linux/drivers/net/wireless/libertas/if_sdio.h
++ *
++ * Copyright 2007 Pierre Ossman
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef _LBS_IF_SDIO_H
++#define _LBS_IF_SDIO_H
++
++#define IF_SDIO_IOPORT 0x00
++
++#define IF_SDIO_H_INT_MASK 0x04
++#define IF_SDIO_H_INT_OFLOW 0x08
++#define IF_SDIO_H_INT_UFLOW 0x04
++#define IF_SDIO_H_INT_DNLD 0x02
++#define IF_SDIO_H_INT_UPLD 0x01
++
++#define IF_SDIO_H_INT_STATUS 0x05
++#define IF_SDIO_H_INT_RSR 0x06
++#define IF_SDIO_H_INT_STATUS2 0x07
++
++#define IF_SDIO_RD_BASE 0x10
++
++#define IF_SDIO_STATUS 0x20
++#define IF_SDIO_IO_RDY 0x08
++#define IF_SDIO_CIS_RDY 0x04
++#define IF_SDIO_UL_RDY 0x02
++#define IF_SDIO_DL_RDY 0x01
++
++#define IF_SDIO_C_INT_MASK 0x24
++#define IF_SDIO_C_INT_STATUS 0x28
++#define IF_SDIO_C_INT_RSR 0x2C
++
++#define IF_SDIO_SCRATCH 0x34
++#define IF_SDIO_SCRATCH_OLD 0x80fe
++#define IF_SDIO_FIRMWARE_OK 0xfedc
++
++#define IF_SDIO_EVENT 0x80fc
++
++#endif
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/if_usb.c linux-2.6.22-300/drivers/net/wireless/libertas/if_usb.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/if_usb.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/if_usb.c 2008-06-05 18:29:37.000000000 -0400
+@@ -5,8 +5,8 @@
+ #include <linux/moduleparam.h>
+ #include <linux/firmware.h>
+ #include <linux/netdevice.h>
+-#include <linux/list.h>
+ #include <linux/usb.h>
++#include <asm/olpc.h>
+
+ #define DRV_NAME "usb8xxx"
+
+@@ -14,24 +14,16 @@
+ #include "decl.h"
+ #include "defs.h"
+ #include "dev.h"
++#include "cmd.h"
+ #include "if_usb.h"
+
+-#define MESSAGE_HEADER_LEN 4
+-
+-static const char usbdriver_name[] = "usb8xxx";
+-static u8 *default_fw_name = "usb8388.bin";
++#define INSANEDEBUG 0
++#define lbs_deb_usb2(...) do { if (INSANEDEBUG) lbs_deb_usbd(__VA_ARGS__); } while (0)
+
+-char *libertas_fw_name = NULL;
+-module_param_named(fw_name, libertas_fw_name, charp, 0644);
++#define MESSAGE_HEADER_LEN 4
+
+-/*
+- * We need to send a RESET command to all USB devices before
+- * we tear down the USB connection. Otherwise we would not
+- * be able to re-init device the device if the module gets
+- * loaded again. This is a list of all initialized USB devices,
+- * for the reset code see if_usb_reset_device()
+-*/
+-static LIST_HEAD(usb_devices);
++static char *lbs_fw_name = "usb8388.bin";
++module_param_named(fw_name, lbs_fw_name, charp, 0644);
+
+ static struct usb_device_id if_usb_table[] = {
+ /* Enter the device signature inside */
+@@ -44,13 +36,73 @@ MODULE_DEVICE_TABLE(usb, if_usb_table);
+
+ static void if_usb_receive(struct urb *urb);
+ static void if_usb_receive_fwload(struct urb *urb);
+-static int if_usb_reset_device(wlan_private *priv);
+-static int if_usb_register_dev(wlan_private * priv);
+-static int if_usb_unregister_dev(wlan_private *);
+-static int if_usb_prog_firmware(wlan_private *);
+-static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
+-static int if_usb_get_int_status(wlan_private * priv, u8 *);
+-static int if_usb_read_event_cause(wlan_private *);
++static int if_usb_prog_firmware(struct if_usb_card *cardp,
++ const char *fwname, int cmd);
++static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
++ uint8_t *payload, uint16_t nb);
++static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *);
++static int if_usb_read_event_cause(struct lbs_private *);
++static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
++ uint16_t nb);
++static void if_usb_free(struct if_usb_card *cardp);
++static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
++static int if_usb_reset_device(struct if_usb_card *cardp);
++
++/* sysfs hooks */
++
++/**
++ * Set function to write firmware to device's persistent memory
++ */
++static ssize_t if_usb_firmware_set(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct lbs_private *priv = to_net_dev(dev)->priv;
++ struct if_usb_card *cardp = priv->card;
++ char fwname[FIRMWARE_NAME_MAX];
++ int ret;
++
++ sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */
++ ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_FW);
++ if (ret == 0)
++ return count;
++
++ return ret;
++}
++
++/**
++ * lbs_fw attribute to be exported per ethX interface through sysfs
++ * (/sys/class/net/ethX/lbs_fw). Use this like so to write firmware to the
++ * device's persistent memory:
++ * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_fw
++ */
++static DEVICE_ATTR(lbs_fw, 0200, NULL, if_usb_firmware_set);
++
++/**
++ * Set function to write firmware to device's persistent memory
++ */
++static ssize_t if_usb_boot2_set(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct lbs_private *priv = to_net_dev(dev)->priv;
++ struct if_usb_card *cardp = priv->card;
++ char fwname[FIRMWARE_NAME_MAX];
++ int ret;
++
++ sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */
++ ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_BOOT2);
++ if (ret == 0)
++ return count;
++
++ return ret;
++}
++
++/**
++ * lbs_boot2 attribute to be exported per ethX interface through sysfs
++ * (/sys/class/net/ethX/lbs_boot2). Use this like so to write firmware to the
++ * device's persistent memory:
++ * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_boot2
++ */
++static DEVICE_ATTR(lbs_boot2, 0200, NULL, if_usb_boot2_set);
+
+ /**
+ * @brief call back function to handle the status of the URB
+@@ -59,29 +111,25 @@ static int if_usb_read_event_cause(wlan_
+ */
+ static void if_usb_write_bulk_callback(struct urb *urb)
+ {
+- wlan_private *priv = (wlan_private *) (urb->context);
+- wlan_adapter *adapter = priv->adapter;
+- struct net_device *dev = priv->dev;
++ struct if_usb_card *cardp = (struct if_usb_card *) urb->context;
+
+ /* handle the transmission complete validations */
+
+- if (urb->status != 0) {
++ if (urb->status == 0) {
++ struct lbs_private *priv = cardp->priv;
++
++ lbs_deb_usb2(&urb->dev->dev, "URB status is successful\n");
++ lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n",
++ urb->actual_length);
++
++ /* Used for both firmware TX and regular TX. priv isn't
++ * valid at firmware load time.
++ */
++ if (priv)
++ lbs_host_to_card_done(priv);
++ } else {
+ /* print the failure status number for debug */
+ lbs_pr_info("URB in failure status: %d\n", urb->status);
+- } else {
+- /*
+- lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n");
+- lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n",
+- urb->actual_length);
+- */
+- priv->dnld_sent = DNLD_RES_RECEIVED;
+- /* Wake main thread if commands are pending */
+- if (!adapter->cur_cmd)
+- wake_up_interruptible(&priv->mainthread.waitq);
+- if ((adapter->connect_status == libertas_connected)) {
+- netif_wake_queue(dev);
+- netif_wake_queue(priv->mesh_dev);
+- }
+ }
+
+ return;
+@@ -89,10 +137,10 @@ static void if_usb_write_bulk_callback(s
+
+ /**
+ * @brief free tx/rx urb, skb and rx buffer
+- * @param cardp pointer usb_card_rec
++ * @param cardp pointer if_usb_card
+ * @return N/A
+ */
+-void if_usb_free(struct usb_card_rec *cardp)
++static void if_usb_free(struct if_usb_card *cardp)
+ {
+ lbs_deb_enter(LBS_DEB_USB);
+
+@@ -106,12 +154,57 @@ void if_usb_free(struct usb_card_rec *ca
+ usb_free_urb(cardp->rx_urb);
+ cardp->rx_urb = NULL;
+
+- kfree(cardp->bulk_out_buffer);
+- cardp->bulk_out_buffer = NULL;
++ kfree(cardp->ep_out_buf);
++ cardp->ep_out_buf = NULL;
+
+ lbs_deb_leave(LBS_DEB_USB);
+ }
+
++static void if_usb_setup_firmware(struct lbs_private *priv)
++{
++ struct cmd_ds_set_boot2_ver b2_cmd;
++ struct cmd_ds_802_11_fw_wake_method wake_method;
++
++ b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
++ b2_cmd.action = 0;
++ b2_cmd.version = priv->boot2_version;
++
++ if (lbs_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd))
++ lbs_deb_usb("Setting boot2 version failed\n");
++
++ priv->wol_gpio = 2; /* Wake via GPIO2... */
++ priv->wol_gap = 20; /* ... after 20ms */
++ lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA);
++
++ wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
++ wake_method.action = cpu_to_le16(CMD_ACT_GET);
++ if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
++ lbs_pr_info("Firmware does not seem to support PS mode\n");
++ } else {
++ if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
++ lbs_deb_usb("Firmware seems to support PS with wake-via-command\n");
++ priv->ps_supported = 1;
++ } else {
++ /* The versions which boot up this way don't seem to
++ work even if we set it to the command interrupt */
++ lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
++ }
++ }
++}
++
++static void if_usb_fw_timeo(unsigned long priv)
++{
++ struct if_usb_card *cardp = (void *)priv;
++
++ if (cardp->fwdnldover) {
++ lbs_deb_usb("Download complete, no event. Assuming success\n");
++ } else {
++ lbs_pr_err("Download timed out\n");
++ cardp->surprise_removed = 1;
++ }
++ wake_up(&cardp->fw_wq);
++}
++
+ /**
+ * @brief sets the configuration values
+ * @param ifnum interface number
+@@ -124,23 +217,26 @@ static int if_usb_probe(struct usb_inter
+ struct usb_device *udev;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+- wlan_private *priv;
+- struct usb_card_rec *cardp;
++ struct lbs_private *priv;
++ struct if_usb_card *cardp;
+ int i;
+
+ udev = interface_to_usbdev(intf);
+
+- cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL);
++ cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
+ if (!cardp) {
+ lbs_pr_err("Out of memory allocating private data.\n");
+ goto error;
+ }
+
++ setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp);
++ init_waitqueue_head(&cardp->fw_wq);
++
+ cardp->udev = udev;
+ iface_desc = intf->cur_altsetting;
+
+ lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
+- " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
++ " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
+ le16_to_cpu(udev->descriptor.bcdUSB),
+ udev->descriptor.bDeviceClass,
+ udev->descriptor.bDeviceSubClass,
+@@ -148,89 +244,78 @@ static int if_usb_probe(struct usb_inter
+
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+- if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+- && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+- USB_ENDPOINT_XFER_BULK)) {
+- /* we found a bulk in endpoint */
+- lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n",
+- le16_to_cpu(endpoint->wMaxPacketSize));
+- if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
+- lbs_deb_usbd(&udev->dev,
+- "Rx URB allocation failed\n");
+- goto dealloc;
+- }
+- cardp->rx_urb_recall = 0;
++ if (usb_endpoint_is_bulk_in(endpoint)) {
++ cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
++ cardp->ep_in = usb_endpoint_num(endpoint);
++
++ lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
++ lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
++
++ } else if (usb_endpoint_is_bulk_out(endpoint)) {
++ cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
++ cardp->ep_out = usb_endpoint_num(endpoint);
+
+- cardp->bulk_in_size =
+- le16_to_cpu(endpoint->wMaxPacketSize);
+- cardp->bulk_in_endpointAddr =
+- (endpoint->
+- bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+- lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n",
+- endpoint->bEndpointAddress);
++ lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
++ lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
+ }
++ }
++ if (!cardp->ep_out_size || !cardp->ep_in_size) {
++ lbs_deb_usbd(&udev->dev, "Endpoints not found\n");
++ goto dealloc;
++ }
++ if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
++ lbs_deb_usbd(&udev->dev, "Rx URB allocation failed\n");
++ goto dealloc;
++ }
++ if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
++ lbs_deb_usbd(&udev->dev, "Tx URB allocation failed\n");
++ goto dealloc;
++ }
++ cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, GFP_KERNEL);
++ if (!cardp->ep_out_buf) {
++ lbs_deb_usbd(&udev->dev, "Could not allocate buffer\n");
++ goto dealloc;
++ }
+
+- if (((endpoint->
+- bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+- USB_DIR_OUT)
+- && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+- USB_ENDPOINT_XFER_BULK)) {
+- /* We found bulk out endpoint */
+- if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
+- lbs_deb_usbd(&udev->dev,
+- "Tx URB allocation failed\n");
+- goto dealloc;
+- }
+-
+- cardp->bulk_out_size =
+- le16_to_cpu(endpoint->wMaxPacketSize);
+- lbs_deb_usbd(&udev->dev,
+- "Bulk out size is %d\n",
+- le16_to_cpu(endpoint->wMaxPacketSize));
+- cardp->bulk_out_endpointAddr =
+- endpoint->bEndpointAddress;
+- lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n",
+- endpoint->bEndpointAddress);
+- cardp->bulk_out_buffer =
+- kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
+- GFP_KERNEL);
+-
+- if (!cardp->bulk_out_buffer) {
+- lbs_deb_usbd(&udev->dev,
+- "Could not allocate buffer\n");
+- goto dealloc;
+- }
+- }
++ /* Upload firmware */
++ if (if_usb_prog_firmware(cardp, lbs_fw_name, BOOT_CMD_FW_BY_USB)) {
++ lbs_deb_usbd(&udev->dev, "FW upload failed\n");
++ goto err_prog_firmware;
+ }
+
+- if (!(priv = libertas_add_card(cardp, &udev->dev)))
+- goto dealloc;
++ if (!(priv = lbs_add_card(cardp, &udev->dev)))
++ goto err_prog_firmware;
+
+- if (libertas_add_mesh(priv, &udev->dev))
+- goto err_add_mesh;
++ cardp->priv = priv;
++ cardp->priv->fw_ready = 1;
+
+- priv->hw_register_dev = if_usb_register_dev;
+- priv->hw_unregister_dev = if_usb_unregister_dev;
+- priv->hw_prog_firmware = if_usb_prog_firmware;
+ priv->hw_host_to_card = if_usb_host_to_card;
+ priv->hw_get_int_status = if_usb_get_int_status;
+ priv->hw_read_event_cause = if_usb_read_event_cause;
++ priv->boot2_version = udev->descriptor.bcdDevice;
++
++ if_usb_submit_rx_urb(cardp);
+
+- if (libertas_activate_card(priv, libertas_fw_name))
+- goto err_activate_card;
++ if (lbs_start_card(priv))
++ goto err_start_card;
+
+- list_add_tail(&cardp->list, &usb_devices);
++ if_usb_setup_firmware(priv);
+
+ usb_get_dev(udev);
+ usb_set_intfdata(intf, cardp);
+
++ if (device_create_file(&priv->dev->dev, &dev_attr_lbs_fw))
++ lbs_pr_err("cannot register lbs_fw attribute\n");
++
++ if (device_create_file(&priv->dev->dev, &dev_attr_lbs_boot2))
++ lbs_pr_err("cannot register lbs_boot2 attribute\n");
++
+ return 0;
+
+-err_activate_card:
+- libertas_remove_mesh(priv);
+-err_add_mesh:
+- free_netdev(priv->dev);
+- kfree(priv->adapter);
++err_start_card:
++ lbs_remove_card(priv);
++err_prog_firmware:
++ if_usb_reset_device(cardp);
+ dealloc:
+ if_usb_free(cardp);
+
+@@ -245,23 +330,21 @@ error:
+ */
+ static void if_usb_disconnect(struct usb_interface *intf)
+ {
+- struct usb_card_rec *cardp = usb_get_intfdata(intf);
+- wlan_private *priv = (wlan_private *) cardp->priv;
+- wlan_adapter *adapter = NULL;
+-
+- adapter = priv->adapter;
+-
+- /*
+- * Update Surprise removed to TRUE
+- */
+- adapter->surpriseremoved = 1;
+-
+- list_del(&cardp->list);
+-
+- /* card is removed and we can call wlan_remove_card */
+- lbs_deb_usbd(&cardp->udev->dev, "call remove card\n");
+- libertas_remove_mesh(priv);
+- libertas_remove_card(priv);
++ struct if_usb_card *cardp = usb_get_intfdata(intf);
++ struct lbs_private *priv = (struct lbs_private *) cardp->priv;
++
++ lbs_deb_enter(LBS_DEB_MAIN);
++
++ device_remove_file(&priv->dev->dev, &dev_attr_lbs_boot2);
++ device_remove_file(&priv->dev->dev, &dev_attr_lbs_fw);
++
++ cardp->surprise_removed = 1;
++
++ if (priv) {
++ priv->surpriseremoved = 1;
++ lbs_stop_card(priv);
++ lbs_remove_card(priv);
++ }
+
+ /* Unlink and free urb */
+ if_usb_free(cardp);
+@@ -269,105 +352,94 @@ static void if_usb_disconnect(struct usb
+ usb_set_intfdata(intf, NULL);
+ usb_put_dev(interface_to_usbdev(intf));
+
+- return;
++ lbs_deb_leave(LBS_DEB_MAIN);
+ }
+
+ /**
+ * @brief This function download FW
+- * @param priv pointer to wlan_private
++ * @param priv pointer to struct lbs_private
+ * @return 0
+ */
+-static int if_prog_firmware(wlan_private * priv)
++static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
+ {
+- struct usb_card_rec *cardp = priv->card;
+- struct FWData *fwdata;
+- struct fwheader *fwheader;
+- u8 *firmware = priv->firmware->data;
+-
+- fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
+-
+- if (!fwdata)
+- return -1;
+-
+- fwheader = &fwdata->fwheader;
++ struct fwdata *fwdata = cardp->ep_out_buf;
++ uint8_t *firmware = cardp->fw->data;
+
++ /* If we got a CRC failure on the last block, back
++ up and retry it */
+ if (!cardp->CRC_OK) {
+ cardp->totalbytes = cardp->fwlastblksent;
+- cardp->fwseqnum = cardp->lastseqnum - 1;
++ cardp->fwseqnum--;
+ }
+
+- /*
+- lbs_deb_usbd(&cardp->udev->dev, "totalbytes = %d\n",
+- cardp->totalbytes);
+- */
++ lbs_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n",
++ cardp->totalbytes);
+
+- memcpy(fwheader, &firmware[cardp->totalbytes],
++ /* struct fwdata (which we sent to the card) has an
++ extra __le32 field in between the header and the data,
++ which is not in the struct fwheader in the actual
++ firmware binary. Insert the seqnum in the middle... */
++ memcpy(&fwdata->hdr, &firmware[cardp->totalbytes],
+ sizeof(struct fwheader));
+
+ cardp->fwlastblksent = cardp->totalbytes;
+ cardp->totalbytes += sizeof(struct fwheader);
+
+- /* lbs_deb_usbd(&cardp->udev->dev,"Copy Data\n"); */
+ memcpy(fwdata->data, &firmware[cardp->totalbytes],
+- le32_to_cpu(fwdata->fwheader.datalength));
++ le32_to_cpu(fwdata->hdr.datalength));
+
+- /*
+- lbs_deb_usbd(&cardp->udev->dev,
+- "Data length = %d\n", le32_to_cpu(fwdata->fwheader.datalength));
+- */
++ lbs_deb_usb2(&cardp->udev->dev, "Data length = %d\n",
++ le32_to_cpu(fwdata->hdr.datalength));
+
+- cardp->fwseqnum = cardp->fwseqnum + 1;
++ fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
++ cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
+
+- fwdata->seqnum = cpu_to_le32(cardp->fwseqnum);
+- cardp->lastseqnum = cardp->fwseqnum;
+- cardp->totalbytes += le32_to_cpu(fwdata->fwheader.datalength);
+-
+- if (fwheader->dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
+- /*
+- lbs_deb_usbd(&cardp->udev->dev, "There are data to follow\n");
+- lbs_deb_usbd(&cardp->udev->dev,
+- "seqnum = %d totalbytes = %d\n", cardp->fwseqnum,
+- cardp->totalbytes);
+- */
+- memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
+- usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
++ usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
++ le32_to_cpu(fwdata->hdr.datalength));
++
++ if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
++ lbs_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
++ lbs_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
++ cardp->fwseqnum, cardp->totalbytes);
++ } else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
++ lbs_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
++ lbs_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
+
+- } else if (fwdata->fwheader.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
+- /*
+- lbs_deb_usbd(&cardp->udev->dev,
+- "Host has finished FW downloading\n");
+- lbs_deb_usbd(&cardp->udev->dev,
+- "Donwloading FW JUMP BLOCK\n");
+- */
+- memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
+- usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+ cardp->fwfinalblk = 1;
+ }
+
+- /*
+- lbs_deb_usbd(&cardp->udev->dev,
+- "The firmware download is done size is %d\n",
+- cardp->totalbytes);
+- */
+-
+- kfree(fwdata);
++ lbs_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n",
++ cardp->totalbytes);
+
+ return 0;
+ }
+
+-static int libertas_do_reset(wlan_private *priv)
++static int if_usb_reset_device(struct if_usb_card *cardp)
+ {
++ struct cmd_ds_command *cmd = cardp->ep_out_buf + 4;
+ int ret;
+- struct usb_card_rec *cardp = priv->card;
+
+ lbs_deb_enter(LBS_DEB_USB);
+
++ *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
++
++ cmd->command = cpu_to_le16(CMD_802_11_RESET);
++ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
++ cmd->result = cpu_to_le16(0);
++ cmd->seqnum = cpu_to_le16(0x5a5a);
++ cmd->params.reset.action = cpu_to_le16(CMD_ACT_HALT);
++ usb_tx_block(cardp, cardp->ep_out_buf, 4 + S_DS_GEN + sizeof(struct cmd_ds_802_11_reset));
++
++ msleep(100);
+ ret = usb_reset_device(cardp->udev);
+- if (!ret) {
+- msleep(10);
+- if_usb_reset_device(priv);
+- msleep(10);
++ msleep(100);
++
++#ifdef CONFIG_OLPC
++ if (ret && machine_is_olpc()) {
++ printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
++ olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
+ }
++#endif
+
+ lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
+
+@@ -376,36 +448,33 @@ static int libertas_do_reset(wlan_privat
+
+ /**
+ * @brief This function transfer the data to the device.
+- * @param priv pointer to wlan_private
++ * @param priv pointer to struct lbs_private
+ * @param payload pointer to payload data
+ * @param nb data length
+ * @return 0 or -1
+ */
+-int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
++static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb)
+ {
+- /* pointer to card structure */
+- struct usb_card_rec *cardp = priv->card;
+ int ret = -1;
+
+ /* check if device is removed */
+- if (priv->adapter->surpriseremoved) {
++ if (cardp->surprise_removed) {
+ lbs_deb_usbd(&cardp->udev->dev, "Device removed\n");
+ goto tx_ret;
+ }
+
+ usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
+ usb_sndbulkpipe(cardp->udev,
+- cardp->bulk_out_endpointAddr),
+- payload, nb, if_usb_write_bulk_callback, priv);
++ cardp->ep_out),
++ payload, nb, if_usb_write_bulk_callback, cardp);
+
+ cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+ if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
+- /* transfer failed */
+- lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed\n");
++ lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
+ ret = -1;
+ } else {
+- /* lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb success\n"); */
++ lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
+ ret = 0;
+ }
+
+@@ -413,13 +482,10 @@ tx_ret:
+ return ret;
+ }
+
+-static int __if_usb_submit_rx_urb(wlan_private * priv,
+- void (*callbackfn)
+- (struct urb *urb))
++static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
++ void (*callbackfn)(struct urb *urb))
+ {
+- struct usb_card_rec *cardp = priv->card;
+ struct sk_buff *skb;
+- struct read_cb_info *rinfo = &cardp->rinfo;
+ int ret = -1;
+
+ if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
+@@ -427,25 +493,25 @@ static int __if_usb_submit_rx_urb(wlan_p
+ goto rx_ret;
+ }
+
+- rinfo->skb = skb;
++ cardp->rx_skb = skb;
+
+ /* Fill the receive configuration URB and initialise the Rx call back */
+ usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
+- usb_rcvbulkpipe(cardp->udev,
+- cardp->bulk_in_endpointAddr),
++ usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
+ (void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET),
+ MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
+- rinfo);
++ cardp);
+
+ cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+- /* lbs_deb_usbd(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); */
++ lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
+ if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
+- /* handle failure conditions */
+- lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed\n");
++ lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
++ kfree_skb(skb);
++ cardp->rx_skb = NULL;
+ ret = -1;
+ } else {
+- /* lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB success\n"); */
++ lbs_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n");
+ ret = 0;
+ }
+
+@@ -453,62 +519,83 @@ rx_ret:
+ return ret;
+ }
+
+-static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv)
++static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp)
+ {
+- return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload);
++ return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
+ }
+
+-static inline int if_usb_submit_rx_urb(wlan_private * priv)
++static int if_usb_submit_rx_urb(struct if_usb_card *cardp)
+ {
+- return __if_usb_submit_rx_urb(priv, &if_usb_receive);
++ return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
+ }
+
+ static void if_usb_receive_fwload(struct urb *urb)
+ {
+- struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
+- wlan_private *priv = rinfo->priv;
+- struct sk_buff *skb = rinfo->skb;
+- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
++ struct if_usb_card *cardp = urb->context;
++ struct sk_buff *skb = cardp->rx_skb;
+ struct fwsyncheader *syncfwheader;
+- struct bootcmdrespStr bootcmdresp;
++ struct bootcmdresp bootcmdresp;
+
+ if (urb->status) {
+ lbs_deb_usbd(&cardp->udev->dev,
+- "URB status is failed during fw load\n");
++ "URB status is failed during fw load\n");
+ kfree_skb(skb);
+ return;
+ }
+
+- if (cardp->bootcmdresp == 0) {
++ if (cardp->fwdnldover) {
++ __le32 *tmp = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
++
++ if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
++ tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
++ lbs_pr_info("Firmware ready event received\n");
++ wake_up(&cardp->fw_wq);
++ } else {
++ lbs_deb_usb("Waiting for confirmation; got %x %x\n",
++ le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1]));
++ if_usb_submit_rx_urb_fwload(cardp);
++ }
++ kfree_skb(skb);
++ return;
++ }
++ if (cardp->bootcmdresp <= 0) {
+ memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
+ sizeof(bootcmdresp));
++
+ if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
+ kfree_skb(skb);
+- if_usb_submit_rx_urb_fwload(priv);
++ if_usb_submit_rx_urb_fwload(cardp);
+ cardp->bootcmdresp = 1;
+ lbs_deb_usbd(&cardp->udev->dev,
+- "Received valid boot command response\n");
++ "Received valid boot command response\n");
+ return;
+ }
+- if (bootcmdresp.u32magicnumber != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
+- lbs_pr_info(
+- "boot cmd response wrong magic number (0x%x)\n",
+- le32_to_cpu(bootcmdresp.u32magicnumber));
+- } else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) {
+- lbs_pr_info(
+- "boot cmd response cmd_tag error (%d)\n",
+- bootcmdresp.u8cmd_tag);
+- } else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) {
+- lbs_pr_info(
+- "boot cmd response result error (%d)\n",
+- bootcmdresp.u8result);
++ if (bootcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
++ if (bootcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) ||
++ bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
++ bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
++ if (!cardp->bootcmdresp)
++ lbs_pr_info("Firmware already seems alive; resetting\n");
++ cardp->bootcmdresp = -1;
++ } else {
++ lbs_pr_info("boot cmd response wrong magic number (0x%x)\n",
++ le32_to_cpu(bootcmdresp.magic));
++ }
++ } else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) &&
++ (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) &&
++ (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) {
++ lbs_pr_info("boot cmd response cmd_tag error (%d)\n",
++ bootcmdresp.cmd);
++ } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
++ lbs_pr_info("boot cmd response result error (%d)\n",
++ bootcmdresp.result);
+ } else {
+ cardp->bootcmdresp = 1;
+ lbs_deb_usbd(&cardp->udev->dev,
+- "Received valid boot command response\n");
++ "Received valid boot command response\n");
+ }
+ kfree_skb(skb);
+- if_usb_submit_rx_urb_fwload(priv);
++ if_usb_submit_rx_urb_fwload(cardp);
+ return;
+ }
+
+@@ -520,50 +607,47 @@ static void if_usb_receive_fwload(struct
+ }
+
+ memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
+- sizeof(struct fwsyncheader));
++ sizeof(struct fwsyncheader));
+
+ if (!syncfwheader->cmd) {
+- /*
+- lbs_deb_usbd(&cardp->udev->dev,
+- "FW received Blk with correct CRC\n");
+- lbs_deb_usbd(&cardp->udev->dev,
+- "FW received Blk seqnum = %d\n",
+- syncfwheader->seqnum);
+- */
++ lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
++ lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
++ le32_to_cpu(syncfwheader->seqnum));
+ cardp->CRC_OK = 1;
+ } else {
+- lbs_deb_usbd(&cardp->udev->dev,
+- "FW received Blk with CRC error\n");
++ lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
+ cardp->CRC_OK = 0;
+ }
+
+ kfree_skb(skb);
+
++ /* Give device 5s to either write firmware to its RAM or eeprom */
++ mod_timer(&cardp->fw_timeout, jiffies + (HZ*5));
++
+ if (cardp->fwfinalblk) {
+ cardp->fwdnldover = 1;
+ goto exit;
+ }
+
+- if_prog_firmware(priv);
++ if_usb_send_fw_pkt(cardp);
++
++ exit:
++ if_usb_submit_rx_urb_fwload(cardp);
+
+- if_usb_submit_rx_urb_fwload(priv);
+-exit:
+ kfree(syncfwheader);
+
+ return;
+-
+ }
+
+ #define MRVDRV_MIN_PKT_LEN 30
+
+ static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
+- struct usb_card_rec *cardp,
+- wlan_private *priv)
++ struct if_usb_card *cardp,
++ struct lbs_private *priv)
+ {
+- if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE +
+- MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) {
+- lbs_deb_usbd(&cardp->udev->dev,
+- "Packet length is Invalid\n");
++ if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
++ || recvlength < MRVDRV_MIN_PKT_LEN) {
++ lbs_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n");
+ kfree_skb(skb);
+ return;
+ }
+@@ -571,19 +655,19 @@ static inline void process_cmdtypedata(i
+ skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
+ skb_put(skb, recvlength);
+ skb_pull(skb, MESSAGE_HEADER_LEN);
+- libertas_process_rxed_packet(priv, skb);
++
++ lbs_process_rxed_packet(priv, skb);
+ priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
+ }
+
+-static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
++static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
+ struct sk_buff *skb,
+- struct usb_card_rec *cardp,
+- wlan_private *priv)
++ struct if_usb_card *cardp,
++ struct lbs_private *priv)
+ {
+- u8 *cmdbuf;
+- if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) {
++ if (recvlength > LBS_CMD_BUFFER_SIZE) {
+ lbs_deb_usbd(&cardp->udev->dev,
+- "The receive buffer is too large\n");
++ "The receive buffer is too large\n");
+ kfree_skb(skb);
+ return;
+ }
+@@ -591,28 +675,17 @@ static inline void process_cmdrequest(in
+ if (!in_interrupt())
+ BUG();
+
+- spin_lock(&priv->adapter->driver_lock);
+- /* take care of cur_cmd = NULL case by reading the
+- * data to clear the interrupt */
+- if (!priv->adapter->cur_cmd) {
+- cmdbuf = priv->upld_buf;
+- priv->adapter->hisregcpy &= ~his_cmdupldrdy;
+- } else
+- cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
+-
+- cardp->usb_int_cause |= his_cmdupldrdy;
++ spin_lock(&priv->driver_lock);
++ cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY;
+ priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
+- memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN,
+- priv->upld_len);
++ memcpy(priv->upld_buf, recvbuff + MESSAGE_HEADER_LEN, priv->upld_len);
+
+ kfree_skb(skb);
+- libertas_interrupt(priv->dev);
+- spin_unlock(&priv->adapter->driver_lock);
++ lbs_interrupt(priv);
++ spin_unlock(&priv->driver_lock);
+
+ lbs_deb_usbd(&cardp->udev->dev,
+ "Wake up main thread to handle cmd response\n");
+-
+- return;
+ }
+
+ /**
+@@ -624,37 +697,33 @@ static inline void process_cmdrequest(in
+ */
+ static void if_usb_receive(struct urb *urb)
+ {
+- struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
+- wlan_private *priv = rinfo->priv;
+- struct sk_buff *skb = rinfo->skb;
+- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+-
++ struct if_usb_card *cardp = urb->context;
++ struct sk_buff *skb = cardp->rx_skb;
++ struct lbs_private *priv = cardp->priv;
+ int recvlength = urb->actual_length;
+- u8 *recvbuff = NULL;
+- u32 recvtype;
++ uint8_t *recvbuff = NULL;
++ uint32_t recvtype = 0;
++ __le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
+
+ lbs_deb_enter(LBS_DEB_USB);
+
+ if (recvlength) {
+ if (urb->status) {
+- lbs_deb_usbd(&cardp->udev->dev,
+- "URB status is failed\n");
++ lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n",
++ urb->status);
+ kfree_skb(skb);
+ goto setup_for_next;
+ }
+
+ recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
+- memcpy(&recvtype, recvbuff, sizeof(u32));
++ recvtype = le32_to_cpu(pkt[0]);
+ lbs_deb_usbd(&cardp->udev->dev,
+- "Recv length = 0x%x\n", recvlength);
+- lbs_deb_usbd(&cardp->udev->dev,
+- "Receive type = 0x%X\n", recvtype);
+- recvtype = le32_to_cpu(recvtype);
+- lbs_deb_usbd(&cardp->udev->dev,
+- "Receive type after = 0x%X\n", recvtype);
+- } else if (urb->status)
++ "Recv length = 0x%x, Recv type = 0x%X\n",
++ recvlength, recvtype);
++ } else if (urb->status) {
++ kfree_skb(skb);
+ goto rx_exit;
+-
++ }
+
+ switch (recvtype) {
+ case CMD_TYPE_DATA:
+@@ -667,168 +736,219 @@ static void if_usb_receive(struct urb *u
+
+ case CMD_TYPE_INDICATION:
+ /* Event cause handling */
+- spin_lock(&priv->adapter->driver_lock);
+- cardp->usb_event_cause = le32_to_cpu(*(__le32 *) (recvbuff + MESSAGE_HEADER_LEN));
++ spin_lock(&priv->driver_lock);
++
++ cardp->usb_event_cause = le32_to_cpu(pkt[1]);
++
+ lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n",
+- cardp->usb_event_cause);
++ cardp->usb_event_cause);
++
++ /* Icky undocumented magic special case */
+ if (cardp->usb_event_cause & 0xffff0000) {
+- libertas_send_tx_feedback(priv);
+- spin_unlock(&priv->adapter->driver_lock);
++ lbs_send_tx_feedback(priv);
++ spin_unlock(&priv->driver_lock);
+ break;
+ }
+ cardp->usb_event_cause <<= 3;
+- cardp->usb_int_cause |= his_cardevent;
++ cardp->usb_int_cause |= MRVDRV_CARDEVENT;
+ kfree_skb(skb);
+- libertas_interrupt(priv->dev);
+- spin_unlock(&priv->adapter->driver_lock);
++ lbs_interrupt(priv);
++ spin_unlock(&priv->driver_lock);
+ goto rx_exit;
+ default:
++ lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
++ recvtype);
+ kfree_skb(skb);
+ break;
+ }
+
+ setup_for_next:
+- if_usb_submit_rx_urb(priv);
++ if_usb_submit_rx_urb(cardp);
+ rx_exit:
+ lbs_deb_leave(LBS_DEB_USB);
+ }
+
+ /**
+ * @brief This function downloads data to FW
+- * @param priv pointer to wlan_private structure
++ * @param priv pointer to struct lbs_private structure
+ * @param type type of data
+ * @param buf pointer to data buffer
+ * @param len number of bytes
+ * @return 0 or -1
+ */
+-static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
++static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
++ uint8_t *payload, uint16_t nb)
+ {
+- int ret = -1;
+- u32 tmp;
+- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
++ struct if_usb_card *cardp = priv->card;
+
+ lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type);
+ lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb);
+
+ if (type == MVMS_CMD) {
+- tmp = cpu_to_le32(CMD_TYPE_REQUEST);
++ *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
+ priv->dnld_sent = DNLD_CMD_SENT;
+- memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
+- MESSAGE_HEADER_LEN);
+-
+ } else {
+- tmp = cpu_to_le32(CMD_TYPE_DATA);
++ *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA);
+ priv->dnld_sent = DNLD_DATA_SENT;
+- memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
+- MESSAGE_HEADER_LEN);
+ }
+
+- memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb);
+-
+- ret =
+- usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN);
++ memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb);
+
+- return ret;
++ return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN);
+ }
+
+-/* called with adapter->driver_lock held */
+-static int if_usb_get_int_status(wlan_private * priv, u8 * ireg)
++/* called with priv->driver_lock held */
++static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *ireg)
+ {
+- struct usb_card_rec *cardp = priv->card;
++ struct if_usb_card *cardp = priv->card;
+
+ *ireg = cardp->usb_int_cause;
+ cardp->usb_int_cause = 0;
+
+- lbs_deb_usbd(&cardp->udev->dev,"Int cause is 0x%X\n", *ireg);
++ lbs_deb_usbd(&cardp->udev->dev, "Int cause is 0x%X\n", *ireg);
+
+ return 0;
+ }
+
+-static int if_usb_read_event_cause(wlan_private * priv)
++static int if_usb_read_event_cause(struct lbs_private *priv)
+ {
+- struct usb_card_rec *cardp = priv->card;
+- priv->adapter->eventcause = cardp->usb_event_cause;
++ struct if_usb_card *cardp = priv->card;
++
++ priv->eventcause = cardp->usb_event_cause;
+ /* Re-submit rx urb here to avoid event lost issue */
+- if_usb_submit_rx_urb(priv);
++ if_usb_submit_rx_urb(cardp);
++
+ return 0;
+ }
+
+-static int if_usb_reset_device(wlan_private *priv)
++/**
++ * @brief This function issues Boot command to the Boot2 code
++ * @param ivalue 1:Boot from FW by USB-Download
++ * 2:Boot from FW in EEPROM
++ * @return 0
++ */
++static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
+ {
+- int ret;
+-
+- lbs_deb_enter(LBS_DEB_USB);
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset,
+- cmd_act_halt, 0, 0, NULL);
+- msleep_interruptible(10);
+-
+- lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
+- return ret;
+-}
++ struct bootcmd *bootcmd = cardp->ep_out_buf;
+
+-static int if_usb_unregister_dev(wlan_private * priv)
+-{
+- int ret = 0;
++ /* Prepare command */
++ bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
++ bootcmd->cmd = ivalue;
++ memset(bootcmd->pad, 0, sizeof(bootcmd->pad));
+
+- /* Need to send a Reset command to device before USB resources freed
+- * and wlan_remove_card() called, then device can handle FW download
+- * again.
+- */
+- if (priv)
+- if_usb_reset_device(priv);
++ /* Issue command */
++ usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd));
+
+- return ret;
++ return 0;
+ }
+
+
+ /**
+- * @brief This function register usb device and initialize parameter
+- * @param priv pointer to wlan_private
+- * @return 0 or -1
++ * @brief This function checks the validity of Boot2/FW image.
++ *
++ * @param data pointer to image
++ * len image length
++ * @return 0 or -1
+ */
+-static int if_usb_register_dev(wlan_private * priv)
++static int check_fwfile_format(uint8_t *data, uint32_t totlen)
+ {
+- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+-
+- lbs_deb_enter(LBS_DEB_USB);
++ uint32_t bincmd, exit;
++ uint32_t blksize, offset, len;
++ int ret;
+
+- cardp->priv = priv;
+- cardp->eth_dev = priv->dev;
+- priv->hotplug_device = &(cardp->udev->dev);
++ ret = 1;
++ exit = len = 0;
+
+- lbs_deb_usbd(&cardp->udev->dev, "udev pointer is at %p\n",
+- cardp->udev);
++ do {
++ struct fwheader *fwh = (void *)data;
+
+- lbs_deb_leave(LBS_DEB_USB);
+- return 0;
+-}
++ bincmd = le32_to_cpu(fwh->dnldcmd);
++ blksize = le32_to_cpu(fwh->datalength);
++ switch (bincmd) {
++ case FW_HAS_DATA_TO_RECV:
++ offset = sizeof(struct fwheader) + blksize;
++ data += offset;
++ len += offset;
++ if (len >= totlen)
++ exit = 1;
++ break;
++ case FW_HAS_LAST_BLOCK:
++ exit = 1;
++ ret = 0;
++ break;
++ default:
++ exit = 1;
++ break;
++ }
++ } while (!exit);
+
++ if (ret)
++ lbs_pr_err("firmware file format check FAIL\n");
++ else
++ lbs_deb_fw("firmware file format check PASS\n");
+
++ return ret;
++}
+
+-static int if_usb_prog_firmware(wlan_private * priv)
++/**
++ * @brief This function programs the firmware subject to cmd
++ *
++ * @param cardp the if_usb_card descriptor
++ * fwname firmware or boot2 image file name
++ * cmd either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW,
++ * or BOOT_CMD_UPDATE_BOOT2.
++ * @return 0 or error code
++ */
++static int if_usb_prog_firmware(struct if_usb_card *cardp,
++ const char *fwname, int cmd)
+ {
+- struct usb_card_rec *cardp = priv->card;
+ int i = 0;
+ static int reset_count = 10;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_USB);
+
+- cardp->rinfo.priv = priv;
++ /* Don't mess with the firmware if the interface is up */
++ if (cardp->priv &&
++ (cardp->priv->mesh_open || cardp->priv->infra_open)) {
++ ret = -EPERM;
++ goto done;
++ }
++
++ ret = request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
++ if (ret < 0) {
++ lbs_pr_err("request_firmware() failed with %#x\n", ret);
++ lbs_pr_err("firmware %s not found\n", fwname);
++ goto done;
++ }
++
++ if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
++ ret = -EINVAL;
++ goto release_fw;
++ }
++
++ /* Cancel any pending usb business */
++ usb_kill_urb(cardp->rx_urb);
++ usb_kill_urb(cardp->tx_urb);
++
++ cardp->fwlastblksent = 0;
++ cardp->fwdnldover = 0;
++ cardp->totalbytes = 0;
++ cardp->fwfinalblk = 0;
++ cardp->bootcmdresp = 0;
+
+ restart:
+- if (if_usb_submit_rx_urb_fwload(priv) < 0) {
++ if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
+ lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
+- ret = -1;
+- goto done;
++ ret = -EIO;
++ goto release_fw;
+ }
+
+ cardp->bootcmdresp = 0;
+ do {
+ int j = 0;
+ i++;
+- /* Issue Boot command = 1, Boot from Download-FW */
+- if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB);
++ if_usb_issue_boot_command(cardp, cmd);
+ /* wait for command response */
+ do {
+ j++;
+@@ -836,16 +956,15 @@ restart:
+ } while (cardp->bootcmdresp == 0 && j < 10);
+ } while (cardp->bootcmdresp == 0 && i < 5);
+
+- if (cardp->bootcmdresp == 0) {
++ if (cardp->bootcmdresp <= 0) {
+ if (--reset_count >= 0) {
+- libertas_do_reset(priv);
++ if_usb_reset_device(cardp);
+ goto restart;
+ }
+- return -1;
++ return -EIO;
+ }
+
+ i = 0;
+- priv->adapter->fw_ready = 0;
+
+ cardp->totalbytes = 0;
+ cardp->fwlastblksent = 0;
+@@ -855,77 +974,72 @@ restart:
+ cardp->totalbytes = 0;
+ cardp->fwfinalblk = 0;
+
+- if_prog_firmware(priv);
++ /* Send the first firmware packet... */
++ if_usb_send_fw_pkt(cardp);
+
+- do {
+- lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n");
+- i++;
+- msleep_interruptible(100);
+- if (priv->adapter->surpriseremoved || i >= 20)
+- break;
+- } while (!cardp->fwdnldover);
++ /* ... and wait for the process to complete */
++ wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover);
++
++ del_timer_sync(&cardp->fw_timeout);
++ usb_kill_urb(cardp->rx_urb);
+
+ if (!cardp->fwdnldover) {
+ lbs_pr_info("failed to load fw, resetting device!\n");
+ if (--reset_count >= 0) {
+- libertas_do_reset(priv);
++ if_usb_reset_device(cardp);
+ goto restart;
+ }
+
+ lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
+- ret = -1;
+- goto done;
++ ret = -EIO;
++ goto release_fw;
+ }
+
+- if_usb_submit_rx_urb(priv);
++ release_fw:
++ release_firmware(cardp->fw);
++ cardp->fw = NULL;
+
+- /* Delay 200 ms to waiting for the FW ready */
+- msleep_interruptible(200);
+-
+- priv->adapter->fw_ready = 1;
+-
+-done:
++ done:
+ lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
+ return ret;
+ }
+
++
+ #ifdef CONFIG_PM
+ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
+ {
+- struct usb_card_rec *cardp = usb_get_intfdata(intf);
+- wlan_private *priv = cardp->priv;
++ struct if_usb_card *cardp = usb_get_intfdata(intf);
++ struct lbs_private *priv = cardp->priv;
++ int ret;
+
+ lbs_deb_enter(LBS_DEB_USB);
+
+- if (priv->adapter->psstate != PS_STATE_FULL_POWER)
++ if (priv->psstate != PS_STATE_FULL_POWER)
+ return -1;
+
+- netif_device_detach(cardp->eth_dev);
+- netif_device_detach(priv->mesh_dev);
++ ret = lbs_suspend(priv);
++ if (ret)
++ goto out;
+
+ /* Unlink tx & rx urb */
+ usb_kill_urb(cardp->tx_urb);
+ usb_kill_urb(cardp->rx_urb);
+
+- cardp->rx_urb_recall = 1;
+-
++ out:
+ lbs_deb_leave(LBS_DEB_USB);
+- return 0;
++ return ret;
+ }
+
+ static int if_usb_resume(struct usb_interface *intf)
+ {
+- struct usb_card_rec *cardp = usb_get_intfdata(intf);
+- wlan_private *priv = cardp->priv;
++ struct if_usb_card *cardp = usb_get_intfdata(intf);
++ struct lbs_private *priv = cardp->priv;
+
+ lbs_deb_enter(LBS_DEB_USB);
+
+- cardp->rx_urb_recall = 0;
+-
+- if_usb_submit_rx_urb(cardp->priv);
++ if_usb_submit_rx_urb(cardp);
+
+- netif_device_attach(cardp->eth_dev);
+- netif_device_attach(priv->mesh_dev);
++ lbs_resume(priv);
+
+ lbs_deb_leave(LBS_DEB_USB);
+ return 0;
+@@ -936,44 +1050,30 @@ static int if_usb_resume(struct usb_inte
+ #endif
+
+ static struct usb_driver if_usb_driver = {
+- /* driver name */
+- .name = usbdriver_name,
+- /* probe function name */
++ .name = DRV_NAME,
+ .probe = if_usb_probe,
+- /* disconnect function name */
+ .disconnect = if_usb_disconnect,
+- /* device signature table */
+ .id_table = if_usb_table,
+ .suspend = if_usb_suspend,
+ .resume = if_usb_resume,
+ };
+
+-static int if_usb_init_module(void)
++static int __init if_usb_init_module(void)
+ {
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+- if (libertas_fw_name == NULL) {
+- libertas_fw_name = default_fw_name;
+- }
+-
+ ret = usb_register(&if_usb_driver);
+
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+ return ret;
+ }
+
+-static void if_usb_exit_module(void)
++static void __exit if_usb_exit_module(void)
+ {
+- struct usb_card_rec *cardp, *cardp_temp;
+-
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+- list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list)
+- if_usb_reset_device((wlan_private *) cardp->priv);
+-
+- /* API unregisters the driver from USB subsystem */
+ usb_deregister(&if_usb_driver);
+
+ lbs_deb_leave(LBS_DEB_MAIN);
+@@ -983,5 +1083,5 @@ module_init(if_usb_init_module);
+ module_exit(if_usb_exit_module);
+
+ MODULE_DESCRIPTION("8388 USB WLAN Driver");
+-MODULE_AUTHOR("Marvell International Ltd.");
++MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc.");
+ MODULE_LICENSE("GPL");
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/if_usb.c.orig linux-2.6.22-300/drivers/net/wireless/libertas/if_usb.c.orig
+--- linux-2.6.22-250/drivers/net/wireless/libertas/if_usb.c.orig 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.22-300/drivers/net/wireless/libertas/if_usb.c.orig 2008-06-05 18:29:26.000000000 -0400
+@@ -0,0 +1,1022 @@
++/**
++ * This file contains functions used in USB interface module.
++ */
++#include <linux/delay.h>
++#include <linux/moduleparam.h>
++#include <linux/firmware.h>
++#include <linux/netdevice.h>
++#include <linux/usb.h>
++#include <asm/olpc.h>
++
++#define DRV_NAME "usb8xxx"
++
++#include "host.h"
++#include "decl.h"
++#include "defs.h"
++#include "dev.h"
++#include "cmd.h"
++#include "if_usb.h"
++
++#define INSANEDEBUG 0
++#define lbs_deb_usb2(...) do { if (INSANEDEBUG) lbs_deb_usbd(__VA_ARGS__); } while (0)
++
++#define MESSAGE_HEADER_LEN 4
++
++static char *lbs_fw_name = "usb8388.bin";
++module_param_named(fw_name, lbs_fw_name, charp, 0644);
++
++static struct usb_device_id if_usb_table[] = {
++ /* Enter the device signature inside */
++ { USB_DEVICE(0x1286, 0x2001) },
++ { USB_DEVICE(0x05a3, 0x8388) },
++ {} /* Terminating entry */
++};
++
++MODULE_DEVICE_TABLE(usb, if_usb_table);
++
++static void if_usb_receive(struct urb *urb);
++static void if_usb_receive_fwload(struct urb *urb);
++static int if_usb_prog_firmware(struct if_usb_card *cardp,
++ const char *fwname, int cmd);
++static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
++ uint8_t *payload, uint16_t nb);
++static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *);
++static int if_usb_read_event_cause(struct lbs_private *);
++static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
++ uint16_t nb);
++static void if_usb_free(struct if_usb_card *cardp);
++static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
++static int if_usb_reset_device(struct if_usb_card *cardp);
++
++/**
++ * @brief call back function to handle the status of the URB
++ * @param urb pointer to urb structure
++ * @return N/A
++ */
++static void if_usb_write_bulk_callback(struct urb *urb)
++{
++ struct if_usb_card *cardp = (struct if_usb_card *) urb->context;
++
++ /* handle the transmission complete validations */
++
++ if (urb->status == 0) {
++ struct lbs_private *priv = cardp->priv;
++
++ lbs_deb_usb2(&urb->dev->dev, "URB status is successful\n");
++ lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n",
++ urb->actual_length);
++
++ /* Used for both firmware TX and regular TX. priv isn't
++ * valid at firmware load time.
++ */
++ if (priv)
++ lbs_host_to_card_done(priv);
++ } else {
++ /* print the failure status number for debug */
++ lbs_pr_info("URB in failure status: %d\n", urb->status);
++ }
++
++ return;
++}
++
++/**
++ * @brief free tx/rx urb, skb and rx buffer
++ * @param cardp pointer if_usb_card
++ * @return N/A
++ */
++static void if_usb_free(struct if_usb_card *cardp)
++{
++ lbs_deb_enter(LBS_DEB_USB);
++
++ /* Unlink tx & rx urb */
++ usb_kill_urb(cardp->tx_urb);
++ usb_kill_urb(cardp->rx_urb);
++
++ usb_free_urb(cardp->tx_urb);
++ cardp->tx_urb = NULL;
++
++ usb_free_urb(cardp->rx_urb);
++ cardp->rx_urb = NULL;
++
++ kfree(cardp->ep_out_buf);
++ cardp->ep_out_buf = NULL;
++
++ lbs_deb_leave(LBS_DEB_USB);
++}
++
++static void if_usb_setup_firmware(struct lbs_private *priv)
++{
++ struct cmd_ds_set_boot2_ver b2_cmd;
++ struct cmd_ds_802_11_fw_wake_method wake_method;
++
++ b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
++ b2_cmd.action = 0;
++ b2_cmd.version = priv->boot2_version;
++
++ if (lbs_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd))
++ lbs_deb_usb("Setting boot2 version failed\n");
++
++ priv->wol_gpio = 2; /* Wake via GPIO2... */
++ priv->wol_gap = 20; /* ... after 20ms */
++ lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA);
++
++ wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
++ wake_method.action = cpu_to_le16(CMD_ACT_GET);
++ if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
++ lbs_pr_info("Firmware does not seem to support PS mode\n");
++ } else {
++ if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
++ lbs_deb_usb("Firmware seems to support PS with wake-via-command\n");
++ priv->ps_supported = 1;
++ } else {
++ /* The versions which boot up this way don't seem to
++ work even if we set it to the command interrupt */
++ lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
++ }
++ }
++}
++
++static void if_usb_fw_timeo(unsigned long priv)
++{
++ struct if_usb_card *cardp = (void *)priv;
++
++ if (cardp->fwdnldover) {
++ lbs_deb_usb("Download complete, no event. Assuming success\n");
++ } else {
++ lbs_pr_err("Download timed out\n");
++ cardp->surprise_removed = 1;
++ }
++ wake_up(&cardp->fw_wq);
++}
++
++/**
++ * @brief sets the configuration values
++ * @param ifnum interface number
++ * @param id pointer to usb_device_id
++ * @return 0 on success, error code on failure
++ */
++static int if_usb_probe(struct usb_interface *intf,
++ const struct usb_device_id *id)
++{
++ struct usb_device *udev;
++ struct usb_host_interface *iface_desc;
++ struct usb_endpoint_descriptor *endpoint;
++ struct lbs_private *priv;
++ struct if_usb_card *cardp;
++ int i;
++
++ udev = interface_to_usbdev(intf);
++
++ cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
++ if (!cardp) {
++ lbs_pr_err("Out of memory allocating private data.\n");
++ goto error;
++ }
++
++ setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp);
++ init_waitqueue_head(&cardp->fw_wq);
++
++ cardp->udev = udev;
++ iface_desc = intf->cur_altsetting;
++
++ lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
++ " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
++ le16_to_cpu(udev->descriptor.bcdUSB),
++ udev->descriptor.bDeviceClass,
++ udev->descriptor.bDeviceSubClass,
++ udev->descriptor.bDeviceProtocol);
++
++ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
++ endpoint = &iface_desc->endpoint[i].desc;
++ if (usb_endpoint_is_bulk_in(endpoint)) {
++ cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
++ cardp->ep_in = usb_endpoint_num(endpoint);
++
++ lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
++ lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
++
++ } else if (usb_endpoint_is_bulk_out(endpoint)) {
++ cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
++ cardp->ep_out = usb_endpoint_num(endpoint);
++
++ lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
++ lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
++ }
++ }
++ if (!cardp->ep_out_size || !cardp->ep_in_size) {
++ lbs_deb_usbd(&udev->dev, "Endpoints not found\n");
++ goto dealloc;
++ }
++ if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
++ lbs_deb_usbd(&udev->dev, "Rx URB allocation failed\n");
++ goto dealloc;
++ }
++ if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
++ lbs_deb_usbd(&udev->dev, "Tx URB allocation failed\n");
++ goto dealloc;
++ }
++ cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, GFP_KERNEL);
++ if (!cardp->ep_out_buf) {
++ lbs_deb_usbd(&udev->dev, "Could not allocate buffer\n");
++ goto dealloc;
++ }
++
++ /* Upload firmware */
++ if (if_usb_prog_firmware(cardp, lbs_fw_name, BOOT_CMD_FW_BY_USB)) {
++ lbs_deb_usbd(&udev->dev, "FW upload failed\n");
++ goto err_prog_firmware;
++ }
++
++ if (!(priv = lbs_add_card(cardp, &udev->dev)))
++ goto err_prog_firmware;
++
++ cardp->priv = priv;
++ cardp->priv->fw_ready = 1;
++
++ priv->hw_host_to_card = if_usb_host_to_card;
++ priv->hw_get_int_status = if_usb_get_int_status;
++ priv->hw_read_event_cause = if_usb_read_event_cause;
++ priv->boot2_version = udev->descriptor.bcdDevice;
++
++ if_usb_submit_rx_urb(cardp);
++
++ if (lbs_start_card(priv))
++ goto err_start_card;
++
++ if_usb_setup_firmware(priv);
++
++ usb_get_dev(udev);
++ usb_set_intfdata(intf, cardp);
++
++ return 0;
++
++err_start_card:
++ lbs_remove_card(priv);
++err_prog_firmware:
++ if_usb_reset_device(cardp);
++dealloc:
++ if_usb_free(cardp);
++
++error:
++ return -ENOMEM;
++}
++
++/**
++ * @brief free resource and cleanup
++ * @param intf USB interface structure
++ * @return N/A
++ */
++static void if_usb_disconnect(struct usb_interface *intf)
++{
++ struct if_usb_card *cardp = usb_get_intfdata(intf);
++ struct lbs_private *priv = (struct lbs_private *) cardp->priv;
++
++ lbs_deb_enter(LBS_DEB_MAIN);
++
++ cardp->surprise_removed = 1;
++
++ if (priv) {
++ priv->surpriseremoved = 1;
++ lbs_stop_card(priv);
++ lbs_remove_card(priv);
++ }
++
++ /* Unlink and free urb */
++ if_usb_free(cardp);
++
++ usb_set_intfdata(intf, NULL);
++ usb_put_dev(interface_to_usbdev(intf));
++
++ lbs_deb_leave(LBS_DEB_MAIN);
++}
++
++/**
++ * @brief This function download FW
++ * @param priv pointer to struct lbs_private
++ * @return 0
++ */
++static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
++{
++ struct fwdata *fwdata = cardp->ep_out_buf;
++ uint8_t *firmware = cardp->fw->data;
++
++ /* If we got a CRC failure on the last block, back
++ up and retry it */
++ if (!cardp->CRC_OK) {
++ cardp->totalbytes = cardp->fwlastblksent;
++ cardp->fwseqnum--;
++ }
++
++ lbs_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n",
++ cardp->totalbytes);
++
++ /* struct fwdata (which we sent to the card) has an
++ extra __le32 field in between the header and the data,
++ which is not in the struct fwheader in the actual
++ firmware binary. Insert the seqnum in the middle... */
++ memcpy(&fwdata->hdr, &firmware[cardp->totalbytes],
++ sizeof(struct fwheader));
++
++ cardp->fwlastblksent = cardp->totalbytes;
++ cardp->totalbytes += sizeof(struct fwheader);
++
++ memcpy(fwdata->data, &firmware[cardp->totalbytes],
++ le32_to_cpu(fwdata->hdr.datalength));
++
++ lbs_deb_usb2(&cardp->udev->dev, "Data length = %d\n",
++ le32_to_cpu(fwdata->hdr.datalength));
++
++ fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
++ cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
++
++ usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
++ le32_to_cpu(fwdata->hdr.datalength));
++
++ if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
++ lbs_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
++ lbs_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
++ cardp->fwseqnum, cardp->totalbytes);
++ } else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
++ lbs_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
++ lbs_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
++
++ cardp->fwfinalblk = 1;
++ }
++
++ lbs_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n",
++ cardp->totalbytes);
++
++ return 0;
++}
++
++static int if_usb_reset_device(struct if_usb_card *cardp)
++{
++ struct cmd_ds_command *cmd = cardp->ep_out_buf + 4;
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_USB);
++
++ *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
++
++ cmd->command = cpu_to_le16(CMD_802_11_RESET);
++ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
++ cmd->result = cpu_to_le16(0);
++ cmd->seqnum = cpu_to_le16(0x5a5a);
++ cmd->params.reset.action = cpu_to_le16(CMD_ACT_HALT);
++ usb_tx_block(cardp, cardp->ep_out_buf, 4 + S_DS_GEN + sizeof(struct cmd_ds_802_11_reset));
++
++ msleep(100);
++ ret = usb_reset_device(cardp->udev);
++ msleep(100);
++
++#ifdef CONFIG_OLPC
++ if (ret && machine_is_olpc()) {
++ printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
++ olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
++ }
++#endif
++
++ lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
++
++ return ret;
++}
++
++/**
++ * @brief This function transfer the data to the device.
++ * @param priv pointer to struct lbs_private
++ * @param payload pointer to payload data
++ * @param nb data length
++ * @return 0 or -1
++ */
++static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb)
++{
++ int ret = -1;
++
++ /* check if device is removed */
++ if (cardp->surprise_removed) {
++ lbs_deb_usbd(&cardp->udev->dev, "Device removed\n");
++ goto tx_ret;
++ }
++
++ usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
++ usb_sndbulkpipe(cardp->udev,
++ cardp->ep_out),
++ payload, nb, if_usb_write_bulk_callback, cardp);
++
++ cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
++
++ if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
++ lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
++ ret = -1;
++ } else {
++ lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
++ ret = 0;
++ }
++
++tx_ret:
++ return ret;
++}
++
++static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
++ void (*callbackfn)(struct urb *urb))
++{
++ struct sk_buff *skb;
++ int ret = -1;
++
++ if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
++ lbs_pr_err("No free skb\n");
++ goto rx_ret;
++ }
++
++ cardp->rx_skb = skb;
++
++ /* Fill the receive configuration URB and initialise the Rx call back */
++ usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
++ usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
++ (void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET),
++ MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
++ cardp);
++
++ cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
++
++ lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
++ if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
++ lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
++ kfree_skb(skb);
++ cardp->rx_skb = NULL;
++ ret = -1;
++ } else {
++ lbs_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n");
++ ret = 0;
++ }
++
++rx_ret:
++ return ret;
++}
++
++static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp)
++{
++ return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
++}
++
++static int if_usb_submit_rx_urb(struct if_usb_card *cardp)
++{
++ return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
++}
++
++static void if_usb_receive_fwload(struct urb *urb)
++{
++ struct if_usb_card *cardp = urb->context;
++ struct sk_buff *skb = cardp->rx_skb;
++ struct fwsyncheader *syncfwheader;
++ struct bootcmdresp bootcmdresp;
++
++ if (urb->status) {
++ lbs_deb_usbd(&cardp->udev->dev,
++ "URB status is failed during fw load\n");
++ kfree_skb(skb);
++ return;
++ }
++
++ if (cardp->fwdnldover) {
++ __le32 *tmp = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
++
++ if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
++ tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
++ lbs_pr_info("Firmware ready event received\n");
++ wake_up(&cardp->fw_wq);
++ } else {
++ lbs_deb_usb("Waiting for confirmation; got %x %x\n",
++ le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1]));
++ if_usb_submit_rx_urb_fwload(cardp);
++ }
++ kfree_skb(skb);
++ return;
++ }
++ if (cardp->bootcmdresp <= 0) {
++ memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
++ sizeof(bootcmdresp));
++
++ if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
++ kfree_skb(skb);
++ if_usb_submit_rx_urb_fwload(cardp);
++ cardp->bootcmdresp = 1;
++ lbs_deb_usbd(&cardp->udev->dev,
++ "Received valid boot command response\n");
++ return;
++ }
++ if (bootcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
++ if (bootcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) ||
++ bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
++ bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
++ if (!cardp->bootcmdresp)
++ lbs_pr_info("Firmware already seems alive; resetting\n");
++ cardp->bootcmdresp = -1;
++ } else {
++ lbs_pr_info("boot cmd response wrong magic number (0x%x)\n",
++ le32_to_cpu(bootcmdresp.magic));
++ }
++ } else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) &&
++ (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) &&
++ (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) {
++ lbs_pr_info("boot cmd response cmd_tag error (%d)\n",
++ bootcmdresp.cmd);
++ } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
++ lbs_pr_info("boot cmd response result error (%d)\n",
++ bootcmdresp.result);
++ } else {
++ cardp->bootcmdresp = 1;
++ lbs_deb_usbd(&cardp->udev->dev,
++ "Received valid boot command response\n");
++ }
++ kfree_skb(skb);
++ if_usb_submit_rx_urb_fwload(cardp);
++ return;
++ }
++
++ syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
++ if (!syncfwheader) {
++ lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
++ kfree_skb(skb);
++ return;
++ }
++
++ memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
++ sizeof(struct fwsyncheader));
++
++ if (!syncfwheader->cmd) {
++ lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
++ lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
++ le32_to_cpu(syncfwheader->seqnum));
++ cardp->CRC_OK = 1;
++ } else {
++ lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
++ cardp->CRC_OK = 0;
++ }
++
++ kfree_skb(skb);
++
++ /* Give device 5s to either write firmware to its RAM or eeprom */
++ mod_timer(&cardp->fw_timeout, jiffies + (HZ*5));
++
++ if (cardp->fwfinalblk) {
++ cardp->fwdnldover = 1;
++ goto exit;
++ }
++
++ if_usb_send_fw_pkt(cardp);
++
++ exit:
++ if_usb_submit_rx_urb_fwload(cardp);
++
++ kfree(syncfwheader);
++
++ return;
++}
++
++#define MRVDRV_MIN_PKT_LEN 30
++
++static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
++ struct if_usb_card *cardp,
++ struct lbs_private *priv)
++{
++ if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
++ || recvlength < MRVDRV_MIN_PKT_LEN) {
++ lbs_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n");
++ kfree_skb(skb);
++ return;
++ }
++
++ skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
++ skb_put(skb, recvlength);
++ skb_pull(skb, MESSAGE_HEADER_LEN);
++
++ lbs_process_rxed_packet(priv, skb);
++ priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
++}
++
++static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
++ struct sk_buff *skb,
++ struct if_usb_card *cardp,
++ struct lbs_private *priv)
++{
++ if (recvlength > LBS_CMD_BUFFER_SIZE) {
++ lbs_deb_usbd(&cardp->udev->dev,
++ "The receive buffer is too large\n");
++ kfree_skb(skb);
++ return;
++ }
++
++ if (!in_interrupt())
++ BUG();
++
++ spin_lock(&priv->driver_lock);
++ cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY;
++ priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
++ memcpy(priv->upld_buf, recvbuff + MESSAGE_HEADER_LEN, priv->upld_len);
++
++ kfree_skb(skb);
++ lbs_interrupt(priv);
++ spin_unlock(&priv->driver_lock);
++
++ lbs_deb_usbd(&cardp->udev->dev,
++ "Wake up main thread to handle cmd response\n");
++}
++
++/**
++ * @brief This function reads of the packet into the upload buff,
++ * wake up the main thread and initialise the Rx callack.
++ *
++ * @param urb pointer to struct urb
++ * @return N/A
++ */
++static void if_usb_receive(struct urb *urb)
++{
++ struct if_usb_card *cardp = urb->context;
++ struct sk_buff *skb = cardp->rx_skb;
++ struct lbs_private *priv = cardp->priv;
++ int recvlength = urb->actual_length;
++ uint8_t *recvbuff = NULL;
++ uint32_t recvtype = 0;
++ __le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
++
++ lbs_deb_enter(LBS_DEB_USB);
++
++ if (recvlength) {
++ if (urb->status) {
++ lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n",
++ urb->status);
++ kfree_skb(skb);
++ goto setup_for_next;
++ }
++
++ recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
++ recvtype = le32_to_cpu(pkt[0]);
++ lbs_deb_usbd(&cardp->udev->dev,
++ "Recv length = 0x%x, Recv type = 0x%X\n",
++ recvlength, recvtype);
++ } else if (urb->status) {
++ kfree_skb(skb);
++ goto rx_exit;
++ }
++
++ switch (recvtype) {
++ case CMD_TYPE_DATA:
++ process_cmdtypedata(recvlength, skb, cardp, priv);
++ break;
++
++ case CMD_TYPE_REQUEST:
++ process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
++ break;
++
++ case CMD_TYPE_INDICATION:
++ /* Event cause handling */
++ spin_lock(&priv->driver_lock);
++
++ cardp->usb_event_cause = le32_to_cpu(pkt[1]);
++
++ lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n",
++ cardp->usb_event_cause);
++
++ /* Icky undocumented magic special case */
++ if (cardp->usb_event_cause & 0xffff0000) {
++ lbs_send_tx_feedback(priv);
++ spin_unlock(&priv->driver_lock);
++ break;
++ }
++ cardp->usb_event_cause <<= 3;
++ cardp->usb_int_cause |= MRVDRV_CARDEVENT;
++ kfree_skb(skb);
++ lbs_interrupt(priv);
++ spin_unlock(&priv->driver_lock);
++ goto rx_exit;
++ default:
++ lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
++ recvtype);
++ kfree_skb(skb);
++ break;
++ }
++
++setup_for_next:
++ if_usb_submit_rx_urb(cardp);
++rx_exit:
++ lbs_deb_leave(LBS_DEB_USB);
++}
++
++/**
++ * @brief This function downloads data to FW
++ * @param priv pointer to struct lbs_private structure
++ * @param type type of data
++ * @param buf pointer to data buffer
++ * @param len number of bytes
++ * @return 0 or -1
++ */
++static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
++ uint8_t *payload, uint16_t nb)
++{
++ struct if_usb_card *cardp = priv->card;
++
++ lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type);
++ lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb);
++
++ if (type == MVMS_CMD) {
++ *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
++ priv->dnld_sent = DNLD_CMD_SENT;
++ } else {
++ *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA);
++ priv->dnld_sent = DNLD_DATA_SENT;
++ }
++
++ memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb);
++
++ return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN);
++}
++
++/* called with priv->driver_lock held */
++static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *ireg)
++{
++ struct if_usb_card *cardp = priv->card;
++
++ *ireg = cardp->usb_int_cause;
++ cardp->usb_int_cause = 0;
++
++ lbs_deb_usbd(&cardp->udev->dev, "Int cause is 0x%X\n", *ireg);
++
++ return 0;
++}
++
++static int if_usb_read_event_cause(struct lbs_private *priv)
++{
++ struct if_usb_card *cardp = priv->card;
++
++ priv->eventcause = cardp->usb_event_cause;
++ /* Re-submit rx urb here to avoid event lost issue */
++ if_usb_submit_rx_urb(cardp);
++
++ return 0;
++}
++
++/**
++ * @brief This function issues Boot command to the Boot2 code
++ * @param ivalue 1:Boot from FW by USB-Download
++ * 2:Boot from FW in EEPROM
++ * @return 0
++ */
++static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
++{
++ struct bootcmd *bootcmd = cardp->ep_out_buf;
++
++ /* Prepare command */
++ bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
++ bootcmd->cmd = ivalue;
++ memset(bootcmd->pad, 0, sizeof(bootcmd->pad));
++
++ /* Issue command */
++ usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd));
++
++ return 0;
++}
++
++
++/**
++ * @brief This function checks the validity of Boot2/FW image.
++ *
++ * @param data pointer to image
++ * len image length
++ * @return 0 or -1
++ */
++static int check_fwfile_format(uint8_t *data, uint32_t totlen)
++{
++ uint32_t bincmd, exit;
++ uint32_t blksize, offset, len;
++ int ret;
++
++ ret = 1;
++ exit = len = 0;
++
++ do {
++ struct fwheader *fwh = (void *)data;
++
++ bincmd = le32_to_cpu(fwh->dnldcmd);
++ blksize = le32_to_cpu(fwh->datalength);
++ switch (bincmd) {
++ case FW_HAS_DATA_TO_RECV:
++ offset = sizeof(struct fwheader) + blksize;
++ data += offset;
++ len += offset;
++ if (len >= totlen)
++ exit = 1;
++ break;
++ case FW_HAS_LAST_BLOCK:
++ exit = 1;
++ ret = 0;
++ break;
++ default:
++ exit = 1;
++ break;
++ }
++ } while (!exit);
++
++ if (ret)
++ lbs_pr_err("firmware file format check FAIL\n");
++ else
++ lbs_deb_fw("firmware file format check PASS\n");
++
++ return ret;
++}
++
++/**
++ * @brief This function programs the firmware subject to cmd
++ *
++ * @param cardp the if_usb_card descriptor
++ * fwname firmware or boot2 image file name
++ * cmd either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW,
++ * or BOOT_CMD_UPDATE_BOOT2.
++ * @return 0 or error code
++ */
++static int if_usb_prog_firmware(struct if_usb_card *cardp,
++ const char *fwname, int cmd)
++{
++ int i = 0;
++ static int reset_count = 10;
++ int ret = 0;
++
++ lbs_deb_enter(LBS_DEB_USB);
++
++ /* Don't mess with the firmware if the interface is up */
++ if (cardp->priv &&
++ (cardp->priv->mesh_open || cardp->priv->infra_open)) {
++ ret = -EPERM;
++ goto done;
++ }
++
++ ret = request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
++ if (ret < 0) {
++ lbs_pr_err("request_firmware() failed with %#x\n", ret);
++ lbs_pr_err("firmware %s not found\n", fwname);
++ goto done;
++ }
++
++ if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
++ ret = -EINVAL;
++ goto release_fw;
++ }
++
++ /* Cancel any pending usb business */
++ usb_kill_urb(cardp->rx_urb);
++ usb_kill_urb(cardp->tx_urb);
++
++ cardp->fwlastblksent = 0;
++ cardp->fwdnldover = 0;
++ cardp->totalbytes = 0;
++ cardp->fwfinalblk = 0;
++ cardp->bootcmdresp = 0;
++
++restart:
++ if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
++ lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
++ ret = -EIO;
++ goto release_fw;
++ }
++
++ cardp->bootcmdresp = 0;
++ do {
++ int j = 0;
++ i++;
++ if_usb_issue_boot_command(cardp, cmd);
++ /* wait for command response */
++ do {
++ j++;
++ msleep_interruptible(100);
++ } while (cardp->bootcmdresp == 0 && j < 10);
++ } while (cardp->bootcmdresp == 0 && i < 5);
++
++ if (cardp->bootcmdresp <= 0) {
++ if (--reset_count >= 0) {
++ if_usb_reset_device(cardp);
++ goto restart;
++ }
++ return -EIO;
++ }
++
++ i = 0;
++
++ cardp->totalbytes = 0;
++ cardp->fwlastblksent = 0;
++ cardp->CRC_OK = 1;
++ cardp->fwdnldover = 0;
++ cardp->fwseqnum = -1;
++ cardp->totalbytes = 0;
++ cardp->fwfinalblk = 0;
++
++ /* Send the first firmware packet... */
++ if_usb_send_fw_pkt(cardp);
++
++ /* ... and wait for the process to complete */
++ wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover);
++
++ del_timer_sync(&cardp->fw_timeout);
++ usb_kill_urb(cardp->rx_urb);
++
++ if (!cardp->fwdnldover) {
++ lbs_pr_info("failed to load fw, resetting device!\n");
++ if (--reset_count >= 0) {
++ if_usb_reset_device(cardp);
++ goto restart;
++ }
++
++ lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
++ ret = -EIO;
++ goto release_fw;
++ }
++
++ release_fw:
++ release_firmware(cardp->fw);
++ cardp->fw = NULL;
++
++ done:
++ lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
++ return ret;
++}
++
++
++#ifdef CONFIG_PM
++static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
++{
++ struct if_usb_card *cardp = usb_get_intfdata(intf);
++ struct lbs_private *priv = cardp->priv;
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_USB);
++
++ if (priv->psstate != PS_STATE_FULL_POWER)
++ return -1;
++
++ ret = lbs_suspend(priv);
++ if (ret)
++ goto out;
++
++ /* Unlink tx & rx urb */
++ usb_kill_urb(cardp->tx_urb);
++ usb_kill_urb(cardp->rx_urb);
++
++ out:
++ lbs_deb_leave(LBS_DEB_USB);
++ return ret;
++}
++
++static int if_usb_resume(struct usb_interface *intf)
++{
++ struct if_usb_card *cardp = usb_get_intfdata(intf);
++ struct lbs_private *priv = cardp->priv;
++
++ lbs_deb_enter(LBS_DEB_USB);
++
++ if_usb_submit_rx_urb(cardp);
++
++ lbs_resume(priv);
++
++ lbs_deb_leave(LBS_DEB_USB);
++ return 0;
++}
++#else
++#define if_usb_suspend NULL
++#define if_usb_resume NULL
++#endif
++
++static struct usb_driver if_usb_driver = {
++ .name = DRV_NAME,
++ .probe = if_usb_probe,
++ .disconnect = if_usb_disconnect,
++ .id_table = if_usb_table,
++ .suspend = if_usb_suspend,
++ .resume = if_usb_resume,
++};
++
++static int __init if_usb_init_module(void)
++{
++ int ret = 0;
++
++ lbs_deb_enter(LBS_DEB_MAIN);
++
++ ret = usb_register(&if_usb_driver);
++
++ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
++ return ret;
++}
++
++static void __exit if_usb_exit_module(void)
++{
++ lbs_deb_enter(LBS_DEB_MAIN);
++
++ usb_deregister(&if_usb_driver);
++
++ lbs_deb_leave(LBS_DEB_MAIN);
++}
++
++module_init(if_usb_init_module);
++module_exit(if_usb_exit_module);
++
++MODULE_DESCRIPTION("8388 USB WLAN Driver");
++MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc.");
++MODULE_LICENSE("GPL");
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/if_usb.h linux-2.6.22-300/drivers/net/wireless/libertas/if_usb.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/if_usb.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/if_usb.h 2008-06-05 18:10:06.000000000 -0400
+@@ -1,77 +1,75 @@
+-#ifndef _LIBERTAS_IF_USB_H
+-#define _LIBERTAS_IF_USB_H
++#ifndef _LBS_IF_USB_H
++#define _LBS_IF_USB_H
+
+-#include <linux/list.h>
++#include <linux/wait.h>
++#include <linux/timer.h>
++
++struct lbs_private;
+
+ /**
+ * This file contains definition for USB interface.
+ */
+-#define CMD_TYPE_REQUEST 0xF00DFACE
+-#define CMD_TYPE_DATA 0xBEADC0DE
+-#define CMD_TYPE_INDICATION 0xBEEFFACE
+-
+-#define IPFIELD_ALIGN_OFFSET 2
+-
+-#define BOOT_CMD_FW_BY_USB 0x01
+-#define BOOT_CMD_FW_IN_EEPROM 0x02
+-#define BOOT_CMD_UPDATE_BOOT2 0x03
+-#define BOOT_CMD_UPDATE_FW 0x04
+-#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */
++#define CMD_TYPE_REQUEST 0xF00DFACE
++#define CMD_TYPE_DATA 0xBEADC0DE
++#define CMD_TYPE_INDICATION 0xBEEFFACE
++
++#define IPFIELD_ALIGN_OFFSET 2
++
++#define BOOT_CMD_FW_BY_USB 0x01
++#define BOOT_CMD_FW_IN_EEPROM 0x02
++#define BOOT_CMD_UPDATE_BOOT2 0x03
++#define BOOT_CMD_UPDATE_FW 0x04
++#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* LVRM */
+
+-struct bootcmdstr
++struct bootcmd
+ {
+- __le32 u32magicnumber;
+- u8 u8cmd_tag;
+- u8 au8dumy[11];
++ __le32 magic;
++ uint8_t cmd;
++ uint8_t pad[11];
+ };
+
+-#define BOOT_CMD_RESP_OK 0x0001
+-#define BOOT_CMD_RESP_FAIL 0x0000
++#define BOOT_CMD_RESP_OK 0x0001
++#define BOOT_CMD_RESP_FAIL 0x0000
+
+-struct bootcmdrespStr
++struct bootcmdresp
+ {
+- __le32 u32magicnumber;
+- u8 u8cmd_tag;
+- u8 u8result;
+- u8 au8dumy[2];
+-};
+-
+-/* read callback private data */
+-struct read_cb_info {
+- wlan_private *priv;
+- struct sk_buff *skb;
++ __le32 magic;
++ uint8_t cmd;
++ uint8_t result;
++ uint8_t pad[2];
+ };
+
+ /** USB card description structure*/
+-struct usb_card_rec {
+- struct list_head list;
+- struct net_device *eth_dev;
++struct if_usb_card {
+ struct usb_device *udev;
+ struct urb *rx_urb, *tx_urb;
+- void *priv;
+- struct read_cb_info rinfo;
+-
+- int bulk_in_size;
+- u8 bulk_in_endpointAddr;
++ struct lbs_private *priv;
+
+- u8 *bulk_out_buffer;
+- int bulk_out_size;
+- u8 bulk_out_endpointAddr;
+-
+- u8 CRC_OK;
+- u32 fwseqnum;
+- u32 lastseqnum;
+- u32 totalbytes;
+- u32 fwlastblksent;
+- u8 fwdnldover;
+- u8 fwfinalblk;
++ struct sk_buff *rx_skb;
++ uint32_t usb_event_cause;
++ uint8_t usb_int_cause;
++
++ uint8_t ep_in;
++ uint8_t ep_out;
++
++ int8_t bootcmdresp;
++
++ int ep_in_size;
++
++ void *ep_out_buf;
++ int ep_out_size;
++
++ const struct firmware *fw;
++ struct timer_list fw_timeout;
++ wait_queue_head_t fw_wq;
++ uint32_t fwseqnum;
++ uint32_t totalbytes;
++ uint32_t fwlastblksent;
++ uint8_t CRC_OK;
++ uint8_t fwdnldover;
++ uint8_t fwfinalblk;
++ uint8_t surprise_removed;
+
+- u32 usb_event_cause;
+- u8 usb_int_cause;
+-
+- u8 rx_urb_recall;
+-
+- u8 bootcmdresp;
+ };
+
+ /** fwheader */
+@@ -84,10 +82,10 @@ struct fwheader {
+
+ #define FW_MAX_DATA_BLK_SIZE 600
+ /** FWData */
+-struct FWData {
+- struct fwheader fwheader;
++struct fwdata {
++ struct fwheader hdr;
+ __le32 seqnum;
+- u8 data[FW_MAX_DATA_BLK_SIZE];
++ uint8_t data[0];
+ };
+
+ /** fwsyncheader */
+@@ -99,11 +97,5 @@ struct fwsyncheader {
+ #define FW_HAS_DATA_TO_RECV 0x00000001
+ #define FW_HAS_LAST_BLOCK 0x00000004
+
+-#define FW_DATA_XMIT_SIZE \
+- sizeof(struct fwheader) + le32_to_cpu(fwdata->fwheader.datalength) + sizeof(u32)
+-
+-int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb);
+-void if_usb_free(struct usb_card_rec *cardp);
+-int if_usb_issue_boot_command(wlan_private *priv, int ivalue);
+
+ #endif
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/ioctl.c linux-2.6.22-300/drivers/net/wireless/libertas/ioctl.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/ioctl.c 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.22-300/drivers/net/wireless/libertas/ioctl.c 2008-06-05 18:10:06.000000000 -0400
+@@ -0,0 +1,1251 @@
++/**
++ * This file contains ioctl functions
++ */
++
++#include <linux/ctype.h>
++#include <linux/delay.h>
++#include <linux/if.h>
++#include <linux/if_arp.h>
++#include <linux/wireless.h>
++
++#include <net/iw_handler.h>
++#include <net/ieee80211.h>
++
++#include "host.h"
++#include "radiotap.h"
++#include "decl.h"
++#include "defs.h"
++#include "dev.h"
++#include "join.h"
++#include "wext.h"
++#include "cmd.h"
++#include "ioctl.h"
++
++#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \
++ IW_ESSID_MAX_SIZE + \
++ IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
++ IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \
++ IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */
++
++#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ)
++
++static int lbs_set_region(struct lbs_private * priv, u16 region_code)
++{
++ int i;
++ int ret = 0;
++
++ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
++ // use the region code to search for the index
++ if (region_code == lbs_region_code_to_index[i]) {
++ priv->regioncode = region_code;
++ break;
++ }
++ }
++
++ // if it's unidentified region code
++ if (i >= MRVDRV_MAX_REGION_CODE) {
++ lbs_deb_ioctl("region Code not identified\n");
++ ret = -1;
++ goto done;
++ }
++
++ if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
++ ret = -EINVAL;
++ }
++
++done:
++ lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
++ return ret;
++}
++
++static inline int hex2int(char c)
++{
++ if (c >= '0' && c <= '9')
++ return (c - '0');
++ if (c >= 'a' && c <= 'f')
++ return (c - 'a' + 10);
++ if (c >= 'A' && c <= 'F')
++ return (c - 'A' + 10);
++ return -1;
++}
++
++/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx")
++ into binary format (6 bytes).
++
++ This function expects that each byte is represented with 2 characters
++ (e.g., 11:2:11:11:11:11 is invalid)
++
++ */
++static char *eth_str2addr(char *ethstr, u8 * addr)
++{
++ int i, val, val2;
++ char *pos = ethstr;
++
++ /* get rid of initial blanks */
++ while (*pos == ' ' || *pos == '\t')
++ ++pos;
++
++ for (i = 0; i < 6; i++) {
++ val = hex2int(*pos++);
++ if (val < 0)
++ return NULL;
++ val2 = hex2int(*pos++);
++ if (val2 < 0)
++ return NULL;
++ addr[i] = (val * 16 + val2) & 0xff;
++
++ if (i < 5 && *pos++ != ':')
++ return NULL;
++ }
++ return pos;
++}
++
++/* this writes xx:xx:xx:xx:xx:xx into ethstr
++ (ethstr must have space for 18 chars) */
++static int eth_addr2str(u8 * addr, char *ethstr)
++{
++ int i;
++ char *pos = ethstr;
++
++ for (i = 0; i < 6; i++) {
++ sprintf(pos, "%02x", addr[i] & 0xff);
++ pos += 2;
++ if (i < 5)
++ *pos++ = ':';
++ }
++ return 17;
++}
++
++/**
++ * @brief Add an entry to the BT table
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_bt_add_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ char ethaddrs_str[18];
++ char *pos;
++ u8 ethaddr[ETH_ALEN];
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
++ sizeof(ethaddrs_str)))
++ return -EFAULT;
++
++ if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
++ lbs_pr_info("BT_ADD: Invalid MAC address\n");
++ return -EINVAL;
++ }
++
++ lbs_deb_ioctl("BT: adding %s\n", ethaddrs_str);
++ ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS,
++ CMD_ACT_BT_ACCESS_ADD,
++ CMD_OPTION_WAITFORRSP, 0, ethaddr);
++ lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
++ return ret;
++}
++
++/**
++ * @brief Delete an entry from the BT table
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_bt_del_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ char ethaddrs_str[18];
++ u8 ethaddr[ETH_ALEN];
++ char *pos;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
++ sizeof(ethaddrs_str)))
++ return -EFAULT;
++
++ if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
++ lbs_pr_info("Invalid MAC address\n");
++ return -EINVAL;
++ }
++
++ lbs_deb_ioctl("BT: deleting %s\n", ethaddrs_str);
++
++ return (lbs_prepare_and_send_command(priv,
++ CMD_BT_ACCESS,
++ CMD_ACT_BT_ACCESS_DEL,
++ CMD_OPTION_WAITFORRSP, 0, ethaddr));
++
++ lbs_deb_leave(LBS_DEB_IOCTL);
++ return 0;
++}
++
++/**
++ * @brief Reset all entries from the BT table
++ * @param priv A pointer to struct lbs_private structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_bt_reset_ioctl(struct lbs_private * priv)
++{
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ lbs_pr_alert( "BT: resetting\n");
++
++ return (lbs_prepare_and_send_command(priv,
++ CMD_BT_ACCESS,
++ CMD_ACT_BT_ACCESS_RESET,
++ CMD_OPTION_WAITFORRSP, 0, NULL));
++
++ lbs_deb_leave(LBS_DEB_IOCTL);
++ return 0;
++}
++
++/**
++ * @brief List an entry from the BT table
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_bt_list_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ int pos;
++ char *addr1;
++ struct iwreq *wrq = (struct iwreq *)req;
++ /* used to pass id and store the bt entry returned by the FW */
++ union {
++ u32 id;
++ char addr1addr2[2 * ETH_ALEN];
++ } param;
++ static char outstr[64];
++ char *pbuf = outstr;
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) {
++ lbs_deb_ioctl("Copy from user failed\n");
++ return -1;
++ }
++ param.id = simple_strtoul(outstr, NULL, 10);
++ pos = sprintf(pbuf, "%d: ", param.id);
++ pbuf += pos;
++
++ ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS,
++ CMD_ACT_BT_ACCESS_LIST,
++ CMD_OPTION_WAITFORRSP, 0,
++ (char *)¶m);
++
++ if (ret == 0) {
++ addr1 = param.addr1addr2;
++
++ pos = sprintf(pbuf, "BT includes node ");
++ pbuf += pos;
++ pos = eth_addr2str(addr1, pbuf);
++ pbuf += pos;
++ } else {
++ sprintf(pbuf, "(null)");
++ pbuf += pos;
++ }
++
++ wrq->u.data.length = strlen(outstr);
++ if (copy_to_user(wrq->u.data.pointer, (char *)outstr,
++ wrq->u.data.length)) {
++ lbs_deb_ioctl("BT_LIST: Copy to user failed!\n");
++ return -EFAULT;
++ }
++
++ lbs_deb_leave(LBS_DEB_IOCTL);
++ return 0 ;
++}
++
++/**
++ * @brief Sets inverted state of blacklist (non-zero if inverted)
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_bt_set_invert_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ int ret;
++ struct iwreq *wrq = (struct iwreq *)req;
++ union {
++ u32 id;
++ char addr1addr2[2 * ETH_ALEN];
++ } param;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ param.id = SUBCMD_DATA(wrq) ;
++ ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS,
++ CMD_ACT_BT_ACCESS_SET_INVERT,
++ CMD_OPTION_WAITFORRSP, 0,
++ (char *)¶m);
++ if (ret != 0)
++ return -EFAULT;
++ lbs_deb_leave(LBS_DEB_IOCTL);
++ return 0;
++}
++
++/**
++ * @brief Gets inverted state of blacklist (non-zero if inverted)
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_bt_get_invert_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ int ret;
++ union {
++ __le32 id;
++ char addr1addr2[2 * ETH_ALEN];
++ } param;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS,
++ CMD_ACT_BT_ACCESS_GET_INVERT,
++ CMD_OPTION_WAITFORRSP, 0,
++ (char *)¶m);
++
++ if (ret == 0)
++ wrq->u.param.value = le32_to_cpu(param.id);
++ else
++ return -EFAULT;
++
++ lbs_deb_leave(LBS_DEB_IOCTL);
++ return 0;
++}
++
++/**
++ * @brief Find the next parameter in an input string
++ * @param ptr A pointer to the input parameter string
++ * @return A pointer to the next parameter, or 0 if no parameters left.
++ */
++static char * next_param(char * ptr)
++{
++ if (!ptr) return NULL;
++ while (*ptr == ' ' || *ptr == '\t') ++ptr;
++ return (*ptr == '\0') ? NULL : ptr;
++}
++
++/**
++ * @brief Add an entry to the FWT table
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_fwt_add_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ char in_str[128];
++ static struct cmd_ds_fwt_access fwt_access;
++ char *ptr;
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
++ return -EFAULT;
++
++ if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
++ lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
++ return -EINVAL;
++ }
++
++ if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
++ lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
++ return -EINVAL;
++ }
++
++ if ((ptr = next_param(ptr)))
++ fwt_access.metric =
++ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
++ else
++ fwt_access.metric = cpu_to_le32(FWT_DEFAULT_METRIC);
++
++ if ((ptr = next_param(ptr)))
++ fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
++ else
++ fwt_access.dir = FWT_DEFAULT_DIR;
++
++ if ((ptr = next_param(ptr)))
++ fwt_access.rate = (u8) simple_strtoul(ptr, &ptr, 10);
++ else
++ fwt_access.rate = FWT_DEFAULT_RATE;
++
++ if ((ptr = next_param(ptr)))
++ fwt_access.ssn =
++ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
++ else
++ fwt_access.ssn = cpu_to_le32(FWT_DEFAULT_SSN);
++
++ if ((ptr = next_param(ptr)))
++ fwt_access.dsn =
++ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
++ else
++ fwt_access.dsn = cpu_to_le32(FWT_DEFAULT_DSN);
++
++ if ((ptr = next_param(ptr)))
++ fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
++ else
++ fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
++
++ if ((ptr = next_param(ptr)))
++ fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
++ else
++ fwt_access.ttl = FWT_DEFAULT_TTL;
++
++ if ((ptr = next_param(ptr)))
++ fwt_access.expiration =
++ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
++ else
++ fwt_access.expiration = cpu_to_le32(FWT_DEFAULT_EXPIRATION);
++
++ if ((ptr = next_param(ptr)))
++ fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
++ else
++ fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
++
++ if ((ptr = next_param(ptr)))
++ fwt_access.snr =
++ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
++ else
++ fwt_access.snr = cpu_to_le32(FWT_DEFAULT_SNR);
++
++#ifdef DEBUG
++ {
++ char ethaddr1_str[18], ethaddr2_str[18];
++ eth_addr2str(fwt_access.da, ethaddr1_str);
++ eth_addr2str(fwt_access.ra, ethaddr2_str);
++ lbs_deb_ioctl("FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
++ fwt_access.dir, ethaddr2_str);
++ lbs_deb_ioctl("FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
++ fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
++ fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
++ fwt_access.sleepmode, fwt_access.snr);
++ }
++#endif
++
++ ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
++ CMD_ACT_FWT_ACCESS_ADD,
++ CMD_OPTION_WAITFORRSP, 0,
++ (void *)&fwt_access);
++
++ lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
++ return ret;
++}
++
++/**
++ * @brief Delete an entry from the FWT table
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_fwt_del_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ char in_str[64];
++ static struct cmd_ds_fwt_access fwt_access;
++ char *ptr;
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
++ return -EFAULT;
++
++ if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
++ lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
++ return -EINVAL;
++ }
++
++ if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
++ lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
++ return -EINVAL;
++ }
++
++ if ((ptr = next_param(ptr)))
++ fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
++ else
++ fwt_access.dir = FWT_DEFAULT_DIR;
++
++#ifdef DEBUG
++ {
++ char ethaddr1_str[18], ethaddr2_str[18];
++ lbs_deb_ioctl("FWT_DEL: line is %s\n", in_str);
++ eth_addr2str(fwt_access.da, ethaddr1_str);
++ eth_addr2str(fwt_access.ra, ethaddr2_str);
++ lbs_deb_ioctl("FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
++ ethaddr2_str, fwt_access.dir);
++ }
++#endif
++
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_FWT_ACCESS,
++ CMD_ACT_FWT_ACCESS_DEL,
++ CMD_OPTION_WAITFORRSP, 0,
++ (void *)&fwt_access);
++ lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
++ return ret;
++}
++
++
++/**
++ * @brief Print route parameters
++ * @param fwt_access struct cmd_ds_fwt_access with route info
++ * @param buf destination buffer for route info
++ */
++static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
++{
++ buf += sprintf(buf, " ");
++ buf += eth_addr2str(fwt_access.da, buf);
++ buf += sprintf(buf, " ");
++ buf += eth_addr2str(fwt_access.ra, buf);
++ buf += sprintf(buf, " %u", fwt_access.valid);
++ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
++ buf += sprintf(buf, " %u", fwt_access.dir);
++ buf += sprintf(buf, " %u", fwt_access.rate);
++ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
++ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
++ buf += sprintf(buf, " %u", fwt_access.hopcount);
++ buf += sprintf(buf, " %u", fwt_access.ttl);
++ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
++ buf += sprintf(buf, " %u", fwt_access.sleepmode);
++ buf += sprintf(buf, " %u ", le32_to_cpu(fwt_access.snr));
++ buf += eth_addr2str(fwt_access.prec, buf);
++}
++
++/**
++ * @brief Lookup an entry in the FWT table
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_fwt_lookup_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ char in_str[64];
++ char *ptr;
++ static struct cmd_ds_fwt_access fwt_access;
++ static char out_str[128];
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
++ return -EFAULT;
++
++ if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
++ lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
++ return -EINVAL;
++ }
++
++#ifdef DEBUG
++ {
++ char ethaddr1_str[18];
++ lbs_deb_ioctl("FWT_LOOKUP: line is %s\n", in_str);
++ eth_addr2str(fwt_access.da, ethaddr1_str);
++ lbs_deb_ioctl("FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
++ }
++#endif
++
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_FWT_ACCESS,
++ CMD_ACT_FWT_ACCESS_LOOKUP,
++ CMD_OPTION_WAITFORRSP, 0,
++ (void *)&fwt_access);
++
++ if (ret == 0)
++ print_route(fwt_access, out_str);
++ else
++ sprintf(out_str, "(null)");
++
++ wrq->u.data.length = strlen(out_str);
++ if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
++ wrq->u.data.length)) {
++ lbs_deb_ioctl("FWT_LOOKUP: Copy to user failed!\n");
++ return -EFAULT;
++ }
++
++ lbs_deb_leave(LBS_DEB_IOCTL);
++ return 0;
++}
++
++/**
++ * @brief Reset all entries from the FWT table
++ * @param priv A pointer to struct lbs_private structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_fwt_reset_ioctl(struct lbs_private * priv)
++{
++ lbs_deb_ioctl("FWT: resetting\n");
++
++ return (lbs_prepare_and_send_command(priv,
++ CMD_FWT_ACCESS,
++ CMD_ACT_FWT_ACCESS_RESET,
++ CMD_OPTION_WAITFORRSP, 0, NULL));
++}
++
++/**
++ * @brief List an entry from the FWT table
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_fwt_list_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ char in_str[8];
++ static struct cmd_ds_fwt_access fwt_access;
++ char *ptr = in_str;
++ static char out_str[128];
++ char *pbuf = out_str;
++ int ret = 0;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) {
++ ret = -EFAULT;
++ goto out;
++ }
++
++ fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
++
++#ifdef DEBUG
++ {
++ lbs_deb_ioctl("FWT_LIST: line is %s\n", in_str);
++ lbs_deb_ioctl("FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
++ }
++#endif
++
++ ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
++ CMD_ACT_FWT_ACCESS_LIST,
++ CMD_OPTION_WAITFORRSP, 0, (void *)&fwt_access);
++
++ if (ret == 0)
++ print_route(fwt_access, pbuf);
++ else
++ pbuf += sprintf(pbuf, " (null)");
++
++ wrq->u.data.length = strlen(out_str);
++ if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
++ wrq->u.data.length)) {
++ lbs_deb_ioctl("FWT_LIST: Copy to user failed!\n");
++ ret = -EFAULT;
++ goto out;
++ }
++
++ ret = 0;
++
++out:
++ lbs_deb_leave(LBS_DEB_IOCTL);
++ return ret;
++}
++
++/**
++ * @brief List an entry from the FRT table
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_fwt_list_route_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ char in_str[64];
++ static struct cmd_ds_fwt_access fwt_access;
++ char *ptr = in_str;
++ static char out_str[128];
++ char *pbuf = out_str;
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
++ return -EFAULT;
++
++ fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
++
++#ifdef DEBUG
++ {
++ lbs_deb_ioctl("FWT_LIST_ROUTE: line is %s\n", in_str);
++ lbs_deb_ioctl("FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
++ }
++#endif
++
++ ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
++ CMD_ACT_FWT_ACCESS_LIST_ROUTE,
++ CMD_OPTION_WAITFORRSP, 0, (void *)&fwt_access);
++
++ if (ret == 0) {
++ print_route(fwt_access, pbuf);
++ } else
++ pbuf += sprintf(pbuf, " (null)");
++
++ wrq->u.data.length = strlen(out_str);
++ if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
++ wrq->u.data.length)) {
++ lbs_deb_ioctl("FWT_LIST_ROUTE: Copy to user failed!\n");
++ return -EFAULT;
++ }
++
++ lbs_deb_leave(LBS_DEB_IOCTL);
++ return 0;
++}
++
++/**
++ * @brief List an entry from the FNT table
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_fwt_list_neighbor_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ char in_str[8];
++ static struct cmd_ds_fwt_access fwt_access;
++ char *ptr = in_str;
++ static char out_str[128];
++ char *pbuf = out_str;
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
++ return -EFAULT;
++
++ memset(&fwt_access, 0, sizeof(fwt_access));
++ fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
++
++#ifdef DEBUG
++ {
++ lbs_deb_ioctl("FWT_LIST_NEIGHBOR: line is %s\n", in_str);
++ lbs_deb_ioctl("FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
++ }
++#endif
++
++ ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
++ CMD_ACT_FWT_ACCESS_LIST_NEIGHBOR,
++ CMD_OPTION_WAITFORRSP, 0,
++ (void *)&fwt_access);
++
++ if (ret == 0) {
++ pbuf += sprintf(pbuf, " ra ");
++ pbuf += eth_addr2str(fwt_access.ra, pbuf);
++ pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode);
++ pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr));
++ pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references));
++ } else
++ pbuf += sprintf(pbuf, " (null)");
++
++ wrq->u.data.length = strlen(out_str);
++ if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
++ wrq->u.data.length)) {
++ lbs_deb_ioctl("FWT_LIST_NEIGHBOR: Copy to user failed!\n");
++ return -EFAULT;
++ }
++
++ lbs_deb_leave(LBS_DEB_IOCTL);
++ return 0;
++}
++
++/**
++ * @brief Cleans up the route (FRT) and neighbor (FNT) tables
++ * (Garbage Collection)
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_fwt_cleanup_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ static struct cmd_ds_fwt_access fwt_access;
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ lbs_deb_ioctl("FWT: cleaning up\n");
++
++ memset(&fwt_access, 0, sizeof(fwt_access));
++
++ ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
++ CMD_ACT_FWT_ACCESS_CLEANUP,
++ CMD_OPTION_WAITFORRSP, 0,
++ (void *)&fwt_access);
++
++ if (ret == 0)
++ wrq->u.param.value = le32_to_cpu(fwt_access.references);
++ else
++ return -EFAULT;
++
++ lbs_deb_leave(LBS_DEB_IOCTL);
++ return 0;
++}
++
++/**
++ * @brief Gets firmware internal time (debug purposes)
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_fwt_time_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ static struct cmd_ds_fwt_access fwt_access;
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ lbs_deb_ioctl("FWT: getting time\n");
++
++ memset(&fwt_access, 0, sizeof(fwt_access));
++
++ ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
++ CMD_ACT_FWT_ACCESS_TIME,
++ CMD_OPTION_WAITFORRSP, 0,
++ (void *)&fwt_access);
++
++ if (ret == 0)
++ wrq->u.param.value = le32_to_cpu(fwt_access.references);
++ else
++ return -EFAULT;
++
++ lbs_deb_leave(LBS_DEB_IOCTL);
++ return 0;
++}
++
++
++/**
++ * @brief Manages all mesh related ioctls
++ * @param priv A pointer to struct lbs_private structure
++ * @param req A pointer to ifreq structure
++ * @param cmd The command type
++ * @param host_subcmd The device code for the subcommand
++ * 0: sets a value in the firmware
++ * 1: retrieves an int from the firmware
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_mesh_ioctl(struct lbs_private * priv, struct iwreq * wrq,
++ int cmd, int subcmd)
++{
++ struct cmd_ds_mesh_access mesh_access;
++ int parameter;
++ char str[128];
++ char *ptr = str;
++ int ret, i;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ memset(&mesh_access, 0, sizeof(mesh_access));
++
++ if (cmd == LBS_SETONEINT_GETNONE) {
++ parameter = SUBCMD_DATA(wrq);
++
++ /* Convert rate from Mbps -> firmware rate index */
++ if (subcmd == CMD_ACT_MESH_SET_BCAST_RATE)
++ parameter = lbs_data_rate_to_fw_index(parameter);
++ if (subcmd == CMD_ACT_MESH_SET_PRB_RSP_RETRY_LIMIT) {
++ if (parameter > 15)
++ return -EINVAL;
++ }
++ if (parameter < 0)
++ return -EINVAL;
++ mesh_access.data[0] = cpu_to_le32(parameter);
++ } else if (subcmd == CMD_ACT_MESH_SET_LINK_COSTS) {
++ if (copy_from_user(str, wrq->u.data.pointer, sizeof(str)))
++ return -EFAULT;
++
++ for (i = 0; i < COSTS_LIST_SIZE; i++) {
++ mesh_access.data[i] = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
++ if (!(ptr = next_param(ptr)) && i!= (COSTS_LIST_SIZE - 1))
++ return -EINVAL;
++ }
++ }
++
++ ret = lbs_mesh_access(priv, subcmd, &mesh_access);
++
++ if (ret != 0)
++ return ret;
++
++ if (cmd == LBS_SETNONE_GETONEINT) {
++ u32 data = le32_to_cpu(mesh_access.data[0]);
++
++ if (subcmd == CMD_ACT_MESH_GET_BCAST_RATE)
++ wrq->u.param.value = lbs_fw_index_to_data_rate(data);
++ else
++ wrq->u.param.value = data;
++ } else if (subcmd == CMD_ACT_MESH_GET_LINK_COSTS) {
++ for (i = 0; i < COSTS_LIST_SIZE; i++)
++ ptr += sprintf (ptr, " %u", le32_to_cpu(mesh_access.data[i]));
++ wrq->u.data.length = strlen(str);
++
++ if (copy_to_user(wrq->u.data.pointer, (char *)str,
++ wrq->u.data.length)) {
++ lbs_deb_ioctl("MESH_IOCTL: Copy to user failed!\n");
++ ret = -EFAULT;
++ }
++ }
++
++ lbs_deb_leave(LBS_DEB_IOCTL);
++ return ret;
++}
++
++/**
++ * @brief Control Beacon transmissions
++ * @param priv A pointer to struct lbs_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return 0 --success, otherwise fail
++ */
++static int lbs_bcn_ioctl(struct lbs_private * priv, struct iwreq *wrq)
++{
++ int ret;
++ int data[2];
++
++ memset(data, 0, sizeof(data));
++ if (!wrq->u.data.length) {
++ lbs_deb_ioctl("Get Beacon control\n");
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_BEACON_CTRL,
++ CMD_ACT_GET,
++ CMD_OPTION_WAITFORRSP, 0, NULL);
++ data[0] = priv->beacon_enable;
++ data[1] = priv->beacon_period;
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
++ lbs_deb_ioctl("Copy to user failed\n");
++ return -EFAULT;
++ }
++#define GET_TWO_INT 2
++ wrq->u.data.length = GET_TWO_INT;
++ } else {
++ lbs_deb_ioctl("Set beacon control\n");
++ if (wrq->u.data.length > 2)
++ return -EINVAL;
++ if (copy_from_user (data, wrq->u.data.pointer,
++ sizeof(int) * wrq->u.data.length)) {
++ lbs_deb_ioctl("Copy from user failed\n");
++ return -EFAULT;
++ }
++ priv->beacon_enable = data[0];
++ if (wrq->u.data.length > 1) {
++ if ((data[1] > MRVDRV_MAX_BEACON_INTERVAL)
++ || (data[1] < MRVDRV_MIN_BEACON_INTERVAL))
++ return -ENOTSUPP;
++ priv->beacon_period= data[1];
++ }
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_BEACON_CTRL,
++ CMD_ACT_SET,
++ CMD_OPTION_WAITFORRSP, 0, NULL);
++ }
++ return ret;
++}
++
++static int lbs_led_gpio_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ int i, ret = 0;
++ int data[16];
++ struct cmd_ds_802_11_led_ctrl ctrl;
++ struct mrvlietypes_ledgpio *gpio = (struct mrvlietypes_ledgpio *) ctrl.data;
++ int len = wrq->u.data.length;
++
++ if ((len > MAX_LEDS * 2) || (len % 2 != 0))
++ return -ENOTSUPP;
++
++ memset(&ctrl, 0, sizeof(ctrl));
++ if (len == 0) {
++ ctrl.action = cpu_to_le16(CMD_ACT_GET);
++ } else {
++ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * len)) {
++ lbs_deb_ioctl("Copy from user failed\n");
++ ret = -EFAULT;
++ goto out;
++ }
++
++ ctrl.action = cpu_to_le16(CMD_ACT_SET);
++ ctrl.numled = cpu_to_le16(0);
++ gpio->header.type = cpu_to_le16(TLV_TYPE_LED_GPIO);
++ gpio->header.len = cpu_to_le16(len);
++ for (i = 0; i < len; i += 2) {
++ gpio->ledpin[i / 2].led = data[i];
++ gpio->ledpin[i / 2].pin = data[i + 1];
++ }
++ }
++
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_LED_GPIO_CTRL,
++ 0, CMD_OPTION_WAITFORRSP, 0, (void *)&ctrl);
++ if (ret) {
++ lbs_deb_ioctl("Error doing LED GPIO control: %d\n", ret);
++ goto out;
++ }
++ len = le16_to_cpu(gpio->header.len);
++ for (i = 0; i < len; i += 2) {
++ data[i] = gpio->ledpin[i / 2].led;
++ data[i + 1] = gpio->ledpin[i / 2].pin;
++ }
++
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * len)) {
++ lbs_deb_ioctl("Copy to user failed\n");
++ ret = -EFAULT;
++ goto out;
++ }
++
++ wrq->u.data.length = len;
++
++out:
++ return ret;
++}
++
++
++static int lbs_led_bhv_ioctl(struct lbs_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *)req;
++ int i, ret = 0;
++ int data[MAX_LEDS*4];
++ int firmwarestate = 0;
++ struct cmd_ds_802_11_led_ctrl ctrl;
++ struct mrvlietypes_ledbhv *bhv = (struct mrvlietypes_ledbhv *) ctrl.data;
++ int len = wrq->u.data.length;
++
++ if ((len > MAX_LEDS * 4) ||(len == 0) )
++ return -ENOTSUPP;
++
++ memset(&ctrl, 0, sizeof(ctrl));
++ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * len)) {
++ lbs_deb_ioctl("Copy from user failed\n");
++ ret = -EFAULT;
++ goto out;
++ }
++ if (len == 1) {
++ ctrl.action = cpu_to_le16(CMD_ACT_GET);
++ firmwarestate = data[0];
++ } else {
++
++ if (len % 4 != 0 )
++ return -ENOTSUPP;
++
++ bhv->header.type = cpu_to_le16(TLV_TYPE_LEDBEHAVIOR);
++ bhv->header.len = cpu_to_le16(len);
++ ctrl.action = cpu_to_le16(CMD_ACT_SET);
++ ctrl.numled = cpu_to_le16(0);
++ for (i = 0; i < len; i += 4) {
++ bhv->ledbhv[i / 4].firmwarestate = data[i];
++ bhv->ledbhv[i / 4].led = data[i + 1];
++ bhv->ledbhv[i / 4].ledstate = data[i + 2];
++ bhv->ledbhv[i / 4].ledarg = data[i + 3];
++ }
++ }
++
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_LED_GPIO_CTRL,
++ 0, CMD_OPTION_WAITFORRSP, 0, (void *)&ctrl);
++ if (ret) {
++ lbs_deb_ioctl("Error doing LED GPIO control: %d\n", ret);
++ goto out;
++ }
++
++ /* Get LED behavior IE, we have received gpio control as well when len
++ is equal to 1. */
++ if (len ==1 ) {
++ bhv = (struct mrvlietypes_ledbhv *)
++ ((unsigned char *)bhv->ledbhv + le16_to_cpu(bhv->header.len));
++ i = 0;
++ while ( i < (MAX_LEDS*4) &&
++ (bhv->header.type != cpu_to_le16(MRVL_TERMINATE_TLV_ID)) ) {
++ if (bhv->ledbhv[0].firmwarestate == firmwarestate) {
++ data[i++] = bhv->ledbhv[0].firmwarestate;
++ data[i++] = bhv->ledbhv[0].led;
++ data[i++] = bhv->ledbhv[0].ledstate;
++ data[i++] = bhv->ledbhv[0].ledarg;
++ }
++ bhv++;
++ }
++ len = i;
++ } else {
++ for (i = 0; i < le16_to_cpu(bhv->header.len); i += 4) {
++ data[i] = bhv->ledbhv[i / 4].firmwarestate;
++ data[i + 1] = bhv->ledbhv[i / 4].led;
++ data[i + 2] = bhv->ledbhv[i / 4].ledstate;
++ data[i + 3] = bhv->ledbhv[i / 4].ledarg;
++ }
++ len = le16_to_cpu(bhv->header.len);
++ }
++
++ if (copy_to_user(wrq->u.data.pointer, data,
++ sizeof(int) * len)) {
++ lbs_deb_ioctl("Copy to user failed\n");
++ ret = -EFAULT;
++ goto out;
++ }
++
++ wrq->u.data.length = len;
++
++out:
++ return ret;
++}
++
++/**
++ * @brief ioctl function - entry point
++ *
++ * @param dev A pointer to net_device structure
++ * @param req A pointer to ifreq structure
++ * @param cmd command
++ * @return 0--success, otherwise fail
++ */
++int lbs_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
++{
++ int *pdata;
++ int ret = 0;
++ struct lbs_private *priv = dev->priv;
++ struct iwreq *wrq = (struct iwreq *)req;
++
++ lbs_deb_enter(LBS_DEB_IOCTL);
++
++ lbs_deb_ioctl("lbs_do_ioctl: ioctl cmd = 0x%x\n", cmd);
++ switch (cmd) {
++ case LBS_SETNONE_GETNONE:
++ switch (wrq->u.data.flags) {
++ case LBS_SUBCMD_BT_RESET:
++ lbs_bt_reset_ioctl(priv);
++ break;
++ case LBS_SUBCMD_FWT_RESET:
++ lbs_fwt_reset_ioctl(priv);
++ break;
++ }
++ break;
++
++ case LBS_SETONEINT_GETNONE:
++ switch (wrq->u.mode) {
++ case LBS_SUBCMD_SET_REGION:
++ ret = lbs_set_region(priv, (u16) SUBCMD_DATA(wrq));
++ break;
++ case LBS_SUBCMD_MESH_SET_TTL:
++ ret = lbs_mesh_ioctl(priv, wrq, cmd,
++ CMD_ACT_MESH_SET_TTL);
++ break;
++ case LBS_SUBCMD_MESH_SET_BCAST_RATE:
++ ret = lbs_mesh_ioctl(priv, wrq, cmd,
++ CMD_ACT_MESH_SET_BCAST_RATE);
++ break;
++ case LBS_SUBCMD_MESH_SET_RREQ_DELAY:
++ ret = lbs_mesh_ioctl(priv, wrq, cmd,
++ CMD_ACT_MESH_SET_RREQ_DELAY);
++ break;
++ case LBS_SUBCMD_MESH_SET_ROUTE_EXP:
++ ret = lbs_mesh_ioctl(priv, wrq, cmd,
++ CMD_ACT_MESH_SET_ROUTE_EXP);
++ break;
++ case LBS_SUBCMD_BT_SET_INVERT:
++ ret = lbs_bt_set_invert_ioctl(priv, req);
++ break;
++ case LBS_SUBCMD_MESH_SET_PRB_RSP_RETRY_LIMIT:
++ ret = lbs_mesh_ioctl(priv, wrq, cmd,
++ CMD_ACT_MESH_SET_PRB_RSP_RETRY_LIMIT);
++ break;
++ default:
++ ret = -EOPNOTSUPP;
++ break;
++ }
++ break;
++
++ case LBS_SET128CHAR_GET128CHAR:
++ switch ((int)wrq->u.data.flags) {
++ case LBS_SUBCMD_BT_ADD:
++ ret = lbs_bt_add_ioctl(priv, req);
++ break;
++ case LBS_SUBCMD_BT_DEL:
++ ret = lbs_bt_del_ioctl(priv, req);
++ break;
++ case LBS_SUBCMD_BT_LIST:
++ ret = lbs_bt_list_ioctl(priv, req);
++ break;
++ case LBS_SUBCMD_FWT_ADD:
++ ret = lbs_fwt_add_ioctl(priv, req);
++ break;
++ case LBS_SUBCMD_FWT_DEL:
++ ret = lbs_fwt_del_ioctl(priv, req);
++ break;
++ case LBS_SUBCMD_FWT_LOOKUP:
++ ret = lbs_fwt_lookup_ioctl(priv, req);
++ break;
++ case LBS_SUBCMD_FWT_LIST_NEIGHBOR:
++ ret = lbs_fwt_list_neighbor_ioctl(priv, req);
++ break;
++ case LBS_SUBCMD_FWT_LIST:
++ ret = lbs_fwt_list_ioctl(priv, req);
++ break;
++ case LBS_SUBCMD_FWT_LIST_ROUTE:
++ ret = lbs_fwt_list_route_ioctl(priv, req);
++ break;
++ case LBS_SUBCMD_MESH_SET_LINK_COSTS:
++ ret = lbs_mesh_ioctl(priv, wrq, cmd,
++ CMD_ACT_MESH_SET_LINK_COSTS);
++ break ;
++ case LBS_SUBCMD_MESH_GET_LINK_COSTS:
++ ret = lbs_mesh_ioctl(priv, wrq, cmd,
++ CMD_ACT_MESH_GET_LINK_COSTS);
++ break;
++ }
++ break;
++
++ case LBS_SETNONE_GETONEINT:
++ switch (wrq->u.mode) {
++ case LBS_SUBCMD_GET_REGION:
++ pdata = (int *)wrq->u.name;
++ *pdata = (int)priv->regioncode;
++ break;
++ case LBS_SUBCMD_FWT_CLEANUP:
++ ret = lbs_fwt_cleanup_ioctl(priv, req);
++ break;
++ case LBS_SUBCMD_FWT_TIME:
++ ret = lbs_fwt_time_ioctl(priv, req);
++ break;
++ case LBS_SUBCMD_MESH_GET_TTL:
++ ret = lbs_mesh_ioctl(priv, wrq, cmd,
++ CMD_ACT_MESH_GET_TTL);
++ break;
++ case LBS_SUBCMD_MESH_GET_BCAST_RATE:
++ ret = lbs_mesh_ioctl(priv, wrq, cmd,
++ CMD_ACT_MESH_GET_BCAST_RATE);
++ break;
++ case LBS_SUBCMD_MESH_GET_RREQ_DELAY:
++ ret = lbs_mesh_ioctl(priv, wrq, cmd,
++ CMD_ACT_MESH_GET_RREQ_DELAY);
++ break;
++ case LBS_SUBCMD_MESH_GET_ROUTE_EXP:
++ ret = lbs_mesh_ioctl(priv, wrq, cmd,
++ CMD_ACT_MESH_GET_ROUTE_EXP);
++ break;
++ case LBS_SUBCMD_BT_GET_INVERT:
++ ret = lbs_bt_get_invert_ioctl(priv, req);
++ break;
++ default:
++ ret = -EOPNOTSUPP;
++ }
++ break;
++
++ case LBS_SET_GET_SIXTEEN_INT:
++ switch ((int)wrq->u.data.flags) {
++ case LBS_LED_GPIO_CTRL:
++ ret = lbs_led_gpio_ioctl(priv, req);
++ break;
++ case LBS_BCN_CTRL:
++ ret = lbs_bcn_ioctl(priv,wrq);
++ break;
++ case LBS_LED_BEHAVIOR_CTRL:
++ ret = lbs_led_bhv_ioctl(priv, req);
++ break;
++ }
++ break;
++
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
++ return ret;
++}
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/ioctl.h linux-2.6.22-300/drivers/net/wireless/libertas/ioctl.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/ioctl.h 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.22-300/drivers/net/wireless/libertas/ioctl.h 2008-06-05 18:10:06.000000000 -0400
+@@ -0,0 +1,50 @@
++#define COSTS_LIST_SIZE 4
++
++/* iwpriv places the subcmd number in the first uint32_t;
++ data buffer follows that */
++#define SUBCMD_OFFSET sizeof(uint32_t)
++#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET))
++
++/** Private ioctls and ioctls subcommands */
++#define LBS_SETNONE_GETNONE (SIOCIWFIRSTPRIV + 8)
++#define LBS_SUBCMD_BT_RESET 13
++#define LBS_SUBCMD_FWT_RESET 14
++
++#define LBS_SETNONE_GETONEINT (SIOCIWFIRSTPRIV + 15)
++#define LBS_SUBCMD_GET_REGION 1
++#define LBS_SUBCMD_FWT_CLEANUP 15
++#define LBS_SUBCMD_FWT_TIME 16
++#define LBS_SUBCMD_MESH_GET_TTL 17
++#define LBS_SUBCMD_BT_GET_INVERT 18
++#define LBS_SUBCMD_MESH_GET_BCAST_RATE 19
++#define LBS_SUBCMD_MESH_GET_RREQ_DELAY 20
++#define LBS_SUBCMD_MESH_GET_ROUTE_EXP 21
++
++#define LBS_SETONEINT_GETNONE (SIOCIWFIRSTPRIV + 24)
++#define LBS_SUBCMD_SET_REGION 8
++#define LBS_SUBCMD_MESH_SET_TTL 18
++#define LBS_SUBCMD_BT_SET_INVERT 19
++#define LBS_SUBCMD_MESH_SET_BCAST_RATE 20
++#define LBS_SUBCMD_MESH_SET_RREQ_DELAY 21
++#define LBS_SUBCMD_MESH_SET_ROUTE_EXP 22
++#define LBS_SUBCMD_MESH_SET_PRB_RSP_RETRY_LIMIT 23
++
++#define LBS_SET128CHAR_GET128CHAR (SIOCIWFIRSTPRIV + 25)
++#define LBS_SUBCMD_BT_ADD 18
++#define LBS_SUBCMD_BT_DEL 19
++#define LBS_SUBCMD_BT_LIST 20
++#define LBS_SUBCMD_FWT_ADD 21
++#define LBS_SUBCMD_FWT_DEL 22
++#define LBS_SUBCMD_FWT_LOOKUP 23
++#define LBS_SUBCMD_FWT_LIST_NEIGHBOR 24
++#define LBS_SUBCMD_FWT_LIST 25
++#define LBS_SUBCMD_FWT_LIST_ROUTE 26
++#define LBS_SUBCMD_MESH_SET_LINK_COSTS 27
++#define LBS_SUBCMD_MESH_GET_LINK_COSTS 28
++
++#define LBS_SET_GET_SIXTEEN_INT (SIOCIWFIRSTPRIV + 29)
++#define LBS_LED_GPIO_CTRL 5
++#define LBS_BCN_CTRL 6
++#define LBS_LED_BEHAVIOR_CTRL 7
++
++int lbs_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/join.c linux-2.6.22-300/drivers/net/wireless/libertas/join.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/join.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/join.c 2008-06-05 18:10:06.000000000 -0400
+@@ -17,154 +17,171 @@
+ #include "dev.h"
+ #include "assoc.h"
+
+-#define AD_HOC_CAP_PRIVACY_ON 1
++/* The firmware needs certain bits masked out of the beacon-derviced capability
++ * field when associating/joining to BSSs.
++ */
++#define CAPINFO_MASK (~(0xda00))
+
+ /**
+- * @brief This function finds out the common rates between rate1 and rate2.
++ * @brief This function finds common rates between rate1 and card rates.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates need to be taken
+ * care, either before or after calling this function
+ *
+- * @param adapter A pointer to wlan_adapter structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param rate1 the buffer which keeps input and output
+- * @param rate1_size the size of rate1 buffer
+- * @param rate2 the buffer which keeps rate2
+- * @param rate2_size the size of rate2 buffer.
++ * @param rate1_size the size of rate1 buffer; new size of buffer on return
+ *
+ * @return 0 or -1
+ */
+-static int get_common_rates(wlan_adapter * adapter, u8 * rate1,
+- int rate1_size, u8 * rate2, int rate2_size)
+-{
+- u8 *ptr = rate1;
+- int ret = 0;
++static int get_common_rates(struct lbs_private *priv,
++ u8 *rates,
++ u16 *rates_size)
++{
++ u8 *card_rates = lbs_bg_rates;
++ size_t num_card_rates = sizeof(lbs_bg_rates);
++ int ret = 0, i, j;
+ u8 tmp[30];
+- int i;
++ size_t tmp_size = 0;
+
+- memset(&tmp, 0, sizeof(tmp));
+- memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp)));
+- memset(rate1, 0, rate1_size);
+-
+- /* Mask the top bit of the original values */
+- for (i = 0; tmp[i] && i < sizeof(tmp); i++)
+- tmp[i] &= 0x7F;
+-
+- for (i = 0; rate2[i] && i < rate2_size; i++) {
+- /* Check for Card Rate in tmp, excluding the top bit */
+- if (strchr(tmp, rate2[i] & 0x7F)) {
+- /* values match, so copy the Card Rate to rate1 */
+- *rate1++ = rate2[i];
++ /* For each rate in card_rates that exists in rate1, copy to tmp */
++ for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
++ for (j = 0; rates[j] && (j < *rates_size); j++) {
++ if (rates[j] == card_rates[i])
++ tmp[tmp_size++] = card_rates[i];
+ }
+ }
+
+- lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp));
+- lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size);
+- lbs_dbg_hex("Common rates:", ptr, rate1_size);
+- lbs_deb_join("Tx datarate is set to 0x%X\n", adapter->datarate);
+-
+- if (!adapter->is_datarate_auto) {
+- while (*ptr) {
+- if ((*ptr & 0x7f) == adapter->datarate) {
+- ret = 0;
++ lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
++ lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
++ lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
++ lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
++
++ if (!priv->auto_rate) {
++ for (i = 0; i < tmp_size; i++) {
++ if (tmp[i] == priv->cur_rate)
+ goto done;
+- }
+- ptr++;
+ }
+- lbs_pr_alert( "Previously set fixed data rate %#x isn't "
+- "compatible with the network.\n", adapter->datarate);
+-
++ lbs_pr_alert("Previously set fixed data rate %#x isn't "
++ "compatible with the network.\n", priv->cur_rate);
+ ret = -1;
+ goto done;
+ }
+-
+ ret = 0;
++
+ done:
++ memset(rates, 0, *rates_size);
++ *rates_size = min_t(int, tmp_size, *rates_size);
++ memcpy(rates, tmp, *rates_size);
+ return ret;
+ }
+
+-int libertas_send_deauth(wlan_private * priv)
++
++/**
++ * @brief Sets the MSB on basic rates as the firmware requires
++ *
++ * Scan through an array and set the MSB for basic data rates.
++ *
++ * @param rates buffer of data rates
++ * @param len size of buffer
++ */
++static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
+ {
+- wlan_adapter *adapter = priv->adapter;
+- int ret = 0;
++ int i;
+
+- if (adapter->mode == IW_MODE_INFRA &&
+- adapter->connect_status == libertas_connected)
+- ret = libertas_send_deauthentication(priv);
+- else
+- ret = -ENOTSUPP;
++ for (i = 0; i < len; i++) {
++ if (rates[i] == 0x02 || rates[i] == 0x04 ||
++ rates[i] == 0x0b || rates[i] == 0x16)
++ rates[i] |= 0x80;
++ }
++}
+
+- return ret;
++/**
++ * @brief Unsets the MSB on basic rates
++ *
++ * Scan through an array and unset the MSB for basic data rates.
++ *
++ * @param rates buffer of data rates
++ * @param len size of buffer
++ */
++void lbs_unset_basic_rate_flags(u8 *rates, size_t len)
++{
++ int i;
++
++ for (i = 0; i < len; i++)
++ rates[i] &= 0x7f;
+ }
+
++
+ /**
+ * @brief Associate to a specific BSS discovered in a scan
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param pbssdesc Pointer to the BSS descriptor to associate with.
+ *
+ * @return 0-success, otherwise fail
+ */
+-int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req)
++int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret;
+
+- lbs_deb_enter(LBS_DEB_JOIN);
++ lbs_deb_enter(LBS_DEB_ASSOC);
+
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate,
+- 0, cmd_option_waitforrsp,
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
++ 0, CMD_OPTION_WAITFORRSP,
+ 0, assoc_req->bss.bssid);
+
+ if (ret)
+ goto done;
+
+ /* set preamble to firmware */
+- if (adapter->capinfo.shortpreamble && assoc_req->bss.cap.shortpreamble)
+- adapter->preamble = cmd_type_short_preamble;
++ if ( (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
++ && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
++ priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
+ else
+- adapter->preamble = cmd_type_long_preamble;
++ priv->preamble = CMD_TYPE_LONG_PREAMBLE;
+
+- libertas_set_radio_control(priv);
++ lbs_set_radio_control(priv);
+
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate,
+- 0, cmd_option_waitforrsp, 0, assoc_req);
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
++ 0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
+
+ done:
+- lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
++ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+ return ret;
+ }
+
+ /**
+ * @brief Start an Adhoc Network
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param adhocssid The ssid of the Adhoc Network
+ * @return 0--success, -1--fail
+ */
+-int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req)
++int lbs_start_adhoc_network(struct lbs_private *priv,
++ struct assoc_request *assoc_req)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+- adapter->adhoccreate = 1;
++ priv->adhoccreate = 1;
+
+- if (!adapter->capinfo.shortpreamble) {
+- lbs_deb_join("AdhocStart: Long preamble\n");
+- adapter->preamble = cmd_type_long_preamble;
+- } else {
++ if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
+ lbs_deb_join("AdhocStart: Short preamble\n");
+- adapter->preamble = cmd_type_short_preamble;
++ priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
++ } else {
++ lbs_deb_join("AdhocStart: Long preamble\n");
++ priv->preamble = CMD_TYPE_LONG_PREAMBLE;
+ }
+
+- libertas_set_radio_control(priv);
++ lbs_set_radio_control(priv);
+
+ lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
+ lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
+
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start,
+- 0, cmd_option_waitforrsp, 0, assoc_req);
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
++ 0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
+
+ return ret;
+ }
+@@ -172,107 +189,120 @@ int libertas_start_adhoc_network(wlan_pr
+ /**
+ * @brief Join an adhoc network found in a previous scan
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param pbssdesc Pointer to a BSS descriptor found in a previous scan
+ * to attempt to join
+ *
+ * @return 0--success, -1--fail
+ */
+-int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req)
++int lbs_join_adhoc_network(struct lbs_private *priv,
++ struct assoc_request *assoc_req)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ struct bss_descriptor * bss = &assoc_req->bss;
+ int ret = 0;
+
+ lbs_deb_join("%s: Current SSID '%s', ssid length %u\n",
+ __func__,
+- escape_essid(adapter->curbssparams.ssid,
+- adapter->curbssparams.ssid_len),
+- adapter->curbssparams.ssid_len);
++ escape_essid(priv->curbssparams.ssid,
++ priv->curbssparams.ssid_len),
++ priv->curbssparams.ssid_len);
+ lbs_deb_join("%s: requested ssid '%s', ssid length %u\n",
+ __func__, escape_essid(bss->ssid, bss->ssid_len),
+ bss->ssid_len);
+
+ /* check if the requested SSID is already joined */
+- if (adapter->curbssparams.ssid_len
+- && !libertas_ssid_cmp(adapter->curbssparams.ssid,
+- adapter->curbssparams.ssid_len,
++ if ( priv->curbssparams.ssid_len
++ && !lbs_ssid_cmp(priv->curbssparams.ssid,
++ priv->curbssparams.ssid_len,
+ bss->ssid, bss->ssid_len)
+- && (adapter->mode == IW_MODE_ADHOC)) {
+- lbs_deb_join(
+- "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
+- "not attempting to re-join");
+- return -1;
++ && (priv->mode == IW_MODE_ADHOC)
++ && (priv->connect_status == LBS_CONNECTED)) {
++ union iwreq_data wrqu;
++
++ lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
++ "current, not attempting to re-join");
++
++ /* Send the re-association event though, because the association
++ * request really was successful, even if just a null-op.
++ */
++ memset(&wrqu, 0, sizeof(wrqu));
++ memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid,
++ ETH_ALEN);
++ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
++ wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
++ goto out;
+ }
+
+- /*Use shortpreamble only when both creator and card supports
++ /* Use shortpreamble only when both creator and card supports
+ short preamble */
+- if (!bss->cap.shortpreamble || !adapter->capinfo.shortpreamble) {
++ if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
++ || !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
+ lbs_deb_join("AdhocJoin: Long preamble\n");
+- adapter->preamble = cmd_type_long_preamble;
++ priv->preamble = CMD_TYPE_LONG_PREAMBLE;
+ } else {
+ lbs_deb_join("AdhocJoin: Short preamble\n");
+- adapter->preamble = cmd_type_short_preamble;
++ priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
+ }
+
+- libertas_set_radio_control(priv);
++ lbs_set_radio_control(priv);
+
+ lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
+ lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
+
+- adapter->adhoccreate = 0;
++ priv->adhoccreate = 0;
+
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join,
+- 0, cmd_option_waitforrsp,
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
++ 0, CMD_OPTION_WAITFORRSP,
+ OID_802_11_SSID, assoc_req);
+
++out:
+ return ret;
+ }
+
+-int libertas_stop_adhoc_network(wlan_private * priv)
++int lbs_stop_adhoc_network(struct lbs_private *priv)
+ {
+- return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop,
+- 0, cmd_option_waitforrsp, 0, NULL);
++ return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
++ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
+ }
+
+ /**
+ * @brief Send Deauthentication Request
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @return 0--success, -1--fail
+ */
+-int libertas_send_deauthentication(wlan_private * priv)
++int lbs_send_deauthentication(struct lbs_private *priv)
+ {
+- return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate,
+- 0, cmd_option_waitforrsp, 0, NULL);
++ return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
++ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
+ }
+
+ /**
+ * @brief This function prepares command of authenticate.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param cmd A pointer to cmd_ds_command structure
+ * @param pdata_buf Void cast of pointer to a BSSID to authenticate with
+ *
+ * @return 0 or -1
+ */
+-int libertas_cmd_80211_authenticate(wlan_private * priv,
++int lbs_cmd_80211_authenticate(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
+ int ret = -1;
+ u8 *bssid = pdata_buf;
++ DECLARE_MAC_BUF(mac);
+
+ lbs_deb_enter(LBS_DEB_JOIN);
+
+- cmd->command = cpu_to_le16(cmd_802_11_authenticate);
++ cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
+ + S_DS_GEN);
+
+ /* translate auth mode to 802.11 defined wire value */
+- switch (adapter->secinfo.auth_mode) {
++ switch (priv->secinfo.auth_mode) {
+ case IW_AUTH_ALG_OPEN_SYSTEM:
+ pauthenticate->authtype = 0x00;
+ break;
+@@ -284,14 +314,14 @@ int libertas_cmd_80211_authenticate(wlan
+ break;
+ default:
+ lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
+- adapter->secinfo.auth_mode);
++ priv->secinfo.auth_mode);
+ goto out;
+ }
+
+ memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
+
+- lbs_deb_join("AUTH_CMD: BSSID is : " MAC_FMT " auth=0x%X\n",
+- MAC_ARG(bssid), pauthenticate->authtype);
++ lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
++ print_mac(mac, bssid), pauthenticate->authtype);
+ ret = 0;
+
+ out:
+@@ -299,20 +329,19 @@ out:
+ return ret;
+ }
+
+-int libertas_cmd_80211_deauthenticate(wlan_private * priv,
++int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
+ struct cmd_ds_command *cmd)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
+
+ lbs_deb_enter(LBS_DEB_JOIN);
+
+- cmd->command = cpu_to_le16(cmd_802_11_deauthenticate);
++ cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
+ S_DS_GEN);
+
+ /* set AP MAC address */
+- memmove(dauth->macaddr, adapter->curbssparams.bssid, ETH_ALEN);
++ memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN);
+
+ /* Reason code 3 = Station is leaving */
+ #define REASON_CODE_STA_LEAVING 3
+@@ -322,17 +351,14 @@ int libertas_cmd_80211_deauthenticate(wl
+ return 0;
+ }
+
+-int libertas_cmd_80211_associate(wlan_private * priv,
++int lbs_cmd_80211_associate(struct lbs_private *priv,
+ struct cmd_ds_command *cmd, void *pdata_buf)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
+ int ret = 0;
+ struct assoc_request * assoc_req = pdata_buf;
+ struct bss_descriptor * bss = &assoc_req->bss;
+- u8 *card_rates;
+ u8 *pos;
+- int card_rates_size;
+ u16 tmpcap, tmplen;
+ struct mrvlietypes_ssidparamset *ssid;
+ struct mrvlietypes_phyparamset *phy;
+@@ -340,24 +366,24 @@ int libertas_cmd_80211_associate(wlan_pr
+ struct mrvlietypes_ratesparamset *rates;
+ struct mrvlietypes_rsnparamset *rsn;
+
+- lbs_deb_enter(LBS_DEB_JOIN);
++ lbs_deb_enter(LBS_DEB_ASSOC);
+
+ pos = (u8 *) passo;
+
+- if (!adapter) {
++ if (!priv) {
+ ret = -1;
+ goto done;
+ }
+
+- cmd->command = cpu_to_le16(cmd_802_11_associate);
++ cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE);
+
+ memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
+ pos += sizeof(passo->peerstaaddr);
+
+ /* set the listen interval */
+- passo->listeninterval = cpu_to_le16(adapter->listeninterval);
++ passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
+
+- pos += sizeof(passo->capinfo);
++ pos += sizeof(passo->capability);
+ pos += sizeof(passo->listeninterval);
+ pos += sizeof(passo->bcnperiod);
+ pos += sizeof(passo->dtimperiod);
+@@ -386,23 +412,24 @@ int libertas_cmd_80211_associate(wlan_pr
+
+ rates = (struct mrvlietypes_ratesparamset *) pos;
+ rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
+-
+- memcpy(&rates->rates, &bss->libertas_supported_rates, WLAN_SUPPORTED_RATES);
+-
+- card_rates = libertas_supported_rates;
+- card_rates_size = sizeof(libertas_supported_rates);
+-
+- if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
+- card_rates, card_rates_size)) {
++ memcpy(&rates->rates, &bss->rates, MAX_RATES);
++ tmplen = MAX_RATES;
++ if (get_common_rates(priv, rates->rates, &tmplen)) {
+ ret = -1;
+ goto done;
+ }
+-
+- tmplen = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
+- adapter->curbssparams.numofrates = tmplen;
+-
+ pos += sizeof(rates->header) + tmplen;
+ rates->header.len = cpu_to_le16(tmplen);
++ lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
++
++ /* Copy the infra. association rates into Current BSS state structure */
++ memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
++ memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
++
++ /* Set MSB on basic rates as the firmware requires, but _after_
++ * copying to current bss rates.
++ */
++ lbs_set_basic_rate_flags(rates->rates, tmplen);
+
+ if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
+ rsn = (struct mrvlietypes_rsnparamset *) pos;
+@@ -411,70 +438,56 @@ int libertas_cmd_80211_associate(wlan_pr
+ tmplen = (u16) assoc_req->wpa_ie[1];
+ rsn->header.len = cpu_to_le16(tmplen);
+ memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
+- lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
++ lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn,
+ sizeof(rsn->header) + tmplen);
+ pos += sizeof(rsn->header) + tmplen;
+ }
+
+ /* update curbssparams */
+- adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
++ priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
+
+- /* Copy the infra. association rates into Current BSS state structure */
+- memcpy(&adapter->curbssparams.datarates, &rates->rates,
+- min_t(size_t, sizeof(adapter->curbssparams.datarates),
+- cpu_to_le16(rates->header.len)));
+-
+- lbs_deb_join("ASSOC_CMD: rates->header.len = %d\n",
+- cpu_to_le16(rates->header.len));
+-
+- /* set IBSS field */
+- if (bss->mode == IW_MODE_INFRA) {
+-#define CAPINFO_ESS_MODE 1
+- passo->capinfo.ess = CAPINFO_ESS_MODE;
+- }
+-
+- if (libertas_parse_dnld_countryinfo_11d(priv, bss)) {
++ if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
+ ret = -1;
+ goto done;
+ }
+
+ cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
+
+- /* set the capability info at last */
+- memcpy(&tmpcap, &bss->cap, sizeof(passo->capinfo));
+- tmpcap &= CAPINFO_MASK;
+- lbs_deb_join("ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+- tmpcap, CAPINFO_MASK);
+- memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo));
++ /* set the capability info */
++ tmpcap = (bss->capability & CAPINFO_MASK);
++ if (bss->mode == IW_MODE_INFRA)
++ tmpcap |= WLAN_CAPABILITY_ESS;
++ passo->capability = cpu_to_le16(tmpcap);
++ lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
+
+ done:
+- lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
++ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+ return ret;
+ }
+
+-int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
++int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
+ struct cmd_ds_command *cmd, void *pdata_buf)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
+ int ret = 0;
+ int cmdappendsize = 0;
+- int i;
+ struct assoc_request * assoc_req = pdata_buf;
++ u16 tmpcap = 0;
++ size_t ratesize = 0;
+
+ lbs_deb_enter(LBS_DEB_JOIN);
+
+- if (!adapter) {
++ if (!priv) {
+ ret = -1;
+ goto done;
+ }
+
+- cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start);
++ cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START);
+
+ /*
+ * Fill in the parameters for 2 data structures:
+ * 1. cmd_ds_802_11_ad_hoc_start command
+- * 2. adapter->scantable[i]
++ * 2. priv->scantable[i]
+ *
+ * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
+ * probe delay, and cap info.
+@@ -483,17 +496,19 @@ int libertas_cmd_80211_ad_hoc_start(wlan
+ * and operational rates.
+ */
+
+- memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE);
+- memcpy(adhs->SSID, assoc_req->ssid, assoc_req->ssid_len);
++ memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE);
++ memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len);
+
+ lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
+ escape_essid(assoc_req->ssid, assoc_req->ssid_len),
+ assoc_req->ssid_len);
+
+ /* set the BSS type */
+- adhs->bsstype = cmd_bss_type_ibss;
+- adapter->mode = IW_MODE_ADHOC;
+- adhs->beaconperiod = cpu_to_le16(adapter->beaconperiod);
++ adhs->bsstype = CMD_BSS_TYPE_IBSS;
++ priv->mode = IW_MODE_ADHOC;
++ if (priv->beacon_period == 0)
++ priv->beacon_period = MRVDRV_BEACON_INTERVAL;
++ adhs->beaconperiod = cpu_to_le16(priv->beacon_period);
+
+ /* set Physical param set */
+ #define DS_PARA_IE_ID 3
+@@ -515,49 +530,40 @@ int libertas_cmd_80211_ad_hoc_start(wlan
+
+ adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
+ adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
+- adhs->ssparamset.ibssparamset.atimwindow = cpu_to_le16(adapter->atimwindow);
++ adhs->ssparamset.ibssparamset.atimwindow = 0;
+
+ /* set capability info */
+- adhs->cap.ess = 0;
+- adhs->cap.ibss = 1;
+-
+- /* probedelay */
+- adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
+-
+- /* set up privacy in adapter->scantable[i] */
++ tmpcap = WLAN_CAPABILITY_IBSS;
+ if (assoc_req->secinfo.wep_enabled) {
+ lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n");
+- adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
++ tmpcap |= WLAN_CAPABILITY_PRIVACY;
+ } else {
+ lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n");
+ }
++ adhs->capability = cpu_to_le16(tmpcap);
+
+- memset(adhs->datarate, 0, sizeof(adhs->datarate));
+-
+- if (adapter->adhoc_grate_enabled) {
+- memcpy(adhs->datarate, libertas_adhoc_rates_g,
+- min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g)));
+- } else {
+- memcpy(adhs->datarate, libertas_adhoc_rates_b,
+- min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b)));
+- }
+-
+- /* Find the last non zero */
+- for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;
++ /* probedelay */
++ adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+
+- adapter->curbssparams.numofrates = i;
++ memset(adhs->rates, 0, sizeof(adhs->rates));
++ ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates));
++ memcpy(adhs->rates, lbs_bg_rates, ratesize);
+
+ /* Copy the ad-hoc creating rates into Current BSS state structure */
+- memcpy(&adapter->curbssparams.datarates,
+- &adhs->datarate, adapter->curbssparams.numofrates);
++ memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
++ memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize);
++
++ /* Set MSB on basic rates as the firmware requires, but _after_
++ * copying to current bss rates.
++ */
++ lbs_set_basic_rate_flags(adhs->rates, ratesize);
+
+ lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
+- adhs->datarate[0], adhs->datarate[1],
+- adhs->datarate[2], adhs->datarate[3]);
++ adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]);
+
+ lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+- if (libertas_create_dnld_countryinfo_11d(priv)) {
++ if (lbs_create_dnld_countryinfo_11d(priv)) {
+ lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+ ret = -1;
+ goto done;
+@@ -572,114 +578,96 @@ done:
+ return ret;
+ }
+
+-int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
++int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv,
+ struct cmd_ds_command *cmd)
+ {
+- cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop);
++ cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP);
+ cmd->size = cpu_to_le16(S_DS_GEN);
+
+ return 0;
+ }
+
+-int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
++int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
+ struct cmd_ds_command *cmd, void *pdata_buf)
+ {
+- wlan_adapter *adapter = priv->adapter;
+- struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj;
++ struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj;
+ struct assoc_request * assoc_req = pdata_buf;
+ struct bss_descriptor *bss = &assoc_req->bss;
+ int cmdappendsize = 0;
+ int ret = 0;
+- u8 *card_rates;
+- int card_rates_size;
+- u16 tmpcap;
+- int i;
++ u16 ratesize = 0;
++ DECLARE_MAC_BUF(mac);
+
+ lbs_deb_enter(LBS_DEB_JOIN);
+
+- cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join);
+-
+- padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss;
+-
+- padhocjoin->bssdescriptor.beaconperiod = cpu_to_le16(bss->beaconperiod);
++ cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN);
+
+- memcpy(&padhocjoin->bssdescriptor.BSSID, &bss->bssid, ETH_ALEN);
+- memcpy(&padhocjoin->bssdescriptor.SSID, &bss->ssid, bss->ssid_len);
++ join_cmd->bss.type = CMD_BSS_TYPE_IBSS;
++ join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
+
+- memcpy(&padhocjoin->bssdescriptor.phyparamset,
+- &bss->phyparamset, sizeof(union ieeetypes_phyparamset));
++ memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN);
++ memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len);
+
+- memcpy(&padhocjoin->bssdescriptor.ssparamset,
+- &bss->ssparamset, sizeof(union IEEEtypes_ssparamset));
++ memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset,
++ sizeof(union ieeetypes_phyparamset));
+
+- memcpy(&tmpcap, &bss->cap, sizeof(struct ieeetypes_capinfo));
+- tmpcap &= CAPINFO_MASK;
++ memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset,
++ sizeof(union IEEEtypes_ssparamset));
+
++ join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
+ lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+- tmpcap, CAPINFO_MASK);
+- memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap,
+- sizeof(struct ieeetypes_capinfo));
++ bss->capability, CAPINFO_MASK);
+
+ /* information on BSSID descriptor passed to FW */
+ lbs_deb_join(
+- "ADHOC_J_CMD: BSSID = " MAC_FMT ", SSID = '%s'\n",
+- MAC_ARG(padhocjoin->bssdescriptor.BSSID),
+- padhocjoin->bssdescriptor.SSID);
++ "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
++ print_mac(mac, join_cmd->bss.bssid),
++ join_cmd->bss.ssid);
+
+ /* failtimeout */
+- padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
++ join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+
+ /* probedelay */
+- padhocjoin->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
++ join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
++
++ priv->curbssparams.channel = bss->channel;
+
+ /* Copy Data rates from the rates recorded in scan response */
+- memset(padhocjoin->bssdescriptor.datarates, 0,
+- sizeof(padhocjoin->bssdescriptor.datarates));
+- memcpy(padhocjoin->bssdescriptor.datarates, bss->datarates,
+- min(sizeof(padhocjoin->bssdescriptor.datarates),
+- sizeof(bss->datarates)));
+-
+- card_rates = libertas_supported_rates;
+- card_rates_size = sizeof(libertas_supported_rates);
+-
+- adapter->curbssparams.channel = bss->channel;
+-
+- if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates,
+- sizeof(padhocjoin->bssdescriptor.datarates),
+- card_rates, card_rates_size)) {
++ memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates));
++ ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES);
++ memcpy(join_cmd->bss.rates, bss->rates, ratesize);
++ if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) {
+ lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
+ ret = -1;
+ goto done;
+ }
+
+- /* Find the last non zero */
+- for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates)
+- && padhocjoin->bssdescriptor.datarates[i]; i++) ;
+-
+- adapter->curbssparams.numofrates = i;
++ /* Copy the ad-hoc creating rates into Current BSS state structure */
++ memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
++ memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize);
+
+- /*
+- * Copy the adhoc joining rates to Current BSS State structure
++ /* Set MSB on basic rates as the firmware requires, but _after_
++ * copying to current bss rates.
+ */
+- memcpy(adapter->curbssparams.datarates,
+- padhocjoin->bssdescriptor.datarates,
+- adapter->curbssparams.numofrates);
++ lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
+
+- padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow =
++ join_cmd->bss.ssparamset.ibssparamset.atimwindow =
+ cpu_to_le16(bss->atimwindow);
+
+ if (assoc_req->secinfo.wep_enabled) {
+- padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
++ u16 tmp = le16_to_cpu(join_cmd->bss.capability);
++ tmp |= WLAN_CAPABILITY_PRIVACY;
++ join_cmd->bss.capability = cpu_to_le16(tmp);
+ }
+
+- if (adapter->psmode == wlan802_11powermodemax_psp) {
++ if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
+ /* wake up first */
+ __le32 Localpsmode;
+
+- Localpsmode = cpu_to_le32(wlan802_11powermodecam);
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_ps_mode,
+- cmd_act_set,
++ Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_PS_MODE,
++ CMD_ACT_SET,
+ 0, 0, &Localpsmode);
+
+ if (ret) {
+@@ -688,7 +676,7 @@ int libertas_cmd_80211_ad_hoc_join(wlan_
+ }
+ }
+
+- if (libertas_parse_dnld_countryinfo_11d(priv, bss)) {
++ if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
+ ret = -1;
+ goto done;
+ }
+@@ -701,99 +689,131 @@ done:
+ return ret;
+ }
+
+-int libertas_ret_80211_associate(wlan_private * priv,
++int lbs_ret_80211_associate(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ union iwreq_data wrqu;
+ struct ieeetypes_assocrsp *passocrsp;
+ struct bss_descriptor * bss;
++ u16 status_code;
+
+- lbs_deb_enter(LBS_DEB_JOIN);
++ lbs_deb_enter(LBS_DEB_ASSOC);
+
+- if (!adapter->in_progress_assoc_req) {
+- lbs_deb_join("ASSOC_RESP: no in-progress association request\n");
++ if (!priv->in_progress_assoc_req) {
++ lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
+ ret = -1;
+ goto done;
+ }
+- bss = &adapter->in_progress_assoc_req->bss;
++ bss = &priv->in_progress_assoc_req->bss;
+
+ passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
+
+- if (le16_to_cpu(passocrsp->statuscode)) {
+- libertas_mac_event_disconnected(priv);
++ /*
++ * Older FW versions map the IEEE 802.11 Status Code in the association
++ * response to the following values returned in passocrsp->statuscode:
++ *
++ * IEEE Status Code Marvell Status Code
++ * 0 -> 0x0000 ASSOC_RESULT_SUCCESS
++ * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
++ * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
++ * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
++ * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
++ * others -> 0x0003 ASSOC_RESULT_REFUSED
++ *
++ * Other response codes:
++ * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
++ * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
++ * association response from the AP)
++ */
+
+- lbs_deb_join("ASSOC_RESP: Association failed, status code = %d\n",
+- le16_to_cpu(passocrsp->statuscode));
++ status_code = le16_to_cpu(passocrsp->statuscode);
++ switch (status_code) {
++ case 0x00:
++ break;
++ case 0x01:
++ lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
++ break;
++ case 0x02:
++ lbs_deb_assoc("ASSOC_RESP: internal timer "
++ "expired while waiting for the AP\n");
++ break;
++ case 0x03:
++ lbs_deb_assoc("ASSOC_RESP: association "
++ "refused by AP\n");
++ break;
++ case 0x04:
++ lbs_deb_assoc("ASSOC_RESP: authentication "
++ "refused by AP\n");
++ break;
++ default:
++ lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
++ " unknown\n", status_code);
++ break;
++ }
+
++ if (status_code) {
++ lbs_mac_event_disconnected(priv);
+ ret = -1;
+ goto done;
+ }
+
+- lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
++ lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params,
+ le16_to_cpu(resp->size) - S_DS_GEN);
+
+ /* Send a Media Connected event, according to the Spec */
+- adapter->connect_status = libertas_connected;
+-
+- lbs_deb_join("ASSOC_RESP: assocated to '%s'\n",
+- escape_essid(bss->ssid, bss->ssid_len));
++ priv->connect_status = LBS_CONNECTED;
+
+ /* Update current SSID and BSSID */
+- memcpy(&adapter->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+- adapter->curbssparams.ssid_len = bss->ssid_len;
+- memcpy(adapter->curbssparams.bssid, bss->bssid, ETH_ALEN);
+-
+- lbs_deb_join("ASSOC_RESP: currentpacketfilter is %x\n",
+- adapter->currentpacketfilter);
+-
+- adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
+- adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;
+-
+- memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
+- memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
+- adapter->nextSNRNF = 0;
+- adapter->numSNRNF = 0;
++ memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
++ priv->curbssparams.ssid_len = bss->ssid_len;
++ memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
++
++ lbs_deb_assoc("ASSOC_RESP: mac_control is 0x%x\n",
++ priv->mac_control);
++
++ priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
++ priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
++
++ memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
++ memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
++ priv->nextSNRNF = 0;
++ priv->numSNRNF = 0;
+
+ netif_carrier_on(priv->dev);
+- netif_wake_queue(priv->dev);
+-
+- netif_carrier_on(priv->mesh_dev);
+- netif_wake_queue(priv->mesh_dev);
+-
+- lbs_deb_join("ASSOC_RESP: Associated \n");
++ if (!priv->tx_pending_len)
++ netif_wake_queue(priv->dev);
+
+- memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
++ memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
+ done:
+- lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
++ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+ return ret;
+ }
+
+-int libertas_ret_80211_disassociate(wlan_private * priv,
++int lbs_ret_80211_disassociate(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+ lbs_deb_enter(LBS_DEB_JOIN);
+
+- libertas_mac_event_disconnected(priv);
++ lbs_mac_event_disconnected(priv);
+
+ lbs_deb_leave(LBS_DEB_JOIN);
+ return 0;
+ }
+
+-int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
++int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ u16 command = le16_to_cpu(resp->command);
+ u16 result = le16_to_cpu(resp->result);
+ struct cmd_ds_802_11_ad_hoc_result *padhocresult;
+ union iwreq_data wrqu;
+ struct bss_descriptor *bss;
++ DECLARE_MAC_BUF(mac);
+
+ lbs_deb_enter(LBS_DEB_JOIN);
+
+@@ -803,20 +823,20 @@ int libertas_ret_80211_ad_hoc_start(wlan
+ lbs_deb_join("ADHOC_RESP: command = %x\n", command);
+ lbs_deb_join("ADHOC_RESP: result = %x\n", result);
+
+- if (!adapter->in_progress_assoc_req) {
++ if (!priv->in_progress_assoc_req) {
+ lbs_deb_join("ADHOC_RESP: no in-progress association request\n");
+ ret = -1;
+ goto done;
+ }
+- bss = &adapter->in_progress_assoc_req->bss;
++ bss = &priv->in_progress_assoc_req->bss;
+
+ /*
+ * Join result code 0 --> SUCCESS
+ */
+ if (result) {
+ lbs_deb_join("ADHOC_RESP: failed\n");
+- if (adapter->connect_status == libertas_connected) {
+- libertas_mac_event_disconnected(priv);
++ if (priv->connect_status == LBS_CONNECTED) {
++ lbs_mac_event_disconnected(priv);
+ }
+ ret = -1;
+ goto done;
+@@ -830,47 +850,45 @@ int libertas_ret_80211_ad_hoc_start(wlan
+ escape_essid(bss->ssid, bss->ssid_len));
+
+ /* Send a Media Connected event, according to the Spec */
+- adapter->connect_status = libertas_connected;
++ priv->connect_status = LBS_CONNECTED;
+
+- if (command == cmd_ret_802_11_ad_hoc_start) {
++ if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
+ /* Update the created network descriptor with the new BSSID */
+- memcpy(bss->bssid, padhocresult->BSSID, ETH_ALEN);
++ memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN);
+ }
+
+ /* Set the BSSID from the joined/started descriptor */
+- memcpy(&adapter->curbssparams.bssid, bss->bssid, ETH_ALEN);
++ memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
+
+ /* Set the new SSID to current SSID */
+- memcpy(&adapter->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+- adapter->curbssparams.ssid_len = bss->ssid_len;
++ memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
++ priv->curbssparams.ssid_len = bss->ssid_len;
+
+ netif_carrier_on(priv->dev);
+- netif_wake_queue(priv->dev);
+-
+- netif_carrier_on(priv->mesh_dev);
+- netif_wake_queue(priv->mesh_dev);
++ if (!priv->tx_pending_len)
++ netif_wake_queue(priv->dev);
+
+ memset(&wrqu, 0, sizeof(wrqu));
+- memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
++ memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
+ lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
+- lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel);
+- lbs_deb_join("ADHOC_RESP: BSSID = " MAC_FMT "\n",
+- MAC_ARG(padhocresult->BSSID));
++ lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel);
++ lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
++ print_mac(mac, padhocresult->bssid));
+
+ done:
+ lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
+ return ret;
+ }
+
+-int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
++int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+ {
+ lbs_deb_enter(LBS_DEB_JOIN);
+
+- libertas_mac_event_disconnected(priv);
++ lbs_mac_event_disconnected(priv);
+
+ lbs_deb_leave(LBS_DEB_JOIN);
+ return 0;
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/join.h linux-2.6.22-300/drivers/net/wireless/libertas/join.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/join.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/join.h 2008-06-05 18:10:06.000000000 -0400
+@@ -2,55 +2,52 @@
+ * Interface for the wlan infrastructure and adhoc join routines
+ *
+ * Driver interface functions and type declarations for the join module
+- * implemented in wlan_join.c. Process all start/join requests for
++ * implemented in join.c. Process all start/join requests for
+ * both adhoc and infrastructure networks
+ */
+-#ifndef _WLAN_JOIN_H
+-#define _WLAN_JOIN_H
++#ifndef _LBS_JOIN_H
++#define _LBS_JOIN_H
+
+ #include "defs.h"
+ #include "dev.h"
+
+ struct cmd_ds_command;
+-extern int libertas_cmd_80211_authenticate(wlan_private * priv,
++int lbs_cmd_80211_authenticate(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+-extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
++int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+-extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
++int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv,
+ struct cmd_ds_command *cmd);
+-extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
++int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+-extern int libertas_cmd_80211_deauthenticate(wlan_private * priv,
++int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
+ struct cmd_ds_command *cmd);
+-extern int libertas_cmd_80211_associate(wlan_private * priv,
++int lbs_cmd_80211_associate(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+
+-extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
++int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
+ struct cmd_ds_command *resp);
+-extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
++int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv,
+ struct cmd_ds_command *resp);
+-extern int libertas_ret_80211_disassociate(wlan_private * priv,
++int lbs_ret_80211_disassociate(struct lbs_private *priv,
+ struct cmd_ds_command *resp);
+-extern int libertas_ret_80211_associate(wlan_private * priv,
++int lbs_ret_80211_associate(struct lbs_private *priv,
+ struct cmd_ds_command *resp);
+
+-extern int libertas_reassociation_thread(void *data);
+-
+-extern int libertas_start_adhoc_network(wlan_private * priv,
++int lbs_start_adhoc_network(struct lbs_private *priv,
+ struct assoc_request * assoc_req);
+-extern int libertas_join_adhoc_network(wlan_private * priv,
++int lbs_join_adhoc_network(struct lbs_private *priv,
+ struct assoc_request * assoc_req);
+-extern int libertas_stop_adhoc_network(wlan_private * priv);
++int lbs_stop_adhoc_network(struct lbs_private *priv);
+
+-extern int libertas_send_deauthentication(wlan_private * priv);
+-extern int libertas_send_deauth(wlan_private * priv);
++int lbs_send_deauthentication(struct lbs_private *priv);
+
+-extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
++int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req);
+
+-int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req);
++void lbs_unset_basic_rate_flags(u8 *rates, size_t len);
+
+ #endif
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/main.c linux-2.6.22-300/drivers/net/wireless/libertas/main.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/main.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/main.c 2008-06-05 18:10:06.000000000 -0400
+@@ -6,10 +6,12 @@
+
+ #include <linux/moduleparam.h>
+ #include <linux/delay.h>
+-#include <linux/freezer.h>
+ #include <linux/etherdevice.h>
+ #include <linux/netdevice.h>
+ #include <linux/if_arp.h>
++#include <linux/kthread.h>
++#include <asm/olpc.h>
++#include <linux/stddef.h>
+
+ #include <net/iw_handler.h>
+ #include <net/ieee80211.h>
+@@ -20,9 +22,12 @@
+ #include "wext.h"
+ #include "debugfs.h"
+ #include "assoc.h"
++#include "join.h"
++#include "cmd.h"
++#include "ioctl.h"
+
+-#define DRIVER_RELEASE_VERSION "322.p0"
+-const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
++#define DRIVER_RELEASE_VERSION "323.p0"
++const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
+ #ifdef DEBUG
+ "-dbg"
+ #endif
+@@ -30,80 +35,80 @@ const char libertas_driver_version[] = "
+
+
+ /* Module parameters */
+-unsigned int libertas_debug = 0;
+-module_param(libertas_debug, int, 0644);
+-EXPORT_SYMBOL_GPL(libertas_debug);
++unsigned int lbs_debug;
++EXPORT_SYMBOL_GPL(lbs_debug);
++module_param_named(libertas_debug, lbs_debug, int, 0644);
+
+
+-#define WLAN_TX_PWR_DEFAULT 20 /*100mW */
+-#define WLAN_TX_PWR_US_DEFAULT 20 /*100mW */
+-#define WLAN_TX_PWR_JP_DEFAULT 16 /*50mW */
+-#define WLAN_TX_PWR_FR_DEFAULT 20 /*100mW */
+-#define WLAN_TX_PWR_EMEA_DEFAULT 20 /*100mW */
++#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, WLAN_TX_PWR_US_DEFAULT},
+- {2, 2417, WLAN_TX_PWR_US_DEFAULT},
+- {3, 2422, WLAN_TX_PWR_US_DEFAULT},
+- {4, 2427, WLAN_TX_PWR_US_DEFAULT},
+- {5, 2432, WLAN_TX_PWR_US_DEFAULT},
+- {6, 2437, WLAN_TX_PWR_US_DEFAULT},
+- {7, 2442, WLAN_TX_PWR_US_DEFAULT},
+- {8, 2447, WLAN_TX_PWR_US_DEFAULT},
+- {9, 2452, WLAN_TX_PWR_US_DEFAULT},
+- {10, 2457, WLAN_TX_PWR_US_DEFAULT},
+- {11, 2462, WLAN_TX_PWR_US_DEFAULT}
++ {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, WLAN_TX_PWR_EMEA_DEFAULT},
+- {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
+- {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
+- {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
+- {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
+- {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
+- {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
+- {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
+- {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
+- {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
+- {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
+- {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
+- {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
++ {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, WLAN_TX_PWR_DEFAULT},
+- {11, 2462, WLAN_TX_PWR_DEFAULT}
++ {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, WLAN_TX_PWR_FR_DEFAULT},
+- {11, 2462, WLAN_TX_PWR_FR_DEFAULT},
+- {12, 2467, WLAN_TX_PWR_FR_DEFAULT},
+- {13, 2472, WLAN_TX_PWR_FR_DEFAULT}
++ {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, WLAN_TX_PWR_JP_DEFAULT},
+- {2, 2417, WLAN_TX_PWR_JP_DEFAULT},
+- {3, 2422, WLAN_TX_PWR_JP_DEFAULT},
+- {4, 2427, WLAN_TX_PWR_JP_DEFAULT},
+- {5, 2432, WLAN_TX_PWR_JP_DEFAULT},
+- {6, 2437, WLAN_TX_PWR_JP_DEFAULT},
+- {7, 2442, WLAN_TX_PWR_JP_DEFAULT},
+- {8, 2447, WLAN_TX_PWR_JP_DEFAULT},
+- {9, 2452, WLAN_TX_PWR_JP_DEFAULT},
+- {10, 2457, WLAN_TX_PWR_JP_DEFAULT},
+- {11, 2462, WLAN_TX_PWR_JP_DEFAULT},
+- {12, 2467, WLAN_TX_PWR_JP_DEFAULT},
+- {13, 2472, WLAN_TX_PWR_JP_DEFAULT},
+- {14, 2484, WLAN_TX_PWR_JP_DEFAULT}
++ {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}
+ };
+
+ /**
+@@ -121,57 +126,88 @@ struct region_cfp_table {
+ static struct region_cfp_table region_cfp_table[] = {
+ {0x10, /*US FCC */
+ channel_freq_power_US_BG,
+- sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
++ ARRAY_SIZE(channel_freq_power_US_BG),
+ }
+ ,
+ {0x20, /*CANADA IC */
+ channel_freq_power_US_BG,
+- sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
++ ARRAY_SIZE(channel_freq_power_US_BG),
+ }
+ ,
+ {0x30, /*EU*/ channel_freq_power_EU_BG,
+- sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power),
++ ARRAY_SIZE(channel_freq_power_EU_BG),
+ }
+ ,
+ {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
+- sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power),
++ ARRAY_SIZE(channel_freq_power_SPN_BG),
+ }
+ ,
+ {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
+- sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power),
++ ARRAY_SIZE(channel_freq_power_FR_BG),
+ }
+ ,
+ {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
+- sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power),
++ ARRAY_SIZE(channel_freq_power_JPN_BG),
+ }
+ ,
+ /*Add new region here */
+ };
+
+ /**
+- * the rates supported
++ * the table to keep region code
+ */
+-u8 libertas_supported_rates[G_SUPPORTED_RATES] =
+- { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+-0 };
++u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
++ { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
+
+ /**
+- * the rates supported for ad-hoc G mode
++ * 802.11b/g supported bitrates (in 500Kb/s units)
+ */
+-u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] =
+- { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+-0 };
++u8 lbs_bg_rates[MAX_RATES] =
++ { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
++0x00, 0x00 };
+
+ /**
+- * the rates supported for ad-hoc B mode
++ * FW rate table. FW refers to rates by their index in this table, not by the
++ * rate value itself. Values of 0x00 are
++ * reserved positions.
+ */
+-u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 };
++static u8 fw_data_rates[MAX_RATES] =
++ { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
++ 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
++};
+
+ /**
+- * the table to keep region code
++ * @brief use index to get the data rate
++ *
++ * @param idx The index of data rate
++ * @return data rate or 0
+ */
+-u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
+- { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
++u32 lbs_fw_index_to_data_rate(u8 idx)
++{
++ if (idx >= sizeof(fw_data_rates))
++ idx = 0;
++ return fw_data_rates[idx];
++}
++
++/**
++ * @brief use rate to get the index
++ *
++ * @param rate data rate
++ * @return index or 0
++ */
++u8 lbs_data_rate_to_fw_index(u32 rate)
++{
++ u8 i;
++
++ if (!rate)
++ return 0;
++
++ for (i = 0; i < sizeof(fw_data_rates); i++) {
++ if (rate == fw_data_rates[i])
++ return i;
++ }
++ return 0;
++}
+
+ /**
+ * Attributes exported through sysfs
+@@ -180,16 +216,18 @@ u16 libertas_region_code_to_index[MRVDRV
+ /**
+ * @brief Get function for sysfs attribute anycast_mask
+ */
+-static ssize_t libertas_anycast_get(struct device * dev,
++static ssize_t lbs_anycast_get(struct device *dev,
+ struct device_attribute *attr, char * buf)
+ {
++ struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct cmd_ds_mesh_access mesh_access;
++ int ret;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+- libertas_prepare_and_send_command(to_net_dev(dev)->priv,
+- cmd_mesh_access,
+- cmd_act_mesh_get_anycast,
+- cmd_option_waitforrsp, 0, (void *)&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]));
+ }
+@@ -197,274 +235,299 @@ static ssize_t libertas_anycast_get(stru
+ /**
+ * @brief Set function for sysfs attribute anycast_mask
+ */
+-static ssize_t libertas_anycast_set(struct device * dev,
++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)->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);
+
+- libertas_prepare_and_send_command((to_net_dev(dev))->priv,
+- cmd_mesh_access,
+- cmd_act_mesh_set_anycast,
+- cmd_option_waitforrsp, 0, (void *)&mesh_access);
++ ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
++ if (ret)
++ return ret;
++
+ return strlen(buf);
+ }
+
+-/**
+- * anycast_mask attribute to be exported per mshX interface
+- * through sysfs (/sys/class/net/mshX/anycast_mask)
+- */
+-static DEVICE_ATTR(anycast_mask, 0644, libertas_anycast_get, libertas_anycast_set);
++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);
++
+
+ /**
+- * @brief Check if the device can be open and wait if necessary.
+- *
+- * @param dev A pointer to net_device structure
+- * @return 0
+- *
+- * For USB adapter, on some systems the device open handler will be
+- * called before FW ready. Use the following flag check and wait
+- * function to work around the issue.
+- *
++ * Get function for sysfs attribute rtap
+ */
+-static int pre_open_check(struct net_device *dev)
++static ssize_t lbs_rtap_get(struct device *dev,
++ struct device_attribute *attr, char * buf)
+ {
+- wlan_private *priv = (wlan_private *) dev->priv;
+- wlan_adapter *adapter = priv->adapter;
+- int i = 0;
+-
+- while (!adapter->fw_ready && i < 20) {
+- i++;
+- msleep_interruptible(100);
+- }
+- if (!adapter->fw_ready) {
+- lbs_pr_err("firmware not ready\n");
+- return -1;
+- }
+-
+- return 0;
++ struct lbs_private *priv = to_net_dev(dev)->priv;
++ return snprintf(buf, 5, "0x%X\n", priv->monitormode);
+ }
+
+ /**
+- * @brief This function opens the device
+- *
+- * @param dev A pointer to net_device structure
+- * @return 0
++ * Set function for sysfs attribute rtap
+ */
+-static int wlan_dev_open(struct net_device *dev)
++static ssize_t lbs_rtap_set(struct device *dev,
++ struct device_attribute *attr, const char * buf, size_t count)
+ {
+- wlan_private *priv = (wlan_private *) dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ int monitor_mode;
++ struct lbs_private *priv = to_net_dev(dev)->priv;
+
+- lbs_deb_enter(LBS_DEB_NET);
++ sscanf(buf, "%x", &monitor_mode);
++ if (monitor_mode != LBS_MONITOR_OFF) {
++ if(priv->monitormode == monitor_mode)
++ return strlen(buf);
++ if (priv->monitormode == LBS_MONITOR_OFF) {
++ if (priv->infra_open || priv->mesh_open)
++ return -EBUSY;
++ if (priv->mode == IW_MODE_INFRA)
++ lbs_send_deauthentication(priv);
++ else if (priv->mode == IW_MODE_ADHOC)
++ lbs_stop_adhoc_network(priv);
++ lbs_add_rtap(priv);
++ }
++ priv->monitormode = monitor_mode;
++ }
+
+- priv->open = 1;
++ else {
++ if (priv->monitormode == LBS_MONITOR_OFF)
++ return strlen(buf);
++ priv->monitormode = LBS_MONITOR_OFF;
++ lbs_remove_rtap(priv);
++
++ if (priv->currenttxskb) {
++ dev_kfree_skb_any(priv->currenttxskb);
++ priv->currenttxskb = NULL;
++ }
+
+- if (adapter->connect_status == libertas_connected) {
+- netif_carrier_on(priv->dev);
+- netif_carrier_on(priv->mesh_dev);
+- } else {
+- netif_carrier_off(priv->dev);
+- netif_carrier_off(priv->mesh_dev);
++ /* Wake queues, command thread, etc. */
++ lbs_host_to_card_done(priv);
+ }
+
+- lbs_deb_leave(LBS_DEB_NET);
+- return 0;
++ lbs_prepare_and_send_command(priv,
++ CMD_802_11_MONITOR_MODE, CMD_ACT_SET,
++ CMD_OPTION_WAITFORRSP, 0, &priv->monitormode);
++ return strlen(buf);
+ }
++
+ /**
+- * @brief This function opens the mshX interface
+- *
+- * @param dev A pointer to net_device structure
+- * @return 0
++ * lbs_rtap attribute to be exported per ethX interface
++ * through sysfs (/sys/class/net/ethX/lbs_rtap)
+ */
+-static int mesh_open(struct net_device *dev)
+-{
+- wlan_private *priv = (wlan_private *) dev->priv ;
+-
+- if (pre_open_check(dev) == -1)
+- return -1;
+- priv->mesh_open = 1 ;
+- netif_wake_queue(priv->mesh_dev);
+- if (priv->infra_open == 0)
+- return wlan_dev_open(priv->dev) ;
+- return 0;
+-}
++static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set );
+
+ /**
+- * @brief This function opens the ethX interface
+- *
+- * @param dev A pointer to net_device structure
+- * @return 0
++ * Get function for sysfs attribute mesh
+ */
+-static int wlan_open(struct net_device *dev)
++static ssize_t lbs_mesh_get(struct device *dev,
++ struct device_attribute *attr, char * buf)
+ {
+- wlan_private *priv = (wlan_private *) dev->priv ;
+-
+- if(pre_open_check(dev) == -1)
+- return -1;
+- priv->infra_open = 1 ;
+- netif_wake_queue(priv->dev);
+- if (priv->open == 0)
+- return wlan_dev_open(priv->dev) ;
+- return 0;
++ struct lbs_private *priv = to_net_dev(dev)->priv;
++ return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
+ }
+
+-static int wlan_dev_close(struct net_device *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)
+ {
+- wlan_private *priv = dev->priv;
+-
+- lbs_deb_enter(LBS_DEB_NET);
++ struct lbs_private *priv = to_net_dev(dev)->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;
+
+- netif_carrier_off(priv->dev);
+- priv->open = 0;
++ if (enable)
++ lbs_add_mesh(priv);
++ else
++ lbs_remove_mesh(priv);
+
+- lbs_deb_leave(LBS_DEB_NET);
+- return 0;
++ return count;
+ }
+
+ /**
+- * @brief This function closes the mshX interface
+- *
+- * @param dev A pointer to net_device structure
+- * @return 0
++ * lbs_mesh attribute to be exported per ethX interface
++ * through sysfs (/sys/class/net/ethX/lbs_mesh)
+ */
+-static int mesh_close(struct net_device *dev)
+-{
+- wlan_private *priv = (wlan_private *) (dev->priv);
++static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
+
+- priv->mesh_open = 0;
+- netif_stop_queue(priv->mesh_dev);
+- if (priv->infra_open == 0)
+- return wlan_dev_close(dev);
+- else
+- return 0;
+-}
++/**
++ * 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);
++
++static struct attribute *lbs_mesh_sysfs_entries[] = {
++ &dev_attr_anycast_mask.attr,
++ NULL,
++};
++
++static struct attribute_group lbs_mesh_attr_group = {
++ .attrs = lbs_mesh_sysfs_entries,
++};
+
+ /**
+- * @brief This function closes the ethX interface
++ * @brief This function opens the ethX or mshX interface
+ *
+ * @param dev A pointer to net_device structure
+- * @return 0
++ * @return 0 or -EBUSY if monitor mode active
+ */
+-static int wlan_close(struct net_device *dev)
++static int lbs_dev_open(struct net_device *dev)
+ {
+- wlan_private *priv = (wlan_private *) dev->priv;
+-
+- netif_stop_queue(dev);
+- priv->infra_open = 0;
+- if (priv->mesh_open == 0)
+- return wlan_dev_close(dev);
+- else
+- return 0;
+-}
++ struct lbs_private *priv = (struct lbs_private *) dev->priv ;
++ int ret = 0;
+
++ spin_lock_irq(&priv->driver_lock);
+
+-static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+-{
+- int ret = 0;
+- wlan_private *priv = dev->priv;
++ if (priv->monitormode != LBS_MONITOR_OFF) {
++ ret = -EBUSY;
++ goto out;
++ }
+
+- lbs_deb_enter(LBS_DEB_NET);
++ if (dev == priv->mesh_dev) {
++ priv->mesh_open = 1;
++ priv->mesh_connect_status = LBS_CONNECTED;
++ netif_carrier_on(dev);
++ } else {
++ priv->infra_open = 1;
+
+- if (priv->dnld_sent || priv->adapter->TxLockFlag) {
+- priv->stats.tx_dropped++;
+- goto done;
++ if (priv->connect_status == LBS_CONNECTED)
++ netif_carrier_on(dev);
++ else
++ netif_carrier_off(dev);
+ }
+
+- netif_stop_queue(priv->dev);
+- netif_stop_queue(priv->mesh_dev);
++ if (!priv->tx_pending_len)
++ netif_wake_queue(dev);
++ out:
+
+- if (libertas_process_tx(priv, skb) == 0)
+- dev->trans_start = jiffies;
+-done:
+- lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
++ spin_unlock_irq(&priv->driver_lock);
+ return ret;
+ }
+
++static void lbs_set_multicast_list(struct net_device *dev);
+ /**
+- * @brief Mark mesh packets and handover them to wlan_hard_start_xmit
++ * @brief This function closes the mshX interface
+ *
++ * @param dev A pointer to net_device structure
++ * @return 0
+ */
+-static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
++static int lbs_mesh_stop(struct net_device *dev)
+ {
+- wlan_private *priv = dev->priv;
+- int ret;
++ struct lbs_private *priv = (struct lbs_private *) (dev->priv);
+
+- lbs_deb_enter(LBS_DEB_MESH);
++ spin_lock_irq(&priv->driver_lock);
++
++ priv->mesh_open = 0;
++ priv->mesh_connect_status = LBS_DISCONNECTED;
+
+- SET_MESH_FRAME(skb);
++ netif_stop_queue(dev);
++ netif_carrier_off(dev);
+
+- ret = wlan_hard_start_xmit(skb, priv->dev);
+- lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
+- return ret;
++ schedule_work(&priv->mcast_work);
++
++ spin_unlock_irq(&priv->driver_lock);
++ return 0;
+ }
+
+ /**
+- * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit
++ * @brief This function closes the ethX interface
+ *
++ * @param dev A pointer to net_device structure
++ * @return 0
+ */
+-static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
++static int lbs_eth_stop(struct net_device *dev)
+ {
+- int ret;
++ struct lbs_private *priv = (struct lbs_private *) dev->priv;
+
+- lbs_deb_enter(LBS_DEB_NET);
++ spin_lock_irq(&priv->driver_lock);
+
+- UNSET_MESH_FRAME(skb);
++ priv->infra_open = 0;
+
+- ret = wlan_hard_start_xmit(skb, dev);
+- lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+- return ret;
++ netif_stop_queue(dev);
++
++ schedule_work(&priv->mcast_work);
++
++ spin_unlock_irq(&priv->driver_lock);
++ return 0;
+ }
+
+-static void wlan_tx_timeout(struct net_device *dev)
++static void lbs_tx_timeout(struct net_device *dev)
+ {
+- wlan_private *priv = (wlan_private *) dev->priv;
++ struct lbs_private *priv = (struct lbs_private *) dev->priv;
+
+ lbs_deb_enter(LBS_DEB_TX);
+
+ lbs_pr_err("tx watch dog timeout\n");
+
+- priv->dnld_sent = DNLD_RES_RECEIVED;
+ dev->trans_start = jiffies;
+
+- if (priv->adapter->currenttxskb) {
+- if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+- /* If we are here, we have not received feedback from
+- the previous packet. Assume TX_FAIL and move on. */
+- priv->adapter->eventcause = 0x01000000;
+- libertas_send_tx_feedback(priv);
+- } else
+- wake_up_interruptible(&priv->mainthread.waitq);
+- } else if (priv->adapter->connect_status == libertas_connected) {
+- netif_wake_queue(priv->dev);
+- netif_wake_queue(priv->mesh_dev);
+- }
++ if (priv->currenttxskb) {
++ priv->eventcause = 0x01000000;
++ lbs_send_tx_feedback(priv);
++ }
++ /* XX: Shouldn't we also call into the hw-specific driver
++ to kick it somehow? */
++ lbs_host_to_card_done(priv);
++
++ /* More often than not, this actually happens because the
++ firmware has crapped itself -- rather than just a very
++ busy medium. So send a harmless command, and if/when
++ _that_ times out, we'll kick it in the head. */
++ lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
++ 0, 0, NULL);
+
+ lbs_deb_leave(LBS_DEB_TX);
+ }
+
++void lbs_host_to_card_done(struct lbs_private *priv)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->driver_lock, flags);
++
++ 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);
++
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++}
++EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
++
+ /**
+ * @brief This function returns the network statistics
+ *
+- * @param dev A pointer to wlan_private structure
++ * @param dev A pointer to struct lbs_private structure
+ * @return A pointer to net_device_stats structure
+ */
+-static struct net_device_stats *wlan_get_stats(struct net_device *dev)
++static struct net_device_stats *lbs_get_stats(struct net_device *dev)
+ {
+- wlan_private *priv = (wlan_private *) dev->priv;
++ struct lbs_private *priv = (struct lbs_private *) dev->priv;
+
+ return &priv->stats;
+ }
+
+-static int wlan_set_mac_address(struct net_device *dev, void *addr)
++static int lbs_set_mac_address(struct net_device *dev, void *addr)
+ {
+ int ret = 0;
+- wlan_private *priv = (wlan_private *) dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = (struct lbs_private *) dev->priv;
+ struct sockaddr *phwaddr = addr;
+
+ lbs_deb_enter(LBS_DEB_NET);
+@@ -472,17 +535,17 @@ static int wlan_set_mac_address(struct n
+ /* In case it was called from the mesh device */
+ dev = priv->dev ;
+
+- memset(adapter->current_addr, 0, ETH_ALEN);
++ memset(priv->current_addr, 0, ETH_ALEN);
+
+ /* dev->dev_addr is 8 bytes */
+- lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
++ lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN);
+
+- lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN);
+- memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
++ lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN);
++ memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN);
+
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address,
+- cmd_act_set,
+- cmd_option_waitforrsp, 0, NULL);
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS,
++ CMD_ACT_SET,
++ CMD_OPTION_WAITFORRSP, 0, NULL);
+
+ if (ret) {
+ lbs_deb_net("set MAC address failed\n");
+@@ -490,304 +553,567 @@ static int wlan_set_mac_address(struct n
+ goto done;
+ }
+
+- lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN);
+- memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
++ lbs_deb_hex(LBS_DEB_NET, "priv->macaddr", priv->current_addr, ETH_ALEN);
++ memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN);
+ if (priv->mesh_dev)
+- memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
++ memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
+
+ done:
+ lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+ return ret;
+ }
+
+-static int wlan_copy_multicast_address(wlan_adapter * adapter,
+- struct net_device *dev)
++
++static inline int mac_in_list(unsigned char *list, int list_len,
++ unsigned char *mac)
+ {
+- int i = 0;
+- struct dev_mc_list *mcptr = dev->mc_list;
++ while (list_len) {
++ if (!memcmp(list, mac, ETH_ALEN))
++ return 1;
++ list += ETH_ALEN;
++ list_len--;
++ }
++ return 0;
++}
++
+
+- for (i = 0; i < dev->mc_count; i++) {
+- memcpy(&adapter->multicastlist[i], mcptr->dmi_addr, ETH_ALEN);
+- mcptr = mcptr->next;
++static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
++ struct net_device *dev, int nr_addrs)
++{
++ int i = nr_addrs;
++ struct dev_mc_list *mc_list;
++ DECLARE_MAC_BUF(mac);
++
++ if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST))
++ return nr_addrs;
++
++ netif_tx_lock_bh(dev);
++ for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
++ if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) {
++ lbs_deb_net("mcast address %s:%s skipped\n", dev->name,
++ print_mac(mac, mc_list->dmi_addr));
++ continue;
++ }
++
++ if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE)
++ break;
++ memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN);
++ lbs_deb_net("mcast address %s:%s added to filter\n", dev->name,
++ print_mac(mac, mc_list->dmi_addr));
++ i++;
+ }
++ netif_tx_unlock_bh(dev);
++ if (mc_list)
++ return -EOVERFLOW;
+
+ return i;
+-
+ }
+
+-static void wlan_set_multicast_list(struct net_device *dev)
++static void lbs_set_mcast_worker(struct work_struct *work)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
+- int oldpacketfilter;
++ struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
++ struct cmd_ds_mac_multicast_adr mcast_cmd;
++ int dev_flags;
++ int nr_addrs;
++ int old_mac_control = priv->mac_control;
+
+ lbs_deb_enter(LBS_DEB_NET);
+
+- oldpacketfilter = adapter->currentpacketfilter;
+-
+- if (dev->flags & IFF_PROMISC) {
+- lbs_deb_net("enable promiscuous mode\n");
+- adapter->currentpacketfilter |=
+- cmd_act_mac_promiscuous_enable;
+- adapter->currentpacketfilter &=
+- ~(cmd_act_mac_all_multicast_enable |
+- cmd_act_mac_multicast_enable);
+- } else {
+- /* Multicast */
+- adapter->currentpacketfilter &=
+- ~cmd_act_mac_promiscuous_enable;
+-
+- if (dev->flags & IFF_ALLMULTI || dev->mc_count >
+- MRVDRV_MAX_MULTICAST_LIST_SIZE) {
+- lbs_deb_net( "enabling all multicast\n");
+- adapter->currentpacketfilter |=
+- cmd_act_mac_all_multicast_enable;
+- adapter->currentpacketfilter &=
+- ~cmd_act_mac_multicast_enable;
+- } else {
+- adapter->currentpacketfilter &=
+- ~cmd_act_mac_all_multicast_enable;
+-
+- if (!dev->mc_count) {
+- lbs_deb_net("no multicast addresses, "
+- "disabling multicast\n");
+- adapter->currentpacketfilter &=
+- ~cmd_act_mac_multicast_enable;
+- } else {
+- int i;
+-
+- adapter->currentpacketfilter |=
+- cmd_act_mac_multicast_enable;
++ dev_flags = priv->dev->flags;
++ if (priv->mesh_dev)
++ dev_flags |= priv->mesh_dev->flags;
+
+- adapter->nr_of_multicastmacaddr =
+- wlan_copy_multicast_address(adapter, dev);
++ if (dev_flags & IFF_PROMISC) {
++ priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
++ priv->mac_control &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
++ CMD_ACT_MAC_MULTICAST_ENABLE);
++ goto out_set_mac_control;
++ } else if (dev_flags & IFF_ALLMULTI) {
++ do_allmulti:
++ priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
++ priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
++ CMD_ACT_MAC_MULTICAST_ENABLE);
++ goto out_set_mac_control;
++ }
++
++ /* Once for priv->dev, again for priv->mesh_dev if it exists */
++ nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->dev, 0);
++ if (nr_addrs >= 0 && priv->mesh_dev)
++ nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->mesh_dev, nr_addrs);
++ if (nr_addrs < 0)
++ goto do_allmulti;
++
++ if (nr_addrs) {
++ int size = offsetof(struct cmd_ds_mac_multicast_adr,
++ maclist[6*nr_addrs]);
++
++ mcast_cmd.action = cpu_to_le16(CMD_ACT_SET);
++ mcast_cmd.hdr.size = cpu_to_le16(size);
++ mcast_cmd.nr_of_adrs = cpu_to_le16(nr_addrs);
++
++ lbs_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &mcast_cmd.hdr, size);
++
++ priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
++ } else
++ priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
++
++ priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
++ CMD_ACT_MAC_ALL_MULTICAST_ENABLE);
++ out_set_mac_control:
++ if (priv->mac_control != old_mac_control)
++ lbs_set_mac_control(priv);
+
+- lbs_deb_net("multicast addresses: %d\n",
+- dev->mc_count);
+-
+- for (i = 0; i < dev->mc_count; i++) {
+- lbs_deb_net("Multicast address %d:"
+- MAC_FMT "\n", i,
+- adapter->multicastlist[i][0],
+- adapter->multicastlist[i][1],
+- adapter->multicastlist[i][2],
+- adapter->multicastlist[i][3],
+- adapter->multicastlist[i][4],
+- adapter->multicastlist[i][5]);
+- }
+- /* send multicast addresses to firmware */
+- libertas_prepare_and_send_command(priv,
+- cmd_mac_multicast_adr,
+- cmd_act_set, 0, 0,
+- NULL);
+- }
+- }
+- }
++ lbs_deb_leave(LBS_DEB_NET);
++}
+
+- if (adapter->currentpacketfilter != oldpacketfilter) {
+- libertas_set_mac_packet_filter(priv);
+- }
++static void lbs_set_multicast_list(struct net_device *dev)
++{
++ struct lbs_private *priv = dev->priv;
+
+- lbs_deb_leave(LBS_DEB_NET);
++ schedule_work(&priv->mcast_work);
+ }
+
+ /**
+- * @brief This function handles the major jobs in the WLAN driver.
++ * @brief This function handles the major jobs in the LBS driver.
+ * It handles all events generated by firmware, RX data received
+ * from firmware and TX data sent from kernel.
+ *
+- * @param data A pointer to wlan_thread structure
++ * @param data A pointer to lbs_thread structure
+ * @return 0
+ */
+-static int wlan_service_main_thread(void *data)
++static int lbs_thread(void *data)
+ {
+- struct wlan_thread *thread = data;
+- wlan_private *priv = thread->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct net_device *dev = data;
++ struct lbs_private *priv = dev->priv;
+ wait_queue_t wait;
+ u8 ireg = 0;
+
+ lbs_deb_enter(LBS_DEB_THREAD);
+
+- wlan_activate_thread(thread);
+-
+ init_waitqueue_entry(&wait, current);
+
++ current->flags |= PF_NOFREEZE;
++
+ for (;;) {
+- lbs_deb_thread( "main-thread 111: intcounter=%d "
+- "currenttxskb=%p dnld_sent=%d\n",
+- adapter->intcounter,
+- adapter->currenttxskb, priv->dnld_sent);
++ int shouldsleep;
+
+- add_wait_queue(&thread->waitq, &wait);
++ lbs_deb_thread( "main-thread 111: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
++ priv->intcounter, priv->currenttxskb, priv->dnld_sent);
++
++ add_wait_queue(&priv->waitq, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+- spin_lock_irq(&adapter->driver_lock);
+- if ((adapter->psstate == PS_STATE_SLEEP) ||
+- (!adapter->intcounter
+- && (priv->dnld_sent || adapter->cur_cmd ||
+- list_empty(&adapter->cmdpendingq)))) {
+- lbs_deb_thread(
+- "main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
+- adapter->connect_status, adapter->intcounter,
+- adapter->psmode, adapter->psstate);
+- spin_unlock_irq(&adapter->driver_lock);
++ spin_lock_irq(&priv->driver_lock);
++
++ if (kthread_should_stop())
++ shouldsleep = 0; /* Bye */
++ else if (priv->surpriseremoved)
++ shouldsleep = 1; /* We need to wait until we're _told_ to die */
++ else if (priv->psstate == PS_STATE_SLEEP)
++ shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */
++ else if (priv->intcounter)
++ shouldsleep = 0; /* Interrupt pending. Deal with it now */
++ else if (priv->cmd_timed_out)
++ shouldsleep = 0; /* Command timed out. Recover */
++ else if (!priv->fw_ready)
++ shouldsleep = 1; /* Firmware not ready. We're waiting for it */
++ else if (priv->dnld_sent)
++ shouldsleep = 1; /* Something is en route to the device already */
++ else if (priv->tx_pending_len > 0)
++ shouldsleep = 0; /* We've a packet to send */
++ else if (priv->cur_cmd)
++ shouldsleep = 1; /* Can't send a command; one already running */
++ else if (!list_empty(&priv->cmdpendingq))
++ shouldsleep = 0; /* We have a command to send */
++ else
++ shouldsleep = 1; /* No command */
++
++ if (shouldsleep) {
++ lbs_deb_thread("main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
++ priv->connect_status, priv->intcounter,
++ priv->psmode, priv->psstate);
++ spin_unlock_irq(&priv->driver_lock);
+ schedule();
+ } else
+- spin_unlock_irq(&adapter->driver_lock);
++ spin_unlock_irq(&priv->driver_lock);
+
+-
+- lbs_deb_thread(
+- "main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
+- "dnld_sent=%d\n", adapter->intcounter,
+- adapter->currenttxskb, priv->dnld_sent);
++ lbs_deb_thread("main-thread 222 (waking up): intcounter=%d currenttxskb=%p dnld_sent=%d\n",
++ priv->intcounter, priv->currenttxskb, priv->dnld_sent);
+
+ set_current_state(TASK_RUNNING);
+- remove_wait_queue(&thread->waitq, &wait);
+- try_to_freeze();
++ remove_wait_queue(&priv->waitq, &wait);
++
++ lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
++ priv->intcounter, priv->currenttxskb, priv->dnld_sent);
+
+- lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p "
+- "dnld_sent=%d\n",
+- adapter->intcounter,
+- adapter->currenttxskb, priv->dnld_sent);
+-
+- if (kthread_should_stop()
+- || adapter->surpriseremoved) {
+- lbs_deb_thread(
+- "main-thread: break from main thread: surpriseremoved=0x%x\n",
+- adapter->surpriseremoved);
++ if (kthread_should_stop()) {
++ lbs_deb_thread("main-thread: break from main thread\n");
+ break;
+ }
+
++ if (priv->surpriseremoved) {
++ lbs_deb_thread("adapter removed; waiting to die...\n");
++ continue;
++ }
+
+- spin_lock_irq(&adapter->driver_lock);
+- if (adapter->intcounter) {
++ spin_lock_irq(&priv->driver_lock);
++
++ if (priv->intcounter) {
+ u8 int_status;
+- adapter->intcounter = 0;
++
++ priv->intcounter = 0;
+ int_status = priv->hw_get_int_status(priv, &ireg);
+
+ if (int_status) {
+- lbs_deb_thread(
+- "main-thread: reading HOST_INT_STATUS_REG failed\n");
+- spin_unlock_irq(&adapter->driver_lock);
++ lbs_deb_thread("main-thread: reading HOST_INT_STATUS_REG failed\n");
++ spin_unlock_irq(&priv->driver_lock);
+ continue;
+ }
+- adapter->hisregcpy |= ireg;
++ priv->hisregcpy |= ireg;
+ }
+
+- lbs_deb_thread("main-thread 444: intcounter=%d currenttxskb=%p "
+- "dnld_sent=%d\n",
+- adapter->intcounter,
+- adapter->currenttxskb, priv->dnld_sent);
++ lbs_deb_thread("main-thread 444: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
++ priv->intcounter, priv->currenttxskb, priv->dnld_sent);
+
+ /* command response? */
+- if (adapter->hisregcpy & his_cmdupldrdy) {
++ if (priv->hisregcpy & MRVDRV_CMD_UPLD_RDY) {
+ lbs_deb_thread("main-thread: cmd response ready\n");
+
+- adapter->hisregcpy &= ~his_cmdupldrdy;
+- spin_unlock_irq(&adapter->driver_lock);
+- libertas_process_rx_command(priv);
+- spin_lock_irq(&adapter->driver_lock);
++ priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
++ spin_unlock_irq(&priv->driver_lock);
++ lbs_process_rx_command(priv);
++ spin_lock_irq(&priv->driver_lock);
+ }
+
++ if (priv->cmd_timed_out && priv->cur_cmd) {
++ struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
++
++ if (++priv->nr_retries > 10) {
++ lbs_pr_info("Excessive timeouts submitting command %x\n",
++ le16_to_cpu(cmdnode->cmdbuf->command));
++ lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
++ priv->nr_retries = 0;
++#ifdef CONFIG_OLPC
++ if (machine_is_olpc()) {
++ spin_unlock_irq(&priv->driver_lock);
++ printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
++ olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
++ spin_lock_irq(&priv->driver_lock);
++ }
++#endif
++ } else {
++ priv->cur_cmd = NULL;
++ lbs_pr_info("requeueing command %x due to timeout (#%d)\n",
++ le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries);
++
++ /* Stick it back at the _top_ of the pending queue
++ for immediate resubmission */
++ list_add(&cmdnode->list, &priv->cmdpendingq);
++ }
++ }
++ priv->cmd_timed_out = 0;
++
+ /* Any Card Event */
+- if (adapter->hisregcpy & his_cardevent) {
++ if (priv->hisregcpy & MRVDRV_CARDEVENT) {
+ lbs_deb_thread("main-thread: Card Event Activity\n");
+
+- adapter->hisregcpy &= ~his_cardevent;
++ priv->hisregcpy &= ~MRVDRV_CARDEVENT;
+
+ if (priv->hw_read_event_cause(priv)) {
+- lbs_pr_alert(
+- "main-thread: hw_read_event_cause failed\n");
+- spin_unlock_irq(&adapter->driver_lock);
++ lbs_pr_alert("main-thread: hw_read_event_cause failed\n");
++ spin_unlock_irq(&priv->driver_lock);
+ continue;
+ }
+- spin_unlock_irq(&adapter->driver_lock);
+- libertas_process_event(priv);
++ spin_unlock_irq(&priv->driver_lock);
++ lbs_process_event(priv);
+ } else
+- spin_unlock_irq(&adapter->driver_lock);
++ spin_unlock_irq(&priv->driver_lock);
++
++ if (!priv->fw_ready)
++ continue;
+
+ /* Check if we need to confirm Sleep Request received previously */
+- if (adapter->psstate == PS_STATE_PRE_SLEEP) {
+- if (!priv->dnld_sent && !adapter->cur_cmd) {
+- if (adapter->connect_status ==
+- libertas_connected) {
+- lbs_deb_thread(
+- "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
+- "dnld_sent=%d cur_cmd=%p, confirm now\n",
+- adapter->intcounter,
+- adapter->currenttxskb,
+- priv->dnld_sent,
+- adapter->cur_cmd);
+-
+- libertas_ps_confirm_sleep(priv,
+- (u16) adapter->psmode);
+- } else {
+- /* workaround for firmware sending
+- * deauth/linkloss event immediately
+- * after sleep request, remove this
+- * after firmware fixes it
+- */
+- adapter->psstate = PS_STATE_AWAKE;
+- lbs_pr_alert(
+- "main-thread: ignore PS_SleepConfirm in non-connected state\n");
+- }
++ if (priv->psstate == PS_STATE_PRE_SLEEP &&
++ !priv->dnld_sent && !priv->cur_cmd) {
++ if (priv->connect_status == LBS_CONNECTED) {
++ lbs_deb_thread("main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p dnld_sent=%d cur_cmd=%p, confirm now\n",
++ priv->intcounter, priv->currenttxskb, priv->dnld_sent, priv->cur_cmd);
++
++ lbs_ps_confirm_sleep(priv, (u16) priv->psmode);
++ } else {
++ /* workaround for firmware sending
++ * deauth/linkloss event immediately
++ * after sleep request; remove this
++ * after firmware fixes it
++ */
++ priv->psstate = PS_STATE_AWAKE;
++ lbs_pr_alert("main-thread: ignore PS_SleepConfirm in non-connected state\n");
+ }
+ }
+
+ /* The PS state is changed during processing of Sleep Request
+ * event above
+ */
+- if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
+- (priv->adapter->psstate == PS_STATE_PRE_SLEEP))
++ if ((priv->psstate == PS_STATE_SLEEP) ||
++ (priv->psstate == PS_STATE_PRE_SLEEP))
+ continue;
+
+ /* Execute the next command */
+- if (!priv->dnld_sent && !priv->adapter->cur_cmd)
+- libertas_execute_next_command(priv);
++ if (!priv->dnld_sent && !priv->cur_cmd)
++ lbs_execute_next_command(priv);
+
+ /* Wake-up command waiters which can't sleep in
+- * libertas_prepare_and_send_command
++ * lbs_prepare_and_send_command
+ */
+- if (!adapter->nr_cmd_pending)
+- wake_up_all(&adapter->cmd_pending);
++ if (!list_empty(&priv->cmdpendingq))
++ wake_up_all(&priv->cmd_pending);
+
+- libertas_tx_runqueue(priv);
++ spin_lock_irq(&priv->driver_lock);
++ if (!priv->dnld_sent && priv->tx_pending_len > 0) {
++ int ret = priv->hw_host_to_card(priv, MVMS_DAT,
++ priv->tx_pending_buf,
++ priv->tx_pending_len);
++ if (ret) {
++ lbs_deb_tx("host_to_card failed %d\n", ret);
++ priv->dnld_sent = DNLD_RES_RECEIVED;
++ }
++ priv->tx_pending_len = 0;
++ if (!priv->currenttxskb) {
++ /* We can wake the queues immediately if we aren't
++ waiting for TX feedback */
++ if (priv->connect_status == LBS_CONNECTED)
++ netif_wake_queue(priv->dev);
++ if (priv->mesh_dev &&
++ priv->mesh_connect_status == LBS_CONNECTED)
++ netif_wake_queue(priv->mesh_dev);
++ }
++ }
++ spin_unlock_irq(&priv->driver_lock);
+ }
+
+- del_timer(&adapter->command_timer);
+- adapter->nr_cmd_pending = 0;
+- wake_up_all(&adapter->cmd_pending);
+- wlan_deactivate_thread(thread);
++ del_timer(&priv->command_timer);
++ wake_up_all(&priv->cmd_pending);
+
+ lbs_deb_leave(LBS_DEB_THREAD);
+ return 0;
+ }
+
++static int lbs_suspend_callback(struct lbs_private *priv, unsigned long dummy,
++ struct cmd_header *cmd)
++{
++ lbs_deb_fw("HOST_SLEEP_ACTIVATE succeeded\n");
++
++ netif_device_detach(priv->dev);
++ if (priv->mesh_dev)
++ netif_device_detach(priv->mesh_dev);
++
++ priv->fw_ready = 0;
++ return 0;
++}
++
++
++int lbs_suspend(struct lbs_private *priv)
++{
++ struct cmd_header cmd;
++ int ret;
++
++ if (priv->wol_criteria == 0xffffffff) {
++ lbs_pr_info("Suspend attempt without configuring wake params!\n");
++ return -EINVAL;
++ }
++
++ memset(&cmd, 0, sizeof(cmd));
++
++ ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd,
++ sizeof(cmd), lbs_suspend_callback, 0);
++ if (ret)
++ lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(lbs_suspend);
++
++int lbs_resume(struct lbs_private *priv)
++{
++ priv->fw_ready = 1;
++
++ /* Firmware doesn't seem to give us RX packets any more
++ until we send it some command. Might as well update */
++ lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
++ 0, 0, NULL);
++
++ netif_device_attach(priv->dev);
++ if (priv->mesh_dev)
++ netif_device_attach(priv->mesh_dev);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(lbs_resume);
++
++/**
++ * @brief This function downloads firmware image, gets
++ * HW spec from firmware and set basic parameters to
++ * firmware.
++ *
++ * @param priv A pointer to struct lbs_private structure
++ * @return 0 or -1
++ */
++static int lbs_setup_firmware(struct lbs_private *priv)
++{
++ int ret = -1;
++
++ lbs_deb_enter(LBS_DEB_FW);
++
++ /*
++ * Read MAC address from HW
++ */
++ memset(priv->current_addr, 0xff, ETH_ALEN);
++ ret = lbs_update_hw_spec(priv);
++ if (ret) {
++ ret = -1;
++ goto done;
++ }
++
++ lbs_set_mac_control(priv);
++
++ ret = lbs_get_data_rate(priv);
++ if (ret < 0) {
++ ret = -1;
++ goto done;
++ }
++
++ ret = 0;
++done:
++ lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
++ return ret;
++}
++
++/**
++ * This function handles the timeout of command sending.
++ * It will re-send the same command again.
++ */
++static void command_timer_fn(unsigned long data)
++{
++ struct lbs_private *priv = (struct lbs_private *)data;
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->driver_lock, flags);
++
++ if (!priv->cur_cmd) {
++ lbs_pr_info("Command timer expired; no pending command\n");
++ goto out;
++ }
++
++ lbs_pr_info("Command %x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command));
++
++ priv->cmd_timed_out = 1;
++ wake_up_interruptible(&priv->waitq);
++ out:
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++}
++
++static int lbs_init_adapter(struct lbs_private *priv)
++{
++ size_t bufsize;
++ int i, ret = 0;
++
++ /* Allocate buffer to store the BSSID list */
++ bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
++ priv->networks = kzalloc(bufsize, GFP_KERNEL);
++ if (!priv->networks) {
++ lbs_pr_err("Out of memory allocating beacons\n");
++ ret = -1;
++ goto out;
++ }
++
++ /* Initialize scan result lists */
++ INIT_LIST_HEAD(&priv->network_free_list);
++ INIT_LIST_HEAD(&priv->network_list);
++ for (i = 0; i < MAX_NETWORK_COUNT; i++) {
++ list_add_tail(&priv->networks[i].list,
++ &priv->network_free_list);
++ }
++
++ priv->lbs_ps_confirm_sleep.seqnum = cpu_to_le16(++priv->seqnum);
++ priv->lbs_ps_confirm_sleep.command =
++ cpu_to_le16(CMD_802_11_PS_MODE);
++ priv->lbs_ps_confirm_sleep.size =
++ cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
++ priv->lbs_ps_confirm_sleep.action =
++ cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED);
++
++ memset(priv->current_addr, 0xff, ETH_ALEN);
++
++ priv->connect_status = LBS_DISCONNECTED;
++ 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->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
++ priv->radioon = RADIO_ON;
++ priv->auto_rate = 1;
++ priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
++ priv->psmode = LBS802_11POWERMODECAM;
++ priv->psstate = PS_STATE_FULL_POWER;
++
++ mutex_init(&priv->lock);
++
++ setup_timer(&priv->command_timer, command_timer_fn,
++ (unsigned long)priv);
++
++ INIT_LIST_HEAD(&priv->cmdfreeq);
++ INIT_LIST_HEAD(&priv->cmdpendingq);
++
++ spin_lock_init(&priv->driver_lock);
++ init_waitqueue_head(&priv->cmd_pending);
++
++ /* Allocate the command buffers */
++ if (lbs_allocate_cmd_buffer(priv)) {
++ lbs_pr_err("Out of memory allocating command buffers\n");
++ ret = -1;
++ }
++
++out:
++ return ret;
++}
++
++static void lbs_free_adapter(struct lbs_private *priv)
++{
++ lbs_deb_fw("free command buffer\n");
++ lbs_free_cmd_buffer(priv);
++
++ lbs_deb_fw("free command_timer\n");
++ del_timer(&priv->command_timer);
++
++ lbs_deb_fw("free scan results table\n");
++ kfree(priv->networks);
++ priv->networks = NULL;
++}
++
+ /**
+ * @brief This function adds the card. it will probe the
+- * card, allocate the wlan_priv and initialize the device.
++ * card, allocate the lbs_priv and initialize the device.
+ *
+ * @param card A pointer to card
+- * @return A pointer to wlan_private structure
++ * @return A pointer to struct lbs_private structure
+ */
+-wlan_private *libertas_add_card(void *card, struct device *dmdev)
++struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
+ {
+ struct net_device *dev = NULL;
+- wlan_private *priv = NULL;
++ struct lbs_private *priv = NULL;
+
+ lbs_deb_enter(LBS_DEB_NET);
+
+ /* Allocate an Ethernet device and register it */
+- if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
++ dev = alloc_etherdev(sizeof(struct lbs_private));
++ if (!dev) {
+ lbs_pr_err("init ethX device failed\n");
+- return NULL;
++ goto done;
+ }
+ priv = dev->priv;
+
+- /* allocate buffer for wlan_adapter */
+- if (!(priv->adapter = kzalloc(sizeof(wlan_adapter), GFP_KERNEL))) {
+- lbs_pr_err("allocate buffer for wlan_adapter failed\n");
+- goto err_kzalloc;
++ if (lbs_init_adapter(priv)) {
++ lbs_pr_err("failed to initialize adapter structure.\n");
++ goto err_init_adapter;
+ }
+
+ priv->dev = dev;
+@@ -795,110 +1121,207 @@ wlan_private *libertas_add_card(void *ca
+ priv->mesh_open = 0;
+ priv->infra_open = 0;
+
+- SET_MODULE_OWNER(dev);
+-
+ /* Setup the OS Interface to our functions */
+- dev->open = wlan_open;
+- dev->hard_start_xmit = wlan_pre_start_xmit;
+- dev->stop = wlan_close;
+- dev->set_mac_address = wlan_set_mac_address;
+- dev->tx_timeout = wlan_tx_timeout;
+- dev->get_stats = wlan_get_stats;
++ dev->open = lbs_dev_open;
++ dev->hard_start_xmit = lbs_hard_start_xmit;
++ dev->stop = lbs_eth_stop;
++ dev->set_mac_address = lbs_set_mac_address;
++ dev->tx_timeout = lbs_tx_timeout;
++ dev->do_ioctl = lbs_do_ioctl;
++ dev->get_stats = lbs_get_stats;
+ dev->watchdog_timeo = 5 * HZ;
+- dev->ethtool_ops = &libertas_ethtool_ops;
++ dev->ethtool_ops = &lbs_ethtool_ops;
+ #ifdef WIRELESS_EXT
+- dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
++ dev->wireless_handlers = (struct iw_handler_def *)&lbs_handler_def;
+ #endif
+-#define NETIF_F_DYNALLOC 16
+- dev->features |= NETIF_F_DYNALLOC;
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+- dev->set_multicast_list = wlan_set_multicast_list;
++ dev->set_multicast_list = lbs_set_multicast_list;
+
+ SET_NETDEV_DEV(dev, dmdev);
+
+- INIT_LIST_HEAD(&priv->adapter->cmdfreeq);
+- INIT_LIST_HEAD(&priv->adapter->cmdpendingq);
++ priv->rtap_net_dev = NULL;
++
++ lbs_deb_thread("Starting main thread...\n");
++ init_waitqueue_head(&priv->waitq);
++ 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;
++ }
++
++ priv->work_thread = create_singlethread_workqueue("lbs_worker");
++ INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
++ INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
++ INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
++ INIT_WORK(&priv->sync_channel, lbs_sync_channel);
++
++ sprintf(priv->mesh_ssid, "mesh");
++ priv->mesh_ssid_len = 4;
++
++ priv->wol_criteria = 0xffffffff;
++ priv->wol_gpio = 0xff;
+
+- spin_lock_init(&priv->adapter->driver_lock);
+- init_waitqueue_head(&priv->adapter->cmd_pending);
+- priv->adapter->nr_cmd_pending = 0;
+ goto done;
+
+-err_kzalloc:
++err_init_adapter:
++ lbs_free_adapter(priv);
+ free_netdev(dev);
+ priv = NULL;
++
+ done:
+ lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv);
+ return priv;
+ }
+-EXPORT_SYMBOL_GPL(libertas_add_card);
++EXPORT_SYMBOL_GPL(lbs_add_card);
++
+
+-int libertas_activate_card(wlan_private *priv, char *fw_name)
++int lbs_remove_card(struct lbs_private *priv)
+ {
+ struct net_device *dev = priv->dev;
+- int ret = -1;
++ union iwreq_data wrqu;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+- lbs_deb_thread("Starting kthread...\n");
+- priv->mainthread.priv = priv;
+- wlan_create_thread(wlan_service_main_thread,
+- &priv->mainthread, "wlan_main_service");
+-
+- priv->assoc_thread =
+- create_singlethread_workqueue("libertas_assoc");
+- INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
+- INIT_WORK(&priv->sync_channel, libertas_sync_channel);
++ lbs_remove_mesh(priv);
++ lbs_remove_rtap(priv);
+
+- /*
+- * Register the device. Fillup the private data structure with
+- * relevant information from the card and request for the required
+- * IRQ.
+- */
+- if (priv->hw_register_dev(priv) < 0) {
+- lbs_pr_err("failed to register WLAN device\n");
+- goto err_registerdev;
+- }
++ dev = priv->dev;
++
++ cancel_delayed_work(&priv->scan_work);
++ cancel_delayed_work(&priv->assoc_work);
++ cancel_work_sync(&priv->mcast_work);
++ destroy_workqueue(priv->work_thread);
+
+- /* init FW and HW */
+- if (fw_name && libertas_init_fw(priv, fw_name)) {
+- lbs_pr_err("firmware init failed\n");
+- goto err_registerdev;
++ if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
++ priv->psmode = LBS802_11POWERMODECAM;
++ 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);
++
++ /* Stop the thread servicing the interrupts */
++ priv->surpriseremoved = 1;
++ kthread_stop(priv->main_thread);
++
++ lbs_free_adapter(priv);
++
++ priv->dev = NULL;
++ free_netdev(dev);
++
++ lbs_deb_leave(LBS_DEB_MAIN);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(lbs_remove_card);
++
++
++int lbs_start_card(struct lbs_private *priv)
++{
++ struct net_device *dev = priv->dev;
++ int ret = -1;
++
++ lbs_deb_enter(LBS_DEB_MAIN);
++
++ /* poke the firmware */
++ ret = lbs_setup_firmware(priv);
++ if (ret)
++ goto done;
++
++ /* init 802.11d */
++ lbs_init_11d(priv);
++
+ if (register_netdev(dev)) {
+ lbs_pr_err("cannot register ethX device\n");
+- goto err_init_fw;
++ goto done;
+ }
++ if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
++ lbs_pr_err("cannot register lbs_rtap attribute\n");
+
+- lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
++ /* Enable mesh, if supported, and work out which TLV it uses.
++ 0x100 + 291 is an unofficial value used in 5.110.20.pXX
++ 0x100 + 37 is the official value used in 5.110.21.pXX
++ but we check them in that order because 20.pXX doesn't
++ give an error -- it just silently fails. */
++
++ /* 5.110.20.pXX firmware will fail the command if the channel
++ doesn't match the existing channel. But only if the TLV
++ is correct. If the channel is wrong, _BOTH_ versions will
++ give an error to 0x100+291, and allow 0x100+37 to succeed.
++ It's just that 5.110.20.pXX will not have done anything
++ useful */
++
++ lbs_update_channel(priv);
++ priv->mesh_tlv = 0x100 + 291;
++ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
++ priv->curbssparams.channel)) {
++ priv->mesh_tlv = 0x100 + 37;
++ 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);
+
+- libertas_debugfs_init_one(priv, dev);
++ if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
++ lbs_pr_err("cannot register lbs_mesh attribute\n");
++ }
++
++ lbs_debugfs_init_one(priv, dev);
++
++ lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
+
+ ret = 0;
+- goto done;
+
+-err_init_fw:
+- priv->hw_unregister_dev(priv);
+-err_registerdev:
+- destroy_workqueue(priv->assoc_thread);
+- /* Stop the thread servicing the interrupts */
+- wake_up_interruptible(&priv->mainthread.waitq);
+- wlan_terminate_thread(&priv->mainthread);
+ done:
+- lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
++ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(lbs_start_card);
++
++
++int lbs_stop_card(struct lbs_private *priv)
++{
++ struct net_device *dev = priv->dev;
++ int ret = -1;
++ struct cmd_ctrl_node *cmdnode;
++ unsigned long flags;
++
++ lbs_deb_enter(LBS_DEB_MAIN);
++
++ netif_stop_queue(priv->dev);
++ netif_carrier_off(priv->dev);
++
++ lbs_debugfs_remove_one(priv);
++ device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
++ if (priv->mesh_tlv) {
++ device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
++ }
++
++ /* Flush pending command nodes */
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
++ cmdnode->result = -ENOENT;
++ cmdnode->cmdwaitqwoken = 1;
++ wake_up_interruptible(&cmdnode->cmdwait_q);
++ }
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++
++ unregister_netdev(dev);
++
++ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+ return ret;
+ }
+-EXPORT_SYMBOL_GPL(libertas_activate_card);
++EXPORT_SYMBOL_GPL(lbs_stop_card);
+
+
+ /**
+ * @brief This function adds mshX interface
+ *
+- * @param priv A pointer to the wlan_private structure
++ * @param priv A pointer to the struct lbs_private structure
+ * @return 0 if successful, -X otherwise
+ */
+-int libertas_add_mesh(wlan_private *priv, struct device *dev)
++static int lbs_add_mesh(struct lbs_private *priv)
+ {
+ struct net_device *mesh_dev = NULL;
+ int ret = 0;
+@@ -914,24 +1337,23 @@ int libertas_add_mesh(wlan_private *priv
+ mesh_dev->priv = priv;
+ priv->mesh_dev = mesh_dev;
+
+- SET_MODULE_OWNER(mesh_dev);
+-
+- mesh_dev->open = mesh_open;
+- mesh_dev->hard_start_xmit = mesh_pre_start_xmit;
+- mesh_dev->stop = mesh_close;
+- mesh_dev->get_stats = wlan_get_stats;
+- mesh_dev->set_mac_address = wlan_set_mac_address;
+- mesh_dev->ethtool_ops = &libertas_ethtool_ops;
++ mesh_dev->open = lbs_dev_open;
++ mesh_dev->hard_start_xmit = lbs_hard_start_xmit;
++ mesh_dev->stop = lbs_mesh_stop;
++ mesh_dev->do_ioctl = lbs_do_ioctl;
++ mesh_dev->get_stats = lbs_get_stats;
++ mesh_dev->set_mac_address = lbs_set_mac_address;
++ 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, dev);
++ 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
+-#define NETIF_F_DYNALLOC 16
+-
++ mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
++ mesh_dev->set_multicast_list = lbs_set_multicast_list;
+ /* Register virtual mesh interface */
+ ret = register_netdev(mesh_dev);
+ if (ret) {
+@@ -939,15 +1361,16 @@ int libertas_add_mesh(wlan_private *priv
+ goto err_free;
+ }
+
+- ret = device_create_file(&(mesh_dev->dev), &dev_attr_anycast_mask);
++ 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);
+
+@@ -958,107 +1381,36 @@ done:
+ lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
+ return ret;
+ }
+-EXPORT_SYMBOL_GPL(libertas_add_mesh);
+-
+-static void wake_pending_cmdnodes(wlan_private *priv)
+-{
+- struct cmd_ctrl_node *cmdnode;
+- unsigned long flags;
+-
+- lbs_deb_enter(LBS_DEB_CMD);
+-
+- spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+- list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
+- cmdnode->cmdwaitqwoken = 1;
+- wake_up_interruptible(&cmdnode->cmdwait_q);
+- }
+- spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+-}
++EXPORT_SYMBOL_GPL(lbs_add_mesh);
+
+
+-int libertas_remove_card(wlan_private *priv)
+-{
+- wlan_adapter *adapter;
+- struct net_device *dev;
+- union iwreq_data wrqu;
+-
+- lbs_deb_enter(LBS_DEB_NET);
+-
+- if (!priv)
+- goto out;
+-
+- adapter = priv->adapter;
+-
+- if (!adapter)
+- goto out;
+-
+- dev = priv->dev;
+-
+- netif_stop_queue(priv->dev);
+- netif_carrier_off(priv->dev);
+-
+- wake_pending_cmdnodes(priv);
+-
+- unregister_netdev(dev);
+-
+- cancel_delayed_work(&priv->assoc_work);
+- destroy_workqueue(priv->assoc_thread);
+-
+- if (adapter->psmode == wlan802_11powermodemax_psp) {
+- adapter->psmode = wlan802_11powermodecam;
+- libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+- }
+-
+- memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+-
+- adapter->surpriseremoved = 1;
+-
+- /* Stop the thread servicing the interrupts */
+- wlan_terminate_thread(&priv->mainthread);
+-
+- libertas_debugfs_remove_one(priv);
+-
+- lbs_deb_net("free adapter\n");
+- libertas_free_adapter(priv);
+-
+- lbs_deb_net("unregister finish\n");
+-
+- priv->dev = NULL;
+- free_netdev(dev);
+-
+-out:
+- lbs_deb_leave(LBS_DEB_NET);
+- return 0;
+-}
+-EXPORT_SYMBOL_GPL(libertas_remove_card);
+-
+-
+-void libertas_remove_mesh(wlan_private *priv)
++static void lbs_remove_mesh(struct lbs_private *priv)
+ {
+ struct net_device *mesh_dev;
+
+- lbs_deb_enter(LBS_DEB_NET);
++ lbs_deb_enter(LBS_DEB_MAIN);
+
+ if (!priv)
+ goto out;
+
+ mesh_dev = priv->mesh_dev;
++ if (!mesh_dev)
++ goto out;
+
+ netif_stop_queue(mesh_dev);
+- netif_carrier_off(priv->mesh_dev);
++ netif_carrier_off(mesh_dev);
+
+- device_remove_file(&(mesh_dev->dev), &dev_attr_anycast_mask);
++ 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 ;
++ priv->mesh_dev = NULL;
+ free_netdev(mesh_dev);
+
+ out:
+- lbs_deb_leave(LBS_DEB_NET);
++ lbs_deb_leave(LBS_DEB_MAIN);
+ }
+-EXPORT_SYMBOL_GPL(libertas_remove_mesh);
++EXPORT_SYMBOL_GPL(lbs_remove_mesh);
+
+ /**
+ * @brief This function finds the CFP in
+@@ -1069,13 +1421,13 @@ EXPORT_SYMBOL_GPL(libertas_remove_mesh);
+ * @param cfp_no A pointer to CFP number
+ * @return A pointer to CFP
+ */
+-struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no)
++struct chan_freq_power *lbs_get_region_cfp_table(u8 region, u8 band, int *cfp_no)
+ {
+ int i, end;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+- end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table);
++ end = ARRAY_SIZE(region_cfp_table);
+
+ for (i = 0; i < end ; i++) {
+ lbs_deb_main("region_cfp_table[i].region=%d\n",
+@@ -1091,9 +1443,8 @@ struct chan_freq_power *libertas_get_reg
+ return NULL;
+ }
+
+-int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band)
++int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ int i = 0;
+
+@@ -1102,22 +1453,22 @@ int libertas_set_regiontable(wlan_privat
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+- memset(adapter->region_channel, 0, sizeof(adapter->region_channel));
++ memset(priv->region_channel, 0, sizeof(priv->region_channel));
+
+ {
+- cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
++ cfp = lbs_get_region_cfp_table(region, band, &cfp_no);
+ if (cfp != NULL) {
+- adapter->region_channel[i].nrcfp = cfp_no;
+- adapter->region_channel[i].CFP = cfp;
++ 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;
+ }
+- adapter->region_channel[i].valid = 1;
+- adapter->region_channel[i].region = region;
+- adapter->region_channel[i].band = band;
++ priv->region_channel[i].valid = 1;
++ priv->region_channel[i].region = region;
++ priv->region_channel[i].band = band;
+ i++;
+ }
+ out:
+@@ -1133,48 +1484,137 @@ out:
+ * @param dev A pointer to net_device structure
+ * @return n/a
+ */
+-void libertas_interrupt(struct net_device *dev)
++void lbs_interrupt(struct lbs_private *priv)
+ {
+- wlan_private *priv = dev->priv;
+-
+ lbs_deb_enter(LBS_DEB_THREAD);
+
+- lbs_deb_thread("libertas_interrupt: intcounter=%d\n",
+- priv->adapter->intcounter);
+-
+- priv->adapter->intcounter++;
++ lbs_deb_thread("lbs_interrupt: intcounter=%d\n", priv->intcounter);
+
+- if (priv->adapter->psstate == PS_STATE_SLEEP) {
+- priv->adapter->psstate = PS_STATE_AWAKE;
+- netif_wake_queue(dev);
+- netif_wake_queue(priv->mesh_dev);
++ if (!spin_is_locked(&priv->driver_lock)) {
++ printk(KERN_CRIT "%s called without driver_lock held\n", __func__);
++ WARN_ON(1);
+ }
+
+- wake_up_interruptible(&priv->mainthread.waitq);
++ priv->intcounter++;
++
++ if (priv->psstate == PS_STATE_SLEEP)
++ priv->psstate = PS_STATE_AWAKE;
++
++ wake_up_interruptible(&priv->waitq);
+
+ lbs_deb_leave(LBS_DEB_THREAD);
+ }
+-EXPORT_SYMBOL_GPL(libertas_interrupt);
++EXPORT_SYMBOL_GPL(lbs_interrupt);
++
++int lbs_reset_device(struct lbs_private *priv)
++{
++ int ret;
++
++ lbs_deb_enter(LBS_DEB_MAIN);
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_RESET,
++ CMD_ACT_HALT, 0, 0, NULL);
++#ifdef CONFIG_OLPC
++ if (machine_is_olpc()) {
++ printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
++ olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
++ }
++#endif
++ msleep_interruptible(10);
++
++ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(lbs_reset_device);
+
+-static int libertas_init_module(void)
++static int __init lbs_init_module(void)
+ {
+ lbs_deb_enter(LBS_DEB_MAIN);
+- libertas_debugfs_init();
++ lbs_debugfs_init();
+ lbs_deb_leave(LBS_DEB_MAIN);
+ return 0;
+ }
+
+-static void libertas_exit_module(void)
++static void __exit lbs_exit_module(void)
+ {
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+- libertas_debugfs_remove();
++ lbs_debugfs_remove();
+
+ lbs_deb_leave(LBS_DEB_MAIN);
+ }
+
+-module_init(libertas_init_module);
+-module_exit(libertas_exit_module);
++/*
++ * rtap interface support fuctions
++ */
++
++static int lbs_rtap_open(struct net_device *dev)
++{
++ /* Yes, _stop_ the queue. Because we don't support injection */
++ netif_carrier_off(dev);
++ netif_stop_queue(dev);
++ return 0;
++}
++
++static int lbs_rtap_stop(struct net_device *dev)
++{
++ return 0;
++}
++
++static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ netif_stop_queue(dev);
++ return NETDEV_TX_BUSY;
++}
++
++static struct net_device_stats *lbs_rtap_get_stats(struct net_device *dev)
++{
++ struct lbs_private *priv = dev->priv;
++ return &priv->stats;
++}
++
++
++static void lbs_remove_rtap(struct lbs_private *priv)
++{
++ if (priv->rtap_net_dev == NULL)
++ return;
++ unregister_netdev(priv->rtap_net_dev);
++ free_netdev(priv->rtap_net_dev);
++ priv->rtap_net_dev = NULL;
++}
++
++static int lbs_add_rtap(struct lbs_private *priv)
++{
++ int rc = 0;
++ struct net_device *rtap_dev;
++
++ if (priv->rtap_net_dev)
++ return -EPERM;
++
++ rtap_dev = alloc_netdev(0, "rtap%d", ether_setup);
++ if (rtap_dev == NULL)
++ return -ENOMEM;
++
++ memcpy(rtap_dev->dev_addr, priv->current_addr, ETH_ALEN);
++ rtap_dev->type = ARPHRD_IEEE80211_RADIOTAP;
++ rtap_dev->open = lbs_rtap_open;
++ rtap_dev->stop = lbs_rtap_stop;
++ rtap_dev->get_stats = lbs_rtap_get_stats;
++ rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit;
++ rtap_dev->priv = priv;
++
++ rc = register_netdev(rtap_dev);
++ if (rc) {
++ free_netdev(rtap_dev);
++ return rc;
++ }
++ priv->rtap_net_dev = rtap_dev;
++
++ return 0;
++}
++
++
++module_init(lbs_init_module);
++module_exit(lbs_exit_module);
+
+ MODULE_DESCRIPTION("Libertas WLAN Driver Library");
+ MODULE_AUTHOR("Marvell International Ltd.");
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/Makefile linux-2.6.22-300/drivers/net/wireless/libertas/Makefile
+--- linux-2.6.22-250/drivers/net/wireless/libertas/Makefile 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/Makefile 2008-06-05 18:10:06.000000000 -0400
+@@ -1,12 +1,11 @@
+-libertas-objs := main.o fw.o wext.o \
+- rx.o tx.o cmd.o \
+- cmdresp.o scan.o \
+- join.o 11d.o \
+- debugfs.o \
+- ethtool.o assoc.o
++libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o join.o \
++ 11d.o debugfs.o persistcfg.o ethtool.o assoc.o ioctl.o
+
+-usb8xxx-objs += if_bootcmd.o
+ usb8xxx-objs += if_usb.o
++libertas_cs-objs += if_cs.o
++libertas_sdio-objs += if_sdio.o
+
+ obj-$(CONFIG_LIBERTAS) += libertas.o
+ obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
++obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o
++obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/mesh_opts.c linux-2.6.22-300/drivers/net/wireless/libertas/mesh_opts.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/mesh_opts.c 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.22-300/drivers/net/wireless/libertas/mesh_opts.c 2008-06-05 18:10:06.000000000 -0400
+@@ -0,0 +1,174 @@
++/*
++ * mesh_opts
++ *
++ * Author: Javier Cardona <javier@cozybit.com>
++ * Copyright: Marvell Semiconductors Inc., 2007
++ *
++ * Apply mesh-layer specific configuration to network flows. Currently this
++ * only supports the mesh TTL parameter.
++ *
++ * Users call setsockopt on sockets to configure mesh parameters. This module
++ * maintains a list of sockets (mesh_sks) that have different mesh parameters
++ * than the per-interface defaults. The driver will modify the mesh
++ * configuration for each outgoing frame that belongs to one of the sockets in
++ * the mesh_sks list.
++ */
++
++#include <linux/module.h>
++#include <linux/list.h>
++#include <linux/net.h>
++#include <linux/in.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/netfilter_ipv6.h>
++#include <linux/spinlock.h>
++#include <net/sock.h>
++
++#include <asm/uaccess.h>
++
++#include "mesh_opts.h"
++
++#define MESH_SO_BASE_CTL MESH_SO_SET_TTL
++
++static struct list_head mesh_sks = LIST_HEAD_INIT(mesh_sks);
++static DEFINE_RWLOCK(mesh_sks_lock);
++
++struct mesh_sock {
++ struct list_head list;
++
++ struct sock *sk;
++ unsigned char ttl;
++ void (*orig_sk_destruct) (struct sock *sk);
++};
++
++static struct mesh_sock * lookup_socket(struct sock *sk)
++{
++ struct mesh_sock *mesh_sk;
++ struct mesh_sock *found_sk = NULL;
++
++ read_lock(&mesh_sks_lock);
++ list_for_each_entry(mesh_sk, &mesh_sks, list)
++ if (mesh_sk->sk == sk) {
++ found_sk = mesh_sk;
++ break;
++ }
++ read_unlock(&mesh_sks_lock);
++ return found_sk;
++}
++
++static void mesh_sk_destruct(struct sock *sk)
++{
++ struct mesh_sock *mesh_sk;
++ void (*orig_sk_destruct) (struct sock *sk);
++
++ mesh_sk = lookup_socket(sk);
++
++ if (mesh_sk) {
++ orig_sk_destruct = mesh_sk->orig_sk_destruct;
++ write_lock(&mesh_sks_lock);
++ list_del(&mesh_sk->list);
++ write_unlock(&mesh_sks_lock);
++ kfree(mesh_sk);
++ (*orig_sk_destruct)(sk);
++ }
++}
++
++static int do_mesh_set_mesh_ttl(struct sock *sk, void __user *user, unsigned int len)
++{
++ struct mesh_sock *mesh_sk;
++ unsigned char ttl;
++
++
++ if (len) {
++ if (get_user(ttl, (unsigned char *) user))
++ return -EFAULT;
++ } else
++ return -EINVAL;
++
++ mesh_sk = (struct mesh_sock*) kmalloc(sizeof(struct mesh_sock), GFP_KERNEL);
++ mesh_sk->ttl = ttl;
++ mesh_sk->sk = sk;
++ mesh_sk->orig_sk_destruct = sk->sk_destruct;
++ sk->sk_destruct = mesh_sk_destruct;
++ write_lock(&mesh_sks_lock);
++ list_add(&mesh_sk->list, &mesh_sks);
++ write_unlock(&mesh_sks_lock);
++
++ return 0;
++}
++
++static int do_mesh_get_mesh_ttl(struct sock *sk, void __user *user, int *len)
++{
++ struct mesh_sock *mesh_sk;
++ int rc = 0;
++
++ if ((mesh_sk = lookup_socket(sk)) == NULL)
++ return -ENODATA;
++
++ if (put_user(mesh_sk->ttl, (unsigned char*) user))
++ return -EFAULT;
++
++ /* netfilter wrapper does the copy to user of len */
++ *len = sizeof(unsigned char);
++
++ return rc;
++}
++
++static int do_mesh_set_ctl(struct sock *sk, int optval, void __user *user,
++ unsigned int len)
++{
++ return do_mesh_set_mesh_ttl(sk, user, len);
++}
++
++static int do_mesh_get_ctl(struct sock *sk, int optval, void __user *user,
++ int *len)
++{
++ return do_mesh_get_mesh_ttl(sk, user, len);
++}
++
++static unsigned char get_sock_mesh_ttl(struct sock *sk)
++{
++ struct mesh_sock *mesh_sk;
++
++ mesh_sk = lookup_socket(sk);
++
++ /* zero ttl results in using the network interface default */
++ return mesh_sk ? mesh_sk->ttl : 0;
++}
++
++static struct mesh_options mesh_opts =
++{
++ .get_sock_ttl = get_sock_mesh_ttl,
++};
++
++static struct nf_sockopt_ops mesh_sockopt_ops =
++{
++ .pf = PF_INET,
++ .set_optmin = MESH_SO_BASE_CTL,
++ .set_optmax = MESH_SO_BASE_CTL + 1,
++ .set = do_mesh_set_ctl,
++ .get_optmin = MESH_SO_BASE_CTL,
++ .get_optmax = MESH_SO_BASE_CTL + 1,
++ .get = do_mesh_get_ctl,
++};
++
++static int __init mesh_opts_init(void)
++{
++ int ret;
++
++ if ((ret = nf_register_sockopt(&mesh_sockopt_ops)) < 0) {
++ return ret;
++ }
++ libertas_register_mesh_opts(&mesh_opts);
++ return ret;
++}
++
++static void __exit mesh_opts_fini(void)
++{
++ nf_unregister_sockopt(&mesh_sockopt_ops);
++ libertas_unregister_mesh_opts(&mesh_opts);
++}
++
++module_init(mesh_opts_init);
++module_exit(mesh_opts_fini);
++MODULE_LICENSE("GPL");
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/mesh_opts.h linux-2.6.22-300/drivers/net/wireless/libertas/mesh_opts.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/mesh_opts.h 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.22-300/drivers/net/wireless/libertas/mesh_opts.h 2008-06-05 18:10:06.000000000 -0400
+@@ -0,0 +1,5 @@
++
++struct mesh_options {
++ unsigned char (*get_sock_ttl)(struct sock*);
++};
++
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/persistcfg.c linux-2.6.22-300/drivers/net/wireless/libertas/persistcfg.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/persistcfg.c 1969-12-31 19:00:00.000000000 -0500
++++ linux-2.6.22-300/drivers/net/wireless/libertas/persistcfg.c 2008-06-05 18:10:06.000000000 -0400
+@@ -0,0 +1,453 @@
++#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)->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, "0x%x\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)->priv;
++ struct cmd_ds_mesh_config cmd;
++ uint32_t datum;
++ int ret;
++
++ memset(&cmd, 0, sizeof(cmd));
++ ret = sscanf(buf, "%x", &datum);
++ if (ret != 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, "0x%x\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)->priv;
++ struct cmd_ds_mesh_config cmd;
++ uint32_t datum;
++ int ret;
++
++ memset(&cmd, 0, sizeof(cmd));
++ ret = sscanf(buf, "%x", &datum);
++ if (ret != 1)
++ 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, "0x%x\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)->priv;
++ struct cmd_ds_mesh_config cmd;
++ uint16_t datum;
++ int ret;
++
++ memset(&cmd, 0, sizeof(cmd));
++ ret = sscanf(buf, "%hx", &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) {
++ printk(KERN_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)->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->hdr.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)->priv;
++ uint32_t datum;
++ int ret;
++
++ memset(&cmd, 0, sizeof(cmd));
++ ret = sscanf(buf, "%x", &datum);
++ if (ret != 1)
++ 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)->priv;
++ uint32_t datum;
++ int ret;
++
++ memset(&cmd, 0, sizeof(cmd));
++ ret = sscanf(buf, "%x", &datum);
++ if (ret != 1)
++ 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)->priv;
++ uint32_t datum;
++ int ret;
++
++ memset(&cmd, 0, sizeof(cmd));
++ ret = sscanf(buf, "%x", &datum);
++ if (ret != 1)
++ 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 -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/README linux-2.6.22-300/drivers/net/wireless/libertas/README
+--- linux-2.6.22-250/drivers/net/wireless/libertas/README 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/README 2008-06-05 18:10:06.000000000 -0400
+@@ -195,45 +195,33 @@ setuserscan
+
+ where [ARGS]:
+
+- chan=[chan#][band][mode] where band is [a,b,g] and mode is
+- blank for active or 'p' for passive
+ bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan
+ ssid="[SSID]" specify a SSID filter for the scan
+ keep=[0 or 1] keep the previous scan results (1), discard (0)
+ dur=[scan time] time to scan for each channel in milliseconds
+- probes=[#] number of probe requests to send on each chan
+ type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any)
+
+- Any combination of the above arguments can be supplied on the command line.
+- If the chan token is absent, a full channel scan will be completed by
+- the driver. If the dur or probes tokens are absent, the driver default
+- setting will be used. The bssid and ssid fields, if blank,
+- will produce an unfiltered scan. The type field will default to 3 (Any)
+- and the keep field will default to 0 (Discard).
++ Any combination of the above arguments can be supplied on the command
++ line. If dur tokens are absent, the driver default setting will be used.
++ The bssid and ssid fields, if blank, will produce an unfiltered scan.
++ The type field will default to 3 (Any) and the keep field will default
++ to 0 (Discard).
+
+ Examples:
+- 1) Perform an active scan on channels 1, 6, and 11 in the 'g' band:
+- echo "chan=1g,6g,11g" > setuserscan
++ 1) Perform a passive scan on all channels for 20 ms per channel:
++ echo "dur=20" > setuserscan
+
+- 2) Perform a passive scan on channel 11 for 20 ms:
+- echo "chan=11gp dur=20" > setuserscan
++ 2) Perform an active scan for a specific SSID:
++ echo "ssid="TestAP"" > setuserscan
+
+- 3) Perform an active scan on channels 1, 6, and 11; and a passive scan on
+- channel 36 in the 'a' band:
+-
+- echo "chan=1g,6g,11g,36ap" > setuserscan
+-
+- 4) Perform an active scan on channel 6 and 36 for a specific SSID:
+- echo "chan=6g,36a ssid="TestAP"" > setuserscan
+-
+- 5) Scan all available channels (B/G, A bands) for a specific BSSID, keep
++ 3) Scan all available channels (B/G, A bands) for a specific BSSID, keep
+ the current scan table intact, update existing or append new scan data:
+ echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan
+
+- 6) Scan channel 6, for all infrastructure networks, sending two probe
+- requests. Keep the previous scan table intact. Update any duplicate
+- BSSID/SSID matches with the new scan data:
+- echo "chan=6g type=1 probes=2 keep=1" > setuserscan
++ 4) Scan for all infrastructure networks.
++ Keep the previous scan table intact. Update any duplicate BSSID/SSID
++ matches with the new scan data:
++ echo "type=1 keep=1" > setuserscan
+
+ All entries in the scan table (not just the new scan data when keep=1)
+ will be displayed upon completion by use of the getscantable ioctl.
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/rx.c linux-2.6.22-300/drivers/net/wireless/libertas/rx.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/rx.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/rx.c 2008-06-05 18:10:06.000000000 -0400
+@@ -35,133 +35,114 @@ struct rx80211packethdr {
+ void *eth80211_hdr;
+ } __attribute__ ((packed));
+
+-static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb);
++static int process_rxed_802_11_packet(struct lbs_private *priv,
++ struct sk_buff *skb);
+
+ /**
+ * @brief This function computes the avgSNR .
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @return avgSNR
+ */
+-static u8 wlan_getavgsnr(wlan_private * priv)
++static u8 lbs_getavgsnr(struct lbs_private *priv)
+ {
+ u8 i;
+ u16 temp = 0;
+- wlan_adapter *adapter = priv->adapter;
+- if (adapter->numSNRNF == 0)
++ if (priv->numSNRNF == 0)
+ return 0;
+- for (i = 0; i < adapter->numSNRNF; i++)
+- temp += adapter->rawSNR[i];
+- return (u8) (temp / adapter->numSNRNF);
++ for (i = 0; i < priv->numSNRNF; i++)
++ temp += priv->rawSNR[i];
++ return (u8) (temp / priv->numSNRNF);
+
+ }
+
+ /**
+ * @brief This function computes the AvgNF
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @return AvgNF
+ */
+-static u8 wlan_getavgnf(wlan_private * priv)
++static u8 lbs_getavgnf(struct lbs_private *priv)
+ {
+ u8 i;
+ u16 temp = 0;
+- wlan_adapter *adapter = priv->adapter;
+- if (adapter->numSNRNF == 0)
++ if (priv->numSNRNF == 0)
+ return 0;
+- for (i = 0; i < adapter->numSNRNF; i++)
+- temp += adapter->rawNF[i];
+- return (u8) (temp / adapter->numSNRNF);
++ for (i = 0; i < priv->numSNRNF; i++)
++ temp += priv->rawNF[i];
++ return (u8) (temp / priv->numSNRNF);
+
+ }
+
+ /**
+ * @brief This function save the raw SNR/NF to our internel buffer
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param prxpd A pointer to rxpd structure of received packet
+ * @return n/a
+ */
+-static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd)
++static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd)
+ {
+- wlan_adapter *adapter = priv->adapter;
+- if (adapter->numSNRNF < adapter->data_avg_factor)
+- adapter->numSNRNF++;
+- adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr;
+- adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf;
+- adapter->nextSNRNF++;
+- if (adapter->nextSNRNF >= adapter->data_avg_factor)
+- adapter->nextSNRNF = 0;
++ if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
++ priv->numSNRNF++;
++ priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr;
++ priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf;
++ priv->nextSNRNF++;
++ if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
++ priv->nextSNRNF = 0;
+ return;
+ }
+
+ /**
+ * @brief This function computes the RSSI in received packet.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param prxpd A pointer to rxpd structure of received packet
+ * @return n/a
+ */
+-static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd)
++static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd)
+ {
+- wlan_adapter *adapter = priv->adapter;
+
+ lbs_deb_enter(LBS_DEB_RX);
+
+ lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf);
+ lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n",
+- adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+- adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
++ priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
++ priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+- adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
+- adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
+- wlan_save_rawSNRNF(priv, p_rx_pd);
++ priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
++ priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
++ lbs_save_rawSNRNF(priv, p_rx_pd);
+
+- adapter->rxpd_rate = p_rx_pd->rx_rate;
+-
+- adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE;
+- adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE;
++ priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE;
++ priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE;
+ lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",
+- adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+- adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
++ priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
++ priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+- adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] =
+- CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+- adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+-
+- adapter->RSSI[TYPE_RXPD][TYPE_AVG] =
+- CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+- adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
++ priv->RSSI[TYPE_RXPD][TYPE_NOAVG] =
++ CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG],
++ priv->NF[TYPE_RXPD][TYPE_NOAVG]);
++
++ priv->RSSI[TYPE_RXPD][TYPE_AVG] =
++ CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
++ priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+ lbs_deb_leave(LBS_DEB_RX);
+ }
+
+-void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
+-{
+- lbs_deb_rx("skb->data %p\n", skb->data);
+-
+- if (priv->mesh_dev && IS_MESH_FRAME(skb))
+- skb->protocol = eth_type_trans(skb, priv->mesh_dev);
+- else
+- skb->protocol = eth_type_trans(skb, priv->dev);
+- skb->ip_summed = CHECKSUM_UNNECESSARY;
+-
+- netif_rx(skb);
+-}
+-
+ /**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+- * @param priv A pointer to wlan_private
++ * @param priv A pointer to struct lbs_private
+ * @param skb A pointer to skb which includes the received packet
+ * @return 0 or -1
+ */
+-int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
++int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+-
++ struct net_device *dev = priv->dev;
+ struct rxpackethdr *p_rx_pkt;
+ struct rxpd *p_rx_pd;
+
+@@ -172,21 +153,17 @@ int libertas_process_rxed_packet(wlan_pr
+
+ lbs_deb_enter(LBS_DEB_RX);
+
+- if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH)
+- lbs_dbg_hex("RX packet: ", skb->data,
+- min_t(unsigned int, skb->len, 100));
++ skb->ip_summed = CHECKSUM_NONE;
+
+- if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
++ if (priv->monitormode != LBS_MONITOR_OFF)
+ return process_rxed_802_11_packet(priv, skb);
+
+ p_rx_pkt = (struct rxpackethdr *) skb->data;
+ p_rx_pd = &p_rx_pkt->rx_pd;
+- if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
+- SET_MESH_FRAME(skb);
+- else
+- UNSET_MESH_FRAME(skb);
++ if (priv->mesh_dev && (p_rx_pd->rx_control & RxPD_MESH_FRAME))
++ dev = priv->mesh_dev;
+
+- lbs_dbg_hex("RX Data: Before chop rxpd", skb->data,
++ lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
+ min_t(unsigned int, skb->len, 100));
+
+ if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+@@ -210,9 +187,9 @@ int libertas_process_rxed_packet(wlan_pr
+ lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
+ skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+
+- lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
++ lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
+ sizeof(p_rx_pkt->eth803_hdr.dest_addr));
+- lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
++ lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
+ sizeof(p_rx_pkt->eth803_hdr.src_addr));
+
+ if (memcmp(&p_rx_pkt->rfc1042_hdr,
+@@ -244,7 +221,7 @@ int libertas_process_rxed_packet(wlan_pr
+ */
+ hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
+ } else {
+- lbs_dbg_hex("RX Data: LLC/SNAP",
++ lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP",
+ (u8 *) & p_rx_pkt->rfc1042_hdr,
+ sizeof(p_rx_pkt->rfc1042_hdr));
+
+@@ -260,23 +237,24 @@ int libertas_process_rxed_packet(wlan_pr
+ /* Take the data rate from the rxpd structure
+ * only if the rate is auto
+ */
+- if (adapter->is_datarate_auto)
+- adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate);
++ if (priv->auto_rate)
++ priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
+
+- wlan_compute_rssi(priv, p_rx_pd);
++ lbs_compute_rssi(priv, p_rx_pd);
+
+ lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+
+- libertas_upload_rx_packet(priv, skb);
++ skb->protocol = eth_type_trans(skb, dev);
++ netif_rx(skb);
+
+ ret = 0;
+ done:
+ lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
+ return ret;
+ }
+-EXPORT_SYMBOL_GPL(libertas_process_rxed_packet);
++EXPORT_SYMBOL_GPL(lbs_process_rxed_packet);
+
+ /**
+ * @brief This function converts Tx/Rx rates from the Marvell WLAN format
+@@ -296,21 +274,22 @@ static u8 convert_mv_rate_to_radiotap(u8
+ return 11;
+ case 3: /* 11 Mbps */
+ return 22;
+- case 4: /* 6 Mbps */
++ /* case 4: reserved */
++ case 5: /* 6 Mbps */
+ return 12;
+- case 5: /* 9 Mbps */
++ case 6: /* 9 Mbps */
+ return 18;
+- case 6: /* 12 Mbps */
++ case 7: /* 12 Mbps */
+ return 24;
+- case 7: /* 18 Mbps */
++ case 8: /* 18 Mbps */
+ return 36;
+- case 8: /* 24 Mbps */
++ case 9: /* 24 Mbps */
+ return 48;
+- case 9: /* 36 Mbps */
++ case 10: /* 36 Mbps */
+ return 72;
+- case 10: /* 48 Mbps */
++ case 11: /* 48 Mbps */
+ return 96;
+- case 11: /* 54 Mbps */
++ case 12: /* 54 Mbps */
+ return 108;
+ }
+ lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate);
+@@ -321,13 +300,13 @@ static u8 convert_mv_rate_to_radiotap(u8
+ * @brief This function processes a received 802.11 packet and forwards it
+ * to kernel/upper layer
+ *
+- * @param priv A pointer to wlan_private
++ * @param priv A pointer to struct lbs_private
+ * @param skb A pointer to skb which includes the received packet
+ * @return 0 or -1
+ */
+-static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
++static int process_rxed_802_11_packet(struct lbs_private *priv,
++ struct sk_buff *skb)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ struct rx80211packethdr *p_rx_pkt;
+@@ -340,12 +319,13 @@ static int process_rxed_802_11_packet(wl
+ p_rx_pkt = (struct rx80211packethdr *) skb->data;
+ prxpd = &p_rx_pkt->rx_pd;
+
+- // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
++ // lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
+
+ if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+- lbs_deb_rx("rx err: frame received wit bad length\n");
++ lbs_deb_rx("rx err: frame received with bad length\n");
+ priv->stats.rx_length_errors++;
+- ret = 0;
++ ret = -EINVAL;
++ kfree(skb);
+ goto done;
+ }
+
+@@ -361,85 +341,60 @@ static int process_rxed_802_11_packet(wl
+ skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+
+ /* create the exported radio header */
+- switch (priv->adapter->radiomode) {
+- case WLAN_RADIOMODE_NONE:
+- /* no radio header */
+- /* chop the rxpd */
+- skb_pull(skb, sizeof(struct rxpd));
+- break;
+-
+- case WLAN_RADIOMODE_RADIOTAP:
+- /* radiotap header */
+- radiotap_hdr.hdr.it_version = 0;
+- /* XXX must check this value for pad */
+- radiotap_hdr.hdr.it_pad = 0;
+- radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr);
+- radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT;
+- /* unknown values */
+- radiotap_hdr.flags = 0;
+- radiotap_hdr.chan_freq = 0;
+- radiotap_hdr.chan_flags = 0;
+- radiotap_hdr.antenna = 0;
+- /* known values */
+- radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
+- /* XXX must check no carryout */
+- radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
+- radiotap_hdr.rx_flags = 0;
+- if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK)))
+- radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
+- //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
+-
+- // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100));
+-
+- /* chop the rxpd */
+- skb_pull(skb, sizeof(struct rxpd));
+-
+- /* add space for the new radio header */
+- if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
+- pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0,
+- GFP_ATOMIC)) {
+- lbs_pr_alert("%s: couldn't pskb_expand_head\n",
+- __func__);
+- }
+-
+- pradiotap_hdr =
+- (struct rx_radiotap_hdr *)skb_push(skb,
+- sizeof(struct
+- rx_radiotap_hdr));
+- memcpy(pradiotap_hdr, &radiotap_hdr,
+- sizeof(struct rx_radiotap_hdr));
+- //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100));
+- break;
+-
+- default:
+- /* unknown header */
+- lbs_pr_alert("Unknown radiomode %i\n",
+- priv->adapter->radiomode);
+- /* don't export any header */
+- /* chop the rxpd */
+- skb_pull(skb, sizeof(struct rxpd));
+- break;
++
++ /* radiotap header */
++ radiotap_hdr.hdr.it_version = 0;
++ /* XXX must check this value for pad */
++ radiotap_hdr.hdr.it_pad = 0;
++ radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
++ radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
++ /* unknown values */
++ radiotap_hdr.flags = 0;
++ radiotap_hdr.chan_freq = 0;
++ radiotap_hdr.chan_flags = 0;
++ radiotap_hdr.antenna = 0;
++ /* known values */
++ radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
++ /* XXX must check no carryout */
++ radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
++ radiotap_hdr.rx_flags = 0;
++ if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK)))
++ radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
++ //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
++
++ /* chop the rxpd */
++ skb_pull(skb, sizeof(struct rxpd));
++
++ /* add space for the new radio header */
++ if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
++ pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) {
++ lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__);
++ ret = -ENOMEM;
++ kfree_skb(skb);
++ goto done;
+ }
+
++ pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr));
++ memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr));
++
+ /* Take the data rate from the rxpd structure
+ * only if the rate is auto
+ */
+- if (adapter->is_datarate_auto) {
+- adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate);
+- }
++ if (priv->auto_rate)
++ priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
+
+- wlan_compute_rssi(priv, prxpd);
++ lbs_compute_rssi(priv, prxpd);
+
+ lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+
+- libertas_upload_rx_packet(priv, skb);
++ skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
++ netif_rx(skb);
+
+ ret = 0;
+
+ done:
+- skb->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */
+ lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
+ return ret;
+ }
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/scan.c linux-2.6.22-300/drivers/net/wireless/libertas/scan.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/scan.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/scan.c 2008-06-05 18:10:06.000000000 -0400
+@@ -13,10 +13,13 @@
+ #include <net/ieee80211.h>
+ #include <net/iw_handler.h>
+
++#include <asm/unaligned.h>
++
+ #include "host.h"
+ #include "decl.h"
+ #include "dev.h"
+ #include "scan.h"
++#include "join.h"
+
+ //! Approximate amount of data needed to pass a scan result back to iwlist
+ #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
+@@ -36,9 +39,8 @@
+ //! Memory needed to store a max number/size SSID TLV for a firmware scan
+ #define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset))
+
+-//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max
+-#define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config) \
+- + sizeof(struct mrvlietypes_numprobes) \
++//! Maximum memory needed for a lbs_scan_cmd_config with all TLVs at max
++#define MAX_SCAN_CFG_ALLOC (sizeof(struct lbs_scan_cmd_config) \
+ + CHAN_TLV_MAX_SIZE \
+ + SSID_TLV_MAX_SIZE)
+
+@@ -62,80 +64,119 @@
+ static const u8 zeromac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const u8 bcastmac[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
++
++
++
++/*********************************************************************/
++/* */
++/* Misc helper functions */
++/* */
++/*********************************************************************/
++
+ static inline void clear_bss_descriptor (struct bss_descriptor * bss)
+ {
+ /* Don't blow away ->list, just BSS data */
+ memset(bss, 0, offsetof(struct bss_descriptor, list));
+ }
+
+-static inline int match_bss_no_security(struct wlan_802_11_security * secinfo,
++/**
++ * @brief Compare two SSIDs
++ *
++ * @param ssid1 A pointer to ssid to compare
++ * @param ssid2 A pointer to ssid to compare
++ *
++ * @return 0: ssid is same, otherwise is different
++ */
++int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
++{
++ if (ssid1_len != ssid2_len)
++ return -1;
++
++ return memcmp(ssid1, ssid2, ssid1_len);
++}
++
++static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
+ struct bss_descriptor * match_bss)
+ {
+ if ( !secinfo->wep_enabled
+ && !secinfo->WPAenabled
+ && !secinfo->WPA2enabled
+- && match_bss->wpa_ie[0] != WPA_IE
+- && match_bss->rsn_ie[0] != WPA2_IE
+- && !match_bss->privacy) {
++ && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC
++ && match_bss->rsn_ie[0] != MFIE_TYPE_RSN
++ && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
+ return 1;
+ }
+ return 0;
+ }
+
+-static inline int match_bss_static_wep(struct wlan_802_11_security * secinfo,
++static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
+ struct bss_descriptor * match_bss)
+ {
+ if ( secinfo->wep_enabled
+ && !secinfo->WPAenabled
+ && !secinfo->WPA2enabled
+- && match_bss->privacy) {
++ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
+ return 1;
+ }
+ return 0;
+ }
+
+-static inline int match_bss_wpa(struct wlan_802_11_security * secinfo,
++static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
+ struct bss_descriptor * match_bss)
+ {
+ if ( !secinfo->wep_enabled
+ && secinfo->WPAenabled
+- && (match_bss->wpa_ie[0] == WPA_IE)
++ && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC)
+ /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+- && bss->privacy */
++ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
++ */
+ ) {
+ return 1;
+ }
+ return 0;
+ }
+
+-static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo,
++static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
+ struct bss_descriptor * match_bss)
+ {
+ if ( !secinfo->wep_enabled
+ && secinfo->WPA2enabled
+- && (match_bss->rsn_ie[0] == WPA2_IE)
++ && (match_bss->rsn_ie[0] == MFIE_TYPE_RSN)
+ /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+- && bss->privacy */
++ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
++ */
+ ) {
+ return 1;
+ }
+ return 0;
+ }
+
+-static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo,
++static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
+ struct bss_descriptor * match_bss)
+ {
+ if ( !secinfo->wep_enabled
+ && !secinfo->WPAenabled
+ && !secinfo->WPA2enabled
+- && (match_bss->wpa_ie[0] != WPA_IE)
+- && (match_bss->rsn_ie[0] != WPA2_IE)
+- && match_bss->privacy) {
++ && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC)
++ && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN)
++ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
+ return 1;
+ }
+ return 0;
+ }
+
++static inline int is_same_network(struct bss_descriptor *src,
++ struct bss_descriptor *dst)
++{
++ /* A network is only a duplicate if the channel, BSSID, and ESSID
++ * all match. We treat all <hidden> with the same BSSID and channel
++ * as one network */
++ return ((src->ssid_len == dst->ssid_len) &&
++ (src->channel == dst->channel) &&
++ !compare_ether_addr(src->bssid, dst->bssid) &&
++ !memcmp(src->ssid, dst->ssid, src->ssid_len));
++}
++
+ /**
+ * @brief Check if a scanned network compatible with the driver settings
+ *
+@@ -149,79 +190,100 @@ static inline int match_bss_dynamic_wep(
+ * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
+ *
+ *
+- * @param adapter A pointer to wlan_adapter
++ * @param priv A pointer to struct lbs_private
+ * @param index Index in scantable to check against current driver settings
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return Index in scantable, or error code if negative
+ */
+-static int is_network_compatible(wlan_adapter * adapter,
++static int is_network_compatible(struct lbs_private *priv,
+ struct bss_descriptor * bss, u8 mode)
+ {
+ int matched = 0;
+
+- lbs_deb_enter(LBS_DEB_ASSOC);
++ lbs_deb_enter(LBS_DEB_SCAN);
+
+ if (bss->mode != mode)
+ goto done;
+
+- if ((matched = match_bss_no_security(&adapter->secinfo, bss))) {
++ if ((matched = match_bss_no_security(&priv->secinfo, bss))) {
+ goto done;
+- } else if ((matched = match_bss_static_wep(&adapter->secinfo, bss))) {
++ } else if ((matched = match_bss_static_wep(&priv->secinfo, bss))) {
+ goto done;
+- } else if ((matched = match_bss_wpa(&adapter->secinfo, bss))) {
++ } else if ((matched = match_bss_wpa(&priv->secinfo, bss))) {
+ lbs_deb_scan(
+- "is_network_compatible() WPA: wpa_ie=%#x "
+- "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
+- "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0],
+- adapter->secinfo.wep_enabled ? "e" : "d",
+- adapter->secinfo.WPAenabled ? "e" : "d",
+- adapter->secinfo.WPA2enabled ? "e" : "d",
+- bss->privacy);
++ "is_network_compatible() WPA: wpa_ie 0x%x "
++ "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
++ "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
++ priv->secinfo.wep_enabled ? "e" : "d",
++ priv->secinfo.WPAenabled ? "e" : "d",
++ priv->secinfo.WPA2enabled ? "e" : "d",
++ (bss->capability & WLAN_CAPABILITY_PRIVACY));
+ goto done;
+- } else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) {
++ } else if ((matched = match_bss_wpa2(&priv->secinfo, bss))) {
+ lbs_deb_scan(
+- "is_network_compatible() WPA2: wpa_ie=%#x "
+- "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
+- "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0],
+- adapter->secinfo.wep_enabled ? "e" : "d",
+- adapter->secinfo.WPAenabled ? "e" : "d",
+- adapter->secinfo.WPA2enabled ? "e" : "d",
+- bss->privacy);
++ "is_network_compatible() WPA2: wpa_ie 0x%x "
++ "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
++ "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
++ priv->secinfo.wep_enabled ? "e" : "d",
++ priv->secinfo.WPAenabled ? "e" : "d",
++ priv->secinfo.WPA2enabled ? "e" : "d",
++ (bss->capability & WLAN_CAPABILITY_PRIVACY));
+ goto done;
+- } else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) {
++ } else if ((matched = match_bss_dynamic_wep(&priv->secinfo, bss))) {
+ lbs_deb_scan(
+ "is_network_compatible() dynamic WEP: "
+- "wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n",
+- bss->wpa_ie[0],
+- bss->rsn_ie[0],
+- bss->privacy);
++ "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
++ bss->wpa_ie[0], bss->rsn_ie[0],
++ (bss->capability & WLAN_CAPABILITY_PRIVACY));
+ goto done;
+ }
+
+ /* bss security settings don't match those configured on card */
+ lbs_deb_scan(
+- "is_network_compatible() FAILED: wpa_ie=%#x "
+- "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s privacy=%#x\n",
++ "is_network_compatible() FAILED: wpa_ie 0x%x "
++ "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
+ bss->wpa_ie[0], bss->rsn_ie[0],
+- adapter->secinfo.wep_enabled ? "e" : "d",
+- adapter->secinfo.WPAenabled ? "e" : "d",
+- adapter->secinfo.WPA2enabled ? "e" : "d",
+- bss->privacy);
++ priv->secinfo.wep_enabled ? "e" : "d",
++ priv->secinfo.WPAenabled ? "e" : "d",
++ priv->secinfo.WPA2enabled ? "e" : "d",
++ (bss->capability & WLAN_CAPABILITY_PRIVACY));
+
+ done:
+- lbs_deb_leave(LBS_DEB_SCAN);
++ lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched);
+ return matched;
+ }
+
++
++
++
++/*********************************************************************/
++/* */
++/* Main scanning support */
++/* */
++/*********************************************************************/
++
++void lbs_scan_worker(struct work_struct *work)
++{
++ struct lbs_private *priv =
++ container_of(work, struct lbs_private, scan_work.work);
++
++ lbs_deb_enter(LBS_DEB_SCAN);
++ lbs_scan_networks(priv, NULL, 0);
++ lbs_deb_leave(LBS_DEB_SCAN);
++}
++
++
+ /**
+ * @brief Create a channel list for the driver to scan based on region info
+ *
++ * Only used from lbs_scan_setup_scan_config()
++ *
+ * Use the driver region/band information to construct a comprehensive list
+ * of channels to scan. This routine is used for any scan that is not
+ * provided a specific channel list to scan.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param scanchanlist Output parameter: resulting channel list to scan
+ * @param filteredscan Flag indicating whether or not a BSSID or SSID filter
+ * is being sent in the command to firmware. Used to
+@@ -231,12 +293,11 @@ done:
+ *
+ * @return void
+ */
+-static void wlan_scan_create_channel_list(wlan_private * priv,
++static int lbs_scan_create_channel_list(struct lbs_private *priv,
+ struct chanscanparamset * scanchanlist,
+ u8 filteredscan)
+ {
+
+- wlan_adapter *adapter = priv->adapter;
+ struct region_channel *scanregion;
+ struct chan_freq_power *cfp;
+ int rgnidx;
+@@ -250,23 +311,24 @@ static void wlan_scan_create_channel_lis
+ * be changed to passive on a per channel basis if restricted by
+ * regulatory requirements (11d or 11h)
+ */
+- scantype = adapter->scantype;
++ scantype = CMD_SCAN_TYPE_ACTIVE;
+
+- for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) {
+- if (priv->adapter->enable11d &&
+- adapter->connect_status != libertas_connected) {
++ 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 (!adapter->universal_channel[rgnidx].valid)
++ if (!priv->universal_channel[rgnidx].valid)
+ continue;
+- scanregion = &adapter->universal_channel[rgnidx];
++ scanregion = &priv->universal_channel[rgnidx];
+
+ /* clear the parsed_region_chan for the first scan */
+- memset(&adapter->parsed_region_chan, 0x00,
+- sizeof(adapter->parsed_region_chan));
++ memset(&priv->parsed_region_chan, 0x00,
++ sizeof(priv->parsed_region_chan));
+ } else {
+- if (!adapter->region_channel[rgnidx].valid)
++ if (!priv->region_channel[rgnidx].valid)
+ continue;
+- scanregion = &adapter->region_channel[rgnidx];
++ scanregion = &priv->region_channel[rgnidx];
+ }
+
+ for (nextchan = 0;
+@@ -274,10 +336,10 @@ static void wlan_scan_create_channel_lis
+
+ cfp = scanregion->CFP + nextchan;
+
+- if (priv->adapter->enable11d) {
++ if (priv->enable11d) {
+ scantype =
+- libertas_get_scan_type_11d(cfp->channel,
+- &adapter->
++ lbs_get_scan_type_11d(cfp->channel,
++ &priv->
+ parsed_region_chan);
+ }
+
+@@ -286,11 +348,11 @@ static void wlan_scan_create_channel_lis
+ case BAND_G:
+ default:
+ scanchanlist[chanidx].radiotype =
+- cmd_scan_radio_type_bg;
++ CMD_SCAN_RADIO_TYPE_BG;
+ break;
+ }
+
+- if (scantype == cmd_scan_type_passive) {
++ if (scantype == CMD_SCAN_TYPE_PASSIVE) {
+ scanchanlist[chanidx].maxscantime =
+ cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME);
+ scanchanlist[chanidx].chanscanmode.passivescan =
+@@ -310,656 +372,373 @@ static void wlan_scan_create_channel_lis
+ }
+ }
+ }
++ return chanidx;
+ }
+
+-/**
+- * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
+- *
+- * Application layer or other functions can invoke wlan_scan_networks
+- * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
+- * This structure is used as the basis of one or many wlan_scan_cmd_config
+- * commands that are sent to the command processing module and sent to
+- * firmware.
+- *
+- * Create a wlan_scan_cmd_config based on the following user supplied
+- * parameters (if present):
+- * - SSID filter
+- * - BSSID filter
+- * - Number of Probes to be sent
+- * - channel list
+- *
+- * If the SSID or BSSID filter is not present, disable/clear the filter.
+- * If the number of probes is not set, use the adapter default setting
+- * Qualify the channel
+- *
+- * @param priv A pointer to wlan_private structure
+- * @param puserscanin NULL or pointer to scan configuration parameters
+- * @param ppchantlvout Output parameter: Pointer to the start of the
+- * channel TLV portion of the output scan config
+- * @param pscanchanlist Output parameter: Pointer to the resulting channel
+- * list to scan
+- * @param pmaxchanperscan Output parameter: Number of channels to scan for
+- * each issuance of the firmware scan command
+- * @param pfilteredscan Output parameter: Flag indicating whether or not
+- * a BSSID or SSID filter is being sent in the
+- * command to firmware. Used to increase the number
+- * of channels sent in a scan command and to
+- * disable the firmware channel scan filter.
+- * @param pscancurrentonly Output parameter: Flag indicating whether or not
+- * we are only scanning our current active channel
++
++/*
++ * Add SSID TLV of the form:
+ *
+- * @return resulting scan configuration
++ * TLV-ID SSID 00 00
++ * length 06 00
++ * ssid 4d 4e 54 45 53 54
+ */
+-static struct wlan_scan_cmd_config *
+-wlan_scan_setup_scan_config(wlan_private * priv,
+- const struct wlan_ioctl_user_scan_cfg * puserscanin,
+- struct mrvlietypes_chanlistparamset ** ppchantlvout,
+- struct chanscanparamset * pscanchanlist,
+- int *pmaxchanperscan,
+- u8 * pfilteredscan,
+- u8 * pscancurrentonly)
+-{
+- wlan_adapter *adapter = priv->adapter;
+- struct mrvlietypes_numprobes *pnumprobestlv;
+- struct mrvlietypes_ssidparamset *pssidtlv;
+- struct wlan_scan_cmd_config * pscancfgout = NULL;
+- u8 *ptlvpos;
+- u16 numprobes;
+- int chanidx;
+- int scantype;
+- int scandur;
+- int channel;
+- int radiotype;
+-
+- pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
+- if (pscancfgout == NULL)
+- goto out;
+-
+- /* The tlvbufferlen is calculated for each scan command. The TLVs added
+- * in this routine will be preserved since the routine that sends
+- * the command will append channelTLVs at *ppchantlvout. The difference
+- * between the *ppchantlvout and the tlvbuffer start will be used
+- * to calculate the size of anything we add in this routine.
+- */
+- pscancfgout->tlvbufferlen = 0;
+-
+- /* Running tlv pointer. Assigned to ppchantlvout at end of function
+- * so later routines know where channels can be added to the command buf
+- */
+- ptlvpos = pscancfgout->tlvbuffer;
+-
+- /*
+- * Set the initial scan paramters for progressive scanning. If a specific
+- * BSSID or SSID is used, the number of channels in the scan command
+- * will be increased to the absolute maximum
+- */
+- *pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD;
+-
+- /* Initialize the scan as un-filtered by firmware, set to TRUE below if
+- * a SSID or BSSID filter is sent in the command
+- */
+- *pfilteredscan = 0;
+-
+- /* Initialize the scan as not being only on the current channel. If
+- * the channel list is customized, only contains one channel, and
+- * is the active channel, this is set true and data flow is not halted.
+- */
+- *pscancurrentonly = 0;
+-
+- if (puserscanin) {
+-
+- /* Set the bss type scan filter, use adapter setting if unset */
+- pscancfgout->bsstype =
+- (puserscanin->bsstype ? puserscanin->bsstype : adapter->
+- scanmode);
+-
+- /* Set the number of probes to send, use adapter setting if unset */
+- numprobes = (puserscanin->numprobes ? puserscanin->numprobes :
+- adapter->scanprobes);
+-
+- /*
+- * Set the BSSID filter to the incoming configuration,
+- * if non-zero. If not set, it will remain disabled (all zeros).
+- */
+- memcpy(pscancfgout->bssid, puserscanin->bssid,
+- sizeof(pscancfgout->bssid));
+-
+- if (puserscanin->ssid_len) {
+- pssidtlv =
+- (struct mrvlietypes_ssidparamset *) pscancfgout->
+- tlvbuffer;
+- pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
+- pssidtlv->header.len = cpu_to_le16(puserscanin->ssid_len);
+- memcpy(pssidtlv->ssid, puserscanin->ssid,
+- puserscanin->ssid_len);
+- ptlvpos += sizeof(pssidtlv->header) + puserscanin->ssid_len;
+- }
+-
+- /*
+- * The default number of channels sent in the command is low to
+- * ensure the response buffer from the firmware does not truncate
+- * scan results. That is not an issue with an SSID or BSSID
+- * filter applied to the scan results in the firmware.
+- */
+- if ( puserscanin->ssid_len
+- || (compare_ether_addr(pscancfgout->bssid, &zeromac[0]) != 0)) {
+- *pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
+- *pfilteredscan = 1;
+- }
+- } else {
+- pscancfgout->bsstype = adapter->scanmode;
+- numprobes = adapter->scanprobes;
+- }
+-
+- /* If the input config or adapter has the number of Probes set, add tlv */
+- if (numprobes) {
+- pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos;
+- pnumprobestlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
+- pnumprobestlv->header.len = cpu_to_le16(2);
+- pnumprobestlv->numprobes = cpu_to_le16(numprobes);
+-
+- ptlvpos += sizeof(*pnumprobestlv);
+- }
+-
+- /*
+- * Set the output for the channel TLV to the address in the tlv buffer
+- * past any TLVs that were added in this fuction (SSID, numprobes).
+- * channel TLVs will be added past this for each scan command, preserving
+- * the TLVs that were previously added.
+- */
+- *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
+-
+- if (puserscanin && puserscanin->chanlist[0].channumber) {
+-
+- lbs_deb_scan("Scan: Using supplied channel list\n");
+-
+- for (chanidx = 0;
+- chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
+- && puserscanin->chanlist[chanidx].channumber; chanidx++) {
+-
+- channel = puserscanin->chanlist[chanidx].channumber;
+- (pscanchanlist + chanidx)->channumber = channel;
+-
+- radiotype = puserscanin->chanlist[chanidx].radiotype;
+- (pscanchanlist + chanidx)->radiotype = radiotype;
+-
+- scantype = puserscanin->chanlist[chanidx].scantype;
+-
+- if (scantype == cmd_scan_type_passive) {
+- (pscanchanlist +
+- chanidx)->chanscanmode.passivescan = 1;
+- } else {
+- (pscanchanlist +
+- chanidx)->chanscanmode.passivescan = 0;
+- }
+-
+- if (puserscanin->chanlist[chanidx].scantime) {
+- scandur =
+- puserscanin->chanlist[chanidx].scantime;
+- } else {
+- if (scantype == cmd_scan_type_passive) {
+- scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+- } else {
+- scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+- }
+- }
+-
+- (pscanchanlist + chanidx)->minscantime =
+- cpu_to_le16(scandur);
+- (pscanchanlist + chanidx)->maxscantime =
+- cpu_to_le16(scandur);
+- }
++static int lbs_scan_add_ssid_tlv(u8 *tlv,
++ const struct lbs_ioctl_user_scan_cfg *user_cfg)
++{
++ struct mrvlietypes_ssidparamset *ssid_tlv =
++ (struct mrvlietypes_ssidparamset *)tlv;
++ ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
++ ssid_tlv->header.len = cpu_to_le16(user_cfg->ssid_len);
++ memcpy(ssid_tlv->ssid, user_cfg->ssid, user_cfg->ssid_len);
++ return sizeof(ssid_tlv->header) + user_cfg->ssid_len;
++}
+
+- /* Check if we are only scanning the current channel */
+- if ((chanidx == 1) && (puserscanin->chanlist[0].channumber
+- ==
+- priv->adapter->curbssparams.channel)) {
+- *pscancurrentonly = 1;
+- lbs_deb_scan("Scan: Scanning current channel only");
+- }
+
+- } else {
+- lbs_deb_scan("Scan: Creating full region channel list\n");
+- wlan_scan_create_channel_list(priv, pscanchanlist,
+- *pfilteredscan);
+- }
++/*
++ * Add CHANLIST TLV of the form
++ *
++ * TLV-ID CHANLIST 01 01
++ * length 5b 00
++ * channel 1 00 01 00 00 00 64 00
++ * radio type 00
++ * channel 01
++ * scan type 00
++ * min scan time 00 00
++ * max scan time 64 00
++ * channel 2 00 02 00 00 00 64 00
++ * channel 3 00 03 00 00 00 64 00
++ * channel 4 00 04 00 00 00 64 00
++ * channel 5 00 05 00 00 00 64 00
++ * channel 6 00 06 00 00 00 64 00
++ * channel 7 00 07 00 00 00 64 00
++ * channel 8 00 08 00 00 00 64 00
++ * channel 9 00 09 00 00 00 64 00
++ * channel 10 00 0a 00 00 00 64 00
++ * channel 11 00 0b 00 00 00 64 00
++ * channel 12 00 0c 00 00 00 64 00
++ * channel 13 00 0d 00 00 00 64 00
++ *
++ */
++static int lbs_scan_add_chanlist_tlv(u8 *tlv,
++ struct chanscanparamset *chan_list,
++ int chan_count)
++{
++ size_t size = sizeof(struct chanscanparamset) * chan_count;
++ struct mrvlietypes_chanlistparamset *chan_tlv =
++ (struct mrvlietypes_chanlistparamset *) tlv;
+
+-out:
+- return pscancfgout;
++ chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
++ memcpy(chan_tlv->chanscanparam, chan_list, size);
++ chan_tlv->header.len = cpu_to_le16(size);
++ return sizeof(chan_tlv->header) + size;
+ }
+
+-/**
+- * @brief Construct and send multiple scan config commands to the firmware
++
++/*
++ * Add RATES TLV of the form
+ *
+- * Previous routines have created a wlan_scan_cmd_config with any requested
+- * TLVs. This function splits the channel TLV into maxchanperscan lists
+- * and sends the portion of the channel TLV along with the other TLVs
+- * to the wlan_cmd routines for execution in the firmware.
+- *
+- * @param priv A pointer to wlan_private structure
+- * @param maxchanperscan Maximum number channels to be included in each
+- * scan command sent to firmware
+- * @param filteredscan Flag indicating whether or not a BSSID or SSID
+- * filter is being used for the firmware command
+- * scan command sent to firmware
+- * @param pscancfgout Scan configuration used for this scan.
+- * @param pchantlvout Pointer in the pscancfgout where the channel TLV
+- * should start. This is past any other TLVs that
+- * must be sent down in each firmware command.
+- * @param pscanchanlist List of channels to scan in maxchanperscan segments
++ * TLV-ID RATES 01 00
++ * length 0e 00
++ * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c
+ *
+- * @return 0 or error return otherwise
++ * The rates are in lbs_bg_rates[], but for the 802.11b
++ * rates the high bit isn't set.
+ */
+-static int wlan_scan_channel_list(wlan_private * priv,
+- int maxchanperscan,
+- u8 filteredscan,
+- struct wlan_scan_cmd_config * pscancfgout,
+- struct mrvlietypes_chanlistparamset * pchantlvout,
+- struct chanscanparamset * pscanchanlist,
+- const struct wlan_ioctl_user_scan_cfg * puserscanin,
+- int full_scan)
+-{
+- struct chanscanparamset *ptmpchan;
+- struct chanscanparamset *pstartchan;
+- u8 scanband;
+- int doneearly;
+- int tlvidx;
+- int ret = 0;
+- int scanned = 0;
+- union iwreq_data wrqu;
+-
+- lbs_deb_enter(LBS_DEB_ASSOC);
+-
+- if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) {
+- lbs_deb_scan("Scan: Null detect: %p, %p, %p\n",
+- pscancfgout, pchantlvout, pscanchanlist);
+- return -1;
+- }
+-
+- pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+-
+- /* Set the temp channel struct pointer to the start of the desired list */
+- ptmpchan = pscanchanlist;
+-
+- if (priv->adapter->last_scanned_channel && !puserscanin)
+- ptmpchan += priv->adapter->last_scanned_channel;
+-
+- /* Loop through the desired channel list, sending a new firmware scan
+- * commands for each maxchanperscan channels (or for 1,6,11 individually
+- * if configured accordingly)
+- */
+- while (ptmpchan->channumber) {
+-
+- tlvidx = 0;
+- pchantlvout->header.len = 0;
+- scanband = ptmpchan->radiotype;
+- pstartchan = ptmpchan;
+- doneearly = 0;
+-
+- /* Construct the channel TLV for the scan command. Continue to
+- * insert channel TLVs until:
+- * - the tlvidx hits the maximum configured per scan command
+- * - the next channel to insert is 0 (end of desired channel list)
+- * - doneearly is set (controlling individual scanning of 1,6,11)
+- */
+- while (tlvidx < maxchanperscan && ptmpchan->channumber
+- && !doneearly && scanned < 2) {
+-
+- lbs_deb_scan(
+- "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n",
+- ptmpchan->channumber, ptmpchan->radiotype,
+- ptmpchan->chanscanmode.passivescan,
+- ptmpchan->chanscanmode.disablechanfilt,
+- ptmpchan->maxscantime);
+-
+- /* Copy the current channel TLV to the command being prepared */
+- memcpy(pchantlvout->chanscanparam + tlvidx,
+- ptmpchan, sizeof(pchantlvout->chanscanparam));
+-
+- /* Increment the TLV header length by the size appended */
+- /* Ew, it would be _so_ nice if we could just declare the
+- variable little-endian and let GCC handle it for us */
+- pchantlvout->header.len =
+- cpu_to_le16(le16_to_cpu(pchantlvout->header.len) +
+- sizeof(pchantlvout->chanscanparam));
+-
+- /*
+- * The tlv buffer length is set to the number of bytes of the
+- * between the channel tlv pointer and the start of the
+- * tlv buffer. This compensates for any TLVs that were appended
+- * before the channel list.
+- */
+- pscancfgout->tlvbufferlen = ((u8 *) pchantlvout
+- - pscancfgout->tlvbuffer);
+-
+- /* Add the size of the channel tlv header and the data length */
+- pscancfgout->tlvbufferlen +=
+- (sizeof(pchantlvout->header)
+- + le16_to_cpu(pchantlvout->header.len));
+-
+- /* Increment the index to the channel tlv we are constructing */
+- tlvidx++;
+-
+- doneearly = 0;
+-
+- /* Stop the loop if the *current* channel is in the 1,6,11 set
+- * and we are not filtering on a BSSID or SSID.
+- */
+- if (!filteredscan && (ptmpchan->channumber == 1
+- || ptmpchan->channumber == 6
+- || ptmpchan->channumber == 11)) {
+- doneearly = 1;
+- }
+-
+- /* Increment the tmp pointer to the next channel to be scanned */
+- ptmpchan++;
+- scanned++;
+-
+- /* Stop the loop if the *next* channel is in the 1,6,11 set.
+- * This will cause it to be the only channel scanned on the next
+- * interation
+- */
+- if (!filteredscan && (ptmpchan->channumber == 1
+- || ptmpchan->channumber == 6
+- || ptmpchan->channumber == 11)) {
+- doneearly = 1;
+- }
+- }
+-
+- /* Send the scan command to the firmware with the specified cfg */
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0,
+- 0, 0, pscancfgout);
+- if (scanned >= 2 && !full_scan) {
+- ret = 0;
+- goto done;
+- }
+- scanned = 0;
+- }
++static int lbs_scan_add_rates_tlv(u8 *tlv)
++{
++ int i;
++ struct mrvlietypes_ratesparamset *rate_tlv =
++ (struct mrvlietypes_ratesparamset *) tlv;
++
++ rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
++ tlv += sizeof(rate_tlv->header);
++ for (i = 0; i < MAX_RATES; i++) {
++ *tlv = lbs_bg_rates[i];
++ if (*tlv == 0)
++ break;
++ /* This code makes sure that the 802.11b rates (1 MBit/s, 2
++ MBit/s, 5.5 MBit/s and 11 MBit/s get's the high bit set.
++ Note that the values are MBit/s * 2, to mark them as
++ basic rates so that the firmware likes it better */
++ if (*tlv == 0x02 || *tlv == 0x04 ||
++ *tlv == 0x0b || *tlv == 0x16)
++ *tlv |= 0x80;
++ tlv++;
++ }
++ rate_tlv->header.len = cpu_to_le16(i);
++ return sizeof(rate_tlv->header) + i;
++}
+
+-done:
+- priv->adapter->last_scanned_channel = ptmpchan->channumber;
+
+- /* Tell userspace the scan table has been updated */
+- memset(&wrqu, 0, sizeof(union iwreq_data));
+- wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
++/*
++ * Generate the CMD_802_11_SCAN command with the proper tlv
++ * for a bunch of channels.
++ */
++static int lbs_do_scan(struct lbs_private *priv,
++ u8 bsstype,
++ struct chanscanparamset *chan_list,
++ int chan_count,
++ const struct lbs_ioctl_user_scan_cfg *user_cfg)
++{
++ int ret = -ENOMEM;
++ struct lbs_scan_cmd_config *scan_cmd;
++ u8 *tlv; /* pointer into our current, growing TLV storage area */
++
++ lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, "
++ "chan_count %d",
++ bsstype, chan_list[0].channumber, chan_count);
++
++ /* create the fixed part for scan command */
++ scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
++ if (scan_cmd == NULL)
++ goto out;
++ tlv = scan_cmd->tlvbuffer;
++ if (user_cfg)
++ memcpy(scan_cmd->bssid, user_cfg->bssid, ETH_ALEN);
++ scan_cmd->bsstype = bsstype;
++
++ /* add TLVs */
++ if (user_cfg && user_cfg->ssid_len)
++ tlv += lbs_scan_add_ssid_tlv(tlv, user_cfg);
++ if (chan_list && chan_count)
++ tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count);
++ tlv += lbs_scan_add_rates_tlv(tlv);
++
++ /* This is the final data we are about to send */
++ scan_cmd->tlvbufferlen = tlv - scan_cmd->tlvbuffer;
++ lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, 1+6);
++ lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
++ scan_cmd->tlvbufferlen);
+
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
++ CMD_OPTION_WAITFORRSP, 0, scan_cmd);
++out:
++ kfree(scan_cmd);
+ lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
+ return ret;
+ }
+
+-static void
+-clear_selected_scan_list_entries(wlan_adapter * adapter,
+- const struct wlan_ioctl_user_scan_cfg * scan_cfg)
+-{
+- struct bss_descriptor * bss;
+- struct bss_descriptor * safe;
+- u32 clear_ssid_flag = 0, clear_bssid_flag = 0;
+-
+- if (!scan_cfg)
+- return;
+-
+- if (scan_cfg->clear_ssid && scan_cfg->ssid_len)
+- clear_ssid_flag = 1;
+-
+- if (scan_cfg->clear_bssid
+- && (compare_ether_addr(scan_cfg->bssid, &zeromac[0]) != 0)
+- && (compare_ether_addr(scan_cfg->bssid, &bcastmac[0]) != 0)) {
+- clear_bssid_flag = 1;
+- }
+-
+- if (!clear_ssid_flag && !clear_bssid_flag)
+- return;
+-
+- mutex_lock(&adapter->lock);
+- list_for_each_entry_safe (bss, safe, &adapter->network_list, list) {
+- u32 clear = 0;
+-
+- /* Check for an SSID match */
+- if ( clear_ssid_flag
+- && (bss->ssid_len == scan_cfg->ssid_len)
+- && !memcmp(bss->ssid, scan_cfg->ssid, bss->ssid_len))
+- clear = 1;
+-
+- /* Check for a BSSID match */
+- if ( clear_bssid_flag
+- && !compare_ether_addr(bss->bssid, scan_cfg->bssid))
+- clear = 1;
+-
+- if (clear) {
+- list_move_tail (&bss->list, &adapter->network_free_list);
+- clear_bss_descriptor(bss);
+- }
+- }
+- mutex_unlock(&adapter->lock);
+-}
+-
+
+ /**
+ * @brief Internal function used to start a scan based on an input config
+ *
++ * Also used from debugfs
++ *
+ * Use the input user scan configuration information when provided in
+ * order to send the appropriate scan commands to firmware to populate or
+ * update the internal driver scan table
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param puserscanin Pointer to the input configuration for the requested
+ * scan.
+ *
+ * @return 0 or < 0 if error
+ */
+-int wlan_scan_networks(wlan_private * priv,
+- const struct wlan_ioctl_user_scan_cfg * puserscanin,
+- int full_scan)
+-{
+- wlan_adapter * adapter = priv->adapter;
+- struct mrvlietypes_chanlistparamset *pchantlvout;
+- struct chanscanparamset * scan_chan_list = NULL;
+- struct wlan_scan_cmd_config * scan_cfg = NULL;
+- u8 filteredscan;
+- u8 scancurrentchanonly;
+- int maxchanperscan;
+- int ret;
++int lbs_scan_networks(struct lbs_private *priv,
++ const struct lbs_ioctl_user_scan_cfg *user_cfg,
++ int full_scan)
++{
++ int ret = -ENOMEM;
++ struct chanscanparamset *chan_list;
++ struct chanscanparamset *curr_chans;
++ int chan_count;
++ u8 bsstype = CMD_BSS_TYPE_ANY;
++ int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD;
++ int filteredscan = 0;
++ union iwreq_data wrqu;
+ #ifdef CONFIG_LIBERTAS_DEBUG
+- struct bss_descriptor * iter_bss;
++ struct bss_descriptor *iter;
+ int i = 0;
++ DECLARE_MAC_BUF(mac);
+ #endif
+
+- lbs_deb_enter(LBS_DEB_ASSOC);
++ lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d",
++ full_scan);
+
+- scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
+- WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
+- if (scan_chan_list == NULL) {
+- ret = -ENOMEM;
+- goto out;
+- }
++ /* Cancel any partial outstanding partial scans if this scan
++ * is a full scan.
++ */
++ if (full_scan && delayed_work_pending(&priv->scan_work))
++ cancel_delayed_work(&priv->scan_work);
+
+- scan_cfg = wlan_scan_setup_scan_config(priv,
+- puserscanin,
+- &pchantlvout,
+- scan_chan_list,
+- &maxchanperscan,
+- &filteredscan,
+- &scancurrentchanonly);
+- if (scan_cfg == NULL) {
+- ret = -ENOMEM;
++ /* Determine same scan parameters */
++ if (user_cfg) {
++ if (user_cfg->bsstype)
++ bsstype = user_cfg->bsstype;
++ if (compare_ether_addr(user_cfg->bssid, &zeromac[0]) != 0) {
++ numchannels = MRVDRV_MAX_CHANNELS_PER_SCAN;
++ filteredscan = 1;
++ }
++ }
++ lbs_deb_scan("numchannels %d, bsstype %d, "
++ "filteredscan %d\n",
++ numchannels, bsstype, filteredscan);
++
++ /* Create list of channels to scan */
++ chan_list = kzalloc(sizeof(struct chanscanparamset) *
++ LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
++ if (!chan_list) {
++ lbs_pr_alert("SCAN: chan_list empty\n");
+ goto out;
+ }
+
+- clear_selected_scan_list_entries(adapter, puserscanin);
+-
+- /* Keep the data path active if we are only scanning our current channel */
+- if (!scancurrentchanonly) {
+- netif_stop_queue(priv->dev);
+- netif_carrier_off(priv->dev);
++ /* We want to scan all channels */
++ chan_count = lbs_scan_create_channel_list(priv, chan_list,
++ filteredscan);
++
++ netif_stop_queue(priv->dev);
++ netif_carrier_off(priv->dev);
++ if (priv->mesh_dev) {
+ netif_stop_queue(priv->mesh_dev);
+ netif_carrier_off(priv->mesh_dev);
+ }
+
+- ret = wlan_scan_channel_list(priv,
+- maxchanperscan,
+- filteredscan,
+- scan_cfg,
+- pchantlvout,
+- scan_chan_list,
+- puserscanin,
+- full_scan);
++ /* Prepare to continue an interrupted scan */
++ lbs_deb_scan("chan_count %d, last_scanned_channel %d\n",
++ chan_count, priv->last_scanned_channel);
++ curr_chans = chan_list;
++ /* advance channel list by already-scanned-channels */
++ if (priv->last_scanned_channel > 0) {
++ curr_chans += priv->last_scanned_channel;
++ chan_count -= priv->last_scanned_channel;
++ }
++
++ /* Send scan command(s)
++ * numchannels contains the number of channels we should maximally scan
++ * chan_count is the total number of channels to scan
++ */
++
++ while (chan_count) {
++ int to_scan = min(numchannels, chan_count);
++ lbs_deb_scan("scanning %d of %d channels\n",
++ to_scan, chan_count);
++ ret = lbs_do_scan(priv, bsstype, curr_chans,
++ to_scan, user_cfg);
++ if (ret) {
++ lbs_pr_err("SCAN_CMD failed\n");
++ goto out2;
++ }
++ curr_chans += to_scan;
++ chan_count -= to_scan;
++
++ /* somehow schedule the next part of the scan */
++ if (chan_count &&
++ !full_scan &&
++ !priv->surpriseremoved) {
++ /* -1 marks just that we're currently scanning */
++ if (priv->last_scanned_channel < 0)
++ priv->last_scanned_channel = to_scan;
++ else
++ priv->last_scanned_channel += to_scan;
++ cancel_delayed_work(&priv->scan_work);
++ queue_delayed_work(priv->work_thread, &priv->scan_work,
++ msecs_to_jiffies(300));
++ /* skip over GIWSCAN event */
++ goto out;
++ }
++
++ }
++ memset(&wrqu, 0, sizeof(union iwreq_data));
++ wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+
+ #ifdef CONFIG_LIBERTAS_DEBUG
+ /* Dump the scan table */
+- mutex_lock(&adapter->lock);
+- list_for_each_entry (iter_bss, &adapter->network_list, list) {
+- lbs_deb_scan("Scan:(%02d) " MAC_FMT ", RSSI[%03d], SSID[%s]\n",
+- i++, MAC_ARG(iter_bss->bssid), (s32) iter_bss->rssi,
+- escape_essid(iter_bss->ssid, iter_bss->ssid_len));
+- }
+- mutex_unlock(&adapter->lock);
++ mutex_lock(&priv->lock);
++ lbs_deb_scan("scan table:\n");
++ list_for_each_entry(iter, &priv->network_list, list)
++ lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n",
++ i++, print_mac(mac, iter->bssid), (s32) iter->rssi,
++ escape_essid(iter->ssid, iter->ssid_len));
++ mutex_unlock(&priv->lock);
+ #endif
+
+- if (priv->adapter->connect_status == libertas_connected) {
++out2:
++ priv->last_scanned_channel = 0;
++
++out:
++ if (priv->connect_status == LBS_CONNECTED) {
+ netif_carrier_on(priv->dev);
+- netif_wake_queue(priv->dev);
++ if (!priv->tx_pending_len)
++ netif_wake_queue(priv->dev);
++ }
++ if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) {
+ netif_carrier_on(priv->mesh_dev);
+- netif_wake_queue(priv->mesh_dev);
++ if (!priv->tx_pending_len)
++ netif_wake_queue(priv->mesh_dev);
+ }
+-
+-out:
+- if (scan_cfg)
+- kfree(scan_cfg);
+-
+- if (scan_chan_list)
+- kfree(scan_chan_list);
++ kfree(chan_list);
+
+ lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
+ return ret;
+ }
+
+-/**
+- * @brief Inspect the scan response buffer for pointers to expected TLVs
+- *
+- * TLVs can be included at the end of the scan response BSS information.
+- * Parse the data in the buffer for pointers to TLVs that can potentially
+- * be passed back in the response
+- *
+- * @param ptlv Pointer to the start of the TLV buffer to parse
+- * @param tlvbufsize size of the TLV buffer
+- * @param ptsftlv Output parameter: Pointer to the TSF TLV if found
+- *
+- * @return void
+- */
+-static
+-void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv,
+- int tlvbufsize,
+- struct mrvlietypes_tsftimestamp ** ptsftlv)
+-{
+- struct mrvlietypes_data *pcurrenttlv;
+- int tlvbufleft;
+- u16 tlvtype;
+- u16 tlvlen;
+-
+- pcurrenttlv = ptlv;
+- tlvbufleft = tlvbufsize;
+- *ptsftlv = NULL;
+-
+- lbs_deb_scan("SCAN_RESP: tlvbufsize = %d\n", tlvbufsize);
+- lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize);
+-
+- while (tlvbufleft >= sizeof(struct mrvlietypesheader)) {
+- tlvtype = le16_to_cpu(pcurrenttlv->header.type);
+- tlvlen = le16_to_cpu(pcurrenttlv->header.len);
+-
+- switch (tlvtype) {
+- case TLV_TYPE_TSFTIMESTAMP:
+- *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv;
+- break;
+
+- default:
+- lbs_deb_scan("SCAN_RESP: Unhandled TLV = %d\n",
+- tlvtype);
+- /* Give up, this seems corrupted */
+- return;
+- } /* switch */
+-
+- tlvbufleft -= (sizeof(ptlv->header) + tlvlen);
+- pcurrenttlv =
+- (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen);
+- } /* while */
+-}
++
++
++/*********************************************************************/
++/* */
++/* Result interpretation */
++/* */
++/*********************************************************************/
+
+ /**
+ * @brief Interpret a BSS scan response returned from the firmware
+ *
+ * Parse the various fixed fields and IEs passed back for a a BSS probe
+- * response or beacon from the scan command. Record information as needed
+- * in the scan table struct bss_descriptor for that entry.
++ * response or beacon from the scan command. Record information as needed
++ * in the scan table struct bss_descriptor for that entry.
+ *
+ * @param bss Output parameter: Pointer to the BSS Entry
+ *
+ * @return 0 or -1
+ */
+-static int libertas_process_bss(struct bss_descriptor * bss,
++static int lbs_process_bss(struct bss_descriptor *bss,
+ u8 ** pbeaconinfo, int *bytesleft)
+ {
+- enum ieeetypes_elementid elemID;
+ struct ieeetypes_fhparamset *pFH;
+ struct ieeetypes_dsparamset *pDS;
+ struct ieeetypes_cfparamset *pCF;
+ struct ieeetypes_ibssparamset *pibss;
+- struct ieeetypes_capinfo *pcap;
+- struct WLAN_802_11_FIXED_IEs fixedie;
+- u8 *pcurrentptr;
+- u8 *pRate;
+- u8 elemlen;
+- u8 bytestocopy;
+- u8 ratesize;
+- u16 beaconsize;
+- u8 founddatarateie;
+- int bytesleftforcurrentbeacon;
+- int ret;
+-
+- struct IE_WPA *pIe;
+- const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 };
+-
++ DECLARE_MAC_BUF(mac);
+ struct ieeetypes_countryinfoset *pcountryinfo;
++ u8 *pos, *end, *p;
++ u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
++ u16 beaconsize = 0;
++ int ret;
+
+- lbs_deb_enter(LBS_DEB_ASSOC);
+-
+- founddatarateie = 0;
+- ratesize = 0;
+- beaconsize = 0;
++ lbs_deb_enter(LBS_DEB_SCAN);
+
+ if (*bytesleft >= sizeof(beaconsize)) {
+ /* Extract & convert beacon size from the command buffer */
+- beaconsize = le16_to_cpup((void *)*pbeaconinfo);
++ beaconsize = le16_to_cpu(get_unaligned((__le16 *)*pbeaconinfo));
+ *bytesleft -= sizeof(beaconsize);
+ *pbeaconinfo += sizeof(beaconsize);
+ }
+
+ if (beaconsize == 0 || beaconsize > *bytesleft) {
+-
+ *pbeaconinfo += *bytesleft;
+ *bytesleft = 0;
+-
+- return -1;
++ ret = -1;
++ goto done;
+ }
+
+ /* Initialize the current working beacon pointer for this BSS iteration */
+- pcurrentptr = *pbeaconinfo;
++ pos = *pbeaconinfo;
++ end = pos + beaconsize;
+
+ /* Advance the return beacon pointer past the current beacon */
+ *pbeaconinfo += beaconsize;
+ *bytesleft -= beaconsize;
+
+- bytesleftforcurrentbeacon = beaconsize;
+-
+- memcpy(bss->bssid, pcurrentptr, ETH_ALEN);
+- lbs_deb_scan("process_bss: AP BSSID " MAC_FMT "\n", MAC_ARG(bss->bssid));
+-
+- pcurrentptr += ETH_ALEN;
+- bytesleftforcurrentbeacon -= ETH_ALEN;
++ memcpy(bss->bssid, pos, ETH_ALEN);
++ lbs_deb_scan("process_bss: BSSID %s\n", print_mac(mac, bss->bssid));
++ pos += ETH_ALEN;
+
+- if (bytesleftforcurrentbeacon < 12) {
++ if ((end - pos) < 12) {
+ lbs_deb_scan("process_bss: Not enough bytes left\n");
+- return -1;
++ ret = -1;
++ goto done;
+ }
+
+ /*
+@@ -968,124 +747,97 @@ static int libertas_process_bss(struct b
+ */
+
+ /* RSSI is 1 byte long */
+- bss->rssi = *pcurrentptr;
+- lbs_deb_scan("process_bss: RSSI=%02X\n", *pcurrentptr);
+- pcurrentptr += 1;
+- bytesleftforcurrentbeacon -= 1;
++ bss->rssi = *pos;
++ lbs_deb_scan("process_bss: RSSI %d\n", *pos);
++ pos++;
+
+ /* time stamp is 8 bytes long */
+- fixedie.timestamp = bss->timestamp = le64_to_cpup((void *)pcurrentptr);
+- pcurrentptr += 8;
+- bytesleftforcurrentbeacon -= 8;
++ pos += 8;
+
+ /* beacon interval is 2 bytes long */
+- fixedie.beaconinterval = bss->beaconperiod = le16_to_cpup((void *)pcurrentptr);
+- pcurrentptr += 2;
+- bytesleftforcurrentbeacon -= 2;
++ bss->beaconperiod = le16_to_cpup((void *) pos);
++ pos += 2;
+
+ /* capability information is 2 bytes long */
+- memcpy(&fixedie.capabilities, pcurrentptr, 2);
+- lbs_deb_scan("process_bss: fixedie.capabilities=0x%X\n",
+- fixedie.capabilities);
+- pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities;
+- memcpy(&bss->cap, pcap, sizeof(struct ieeetypes_capinfo));
+- pcurrentptr += 2;
+- bytesleftforcurrentbeacon -= 2;
+-
+- /* rest of the current buffer are IE's */
+- lbs_deb_scan("process_bss: IE length for this AP = %d\n",
+- bytesleftforcurrentbeacon);
+-
+- lbs_dbg_hex("process_bss: IE info", (u8 *) pcurrentptr,
+- bytesleftforcurrentbeacon);
+-
+- if (pcap->privacy) {
+- lbs_deb_scan("process_bss: AP WEP enabled\n");
+- bss->privacy = wlan802_11privfilter8021xWEP;
+- } else {
+- bss->privacy = wlan802_11privfilteracceptall;
+- }
+-
+- if (pcap->ibss == 1) {
++ bss->capability = le16_to_cpup((void *) pos);
++ lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
++ pos += 2;
++
++ if (bss->capability & WLAN_CAPABILITY_PRIVACY)
++ lbs_deb_scan("process_bss: WEP enabled\n");
++ if (bss->capability & WLAN_CAPABILITY_IBSS)
+ bss->mode = IW_MODE_ADHOC;
+- } else {
++ else
+ bss->mode = IW_MODE_INFRA;
+- }
++
++ /* rest of the current buffer are IE's */
++ lbs_deb_scan("process_bss: IE len %zd\n", end - pos);
++ lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
+
+ /* process variable IE */
+- while (bytesleftforcurrentbeacon >= 2) {
+- elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr));
+- elemlen = *((u8 *) pcurrentptr + 1);
++ while (pos <= end - 2) {
++ struct ieee80211_info_element * elem =
++ (struct ieee80211_info_element *) pos;
+
+- if (bytesleftforcurrentbeacon < elemlen) {
++ if (pos + elem->len > end) {
+ lbs_deb_scan("process_bss: error in processing IE, "
+ "bytes left < IE length\n");
+- bytesleftforcurrentbeacon = 0;
+- continue;
++ break;
+ }
+
+- switch (elemID) {
+- case SSID:
+- bss->ssid_len = elemlen;
+- memcpy(bss->ssid, (pcurrentptr + 2), elemlen);
+- lbs_deb_scan("ssid '%s', ssid length %u\n",
++ switch (elem->id) {
++ case MFIE_TYPE_SSID:
++ bss->ssid_len = elem->len;
++ memcpy(bss->ssid, elem->data, elem->len);
++ lbs_deb_scan("got SSID IE: '%s', len %u\n",
+ escape_essid(bss->ssid, bss->ssid_len),
+ bss->ssid_len);
+ break;
+
+- case SUPPORTED_RATES:
+- memcpy(bss->datarates, (pcurrentptr + 2), elemlen);
+- memmove(bss->libertas_supported_rates, (pcurrentptr + 2),
+- elemlen);
+- ratesize = elemlen;
+- founddatarateie = 1;
++ case MFIE_TYPE_RATES:
++ n_basic_rates = min_t(u8, MAX_RATES, elem->len);
++ memcpy(bss->rates, elem->data, n_basic_rates);
++ got_basic_rates = 1;
++ lbs_deb_scan("got RATES IE\n");
+ break;
+
+- case EXTRA_IE:
+- lbs_deb_scan("process_bss: EXTRA_IE Found!\n");
+- break;
+-
+- case FH_PARAM_SET:
+- pFH = (struct ieeetypes_fhparamset *) pcurrentptr;
++ case MFIE_TYPE_FH_SET:
++ pFH = (struct ieeetypes_fhparamset *) pos;
+ memmove(&bss->phyparamset.fhparamset, pFH,
+ sizeof(struct ieeetypes_fhparamset));
+-#if 0 /* I think we can store these LE */
+- bss->phyparamset.fhparamset.dwelltime
+- = le16_to_cpu(bss->phyparamset.fhparamset.dwelltime);
+-#endif
++ lbs_deb_scan("got FH IE\n");
+ break;
+
+- case DS_PARAM_SET:
+- pDS = (struct ieeetypes_dsparamset *) pcurrentptr;
++ case MFIE_TYPE_DS_SET:
++ pDS = (struct ieeetypes_dsparamset *) pos;
+ bss->channel = pDS->currentchan;
+ memcpy(&bss->phyparamset.dsparamset, pDS,
+ sizeof(struct ieeetypes_dsparamset));
++ lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
+ break;
+
+- case CF_PARAM_SET:
+- pCF = (struct ieeetypes_cfparamset *) pcurrentptr;
++ case MFIE_TYPE_CF_SET:
++ pCF = (struct ieeetypes_cfparamset *) pos;
+ memcpy(&bss->ssparamset.cfparamset, pCF,
+ sizeof(struct ieeetypes_cfparamset));
++ lbs_deb_scan("got CF IE\n");
+ break;
+
+- case IBSS_PARAM_SET:
+- pibss = (struct ieeetypes_ibssparamset *) pcurrentptr;
+- bss->atimwindow = le32_to_cpu(pibss->atimwindow);
++ case MFIE_TYPE_IBSS_SET:
++ pibss = (struct ieeetypes_ibssparamset *) pos;
++ bss->atimwindow = le16_to_cpu(pibss->atimwindow);
+ memmove(&bss->ssparamset.ibssparamset, pibss,
+ sizeof(struct ieeetypes_ibssparamset));
+-#if 0
+- bss->ssparamset.ibssparamset.atimwindow
+- = le16_to_cpu(bss->ssparamset.ibssparamset.atimwindow);
+-#endif
++ lbs_deb_scan("got IBSS IE\n");
+ break;
+
+- /* Handle Country Info IE */
+- case COUNTRY_INFO:
+- pcountryinfo = (struct ieeetypes_countryinfoset *) pcurrentptr;
++ case MFIE_TYPE_COUNTRY:
++ pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
++ lbs_deb_scan("got COUNTRY IE\n");
+ if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
+ || pcountryinfo->len > 254) {
+ lbs_deb_scan("process_bss: 11D- Err "
+- "CountryInfo len =%d min=%zd max=254\n",
++ "CountryInfo len %d, min %zd, max 254\n",
+ pcountryinfo->len,
+ sizeof(pcountryinfo->countrycode));
+ ret = -1;
+@@ -1094,70 +846,78 @@ static int libertas_process_bss(struct b
+
+ memcpy(&bss->countryinfo,
+ pcountryinfo, pcountryinfo->len + 2);
+- lbs_dbg_hex("process_bss: 11D- CountryInfo:",
++ lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
+ (u8 *) pcountryinfo,
+ (u32) (pcountryinfo->len + 2));
+ break;
+
+- case EXTENDED_SUPPORTED_RATES:
+- /*
+- * only process extended supported rate
+- * if data rate is already found.
+- * data rate IE should come before
++ case MFIE_TYPE_RATES_EX:
++ /* only process extended supported rate if data rate is
++ * already found. Data rate IE should come before
+ * extended supported rate IE
+ */
+- if (founddatarateie) {
+- if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) {
+- bytestocopy =
+- (WLAN_SUPPORTED_RATES - ratesize);
+- } else {
+- bytestocopy = elemlen;
+- }
+-
+- pRate = (u8 *) bss->datarates;
+- pRate += ratesize;
+- memmove(pRate, (pcurrentptr + 2), bytestocopy);
+- pRate = (u8 *) bss->libertas_supported_rates;
+- pRate += ratesize;
+- memmove(pRate, (pcurrentptr + 2), bytestocopy);
+- }
+- break;
+-
+- case VENDOR_SPECIFIC_221:
+-#define IE_ID_LEN_FIELDS_BYTES 2
+- pIe = (struct IE_WPA *)pcurrentptr;
+-
+- if (memcmp(pIe->oui, oui01, sizeof(oui01)))
++ lbs_deb_scan("got RATESEX IE\n");
++ if (!got_basic_rates) {
++ lbs_deb_scan("... but ignoring it\n");
+ break;
++ }
+
+- bss->wpa_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES,
+- MAX_WPA_IE_LEN);
+- memcpy(bss->wpa_ie, pcurrentptr, bss->wpa_ie_len);
+- lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, elemlen);
+- break;
+- case WPA2_IE:
+- pIe = (struct IE_WPA *)pcurrentptr;
+- bss->rsn_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES,
+- MAX_WPA_IE_LEN);
+- memcpy(bss->rsn_ie, pcurrentptr, bss->rsn_ie_len);
+- lbs_dbg_hex("process_bss: RSN_IE", bss->rsn_ie, elemlen);
++ n_ex_rates = elem->len;
++ if (n_basic_rates + n_ex_rates > MAX_RATES)
++ n_ex_rates = MAX_RATES - n_basic_rates;
++
++ p = bss->rates + n_basic_rates;
++ memcpy(p, elem->data, n_ex_rates);
++ break;
++
++ case MFIE_TYPE_GENERIC:
++ if (elem->len >= 4 &&
++ elem->data[0] == 0x00 &&
++ elem->data[1] == 0x50 &&
++ elem->data[2] == 0xf2 &&
++ elem->data[3] == 0x01) {
++ bss->wpa_ie_len = min(elem->len + 2,
++ MAX_WPA_IE_LEN);
++ memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
++ lbs_deb_scan("got WPA IE\n");
++ lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
++ elem->len);
++ } else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
++ elem->data[0] == 0x00 &&
++ elem->data[1] == 0x50 &&
++ elem->data[2] == 0x43 &&
++ elem->data[3] == 0x04) {
++ lbs_deb_scan("got mesh IE\n");
++ bss->mesh = 1;
++ } else {
++ lbs_deb_scan("got generiec IE: "
++ "%02x:%02x:%02x:%02x, len %d\n",
++ elem->data[0], elem->data[1],
++ elem->data[2], elem->data[3],
++ elem->len);
++ }
+ break;
+- case TIM:
++
++ case MFIE_TYPE_RSN:
++ lbs_deb_scan("got RSN IE\n");
++ bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
++ memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
++ lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
++ bss->rsn_ie, elem->len);
+ break;
+
+- case CHALLENGE_TEXT:
++ default:
++ lbs_deb_scan("got IE 0x%04x, len %d\n",
++ elem->id, elem->len);
+ break;
+ }
+
+- pcurrentptr += elemlen + 2;
+-
+- /* need to account for IE ID and IE len */
+- bytesleftforcurrentbeacon -= (elemlen + 2);
+-
+- } /* while (bytesleftforcurrentbeacon > 2) */
++ pos += elem->len + 2;
++ }
+
+ /* Timestamp */
+ bss->last_scanned = jiffies;
++ lbs_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));
+
+ ret = 0;
+
+@@ -1167,54 +927,42 @@ done:
+ }
+
+ /**
+- * @brief Compare two SSIDs
+- *
+- * @param ssid1 A pointer to ssid to compare
+- * @param ssid2 A pointer to ssid to compare
+- *
+- * @return 0--ssid is same, otherwise is different
+- */
+-int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
+-{
+- if (ssid1_len != ssid2_len)
+- return -1;
+-
+- return memcmp(ssid1, ssid2, ssid1_len);
+-}
+-
+-/**
+ * @brief This function finds a specific compatible BSSID in the scan list
+ *
+- * @param adapter A pointer to wlan_adapter
++ * Used in association code
++ *
++ * @param priv A pointer to struct lbs_private
+ * @param bssid BSSID to find in the scan list
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list, or error return code (< 0)
+ */
+-struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
++struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
+ u8 * bssid, u8 mode)
+ {
+ struct bss_descriptor * iter_bss;
+ struct bss_descriptor * found_bss = NULL;
+
++ lbs_deb_enter(LBS_DEB_SCAN);
++
+ if (!bssid)
+- return NULL;
++ goto out;
+
+- lbs_dbg_hex("libertas_find_BSSID_in_list: looking for ",
++ lbs_deb_hex(LBS_DEB_SCAN, "looking for",
+ bssid, ETH_ALEN);
+
+ /* Look through the scan table for a compatible match. The loop will
+ * continue past a matched bssid that is not compatible in case there
+ * is an AP with multiple SSIDs assigned to the same BSSID
+ */
+- mutex_lock(&adapter->lock);
+- list_for_each_entry (iter_bss, &adapter->network_list, list) {
++ mutex_lock(&priv->lock);
++ list_for_each_entry (iter_bss, &priv->network_list, list) {
+ if (compare_ether_addr(iter_bss->bssid, bssid))
+ continue; /* bssid doesn't match */
+ switch (mode) {
+ case IW_MODE_INFRA:
+ case IW_MODE_ADHOC:
+- if (!is_network_compatible(adapter, iter_bss, mode))
++ if (!is_network_compatible(priv, iter_bss, mode))
+ break;
+ found_bss = iter_bss;
+ break;
+@@ -1223,22 +971,26 @@ struct bss_descriptor * libertas_find_bs
+ break;
+ }
+ }
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
+
++out:
++ lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
+ return found_bss;
+ }
+
+ /**
+ * @brief This function finds ssid in ssid list.
+ *
+- * @param adapter A pointer to wlan_adapter
++ * Used in association code
++ *
++ * @param priv A pointer to struct lbs_private
+ * @param ssid SSID to find in the list
+ * @param bssid BSSID to qualify the SSID selection (if provided)
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list
+ */
+-struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
++struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
+ u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode,
+ int channel)
+ {
+@@ -1247,14 +999,16 @@ struct bss_descriptor * libertas_find_ss
+ struct bss_descriptor * found_bss = NULL;
+ struct bss_descriptor * tmp_oldest = NULL;
+
+- mutex_lock(&adapter->lock);
++ lbs_deb_enter(LBS_DEB_SCAN);
++
++ mutex_lock(&priv->lock);
+
+- list_for_each_entry (iter_bss, &adapter->network_list, list) {
++ list_for_each_entry (iter_bss, &priv->network_list, list) {
+ if ( !tmp_oldest
+ || (iter_bss->last_scanned < tmp_oldest->last_scanned))
+ tmp_oldest = iter_bss;
+
+- if (libertas_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len,
++ if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len,
+ ssid, ssid_len) != 0)
+ continue; /* ssid doesn't match */
+ if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0)
+@@ -1265,7 +1019,7 @@ struct bss_descriptor * libertas_find_ss
+ switch (mode) {
+ case IW_MODE_INFRA:
+ case IW_MODE_ADHOC:
+- if (!is_network_compatible(adapter, iter_bss, mode))
++ if (!is_network_compatible(priv, iter_bss, mode))
+ break;
+
+ if (bssid) {
+@@ -1290,7 +1044,8 @@ struct bss_descriptor * libertas_find_ss
+ }
+
+ out:
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
++ lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
+ return found_bss;
+ }
+
+@@ -1300,24 +1055,27 @@ out:
+ * Search the scan table for the best SSID that also matches the current
+ * adapter network preference (infrastructure or adhoc)
+ *
+- * @param adapter A pointer to wlan_adapter
++ * @param priv A pointer to struct lbs_private
+ *
+ * @return index in BSSID list
+ */
+-struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
+- u8 mode)
++static struct bss_descriptor *lbs_find_best_ssid_in_list(
++ struct lbs_private *priv,
++ u8 mode)
+ {
+ u8 bestrssi = 0;
+ struct bss_descriptor * iter_bss;
+ struct bss_descriptor * best_bss = NULL;
+
+- mutex_lock(&adapter->lock);
++ lbs_deb_enter(LBS_DEB_SCAN);
++
++ mutex_lock(&priv->lock);
+
+- list_for_each_entry (iter_bss, &adapter->network_list, list) {
++ list_for_each_entry (iter_bss, &priv->network_list, list) {
+ switch (mode) {
+ case IW_MODE_INFRA:
+ case IW_MODE_ADHOC:
+- if (!is_network_compatible(adapter, iter_bss, mode))
++ if (!is_network_compatible(priv, iter_bss, mode))
+ break;
+ if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
+ break;
+@@ -1334,34 +1092,34 @@ struct bss_descriptor * libertas_find_be
+ }
+ }
+
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
++ lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss);
+ return best_bss;
+ }
+
+ /**
+ * @brief Find the AP with specific ssid in the scan list
+ *
+- * @param priv A pointer to wlan_private structure
++ * Used from association worker.
++ *
++ * @param priv A pointer to struct lbs_private structure
+ * @param pSSID A pointer to AP's ssid
+ *
+ * @return 0--success, otherwise--fail
+ */
+-int libertas_find_best_network_ssid(wlan_private * priv,
++int lbs_find_best_network_ssid(struct lbs_private *priv,
+ u8 *out_ssid, u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ int ret = -1;
+ struct bss_descriptor * found;
+
+- lbs_deb_enter(LBS_DEB_ASSOC);
+-
+- wlan_scan_networks(priv, NULL, 1);
+- if (adapter->surpriseremoved)
+- return -1;
++ lbs_deb_enter(LBS_DEB_SCAN);
+
+- wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
++ lbs_scan_networks(priv, NULL, 1);
++ if (priv->surpriseremoved)
++ goto out;
+
+- found = libertas_find_best_ssid_in_list(adapter, preferred_mode);
++ 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);
+ *out_ssid_len = found->ssid_len;
+@@ -1369,54 +1127,33 @@ int libertas_find_best_network_ssid(wlan
+ ret = 0;
+ }
+
++out:
+ lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
+ return ret;
+ }
+
+-/**
+- * @brief Scan Network
+- *
+- * @param dev A pointer to net_device structure
+- * @param info A pointer to iw_request_info structure
+- * @param vwrq A pointer to iw_param structure
+- * @param extra A pointer to extra data buf
+- *
+- * @return 0 --success, otherwise fail
+- */
+-int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+- struct iw_param *vwrq, char *extra)
+-{
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
+-
+- lbs_deb_enter(LBS_DEB_SCAN);
+-
+- wlan_scan_networks(priv, NULL, 0);
+-
+- if (adapter->surpriseremoved)
+- return -1;
+-
+- lbs_deb_leave(LBS_DEB_SCAN);
+- return 0;
+-}
+
+ /**
+ * @brief Send a scan command for all available channels filtered on a spec
+ *
+- * @param priv A pointer to wlan_private structure
+- * @param prequestedssid A pointer to AP's ssid
+- * @param keeppreviousscan Flag used to save/clear scan table before scan
++ * Used in association code and from debugfs
++ *
++ * @param priv A pointer to struct lbs_private structure
++ * @param ssid A pointer to the SSID to scan for
++ * @param ssid_len Length of the SSID
++ * @param clear_ssid Should existing scan results with this SSID
++ * be cleared?
+ *
+ * @return 0-success, otherwise fail
+ */
+-int libertas_send_specific_ssid_scan(wlan_private * priv,
++int lbs_send_specific_ssid_scan(struct lbs_private *priv,
+ u8 *ssid, u8 ssid_len, u8 clear_ssid)
+ {
+- wlan_adapter *adapter = priv->adapter;
+- struct wlan_ioctl_user_scan_cfg scancfg;
++ struct lbs_ioctl_user_scan_cfg scancfg;
+ int ret = 0;
+
+- lbs_deb_enter(LBS_DEB_ASSOC);
++ lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d",
++ escape_essid(ssid, ssid_len), clear_ssid);
+
+ if (!ssid_len)
+ goto out;
+@@ -1426,54 +1163,33 @@ int libertas_send_specific_ssid_scan(wla
+ scancfg.ssid_len = ssid_len;
+ scancfg.clear_ssid = clear_ssid;
+
+- wlan_scan_networks(priv, &scancfg, 1);
+- if (adapter->surpriseremoved)
+- return -1;
+- wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
++ lbs_scan_networks(priv, &scancfg, 1);
++ if (priv->surpriseremoved) {
++ ret = -1;
++ goto out;
++ }
+
+ out:
+- lbs_deb_leave(LBS_DEB_ASSOC);
++ lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
+ return ret;
+ }
+
+-/**
+- * @brief scan an AP with specific BSSID
+- *
+- * @param priv A pointer to wlan_private structure
+- * @param bssid A pointer to AP's bssid
+- * @param keeppreviousscan Flag used to save/clear scan table before scan
+- *
+- * @return 0-success, otherwise fail
+- */
+-int libertas_send_specific_bssid_scan(wlan_private * priv, u8 * bssid, u8 clear_bssid)
+-{
+- struct wlan_ioctl_user_scan_cfg scancfg;
+
+- lbs_deb_enter(LBS_DEB_ASSOC);
+
+- if (bssid == NULL)
+- goto out;
+
+- memset(&scancfg, 0x00, sizeof(scancfg));
+- memcpy(scancfg.bssid, bssid, ETH_ALEN);
+- scancfg.clear_bssid = clear_bssid;
++/*********************************************************************/
++/* */
++/* Support for Wireless Extensions */
++/* */
++/*********************************************************************/
+
+- wlan_scan_networks(priv, &scancfg, 1);
+- if (priv->adapter->surpriseremoved)
+- return -1;
+- wait_event_interruptible(priv->adapter->cmd_pending,
+- !priv->adapter->nr_cmd_pending);
+
+-out:
+- lbs_deb_leave(LBS_DEB_ASSOC);
+- return 0;
+-}
++#define MAX_CUSTOM_LEN 64
+
+-static inline char *libertas_translate_scan(wlan_private *priv,
++static inline char *lbs_translate_scan(struct lbs_private *priv,
+ char *start, char *stop,
+ struct bss_descriptor *bss)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ struct chan_freq_power *cfp;
+ char *current_val; /* For rates */
+ struct iw_event iwe; /* Temporary buffer */
+@@ -1483,13 +1199,16 @@ static inline char *libertas_translate_s
+ #define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI))
+ u8 rssi;
+
+- cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, bss->channel);
++ lbs_deb_enter(LBS_DEB_SCAN);
++
++ cfp = lbs_find_cfp_by_band_and_channel(priv, 0, bss->channel);
+ if (!cfp) {
+ lbs_deb_scan("Invalid channel number %d\n", bss->channel);
+- return NULL;
++ start = NULL;
++ goto out;
+ }
+
+- /* First entry *MUST* be the AP BSSID */
++ /* First entry *MUST* be the BSSID */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
+@@ -1525,32 +1244,32 @@ static inline char *libertas_translate_s
+ if (iwe.u.qual.qual > 100)
+ iwe.u.qual.qual = 100;
+
+- if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
++ if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+ iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+ } else {
+ iwe.u.qual.noise =
+- CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
++ CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
+ }
+
+ /* Locally created ad-hoc BSSs won't have beacons if this is the
+ * only station in the adhoc network; so get signal strength
+ * from receive statistics.
+ */
+- if ((adapter->mode == IW_MODE_ADHOC)
+- && adapter->adhoccreate
+- && !libertas_ssid_cmp(adapter->curbssparams.ssid,
+- adapter->curbssparams.ssid_len,
++ if ((priv->mode == IW_MODE_ADHOC)
++ && priv->adhoccreate
++ && !lbs_ssid_cmp(priv->curbssparams.ssid,
++ priv->curbssparams.ssid_len,
+ bss->ssid, bss->ssid_len)) {
+ int snr, nf;
+- snr = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+- nf = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
++ snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
++ nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+ iwe.u.qual.level = CAL_RSSI(snr, nf);
+ }
+ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
+
+ /* Add encryption capability */
+ iwe.cmd = SIOCGIWENCODE;
+- if (bss->privacy) {
++ if (bss->capability & WLAN_CAPABILITY_PRIVACY) {
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ } else {
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+@@ -1565,20 +1284,17 @@ static inline char *libertas_translate_s
+ iwe.u.bitrate.disabled = 0;
+ iwe.u.bitrate.value = 0;
+
+- for (j = 0; j < sizeof(bss->libertas_supported_rates); j++) {
+- u8 rate = bss->libertas_supported_rates[j];
+- if (rate == 0)
+- break; /* no more rates */
+- /* Bit rate given in 500 kb/s units (+ 0x80) */
+- iwe.u.bitrate.value = (rate & 0x7f) * 500000;
++ for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
++ /* Bit rate given in 500 kb/s units */
++ iwe.u.bitrate.value = bss->rates[j] * 500000;
+ current_val = iwe_stream_add_value(start, current_val,
+ stop, &iwe, IW_EV_PARAM_LEN);
+ }
+ if ((bss->mode == IW_MODE_ADHOC)
+- && !libertas_ssid_cmp(adapter->curbssparams.ssid,
+- adapter->curbssparams.ssid_len,
++ && !lbs_ssid_cmp(priv->curbssparams.ssid,
++ priv->curbssparams.ssid_len,
+ bss->ssid, bss->ssid_len)
+- && adapter->adhoccreate) {
++ && priv->adhoccreate) {
+ iwe.u.bitrate.value = 22 * 500000;
+ current_val = iwe_stream_add_value(start, current_val,
+ stop, &iwe, IW_EV_PARAM_LEN);
+@@ -1605,11 +1321,73 @@ static inline char *libertas_translate_s
+ start = iwe_stream_add_point(start, stop, &iwe, buf);
+ }
+
++ if (bss->mesh) {
++ char custom[MAX_CUSTOM_LEN];
++ char *p = custom;
++
++ iwe.cmd = IWEVCUSTOM;
++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
++ "mesh-type: olpc");
++ iwe.u.data.length = p - custom;
++ if (iwe.u.data.length)
++ start = iwe_stream_add_point(start, stop, &iwe, custom);
++ }
++
++out:
++ lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start);
+ return start;
+ }
+
++
+ /**
+- * @brief Retrieve the scan table entries via wireless tools IOCTL call
++ * @brief Handle Scan Network ioctl
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ *
++ * @return 0 --success, otherwise fail
++ */
++int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *wrqu, char *extra)
++{
++ struct lbs_private *priv = dev->priv;
++
++ lbs_deb_enter(LBS_DEB_SCAN);
++
++ if (!netif_running(dev))
++ return -ENETDOWN;
++
++ /* mac80211 does this:
++ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++ if (sdata->type != IEEE80211_IF_TYPE_xxx)
++ return -EOPNOTSUPP;
++
++ if (wrqu->data.length == sizeof(struct iw_scan_req) &&
++ wrqu->data.flags & IW_SCAN_THIS_ESSID) {
++ req = (struct iw_scan_req *)extra;
++ ssid = req->essid;
++ ssid_len = req->essid_len;
++ }
++ */
++
++ if (!delayed_work_pending(&priv->scan_work))
++ queue_delayed_work(priv->work_thread, &priv->scan_work,
++ msecs_to_jiffies(50));
++ /* set marker that currently a scan is taking place */
++ priv->last_scanned_channel = -1;
++
++ if (priv->surpriseremoved)
++ return -EIO;
++
++ lbs_deb_leave(LBS_DEB_SCAN);
++ return 0;
++}
++
++
++/**
++ * @brief Handle Retrieve scan table ioctl
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+@@ -1618,32 +1396,31 @@ static inline char *libertas_translate_s
+ *
+ * @return 0 --success, otherwise fail
+ */
+-int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
++int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+ {
+ #define SCAN_ITEM_SIZE 128
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ int err = 0;
+ char *ev = extra;
+ char *stop = ev + dwrq->length;
+ struct bss_descriptor * iter_bss;
+ struct bss_descriptor * safe;
+
+- lbs_deb_enter(LBS_DEB_ASSOC);
++ lbs_deb_enter(LBS_DEB_SCAN);
+
+- /* If we've got an uncompleted scan, schedule the next part */
+- if (!adapter->nr_cmd_pending && adapter->last_scanned_channel)
+- wlan_scan_networks(priv, NULL, 0);
++ /* iwlist should wait until the current scan is finished */
++ if (priv->last_scanned_channel)
++ return -EAGAIN;
+
+ /* Update RSSI if current BSS is a locally created ad-hoc BSS */
+- if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) {
+- libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
+- cmd_option_waitforrsp, 0, NULL);
++ if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) {
++ lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
++ CMD_OPTION_WAITFORRSP, 0, NULL);
+ }
+
+- mutex_lock(&adapter->lock);
+- list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) {
++ mutex_lock(&priv->lock);
++ list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
+ char * next_ev;
+ unsigned long stale_time;
+
+@@ -1652,95 +1429,87 @@ int libertas_get_scan(struct net_device
+ break;
+ }
+
++ /* For mesh device, list only mesh networks */
++ if (dev == priv->mesh_dev && !iter_bss->mesh)
++ continue;
++
+ /* Prune old an old scan result */
+ stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
+ if (time_after(jiffies, stale_time)) {
+ list_move_tail (&iter_bss->list,
+- &adapter->network_free_list);
++ &priv->network_free_list);
+ clear_bss_descriptor(iter_bss);
+ continue;
+ }
+
+ /* Translate to WE format this entry */
+- next_ev = libertas_translate_scan(priv, ev, stop, iter_bss);
++ next_ev = lbs_translate_scan(priv, ev, stop, iter_bss);
+ if (next_ev == NULL)
+ continue;
+ ev = next_ev;
+ }
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
+
+ dwrq->length = (ev - extra);
+ dwrq->flags = 0;
+
+- lbs_deb_leave(LBS_DEB_ASSOC);
++ lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", err);
+ return err;
+ }
+
++
++
++
++/*********************************************************************/
++/* */
++/* Command execution */
++/* */
++/*********************************************************************/
++
++
+ /**
+ * @brief Prepare a scan command to be sent to the firmware
+ *
+- * Use the wlan_scan_cmd_config sent to the command processing module in
+- * the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command
+- * struct to send to firmware.
++ * Called via lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, ...)
++ * from cmd.c
+ *
+- * The fixed fields specifying the BSS type and BSSID filters as well as a
+- * variable number/length of TLVs are sent in the command to firmware.
++ * Sends a fixed lenght data part (specifying the BSS type and BSSID filters)
++ * as well as a variable number/length of TLVs to the firmware.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param cmd A pointer to cmd_ds_command structure to be sent to
+ * firmware with the cmd_DS_801_11_SCAN structure
+- * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
++ * @param pdata_buf Void pointer cast of a lbs_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return 0 or -1
+- *
+- * @sa wlan_scan_create_channel_list
+ */
+-int libertas_cmd_80211_scan(wlan_private * priv,
+- struct cmd_ds_command *cmd, void *pdata_buf)
++int lbs_cmd_80211_scan(struct lbs_private *priv,
++ struct cmd_ds_command *cmd, void *pdata_buf)
+ {
+ struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
+- struct wlan_scan_cmd_config *pscancfg;
+-
+- lbs_deb_enter(LBS_DEB_ASSOC);
++ struct lbs_scan_cmd_config *pscancfg = pdata_buf;
+
+- pscancfg = pdata_buf;
++ lbs_deb_enter(LBS_DEB_SCAN);
+
+ /* Set fixed field variables in scan command */
+ pscan->bsstype = pscancfg->bsstype;
+- memcpy(pscan->BSSID, pscancfg->bssid, sizeof(pscan->BSSID));
++ memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN);
+ memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
+
+- cmd->command = cpu_to_le16(cmd_802_11_scan);
+-
+ /* size is equal to the sizeof(fixed portions) + the TLV len + header */
+- cmd->size = cpu_to_le16(sizeof(pscan->bsstype)
+- + sizeof(pscan->BSSID)
+- + pscancfg->tlvbufferlen + S_DS_GEN);
+-
+- lbs_deb_scan("SCAN_CMD: command=%x, size=%x, seqnum=%x\n",
+- le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
+- le16_to_cpu(cmd->seqnum));
++ cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN
++ + pscancfg->tlvbufferlen + S_DS_GEN);
+
+- lbs_deb_leave(LBS_DEB_ASSOC);
++ lbs_deb_leave(LBS_DEB_SCAN);
+ return 0;
+ }
+
+-static inline int is_same_network(struct bss_descriptor *src,
+- struct bss_descriptor *dst)
+-{
+- /* A network is only a duplicate if the channel, BSSID, and ESSID
+- * all match. We treat all <hidden> with the same BSSID and channel
+- * as one network */
+- return ((src->ssid_len == dst->ssid_len) &&
+- (src->channel == dst->channel) &&
+- !compare_ether_addr(src->bssid, dst->bssid) &&
+- !memcmp(src->ssid, dst->ssid, src->ssid_len));
+-}
+-
+ /**
+ * @brief This function handles the command response of scan
+ *
++ * Called from handle_cmd_response() in cmdrespc.
++ *
+ * The response buffer for the scan command has the following
+ * memory layout:
+ *
+@@ -1757,17 +1526,14 @@ static inline int is_same_network(struct
+ * | bufsize and sizeof the fixed fields above) |
+ * .-----------------------------------------------------------.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param resp A pointer to cmd_ds_command
+ *
+ * @return 0 or -1
+ */
+-int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
++int lbs_ret_80211_scan(struct lbs_private *priv, struct cmd_ds_command *resp)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_scan_rsp *pscan;
+- struct mrvlietypes_data *ptlv;
+- struct mrvlietypes_tsftimestamp *ptsftlv;
+ struct bss_descriptor * iter_bss;
+ struct bss_descriptor * safe;
+ u8 *pbssinfo;
+@@ -1777,14 +1543,14 @@ int libertas_ret_80211_scan(wlan_private
+ int tlvbufsize;
+ int ret;
+
+- lbs_deb_enter(LBS_DEB_ASSOC);
++ lbs_deb_enter(LBS_DEB_SCAN);
+
+ /* Prune old entries from scan table */
+- list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) {
++ list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
+ unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
+ if (time_before(jiffies, stale_time))
+ continue;
+- list_move_tail (&iter_bss->list, &adapter->network_free_list);
++ list_move_tail (&iter_bss->list, &priv->network_free_list);
+ clear_bss_descriptor(iter_bss);
+ }
+
+@@ -1802,8 +1568,7 @@ int libertas_ret_80211_scan(wlan_private
+ lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
+
+ scanrespsize = le16_to_cpu(resp->size);
+- lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n",
+- pscan->nr_sets);
++ lbs_deb_scan("SCAN_RESP: scan results %d\n", pscan->nr_sets);
+
+ pbssinfo = pscan->bssdesc_and_tlvbuffer;
+
+@@ -1816,11 +1581,6 @@ int libertas_ret_80211_scan(wlan_private
+ + sizeof(pscan->nr_sets)
+ + S_DS_GEN);
+
+- ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft);
+-
+- /* Search the TLV buffer space in the scan response for any valid TLVs */
+- wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv);
+-
+ /*
+ * Process each scan response returned (pscan->nr_sets). Save
+ * the information in the newbssentry and then insert into the
+@@ -1831,17 +1591,18 @@ int libertas_ret_80211_scan(wlan_private
+ struct bss_descriptor new;
+ struct bss_descriptor * found = NULL;
+ struct bss_descriptor * oldest = NULL;
++ DECLARE_MAC_BUF(mac);
+
+ /* Process the data fields and IEs returned for this BSS */
+ memset(&new, 0, sizeof (struct bss_descriptor));
+- if (libertas_process_bss(&new, &pbssinfo, &bytesleft) != 0) {
++ if (lbs_process_bss(&new, &pbssinfo, &bytesleft) != 0) {
+ /* error parsing the scan response, skipped */
+ lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n");
+ continue;
+ }
+
+ /* Try to find this bss in the scan table */
+- list_for_each_entry (iter_bss, &adapter->network_list, list) {
++ list_for_each_entry (iter_bss, &priv->network_list, list) {
+ if (is_same_network(iter_bss, &new)) {
+ found = iter_bss;
+ break;
+@@ -1855,33 +1616,22 @@ int libertas_ret_80211_scan(wlan_private
+ if (found) {
+ /* found, clear it */
+ clear_bss_descriptor(found);
+- } else if (!list_empty(&adapter->network_free_list)) {
++ } else if (!list_empty(&priv->network_free_list)) {
+ /* Pull one from the free list */
+- found = list_entry(adapter->network_free_list.next,
++ found = list_entry(priv->network_free_list.next,
+ struct bss_descriptor, list);
+- list_move_tail(&found->list, &adapter->network_list);
++ list_move_tail(&found->list, &priv->network_list);
+ } else if (oldest) {
+ /* If there are no more slots, expire the oldest */
+ found = oldest;
+ clear_bss_descriptor(found);
+- list_move_tail(&found->list, &adapter->network_list);
++ list_move_tail(&found->list, &priv->network_list);
+ } else {
+ continue;
+ }
+
+- lbs_deb_scan("SCAN_RESP: BSSID = " MAC_FMT "\n",
+- new.bssid[0], new.bssid[1], new.bssid[2],
+- new.bssid[3], new.bssid[4], new.bssid[5]);
+-
+- /*
+- * If the TSF TLV was appended to the scan results, save the
+- * this entries TSF value in the networktsf field. The
+- * networktsf is the firmware's TSF value at the time the
+- * beacon or probe response was received.
+- */
+- if (ptsftlv) {
+- new.networktsf = le64_to_cpup(&ptsftlv->tsftable[idx]);
+- }
++ lbs_deb_scan("SCAN_RESP: BSSID %s\n",
++ print_mac(mac, new.bssid));
+
+ /* Copy the locally created newbssentry to the scan table */
+ memcpy(found, &new, offsetof(struct bss_descriptor, list));
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/scan.h linux-2.6.22-300/drivers/net/wireless/libertas/scan.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/scan.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/scan.h 2008-06-05 18:10:06.000000000 -0400
+@@ -2,10 +2,10 @@
+ * Interface for the wlan network scan routines
+ *
+ * Driver interface functions and type declarations for the scan module
+- * implemented in wlan_scan.c.
++ * implemented in scan.c.
+ */
+-#ifndef _WLAN_SCAN_H
+-#define _WLAN_SCAN_H
++#ifndef _LBS_SCAN_H
++#define _LBS_SCAN_H
+
+ #include <net/ieee80211.h>
+ #include "hostcmd.h"
+@@ -13,38 +13,38 @@
+ /**
+ * @brief Maximum number of channels that can be sent in a setuserscan ioctl
+ *
+- * @sa wlan_ioctl_user_scan_cfg
++ * @sa lbs_ioctl_user_scan_cfg
+ */
+-#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50
++#define LBS_IOCTL_USER_SCAN_CHAN_MAX 50
+
+-//! Infrastructure BSS scan type in wlan_scan_cmd_config
+-#define WLAN_SCAN_BSS_TYPE_BSS 1
++//! Infrastructure BSS scan type in lbs_scan_cmd_config
++#define LBS_SCAN_BSS_TYPE_BSS 1
+
+-//! Adhoc BSS scan type in wlan_scan_cmd_config
+-#define WLAN_SCAN_BSS_TYPE_IBSS 2
++//! Adhoc BSS scan type in lbs_scan_cmd_config
++#define LBS_SCAN_BSS_TYPE_IBSS 2
+
+-//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter
+-#define WLAN_SCAN_BSS_TYPE_ANY 3
++//! Adhoc or Infrastructure BSS scan type in lbs_scan_cmd_config, no filter
++#define LBS_SCAN_BSS_TYPE_ANY 3
+
+ /**
+ * @brief Structure used internally in the wlan driver to configure a scan.
+ *
+ * Sent to the command processing module to configure the firmware
+- * scan command prepared by libertas_cmd_80211_scan.
++ * scan command prepared by lbs_cmd_80211_scan.
+ *
+- * @sa wlan_scan_networks
++ * @sa lbs_scan_networks
+ *
+ */
+-struct wlan_scan_cmd_config {
++struct lbs_scan_cmd_config {
+ /**
+ * @brief BSS type to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. valid settings are:
+ *
+- * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure)
+- * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+- * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
++ * - LBS_SCAN_BSS_TYPE_BSS (infrastructure)
++ * - LBS_SCAN_BSS_TYPE_IBSS (adhoc)
++ * - LBS_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ u8 bsstype;
+
+@@ -68,12 +68,12 @@ struct wlan_scan_cmd_config {
+ };
+
+ /**
+- * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
++ * @brief IOCTL channel sub-structure sent in lbs_ioctl_user_scan_cfg
+ *
+ * Multiple instances of this structure are included in the IOCTL command
+ * to configure a instance of a scan on the specific channel.
+ */
+-struct wlan_ioctl_user_scan_chan {
++struct lbs_ioctl_user_scan_chan {
+ u8 channumber; //!< channel Number to scan
+ u8 radiotype; //!< Radio type: 'B/G' band = 0, 'A' band = 1
+ u8 scantype; //!< Scan type: Active = 0, Passive = 1
+@@ -83,31 +83,26 @@ struct wlan_ioctl_user_scan_chan {
+ /**
+ * @brief IOCTL input structure to configure an immediate scan cmd to firmware
+ *
+- * Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl. Specifies
++ * Used in the setuserscan (LBS_SET_USER_SCAN) private ioctl. Specifies
+ * a number of parameters to be used in general for the scan as well
+- * as a channel list (wlan_ioctl_user_scan_chan) for each scan period
++ * as a channel list (lbs_ioctl_user_scan_chan) for each scan period
+ * desired.
+ *
+- * @sa libertas_set_user_scan_ioctl
++ * @sa lbs_set_user_scan_ioctl
+ */
+-struct wlan_ioctl_user_scan_cfg {
++struct lbs_ioctl_user_scan_cfg {
+ /**
+ * @brief BSS type to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. valid settings are:
+ *
+- * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure)
+- * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+- * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
++ * - LBS_SCAN_BSS_TYPE_BSS (infrastructure)
++ * - LBS_SCAN_BSS_TYPE_IBSS (adhoc)
++ * - LBS_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ u8 bsstype;
+
+- /**
+- * @brief Configure the number of probe requests for active chan scans
+- */
+- u8 numprobes;
+-
+ /**
+ * @brief BSSID filter sent in the firmware command to limit the results
+ */
+@@ -124,11 +119,6 @@ struct wlan_ioctl_user_scan_cfg {
+
+ /* Clear existing scan results matching this SSID */
+ u8 clear_ssid;
+-
+- /**
+- * @brief Variable number (fixed maximum) of channels to scan up
+- */
+- struct wlan_ioctl_user_scan_chan chanlist[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+ };
+
+ /**
+@@ -140,8 +130,7 @@ struct bss_descriptor {
+ u8 ssid[IW_ESSID_MAX_SIZE + 1];
+ u8 ssid_len;
+
+- /* WEP encryption requirement */
+- u32 privacy;
++ u16 capability;
+
+ /* receive signal strength in dBm */
+ long rssi;
+@@ -152,18 +141,16 @@ struct bss_descriptor {
+
+ u32 atimwindow;
+
++ /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
+ u8 mode;
+- u8 libertas_supported_rates[WLAN_SUPPORTED_RATES];
+
+- __le64 timestamp; //!< TSF value included in the beacon/probe response
++ /* zero-terminated array of supported data rates */
++ u8 rates[MAX_RATES + 1];
++
+ unsigned long last_scanned;
+
+ union ieeetypes_phyparamset phyparamset;
+ union IEEEtypes_ssparamset ssparamset;
+- struct ieeetypes_capinfo cap;
+- u8 datarates[WLAN_SUPPORTED_RATES];
+-
+- u64 networktsf; //!< TSF timestamp from the current firmware TSF
+
+ struct ieeetypes_countryinfofullset countryinfo;
+
+@@ -172,38 +159,35 @@ struct bss_descriptor {
+ u8 rsn_ie[MAX_WPA_IE_LEN];
+ size_t rsn_ie_len;
+
++ u8 mesh;
++
+ struct list_head list;
+ };
+
+-extern int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
++int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
+
+-struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
+- u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode,
+- int channel);
++struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
++ u8 *ssid, u8 ssid_len, u8 *bssid, u8 mode,
++ int channel);
+
+-struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
+- u8 mode);
++struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
++ u8 *bssid, u8 mode);
+
+-extern struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
+- u8 * bssid, u8 mode);
+-
+-int libertas_find_best_network_ssid(wlan_private * priv, u8 *out_ssid,
++int lbs_find_best_network_ssid(struct lbs_private *priv, u8 *out_ssid,
+ u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode);
+
+-extern int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid,
++int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
+ u8 ssid_len, u8 clear_ssid);
+-extern int libertas_send_specific_bssid_scan(wlan_private * priv,
+- u8 * bssid, u8 clear_bssid);
+
+-extern int libertas_cmd_80211_scan(wlan_private * priv,
++int lbs_cmd_80211_scan(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+
+-extern int libertas_ret_80211_scan(wlan_private * priv,
++int lbs_ret_80211_scan(struct lbs_private *priv,
+ struct cmd_ds_command *resp);
+
+-int wlan_scan_networks(wlan_private * priv,
+- const struct wlan_ioctl_user_scan_cfg * puserscanin,
++int lbs_scan_networks(struct lbs_private *priv,
++ const struct lbs_ioctl_user_scan_cfg *puserscanin,
+ int full_scan);
+
+ struct ifreq;
+@@ -211,9 +195,11 @@ struct ifreq;
+ struct iw_point;
+ struct iw_param;
+ struct iw_request_info;
+-extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
++int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra);
+-extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
++int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra);
+
+-#endif /* _WLAN_SCAN_H */
++void lbs_scan_worker(struct work_struct *work);
++
++#endif
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/thread.h linux-2.6.22-300/drivers/net/wireless/libertas/thread.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/thread.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/thread.h 1969-12-31 19:00:00.000000000 -0500
+@@ -1,52 +0,0 @@
+-#ifndef __WLAN_THREAD_H_
+-#define __WLAN_THREAD_H_
+-
+-#include <linux/kthread.h>
+-
+-struct wlan_thread {
+- struct task_struct *task;
+- wait_queue_head_t waitq;
+- pid_t pid;
+- void *priv;
+-};
+-
+-static inline void wlan_activate_thread(struct wlan_thread * thr)
+-{
+- /** Record the thread pid */
+- thr->pid = current->pid;
+-
+- /** Initialize the wait queue */
+- init_waitqueue_head(&thr->waitq);
+-}
+-
+-static inline void wlan_deactivate_thread(struct wlan_thread * thr)
+-{
+- lbs_deb_enter(LBS_DEB_THREAD);
+-
+- thr->pid = 0;
+-
+- lbs_deb_leave(LBS_DEB_THREAD);
+-}
+-
+-static inline void wlan_create_thread(int (*wlanfunc) (void *),
+- struct wlan_thread * thr, char *name)
+-{
+- thr->task = kthread_run(wlanfunc, thr, "%s", name);
+-}
+-
+-static inline int wlan_terminate_thread(struct wlan_thread * thr)
+-{
+- lbs_deb_enter(LBS_DEB_THREAD);
+-
+- /* Check if the thread is active or not */
+- if (!thr->pid) {
+- printk(KERN_ERR "Thread does not exist\n");
+- return -1;
+- }
+- kthread_stop(thr->task);
+-
+- lbs_deb_leave(LBS_DEB_THREAD);
+- return 0;
+-}
+-
+-#endif
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/tx.c linux-2.6.22-300/drivers/net/wireless/libertas/tx.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/tx.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/tx.c 2008-06-05 18:10:06.000000000 -0400
+@@ -2,6 +2,7 @@
+ * This file contains the handling of TX in wlan driver.
+ */
+ #include <linux/netdevice.h>
++#include <linux/etherdevice.h>
+
+ #include "hostcmd.h"
+ #include "radiotap.h"
+@@ -10,6 +11,13 @@
+ #include "dev.h"
+ #include "wext.h"
+
++static int multicast_ttl_override = 1;
++static int broadcast_ttl_override = 0;
++static int unicast_ttl_override = 0;
++module_param(multicast_ttl_override, int, 0644);
++module_param(broadcast_ttl_override, int, 0644);
++module_param(unicast_ttl_override, int, 0644);
++
+ /**
+ * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
+ * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
+@@ -49,194 +57,146 @@ static u32 convert_radiotap_rate_to_mv(u
+ }
+
+ /**
+- * @brief This function processes a single packet and sends
+- * to IF layer
++ * @brief This function checks the conditions and sends packet to IF
++ * layer if everything is ok.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param skb A pointer to skb which includes TX packet
+ * @return 0 or -1
+ */
+-static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
++int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+- wlan_adapter *adapter = priv->adapter;
+- int ret = 0;
+- struct txpd localtxpd;
+- struct txpd *plocaltxpd = &localtxpd;
+- u8 *p802x_hdr;
+- struct tx_radiotap_hdr *pradiotap_hdr;
+- u32 new_rate;
+- u8 *ptr = priv->adapter->tmptxbuf;
++ unsigned long flags;
++ struct lbs_private *priv = dev->priv;
++ struct txpd *txpd;
++ char *tx_data;
++ char *p802x_hdr;
++ uint16_t pkt_len;
++ int ret;
+
+ lbs_deb_enter(LBS_DEB_TX);
+
+- if (priv->adapter->surpriseremoved)
+- return -1;
++ ret = NETDEV_TX_OK;
++
++ /* We need to protect against the queues being restarted before
++ we get round to stopping them */
++ spin_lock_irqsave(&priv->driver_lock, flags);
+
+- if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
+- lbs_dbg_hex("TX packet: ", skb->data,
+- min_t(unsigned int, skb->len, 100));
++ if (priv->surpriseremoved)
++ goto free;
+
+ if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
+ lbs_deb_tx("tx err: skb length %d 0 or > %zd\n",
+ skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
+- ret = -1;
+- goto done;
+- }
++ /* We'll never manage to send this one; drop it and return 'OK' */
+
+- memset(plocaltxpd, 0, sizeof(struct txpd));
++ priv->stats.tx_dropped++;
++ priv->stats.tx_errors++;
++ goto free;
++ }
+
+- plocaltxpd->tx_packet_length = cpu_to_le16(skb->len);
+
+- /* offset of actual data */
+- plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
++ netif_stop_queue(priv->dev);
++ if (priv->mesh_dev)
++ netif_stop_queue(priv->mesh_dev);
+
+- /* TxCtrl set by user or default */
+- plocaltxpd->tx_control = cpu_to_le32(adapter->pkttxctrl);
++ if (priv->tx_pending_len) {
++ /* This can happen if packets come in on the mesh and eth
++ device simultaneously -- there's no mutual exclusion on
++ hard_start_xmit() calls between devices. */
++ lbs_deb_tx("Packet on %s while busy\n", dev->name);
++ ret = NETDEV_TX_BUSY;
++ goto unlock;
++ }
++
++ priv->tx_pending_len = -1;
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++
++ lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
++
++ txpd = (void *)priv->tx_pending_buf;
++ tx_data = (void *)&txpd[1];
++ memset(txpd, 0, sizeof(struct txpd));
+
+ p802x_hdr = skb->data;
+- if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
++ pkt_len = skb->len;
+
+- /* locate radiotap header */
+- pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
++ if (dev == priv->rtap_net_dev) {
++ struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
+
+ /* set txpd fields from the radiotap header */
+- new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
+- if (new_rate != 0) {
+- /* use new tx_control[4:0] */
+- new_rate |= (adapter->pkttxctrl & ~0x1f);
+- plocaltxpd->tx_control = cpu_to_le32(new_rate);
+- }
++ txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate));
+
+ /* skip the radiotap header */
+- p802x_hdr += sizeof(struct tx_radiotap_hdr);
+- plocaltxpd->tx_packet_length =
+- cpu_to_le16(le16_to_cpu(plocaltxpd->tx_packet_length)
+- - sizeof(struct tx_radiotap_hdr));
++ p802x_hdr += sizeof(*rtap_hdr);
++ pkt_len -= sizeof(*rtap_hdr);
+
++ /* copy destination address from 802.11 header */
++ memcpy(txpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
++ } else {
++ /* copy destination address from 802.3 header */
++ memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
+ }
+- /* copy destination address from 802.3 or 802.11 header */
+- if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+- memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
+- else
+- memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
+
+- lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
++ txpd->tx_packet_length = cpu_to_le16(pkt_len);
++ txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
+
+- if (IS_MESH_FRAME(skb)) {
+- plocaltxpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
++ if (dev == priv->mesh_dev) {
++ int ttl_override;
++
++ txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
++
++ if (is_broadcast_ether_addr(txpd->tx_dest_addr_high))
++ ttl_override = broadcast_ttl_override;
++ else if (is_multicast_ether_addr(txpd->tx_dest_addr_high))
++ ttl_override = multicast_ttl_override;
++ else
++ ttl_override = unicast_ttl_override;
++
++ if (ttl_override) {
++ /* Hack: set mesh ttl to 1 for mesh multicasts. If
++ tx_packet_location has room for the extra three
++ bytes, the firmware treats it as follows: */
++ tx_data[0] = 0; /* reserved */
++ tx_data[1] = 0; /* reserved */
++ tx_data[2] = ttl_override; /* ttl */
++ tx_data += 3;
++ txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd) + 3);
++ }
+ }
++
+
+- memcpy(ptr, plocaltxpd, sizeof(struct txpd));
++ lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd));
+
+- ptr += sizeof(struct txpd);
++ lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, pkt_len);
+
+- lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
+- memcpy(ptr, p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
+- ret = priv->hw_host_to_card(priv, MVMS_DAT,
+- priv->adapter->tmptxbuf,
+- le16_to_cpu(plocaltxpd->tx_packet_length) +
+- sizeof(struct txpd));
+-
+- if (ret) {
+- lbs_deb_tx("tx err: hw_host_to_card returned 0x%X\n", ret);
+- goto done;
+- }
++ memcpy(tx_data, p802x_hdr, pkt_len);
+
+- lbs_deb_tx("SendSinglePacket succeeds\n");
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ priv->tx_pending_len = pkt_len + le32_to_cpu(txpd->tx_packet_location);
+
+-done:
+- if (!ret) {
+- priv->stats.tx_packets++;
+- priv->stats.tx_bytes += skb->len;
+- } else {
+- priv->stats.tx_dropped++;
+- priv->stats.tx_errors++;
+- }
++ lbs_deb_tx("%s lined up packet\n", __func__);
++
++ priv->stats.tx_packets++;
++ priv->stats.tx_bytes += skb->len;
+
+- if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
++ dev->trans_start = jiffies;
++
++ if (priv->monitormode != LBS_MONITOR_OFF) {
+ /* Keep the skb to echo it back once Tx feedback is
+ received from FW */
+ skb_orphan(skb);
+- /* stop processing outgoing pkts */
+- netif_stop_queue(priv->dev);
+- netif_stop_queue(priv->mesh_dev);
+- /* freeze any packets already in our queues */
+- priv->adapter->TxLockFlag = 1;
+- } else {
+- dev_kfree_skb_any(skb);
+- priv->adapter->currenttxskb = NULL;
+- }
+
+- lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret);
+- return ret;
+-}
+-
+-
+-void libertas_tx_runqueue(wlan_private *priv)
+-{
+- wlan_adapter *adapter = priv->adapter;
+- int i;
+-
+- spin_lock(&adapter->txqueue_lock);
+- for (i = 0; i < adapter->tx_queue_idx; i++) {
+- struct sk_buff *skb = adapter->tx_queue_ps[i];
+- spin_unlock(&adapter->txqueue_lock);
+- SendSinglePacket(priv, skb);
+- spin_lock(&adapter->txqueue_lock);
+- }
+- adapter->tx_queue_idx = 0;
+- spin_unlock(&adapter->txqueue_lock);
+-}
+-
+-static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb)
+-{
+- wlan_adapter *adapter = priv->adapter;
+-
+- spin_lock(&adapter->txqueue_lock);
+-
+- WARN_ON(priv->adapter->tx_queue_idx >= NR_TX_QUEUE);
+- adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb;
+- if (adapter->tx_queue_idx == NR_TX_QUEUE) {
+- netif_stop_queue(priv->dev);
+- netif_stop_queue(priv->mesh_dev);
++ /* Keep the skb around for when we get feedback */
++ priv->currenttxskb = skb;
+ } else {
+- netif_start_queue(priv->dev);
+- netif_start_queue(priv->mesh_dev);
+- }
+-
+- spin_unlock(&adapter->txqueue_lock);
+-}
+-
+-/**
+- * @brief This function checks the conditions and sends packet to IF
+- * layer if everything is ok.
+- *
+- * @param priv A pointer to wlan_private structure
+- * @return n/a
+- */
+-int libertas_process_tx(wlan_private * priv, struct sk_buff *skb)
+-{
+- int ret = -1;
+-
+- lbs_deb_enter(LBS_DEB_TX);
+- lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100));
+-
+- if (priv->dnld_sent) {
+- lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n",
+- priv->dnld_sent);
+- goto done;
+- }
+-
+- if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
+- (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) {
+- wlan_tx_queue(priv, skb);
+- return ret;
++ free:
++ dev_kfree_skb_any(skb);
+ }
++ unlock:
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++ wake_up(&priv->waitq);
+
+- priv->adapter->currenttxskb = skb;
+-
+- ret = SendSinglePacket(priv, skb);
+-done:
+ lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret);
+ return ret;
+ }
+@@ -245,28 +205,23 @@ done:
+ * @brief This function sends to the host the last transmitted packet,
+ * filling the radiotap headers with transmission information.
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param status A 32 bit value containing transmission status.
+ *
+ * @returns void
+ */
+-void libertas_send_tx_feedback(wlan_private * priv)
++void lbs_send_tx_feedback(struct lbs_private *priv)
+ {
+- wlan_adapter *adapter = priv->adapter;
+ struct tx_radiotap_hdr *radiotap_hdr;
+- u32 status = adapter->eventcause;
++ u32 status = priv->eventcause;
+ int txfail;
+ int try_count;
+
+- if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP ||
+- adapter->currenttxskb == NULL)
++ if (priv->monitormode == LBS_MONITOR_OFF ||
++ priv->currenttxskb == NULL)
+ return;
+
+- radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data;
+-
+- if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
+- lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr,
+- min_t(unsigned int, adapter->currenttxskb->len, 100));
++ radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
+
+ txfail = (status >> 24);
+
+@@ -279,13 +234,19 @@ void libertas_send_tx_feedback(wlan_priv
+ #endif
+ try_count = (status >> 16) & 0xff;
+ radiotap_hdr->data_retries = (try_count) ?
+- (1 + adapter->txretrycount - try_count) : 0;
+- libertas_upload_rx_packet(priv, adapter->currenttxskb);
+- adapter->currenttxskb = NULL;
+- priv->adapter->TxLockFlag = 0;
+- if (priv->adapter->connect_status == libertas_connected) {
++ (1 + priv->txretrycount - try_count) : 0;
++
++
++ priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
++ priv->rtap_net_dev);
++ netif_rx(priv->currenttxskb);
++
++ priv->currenttxskb = NULL;
++
++ if (priv->connect_status == LBS_CONNECTED)
+ netif_wake_queue(priv->dev);
++
++ if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED))
+ netif_wake_queue(priv->mesh_dev);
+- }
+ }
+-EXPORT_SYMBOL_GPL(libertas_send_tx_feedback);
++EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/types.h linux-2.6.22-300/drivers/net/wireless/libertas/types.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/types.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/types.h 2008-06-05 18:10:06.000000000 -0400
+@@ -1,76 +1,13 @@
+ /**
+ * This header file contains definition for global types
+ */
+-#ifndef _WLAN_TYPES_
+-#define _WLAN_TYPES_
++#ifndef _LBS_TYPES_H_
++#define _LBS_TYPES_H_
+
+ #include <linux/if_ether.h>
+ #include <asm/byteorder.h>
+-
+-/** IEEE type definitions */
+-enum ieeetypes_elementid {
+- SSID = 0,
+- SUPPORTED_RATES,
+- FH_PARAM_SET,
+- DS_PARAM_SET,
+- CF_PARAM_SET,
+- TIM,
+- IBSS_PARAM_SET,
+- COUNTRY_INFO = 7,
+-
+- CHALLENGE_TEXT = 16,
+-
+- EXTENDED_SUPPORTED_RATES = 50,
+-
+- VENDOR_SPECIFIC_221 = 221,
+-
+- WPA_IE = 221,
+- WPA2_IE = 48,
+-
+- EXTRA_IE = 133,
+-} __attribute__ ((packed));
+-
+-#ifdef __BIG_ENDIAN
+-#define CAPINFO_MASK (~(0xda00))
+-#else
+-#define CAPINFO_MASK (~(0x00da))
+-#endif
+-
+-struct ieeetypes_capinfo {
+-#ifdef __BIG_ENDIAN_BITFIELD
+- u8 chanagility:1;
+- u8 pbcc:1;
+- u8 shortpreamble:1;
+- u8 privacy:1;
+- u8 cfpollrqst:1;
+- u8 cfpollable:1;
+- u8 ibss:1;
+- u8 ess:1;
+- u8 rsrvd1:2;
+- u8 dsssofdm:1;
+- u8 rsvrd2:1;
+- u8 apsd:1;
+- u8 shortslottime:1;
+- u8 rsrvd3:1;
+- u8 spectrummgmt:1;
+-#else
+- u8 ess:1;
+- u8 ibss:1;
+- u8 cfpollable:1;
+- u8 cfpollrqst:1;
+- u8 privacy:1;
+- u8 shortpreamble:1;
+- u8 pbcc:1;
+- u8 chanagility:1;
+- u8 spectrummgmt:1;
+- u8 rsrvd3:1;
+- u8 shortslottime:1;
+- u8 apsd:1;
+- u8 rsvrd2:1;
+- u8 dsssofdm:1;
+- u8 rsrvd1:2;
+-#endif
+-} __attribute__ ((packed));
++#include <linux/wireless.h>
++#include <net/ieee80211.h>
+
+ struct ieeetypes_cfparamset {
+ u8 elementid;
+@@ -114,7 +51,7 @@ union ieeetypes_phyparamset {
+ } __attribute__ ((packed));
+
+ struct ieeetypes_assocrsp {
+- struct ieeetypes_capinfo capability;
++ __le16 capability;
+ __le16 statuscode;
+ __le16 aid;
+ u8 iebuffer[1];
+@@ -266,22 +203,11 @@ struct mrvlietypes_powercapability {
+ s8 maxpower;
+ } __attribute__ ((packed));
+
+-struct mrvlietypes_rssithreshold {
+- struct mrvlietypesheader header;
+- u8 rssivalue;
+- u8 rssifreq;
+-} __attribute__ ((packed));
+-
+-struct mrvlietypes_snrthreshold {
++/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
++struct mrvlietypes_thresholds {
+ struct mrvlietypesheader header;
+- u8 snrvalue;
+- u8 snrfreq;
+-} __attribute__ ((packed));
+-
+-struct mrvlietypes_failurecount {
+- struct mrvlietypesheader header;
+- u8 failvalue;
+- u8 Failfreq;
++ u8 value;
++ u8 freq;
+ } __attribute__ ((packed));
+
+ struct mrvlietypes_beaconsmissed {
+@@ -315,4 +241,45 @@ struct mrvlietypes_ledgpio {
+ struct led_pin ledpin[1];
+ } __attribute__ ((packed));
+
+-#endif /* _WLAN_TYPES_ */
++struct led_bhv {
++ uint8_t firmwarestate;
++ uint8_t led;
++ uint8_t ledstate;
++ uint8_t ledarg;
++} __attribute__ ((packed));
++
++
++struct mrvlietypes_ledbhv {
++ struct mrvlietypesheader header;
++ struct led_bhv ledbhv[1];
++} __attribute__ ((packed));
++
++/* Meant to be packed as the value member of a struct ieee80211_info_element.
++ * Note that the len member of the ieee80211_info_element varies depending on
++ * the mesh_id_len */
++struct mrvl_meshie_val {
++ uint8_t oui[P80211_OUI_LEN];
++ uint8_t type;
++ uint8_t subtype;
++ uint8_t version;
++ uint8_t active_protocol_id;
++ uint8_t active_metric_id;
++ uint8_t mesh_capability;
++ uint8_t mesh_id_len;
++ uint8_t mesh_id[IW_ESSID_MAX_SIZE];
++} __attribute__ ((packed));
++
++struct mrvl_meshie {
++ struct ieee80211_info_element hdr;
++ struct mrvl_meshie_val val;
++} __attribute__ ((packed));
++
++struct mrvl_mesh_defaults {
++ __le32 bootflag;
++ uint8_t boottime;
++ uint8_t reserved;
++ __le16 channel;
++ struct mrvl_meshie meshie;
++} __attribute__ ((packed));
++
++#endif
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/version.h linux-2.6.22-300/drivers/net/wireless/libertas/version.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/version.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/version.h 1969-12-31 19:00:00.000000000 -0500
+@@ -1 +0,0 @@
+-
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/wext.c linux-2.6.22-300/drivers/net/wireless/libertas/wext.c
+--- linux-2.6.22-250/drivers/net/wireless/libertas/wext.c 2008-07-17 00:17:57.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/wext.c 2008-06-05 18:10:06.000000000 -0400
+@@ -19,84 +19,47 @@
+ #include "join.h"
+ #include "wext.h"
+ #include "assoc.h"
++#include "cmd.h"
++#include "ioctl.h"
+
++static inline void lbs_postpone_association_work(struct lbs_private *priv)
++{
++ if (priv->surpriseremoved)
++ return;
++ cancel_delayed_work(&priv->assoc_work);
++ queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2);
++}
+
+-/**
+- * the rates supported by the card
+- */
+-static u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
+- { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+- 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
+-};
+-
+-/**
+- * @brief Convert mw value to dbm value
+- *
+- * @param mw the value of mw
+- * @return the value of dbm
+- */
+-static int mw_to_dbm(int mw)
++static inline void lbs_cancel_association_work(struct lbs_private *priv)
+ {
+- if (mw < 2)
+- return 0;
+- else if (mw < 3)
+- return 3;
+- else if (mw < 4)
+- return 5;
+- else if (mw < 6)
+- return 7;
+- else if (mw < 7)
+- return 8;
+- else if (mw < 8)
+- return 9;
+- else if (mw < 10)
+- return 10;
+- else if (mw < 13)
+- return 11;
+- else if (mw < 16)
+- return 12;
+- else if (mw < 20)
+- return 13;
+- else if (mw < 25)
+- return 14;
+- else if (mw < 32)
+- return 15;
+- else if (mw < 40)
+- return 16;
+- else if (mw < 50)
+- return 17;
+- else if (mw < 63)
+- return 18;
+- else if (mw < 79)
+- return 19;
+- else if (mw < 100)
+- return 20;
+- else
+- return 21;
++ cancel_delayed_work(&priv->assoc_work);
++ kfree(priv->pending_assoc_req);
++ priv->pending_assoc_req = NULL;
+ }
+
++
+ /**
+ * @brief Find the channel frequency power info with specific channel
+ *
+- * @param adapter A pointer to wlan_adapter structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param band it can be BAND_A, BAND_G or BAND_B
+ * @param channel the channel for looking
+ * @return A pointer to struct chan_freq_power structure or NULL if not find.
+ */
+-struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter,
+- u8 band, u16 channel)
++struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
++ struct lbs_private *priv,
++ u8 band,
++ u16 channel)
+ {
+ struct chan_freq_power *cfp = NULL;
+ struct region_channel *rc;
+- int count = sizeof(adapter->region_channel) /
+- sizeof(adapter->region_channel[0]);
+ int i, j;
+
+- for (j = 0; !cfp && (j < count); j++) {
+- rc = &adapter->region_channel[j];
++ for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
++ rc = &priv->region_channel[j];
+
+- if (adapter->enable11d)
+- rc = &adapter->universal_channel[j];
++ if (priv->enable11d)
++ rc = &priv->universal_channel[j];
+ if (!rc->valid || !rc->CFP)
+ continue;
+ if (rc->band != band)
+@@ -110,7 +73,7 @@ struct chan_freq_power *libertas_find_cf
+ }
+
+ if (!cfp && channel)
+- lbs_deb_wext("libertas_find_cfp_by_band_and_channel: can't find "
++ lbs_deb_wext("lbs_find_cfp_by_band_and_channel: can't find "
+ "cfp by band %d / channel %d\n", band, channel);
+
+ return cfp;
+@@ -119,25 +82,25 @@ struct chan_freq_power *libertas_find_cf
+ /**
+ * @brief Find the channel frequency power info with specific frequency
+ *
+- * @param adapter A pointer to wlan_adapter structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param band it can be BAND_A, BAND_G or BAND_B
+ * @param freq the frequency for looking
+ * @return A pointer to struct chan_freq_power structure or NULL if not find.
+ */
+-static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
+- u8 band, u32 freq)
++static struct chan_freq_power *find_cfp_by_band_and_freq(
++ struct lbs_private *priv,
++ u8 band,
++ u32 freq)
+ {
+ struct chan_freq_power *cfp = NULL;
+ struct region_channel *rc;
+- int count = sizeof(adapter->region_channel) /
+- sizeof(adapter->region_channel[0]);
+ int i, j;
+
+- for (j = 0; !cfp && (j < count); j++) {
+- rc = &adapter->region_channel[j];
++ for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
++ rc = &priv->region_channel[j];
+
+- if (adapter->enable11d)
+- rc = &adapter->universal_channel[j];
++ if (priv->enable11d)
++ rc = &priv->universal_channel[j];
+ if (!rc->valid || !rc->CFP)
+ continue;
+ if (rc->band != band)
+@@ -161,25 +124,24 @@ static struct chan_freq_power *find_cfp_
+ /**
+ * @brief Set Radio On/OFF
+ *
+- * @param priv A pointer to wlan_private structure
++ * @param priv A pointer to struct lbs_private structure
+ * @option Radio Option
+ * @return 0 --success, otherwise fail
+ */
+-int wlan_radio_ioctl(wlan_private * priv, u8 option)
++static int lbs_radio_ioctl(struct lbs_private *priv, u8 option)
+ {
+ int ret = 0;
+- wlan_adapter *adapter = priv->adapter;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- if (adapter->radioon != option) {
++ if (priv->radioon != option) {
+ lbs_deb_wext("switching radio %s\n", option ? "on" : "off");
+- adapter->radioon = option;
++ priv->radioon = option;
+
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_radio_control,
+- cmd_act_set,
+- cmd_option_waitforrsp, 0, NULL);
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_RADIO_CONTROL,
++ CMD_ACT_SET,
++ CMD_OPTION_WAITFORRSP, 0, NULL);
+ }
+
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+@@ -187,105 +149,52 @@ int wlan_radio_ioctl(wlan_private * priv
+ }
+
+ /**
+- * @brief Copy rates
+- *
+- * @param dest A pointer to Dest Buf
+- * @param src A pointer to Src Buf
+- * @param len The len of Src Buf
+- * @return Number of rates copyed
+- */
+-static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
+-{
+- int i;
+-
+- for (i = 0; i < len && src[i]; i++, pos++) {
+- if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
+- break;
+- dest[pos] = src[i];
+- }
+-
+- return pos;
+-}
+-
+-/**
+- * @brief Get active data rates
++ * @brief Copy active data rates based on adapter mode and status
+ *
+- * @param adapter A pointer to wlan_adapter structure
++ * @param priv A pointer to struct lbs_private structure
+ * @param rate The buf to return the active rates
+- * @return The number of rates
+ */
+-static int get_active_data_rates(wlan_adapter * adapter,
+- u8* rates)
++static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)
+ {
+- int k = 0;
+-
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- if (adapter->connect_status != libertas_connected) {
+- if (adapter->mode == IW_MODE_INFRA) {
+- lbs_deb_wext("infra\n");
+- k = copyrates(rates, k, libertas_supported_rates,
+- sizeof(libertas_supported_rates));
+- } else {
+- lbs_deb_wext("Adhoc G\n");
+- k = copyrates(rates, k, libertas_adhoc_rates_g,
+- sizeof(libertas_adhoc_rates_g));
+- }
+- } else {
+- k = copyrates(rates, 0, adapter->curbssparams.datarates,
+- adapter->curbssparams.numofrates);
+- }
++ if ((priv->connect_status != LBS_CONNECTED) &&
++ (priv->mesh_connect_status != LBS_CONNECTED))
++ memcpy(rates, lbs_bg_rates, MAX_RATES);
++ else
++ memcpy(rates, priv->curbssparams.rates, MAX_RATES);
+
+- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", k);
+- return k;
++ lbs_deb_leave(LBS_DEB_WEXT);
+ }
+
+-static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
++static int lbs_get_name(struct net_device *dev, struct iw_request_info *info,
+ char *cwrq, char *extra)
+ {
+- const char *cp;
+- char comm[6] = { "COMM-" };
+- char mrvl[6] = { "MRVL-" };
+- int cnt;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- strcpy(cwrq, mrvl);
+-
+- cp = strstr(libertas_driver_version, comm);
+- if (cp == libertas_driver_version) //skip leading "COMM-"
+- cp = libertas_driver_version + strlen(comm);
+- else
+- cp = libertas_driver_version;
+-
+- cnt = strlen(mrvl);
+- cwrq += cnt;
+- while (cnt < 16 && (*cp != '-')) {
+- *cwrq++ = toupper(*cp++);
+- cnt++;
+- }
+- *cwrq = '\0';
++ /* We could add support for 802.11n here as needed. Jean II */
++ snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g");
+
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return 0;
+ }
+
+-static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
++static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ struct chan_freq_power *cfp;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
+- adapter->curbssparams.channel);
++ cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
++ priv->curbssparams.channel);
+
+ if (!cfp) {
+- if (adapter->curbssparams.channel)
++ if (priv->curbssparams.channel)
+ lbs_deb_wext("invalid channel %d\n",
+- adapter->curbssparams.channel);
++ priv->curbssparams.channel);
+ return -EINVAL;
+ }
+
+@@ -297,16 +206,15 @@ static int wlan_get_freq(struct net_devi
+ return 0;
+ }
+
+-static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
++static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- if (adapter->connect_status == libertas_connected) {
+- memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
++ if (priv->connect_status == LBS_CONNECTED) {
++ memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN);
+ } else {
+ memset(awrq->sa_data, 0, ETH_ALEN);
+ }
+@@ -316,11 +224,10 @@ static int wlan_get_wap(struct net_devic
+ return 0;
+ }
+
+-static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
++static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+@@ -332,41 +239,27 @@ static int wlan_set_nick(struct net_devi
+ return -E2BIG;
+ }
+
+- mutex_lock(&adapter->lock);
+- memset(adapter->nodename, 0, sizeof(adapter->nodename));
+- memcpy(adapter->nodename, extra, dwrq->length);
+- mutex_unlock(&adapter->lock);
++ mutex_lock(&priv->lock);
++ memset(priv->nodename, 0, sizeof(priv->nodename));
++ memcpy(priv->nodename, extra, dwrq->length);
++ mutex_unlock(&priv->lock);
+
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return 0;
+ }
+
+-static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
++static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- /*
+- * Get the Nick Name saved
+- */
+-
+- mutex_lock(&adapter->lock);
+- strncpy(extra, adapter->nodename, 16);
+- mutex_unlock(&adapter->lock);
+-
+- extra[16] = '\0';
+-
+- /*
+- * If none, we may want to get the one that was set
+- */
++ dwrq->length = strlen(priv->nodename);
++ memcpy(extra, priv->nodename, dwrq->length);
++ extra[dwrq->length] = '\0';
+
+- /*
+- * Push it out !
+- */
+- dwrq->length = strlen(extra) + 1;
++ dwrq->flags = 1; /* active */
+
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return 0;
+@@ -375,70 +268,68 @@ static int wlan_get_nick(struct net_devi
+ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+ /* Use nickname to indicate that mesh is on */
+
+- if (adapter->connect_status == libertas_connected) {
++ if (priv->mesh_connect_status == LBS_CONNECTED) {
+ strncpy(extra, "Mesh", 12);
+ extra[12] = '\0';
+- dwrq->length = strlen(extra) + 1;
++ dwrq->length = strlen(extra);
+ }
+
+ else {
+ extra[0] = '\0';
+- dwrq->length = 1 ;
++ dwrq->length = 0;
+ }
+
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return 0;
+ }
+-static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
++
++static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+ {
+ int ret = 0;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ u32 rthr = vwrq->value;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+ if (vwrq->disabled) {
+- adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
++ priv->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
+ } else {
+ if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
+ return -EINVAL;
+- adapter->rtsthsd = rthr;
++ priv->rtsthsd = rthr;
+ }
+
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+- cmd_act_set, cmd_option_waitforrsp,
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
++ CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
+ OID_802_11_RTS_THRESHOLD, &rthr);
+
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
+-static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
++static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+ {
+ int ret = 0;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- adapter->rtsthsd = 0;
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+- cmd_act_get, cmd_option_waitforrsp,
++ priv->rtsthsd = 0;
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
++ CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
+ OID_802_11_RTS_THRESHOLD, NULL);
+ if (ret)
+ goto out;
+
+- vwrq->value = adapter->rtsthsd;
++ vwrq->value = priv->rtsthsd;
+ vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
+ || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
+ vwrq->fixed = 1;
+@@ -448,51 +339,49 @@ out:
+ return ret;
+ }
+
+-static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
++static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+ {
+ int ret = 0;
+ u32 fthr = vwrq->value;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+ if (vwrq->disabled) {
+- adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
++ priv->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
+ } else {
+ if (fthr < MRVDRV_FRAG_MIN_VALUE
+ || fthr > MRVDRV_FRAG_MAX_VALUE)
+ return -EINVAL;
+- adapter->fragthsd = fthr;
++ priv->fragthsd = fthr;
+ }
+
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+- cmd_act_set, cmd_option_waitforrsp,
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
++ CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
+ OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
+
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
+-static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
++static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+ {
+ int ret = 0;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- adapter->fragthsd = 0;
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_snmp_mib,
+- cmd_act_get, cmd_option_waitforrsp,
++ priv->fragthsd = 0;
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_SNMP_MIB,
++ CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
+ OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
+ if (ret)
+ goto out;
+
+- vwrq->value = adapter->fragthsd;
++ vwrq->value = priv->fragthsd;
+ vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
+ || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
+ vwrq->fixed = 1;
+@@ -502,15 +391,14 @@ out:
+ return ret;
+ }
+
+-static int wlan_get_mode(struct net_device *dev,
++static int lbs_get_mode(struct net_device *dev,
+ struct iw_request_info *info, u32 * uwrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- *uwrq = adapter->mode;
++ *uwrq = priv->mode;
+
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return 0;
+@@ -528,28 +416,27 @@ static int mesh_wlan_get_mode(struct net
+ return 0;
+ }
+
+-static int wlan_get_txpow(struct net_device *dev,
++static int lbs_get_txpow(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+ {
+ int ret = 0;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_rf_tx_power,
+- cmd_act_tx_power_opt_get,
+- cmd_option_waitforrsp, 0, NULL);
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_RF_TX_POWER,
++ CMD_ACT_TX_POWER_OPT_GET,
++ CMD_OPTION_WAITFORRSP, 0, NULL);
+
+ if (ret)
+ goto out;
+
+- lbs_deb_wext("tx power level %d dbm\n", adapter->txpowerlevel);
+- vwrq->value = adapter->txpowerlevel;
++ lbs_deb_wext("tx power level %d dbm\n", priv->txpowerlevel);
++ vwrq->value = priv->txpowerlevel;
+ vwrq->fixed = 1;
+- if (adapter->radioon) {
++ if (priv->radioon) {
+ vwrq->disabled = 0;
+ vwrq->flags = IW_TXPOW_DBM;
+ } else {
+@@ -561,12 +448,11 @@ out:
+ return ret;
+ }
+
+-static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
++static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+ {
+ int ret = 0;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+@@ -579,11 +465,11 @@ static int wlan_set_retry(struct net_dev
+ return -EINVAL;
+
+ /* Adding 1 to convert retry count to try count */
+- adapter->txretrycount = vwrq->value + 1;
++ priv->txretrycount = vwrq->value + 1;
+
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+- cmd_act_set,
+- cmd_option_waitforrsp,
++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
++ CMD_ACT_SET,
++ CMD_OPTION_WAITFORRSP,
+ OID_802_11_TX_RETRYCOUNT, NULL);
+
+ if (ret)
+@@ -597,19 +483,18 @@ out:
+ return ret;
+ }
+
+-static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
++static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- adapter->txretrycount = 0;
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_snmp_mib,
+- cmd_act_get, cmd_option_waitforrsp,
++ priv->txretrycount = 0;
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_SNMP_MIB,
++ CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
+ OID_802_11_TX_RETRYCOUNT, NULL);
+ if (ret)
+ goto out;
+@@ -618,7 +503,7 @@ static int wlan_get_retry(struct net_dev
+ if (!vwrq->flags) {
+ vwrq->flags = IW_RETRY_LIMIT;
+ /* Subtract 1 to convert try count to retry count */
+- vwrq->value = adapter->txretrycount - 1;
++ vwrq->value = priv->txretrycount - 1;
+ }
+
+ out:
+@@ -665,15 +550,14 @@ static inline void sort_channels(struct
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+-static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
++static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+ {
+ int i, j;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ struct iw_range *range = (struct iw_range *)extra;
+ struct chan_freq_power *cfp;
+- u8 rates[WLAN_SUPPORTED_RATES];
++ u8 rates[MAX_RATES + 1];
+
+ u8 flag = 0;
+
+@@ -686,24 +570,23 @@ static int wlan_get_range(struct net_dev
+ range->max_nwid = 0;
+
+ memset(rates, 0, sizeof(rates));
+- range->num_bitrates = get_active_data_rates(adapter, rates);
+-
+- for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
+- i++) {
+- range->bitrate[i] = (rates[i] & 0x7f) * 500000;
+- }
++ copy_active_data_rates(priv, rates);
++ range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
++ for (i = 0; i < range->num_bitrates; i++)
++ range->bitrate[i] = rates[i] * 500000;
+ range->num_bitrates = i;
+ lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
+ range->num_bitrates);
+
+ range->num_frequency = 0;
+- if (priv->adapter->enable11d &&
+- adapter->connect_status == libertas_connected) {
++ 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 =
+- &adapter->parsed_region_chan;
++ &priv->parsed_region_chan;
+
+ if (parsed_region_chan == NULL) {
+ lbs_deb_wext("11d: parsed_region_chan is NULL\n");
+@@ -719,7 +602,7 @@ static int wlan_get_range(struct net_dev
+ lbs_deb_wext("chan_no %d\n", chan_no);
+ range->freq[range->num_frequency].i = (long)chan_no;
+ range->freq[range->num_frequency].m =
+- (long)libertas_chan_2_freq(chan_no, band) * 100000;
++ (long)lbs_chan_2_freq(chan_no, band) * 100000;
+ range->freq[range->num_frequency].e = 1;
+ range->num_frequency++;
+ }
+@@ -727,13 +610,12 @@ static int wlan_get_range(struct net_dev
+ }
+ if (!flag) {
+ for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+- && (j < sizeof(adapter->region_channel)
+- / sizeof(adapter->region_channel[0])); j++) {
+- cfp = adapter->region_channel[j].CFP;
++ && (j < ARRAY_SIZE(priv->region_channel)); j++) {
++ cfp = priv->region_channel[j].CFP;
+ for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+- && adapter->region_channel[j].valid
++ && priv->region_channel[j].valid
+ && cfp
+- && (i < adapter->region_channel[j].nrcfp); i++) {
++ && (i < priv->region_channel[j].nrcfp); i++) {
+ range->freq[range->num_frequency].i =
+ (long)cfp->channel;
+ range->freq[range->num_frequency].m =
+@@ -833,7 +715,7 @@ static int wlan_get_range(struct net_dev
+ IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
+ range->event_capa[1] = IW_EVENT_CAPA_K_1;
+
+- if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
++ if (priv->fwcapinfo & FW_CAPINFO_WPA) {
+ range->enc_capa = IW_ENC_CAPA_WPA
+ | IW_ENC_CAPA_WPA2
+ | IW_ENC_CAPA_CIPHER_TKIP
+@@ -845,22 +727,28 @@ out:
+ return 0;
+ }
+
+-static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
++static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
++ if (!priv->ps_supported) {
++ if (vwrq->disabled)
++ return 0;
++ else
++ return -EINVAL;
++ }
++
+ /* PS is currently supported only in Infrastructure mode
+ * Remove this check if it is to be supported in IBSS mode also
+ */
+
+ if (vwrq->disabled) {
+- adapter->psmode = wlan802_11powermodecam;
+- if (adapter->psstate != PS_STATE_FULL_POWER) {
+- libertas_ps_wakeup(priv, cmd_option_waitforrsp);
++ priv->psmode = LBS802_11POWERMODECAM;
++ if (priv->psstate != PS_STATE_FULL_POWER) {
++ lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
+ }
+
+ return 0;
+@@ -875,33 +763,32 @@ static int wlan_set_power(struct net_dev
+ return -EINVAL;
+ }
+
+- if (adapter->psmode != wlan802_11powermodecam) {
++ if (priv->psmode != LBS802_11POWERMODECAM) {
+ return 0;
+ }
+
+- adapter->psmode = wlan802_11powermodemax_psp;
++ priv->psmode = LBS802_11POWERMODEMAX_PSP;
+
+- if (adapter->connect_status == libertas_connected) {
+- libertas_ps_sleep(priv, cmd_option_waitforrsp);
++ if (priv->connect_status == LBS_CONNECTED) {
++ lbs_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
+ }
+
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return 0;
+ }
+
+-static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
++static int lbs_get_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ int mode;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- mode = adapter->psmode;
++ mode = priv->psmode;
+
+- if ((vwrq->disabled = (mode == wlan802_11powermodecam))
+- || adapter->connect_status == libertas_disconnected)
++ if ((vwrq->disabled = (mode == LBS802_11POWERMODECAM))
++ || priv->connect_status == LBS_DISCONNECTED)
+ {
+ goto out;
+ }
+@@ -913,7 +800,7 @@ out:
+ return 0;
+ }
+
+-static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
++static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
+ {
+ enum {
+ POOR = 30,
+@@ -923,8 +810,7 @@ static struct iw_statistics *wlan_get_wi
+ EXCELLENT = 95,
+ PERFECT = 100
+ };
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ u32 rssi_qual;
+ u32 tx_qual;
+ u32 quality = 0;
+@@ -934,22 +820,23 @@ static struct iw_statistics *wlan_get_wi
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- priv->wstats.status = adapter->mode;
++ priv->wstats.status = priv->mode;
+
+ /* If we're not associated, all quality values are meaningless */
+- if (adapter->connect_status != libertas_connected)
++ if ((priv->connect_status != LBS_CONNECTED) &&
++ (priv->mesh_connect_status != LBS_CONNECTED))
+ goto out;
+
+ /* Quality by RSSI */
+ priv->wstats.qual.level =
+- CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+- adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
++ CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
++ priv->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+- if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
++ if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+ priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+ } else {
+ priv->wstats.qual.noise =
+- CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
++ CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
+ }
+
+ lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
+@@ -973,7 +860,7 @@ static struct iw_statistics *wlan_get_wi
+ /* Quality by TX errors */
+ priv->wstats.discard.retries = priv->stats.tx_errors;
+
+- tx_retries = le32_to_cpu(adapter->logmsg.retry);
++ tx_retries = le32_to_cpu(priv->logmsg.retry);
+
+ if (tx_retries > 75)
+ tx_qual = (90 - tx_retries) * POOR / 15;
+@@ -989,20 +876,20 @@ static struct iw_statistics *wlan_get_wi
+ (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
+ quality = min(quality, tx_qual);
+
+- priv->wstats.discard.code = le32_to_cpu(adapter->logmsg.wepundecryptable);
+- priv->wstats.discard.fragment = le32_to_cpu(adapter->logmsg.rxfrag);
++ priv->wstats.discard.code = le32_to_cpu(priv->logmsg.wepundecryptable);
++ priv->wstats.discard.fragment = le32_to_cpu(priv->logmsg.rxfrag);
+ priv->wstats.discard.retries = tx_retries;
+- priv->wstats.discard.misc = le32_to_cpu(adapter->logmsg.ackfailure);
++ priv->wstats.discard.misc = le32_to_cpu(priv->logmsg.ackfailure);
+
+ /* Calculate quality */
+- priv->wstats.qual.qual = max(quality, (u32)100);
++ priv->wstats.qual.qual = min_t(u8, quality, 100);
+ priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+ stats_valid = 1;
+
+ /* update stats asynchronously for future calls */
+- libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
++ lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+ 0, 0, NULL);
+- libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
++ lbs_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0,
+ 0, 0, NULL);
+ out:
+ if (!stats_valid) {
+@@ -1022,19 +909,18 @@ out:
+
+ }
+
+-static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
++static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+ {
+ int ret = -EINVAL;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ struct chan_freq_power *cfp;
+ struct assoc_request * assoc_req;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- mutex_lock(&adapter->lock);
+- assoc_req = wlan_get_association_request(adapter);
++ mutex_lock(&priv->lock);
++ assoc_req = lbs_get_association_request(priv);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+@@ -1044,7 +930,7 @@ static int wlan_set_freq(struct net_devi
+ if (fwrq->e == 1) {
+ long f = fwrq->m / 100000;
+
+- cfp = find_cfp_by_band_and_freq(adapter, 0, f);
++ cfp = find_cfp_by_band_and_freq(priv, 0, f);
+ if (!cfp) {
+ lbs_deb_wext("invalid freq %ld\n", f);
+ goto out;
+@@ -1059,7 +945,7 @@ static int wlan_set_freq(struct net_devi
+ goto out;
+ }
+
+- cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, fwrq->m);
++ cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
+ if (!cfp) {
+ goto out;
+ }
+@@ -1070,128 +956,134 @@ static int wlan_set_freq(struct net_devi
+ out:
+ if (ret == 0) {
+ set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);
+- wlan_postpone_association_work(priv);
++ lbs_postpone_association_work(priv);
+ } else {
+- wlan_cancel_association_work(priv);
++ lbs_cancel_association_work(priv);
+ }
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
+
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
+-/**
+- * @brief use index to get the data rate
+- *
+- * @param index The index of data rate
+- * @return data rate or 0
+- */
+-u32 libertas_index_to_data_rate(u8 index)
++static int lbs_mesh_set_freq(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_freq *fwrq, char *extra)
+ {
+- if (index >= sizeof(libertas_wlan_data_rates))
+- index = 0;
++ struct lbs_private *priv = dev->priv;
++ struct chan_freq_power *cfp;
++ int ret = -EINVAL;
+
+- return libertas_wlan_data_rates[index];
+-}
++ lbs_deb_enter(LBS_DEB_WEXT);
+
+-/**
+- * @brief use rate to get the index
+- *
+- * @param rate data rate
+- * @return index or 0
+- */
+-u8 libertas_data_rate_to_index(u32 rate)
+-{
+- u8 *ptr;
++ /* If setting by frequency, convert to a channel */
++ if (fwrq->e == 1) {
++ long f = fwrq->m / 100000;
++
++ cfp = find_cfp_by_band_and_freq(priv, 0, f);
++ if (!cfp) {
++ lbs_deb_wext("invalid freq %ld\n", f);
++ goto out;
++ }
+
+- if (rate)
+- if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
+- sizeof(libertas_wlan_data_rates))))
+- return (ptr - libertas_wlan_data_rates);
++ fwrq->e = 0;
++ fwrq->m = (int) cfp->channel;
++ }
+
+- return 0;
++ /* Setting by channel number */
++ if (fwrq->m > 1000 || fwrq->e > 0) {
++ goto out;
++ }
++
++ cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
++ if (!cfp) {
++ goto out;
++ }
++
++ if (fwrq->m != priv->curbssparams.channel) {
++ lbs_deb_wext("mesh channel change forces eth disconnect\n");
++ if (priv->mode == IW_MODE_INFRA)
++ lbs_send_deauthentication(priv);
++ else if (priv->mode == IW_MODE_ADHOC)
++ lbs_stop_adhoc_network(priv);
++ }
++ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);
++ lbs_update_channel(priv);
++ ret = 0;
++
++out:
++ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
++ return ret;
+ }
+
+-static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
++static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
+- u32 data_rate;
+- u16 action;
+- int ret = 0;
+- u8 rates[WLAN_SUPPORTED_RATES];
+- u8 *rate;
++ struct lbs_private *priv = dev->priv;
++ u8 new_rate = 0;
++ int ret = -EINVAL;
++ u8 rates[MAX_RATES + 1];
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+-
+ lbs_deb_wext("vwrq->value %d\n", vwrq->value);
+
++ /* Auto rate? */
+ if (vwrq->value == -1) {
+- action = cmd_act_set_tx_auto; // Auto
+- adapter->is_datarate_auto = 1;
+- adapter->datarate = 0;
++ priv->auto_rate = 1;
++ priv->cur_rate = 0;
+ } else {
+- if (vwrq->value % 100000) {
+- return -EINVAL;
+- }
+-
+- data_rate = vwrq->value / 500000;
++ if (vwrq->value % 100000)
++ goto out;
+
+ memset(rates, 0, sizeof(rates));
+- get_active_data_rates(adapter, rates);
+- rate = rates;
+- while (*rate) {
+- lbs_deb_wext("rate=0x%X, wanted data_rate 0x%X\n", *rate,
+- data_rate);
+- if ((*rate & 0x7f) == (data_rate & 0x7f))
+- break;
+- rate++;
+- }
+- if (!*rate) {
+- lbs_pr_alert("fixed data rate 0x%X out "
+- "of range\n", data_rate);
+- return -EINVAL;
++ copy_active_data_rates(priv, rates);
++ new_rate = vwrq->value / 500000;
++ if (!memchr(rates, new_rate, sizeof(rates))) {
++ lbs_pr_alert("fixed data rate 0x%X out of range\n",
++ new_rate);
++ goto out;
+ }
+
+- adapter->datarate = data_rate;
+- action = cmd_act_set_tx_fix_rate;
+- adapter->is_datarate_auto = 0;
++ priv->cur_rate = new_rate;
++ priv->auto_rate = 0;
+ }
+
+- ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
+- action, cmd_option_waitforrsp, 0, NULL);
++ ret = lbs_set_data_rate(priv, new_rate);
+
++out:
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
+-static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
++static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- if (adapter->is_datarate_auto) {
+- vwrq->fixed = 0;
++ if (priv->connect_status == LBS_CONNECTED) {
++ vwrq->value = priv->cur_rate * 500000;
++
++ if (priv->auto_rate)
++ vwrq->fixed = 0;
++ else
++ vwrq->fixed = 1;
++
+ } else {
+- vwrq->fixed = 1;
++ vwrq->fixed = 0;
++ vwrq->value = 0;
+ }
+
+- vwrq->value = adapter->datarate * 500000;
+-
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return 0;
+ }
+
+-static int wlan_set_mode(struct net_device *dev,
++static int lbs_set_mode(struct net_device *dev,
+ struct iw_request_info *info, u32 * uwrq, char *extra)
+ {
+ int ret = 0;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ struct assoc_request * assoc_req;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+@@ -1204,18 +1096,18 @@ static int wlan_set_mode(struct net_devi
+ goto out;
+ }
+
+- mutex_lock(&adapter->lock);
+- assoc_req = wlan_get_association_request(adapter);
++ mutex_lock(&priv->lock);
++ assoc_req = lbs_get_association_request(priv);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+- wlan_cancel_association_work(priv);
++ lbs_cancel_association_work(priv);
+ } else {
+ assoc_req->mode = *uwrq;
+ set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
+- wlan_postpone_association_work(priv);
++ lbs_postpone_association_work(priv);
+ lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
+ }
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+@@ -1232,23 +1124,22 @@ out:
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+-static int wlan_get_encode(struct net_device *dev,
++static int lbs_get_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, u8 * extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+ lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
+- dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
++ dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx);
+
+ dwrq->flags = 0;
+
+ /* Authentication method */
+- switch (adapter->secinfo.auth_mode) {
++ switch (priv->secinfo.auth_mode) {
+ case IW_AUTH_ALG_OPEN_SYSTEM:
+ dwrq->flags = IW_ENCODE_OPEN;
+ break;
+@@ -1262,43 +1153,34 @@ static int wlan_get_encode(struct net_de
+ break;
+ }
+
+- if ( adapter->secinfo.wep_enabled
+- || adapter->secinfo.WPAenabled
+- || adapter->secinfo.WPA2enabled) {
+- dwrq->flags &= ~IW_ENCODE_DISABLED;
+- } else {
+- dwrq->flags |= IW_ENCODE_DISABLED;
+- }
+-
+ memset(extra, 0, 16);
+
+- mutex_lock(&adapter->lock);
++ mutex_lock(&priv->lock);
+
+ /* Default to returning current transmit key */
+ if (index < 0)
+- index = adapter->wep_tx_keyidx;
++ index = priv->wep_tx_keyidx;
+
+- if ((adapter->wep_keys[index].len) && adapter->secinfo.wep_enabled) {
+- memcpy(extra, adapter->wep_keys[index].key,
+- adapter->wep_keys[index].len);
+- dwrq->length = adapter->wep_keys[index].len;
++ if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) {
++ memcpy(extra, priv->wep_keys[index].key,
++ priv->wep_keys[index].len);
++ dwrq->length = priv->wep_keys[index].len;
+
+ dwrq->flags |= (index + 1);
+ /* Return WEP enabled */
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+- } else if ((adapter->secinfo.WPAenabled)
+- || (adapter->secinfo.WPA2enabled)) {
++ } else if ((priv->secinfo.WPAenabled)
++ || (priv->secinfo.WPA2enabled)) {
+ /* return WPA enabled */
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
++ dwrq->flags |= IW_ENCODE_NOKEY;
+ } else {
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ }
+
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
+
+- dwrq->flags |= IW_ENCODE_NOKEY;
+-
+- lbs_deb_wext("key: " MAC_FMT ", keylen %d\n",
++ lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
+ extra[0], extra[1], extra[2],
+ extra[3], extra[4], extra[5], dwrq->length);
+
+@@ -1318,14 +1200,14 @@ static int wlan_get_encode(struct net_de
+ * @param set_tx_key Force set TX key (1 = yes, 0 = no)
+ * @return 0 --success, otherwise fail
+ */
+-static int wlan_set_wep_key(struct assoc_request *assoc_req,
++static int lbs_set_wep_key(struct assoc_request *assoc_req,
+ const char *key_material,
+ u16 key_length,
+ u16 index,
+ int set_tx_key)
+ {
+ int ret = 0;
+- struct WLAN_802_11_KEY *pkey;
++ struct enc_key *pkey;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+@@ -1344,7 +1226,7 @@ static int wlan_set_wep_key(struct assoc
+ pkey = &assoc_req->wep_keys[index];
+
+ if (key_length > 0) {
+- memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
++ memset(pkey, 0, sizeof(struct enc_key));
+ pkey->type = KEY_TYPE_ID_WEP;
+
+ /* Standardize the key length */
+@@ -1412,11 +1294,11 @@ static void disable_wpa(struct assoc_req
+ {
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct WLAN_802_11_KEY));
++ memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));
+ assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
+ set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
+
+- memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct WLAN_802_11_KEY));
++ memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));
+ assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
+ set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
+
+@@ -1436,20 +1318,19 @@ static void disable_wpa(struct assoc_req
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+-static int wlan_set_encode(struct net_device *dev,
++static int lbs_set_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+ {
+ int ret = 0;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ struct assoc_request * assoc_req;
+ u16 is_default = 0, index = 0, set_tx_key = 0;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- mutex_lock(&adapter->lock);
+- assoc_req = wlan_get_association_request(adapter);
++ mutex_lock(&priv->lock);
++ assoc_req = lbs_get_association_request(priv);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+@@ -1475,7 +1356,7 @@ static int wlan_set_encode(struct net_de
+ if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
+ set_tx_key = 1;
+
+- ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
++ ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
+ if (ret)
+ goto out;
+
+@@ -1493,11 +1374,11 @@ static int wlan_set_encode(struct net_de
+ out:
+ if (ret == 0) {
+ set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+- wlan_postpone_association_work(priv);
++ lbs_postpone_association_work(priv);
+ } else {
+- wlan_cancel_association_work(priv);
++ lbs_cancel_association_work(priv);
+ }
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
+
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+@@ -1512,14 +1393,13 @@ out:
+ * @param extra A pointer to extra data buf
+ * @return 0 on success, otherwise failure
+ */
+-static int wlan_get_encodeext(struct net_device *dev,
++static int lbs_get_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+ {
+ int ret = -EINVAL;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int index, max_key_len;
+
+@@ -1535,46 +1415,46 @@ static int wlan_get_encodeext(struct net
+ goto out;
+ index--;
+ } else {
+- index = adapter->wep_tx_keyidx;
++ index = priv->wep_tx_keyidx;
+ }
+
+- if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
++ if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
+ ext->alg != IW_ENCODE_ALG_WEP) {
+- if (index != 0 || adapter->mode != IW_MODE_INFRA)
++ if (index != 0 || priv->mode != IW_MODE_INFRA)
+ goto out;
+ }
+
+ dwrq->flags = index + 1;
+ memset(ext, 0, sizeof(*ext));
+
+- if ( !adapter->secinfo.wep_enabled
+- && !adapter->secinfo.WPAenabled
+- && !adapter->secinfo.WPA2enabled) {
++ if ( !priv->secinfo.wep_enabled
++ && !priv->secinfo.WPAenabled
++ && !priv->secinfo.WPA2enabled) {
+ ext->alg = IW_ENCODE_ALG_NONE;
+ ext->key_len = 0;
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ } else {
+ u8 *key = NULL;
+
+- if ( adapter->secinfo.wep_enabled
+- && !adapter->secinfo.WPAenabled
+- && !adapter->secinfo.WPA2enabled) {
++ if ( priv->secinfo.wep_enabled
++ && !priv->secinfo.WPAenabled
++ && !priv->secinfo.WPA2enabled) {
+ /* WEP */
+ ext->alg = IW_ENCODE_ALG_WEP;
+- ext->key_len = adapter->wep_keys[index].len;
+- key = &adapter->wep_keys[index].key[0];
+- } else if ( !adapter->secinfo.wep_enabled
+- && (adapter->secinfo.WPAenabled ||
+- adapter->secinfo.WPA2enabled)) {
++ ext->key_len = priv->wep_keys[index].len;
++ key = &priv->wep_keys[index].key[0];
++ } else if ( !priv->secinfo.wep_enabled
++ && (priv->secinfo.WPAenabled ||
++ priv->secinfo.WPA2enabled)) {
+ /* WPA */
+- struct WLAN_802_11_KEY * pkey = NULL;
++ struct enc_key * pkey = NULL;
+
+- if ( adapter->wpa_mcast_key.len
+- && (adapter->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
+- pkey = &adapter->wpa_mcast_key;
+- else if ( adapter->wpa_unicast_key.len
+- && (adapter->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
+- pkey = &adapter->wpa_unicast_key;
++ if ( priv->wpa_mcast_key.len
++ && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
++ pkey = &priv->wpa_mcast_key;
++ else if ( priv->wpa_unicast_key.len
++ && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
++ pkey = &priv->wpa_unicast_key;
+
+ if (pkey) {
+ if (pkey->type == KEY_TYPE_ID_AES) {
+@@ -1619,22 +1499,21 @@ out:
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+-static int wlan_set_encodeext(struct net_device *dev,
++static int lbs_set_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+ {
+ int ret = 0;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int alg = ext->alg;
+ struct assoc_request * assoc_req;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- mutex_lock(&adapter->lock);
+- assoc_req = wlan_get_association_request(adapter);
++ mutex_lock(&priv->lock);
++ assoc_req = lbs_get_association_request(priv);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+@@ -1661,7 +1540,7 @@ static int wlan_set_encodeext(struct net
+ set_tx_key = 1;
+
+ /* Copy key to driver */
+- ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
++ ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index,
+ set_tx_key);
+ if (ret)
+ goto out;
+@@ -1679,14 +1558,14 @@ static int wlan_set_encodeext(struct net
+ if (set_tx_key)
+ set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
+ } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
+- struct WLAN_802_11_KEY * pkey;
++ struct enc_key * pkey;
+
+ /* validate key length */
+ if (((alg == IW_ENCODE_ALG_TKIP)
+ && (ext->key_len != KEY_LEN_WPA_TKIP))
+ || ((alg == IW_ENCODE_ALG_CCMP)
+ && (ext->key_len != KEY_LEN_WPA_AES))) {
+- lbs_deb_wext("invalid size %d for key of alg"
++ lbs_deb_wext("invalid size %d for key of alg "
+ "type %d\n",
+ ext->key_len,
+ alg);
+@@ -1702,7 +1581,7 @@ static int wlan_set_encodeext(struct net
+ set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
+ }
+
+- memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
++ memset(pkey, 0, sizeof (struct enc_key));
+ memcpy(pkey->key, ext->key, ext->key_len);
+ pkey->len = ext->key_len;
+ if (pkey->len)
+@@ -1719,9 +1598,6 @@ static int wlan_set_encodeext(struct net
+ pkey->type = KEY_TYPE_ID_TKIP;
+ } else if (alg == IW_ENCODE_ALG_CCMP) {
+ pkey->type = KEY_TYPE_ID_AES;
+- } else {
+- ret = -EINVAL;
+- goto out;
+ }
+
+ /* If WPA isn't enabled yet, do that now */
+@@ -1737,31 +1613,30 @@ static int wlan_set_encodeext(struct net
+
+ out:
+ if (ret == 0) {
+- wlan_postpone_association_work(priv);
++ lbs_postpone_association_work(priv);
+ } else {
+- wlan_cancel_association_work(priv);
++ lbs_cancel_association_work(priv);
+ }
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
+
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
+
+-static int wlan_set_genie(struct net_device *dev,
++static int lbs_set_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ int ret = 0;
+ struct assoc_request * assoc_req;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- mutex_lock(&adapter->lock);
+- assoc_req = wlan_get_association_request(adapter);
++ mutex_lock(&priv->lock);
++ assoc_req = lbs_get_association_request(priv);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+@@ -1777,46 +1652,45 @@ static int wlan_set_genie(struct net_dev
+ memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
+ assoc_req->wpa_ie_len = dwrq->length;
+ } else {
+- memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
++ memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie));
+ assoc_req->wpa_ie_len = 0;
+ }
+
+ out:
+ if (ret == 0) {
+ set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
+- wlan_postpone_association_work(priv);
++ lbs_postpone_association_work(priv);
+ } else {
+- wlan_cancel_association_work(priv);
++ lbs_cancel_association_work(priv);
+ }
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
+
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
+-static int wlan_get_genie(struct net_device *dev,
++static int lbs_get_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+ {
+ int ret = 0;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- if (adapter->wpa_ie_len == 0) {
++ if (priv->wpa_ie_len == 0) {
+ dwrq->length = 0;
+ goto out;
+ }
+
+- if (dwrq->length < adapter->wpa_ie_len) {
++ if (dwrq->length < priv->wpa_ie_len) {
+ ret = -E2BIG;
+ goto out;
+ }
+
+- dwrq->length = adapter->wpa_ie_len;
+- memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
++ dwrq->length = priv->wpa_ie_len;
++ memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+@@ -1824,21 +1698,20 @@ out:
+ }
+
+
+-static int wlan_set_auth(struct net_device *dev,
++static int lbs_set_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *dwrq,
+ char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ struct assoc_request * assoc_req;
+ int ret = 0;
+ int updated = 0;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- mutex_lock(&adapter->lock);
+- assoc_req = wlan_get_association_request(adapter);
++ mutex_lock(&priv->lock);
++ assoc_req = lbs_get_association_request(priv);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+@@ -1913,44 +1786,43 @@ out:
+ if (ret == 0) {
+ if (updated)
+ set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+- wlan_postpone_association_work(priv);
++ lbs_postpone_association_work(priv);
+ } else if (ret != -EOPNOTSUPP) {
+- wlan_cancel_association_work(priv);
++ lbs_cancel_association_work(priv);
+ }
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
+
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
+-static int wlan_get_auth(struct net_device *dev,
++static int lbs_get_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *dwrq,
+ char *extra)
+ {
+ int ret = 0;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+ switch (dwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ dwrq->value = 0;
+- if (adapter->secinfo.WPAenabled)
++ if (priv->secinfo.WPAenabled)
+ dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
+- if (adapter->secinfo.WPA2enabled)
++ if (priv->secinfo.WPA2enabled)
+ dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
+ if (!dwrq->value)
+ dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+- dwrq->value = adapter->secinfo.auth_mode;
++ dwrq->value = priv->secinfo.auth_mode;
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+- if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
++ if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled)
+ dwrq->value = 1;
+ break;
+
+@@ -1963,28 +1835,29 @@ static int wlan_get_auth(struct net_devi
+ }
+
+
+-static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
++static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+ {
+ int ret = 0;
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ u16 dbm;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+ if (vwrq->disabled) {
+- wlan_radio_ioctl(priv, RADIO_OFF);
++ lbs_radio_ioctl(priv, RADIO_OFF);
+ return 0;
+ }
+
+- adapter->preamble = cmd_type_auto_preamble;
++ priv->preamble = CMD_TYPE_AUTO_PREAMBLE;
+
+- wlan_radio_ioctl(priv, RADIO_ON);
++ lbs_radio_ioctl(priv, RADIO_ON);
+
++ /* Userspace check in iwrange if it should use dBm or mW,
++ * therefore this should never happen... Jean II */
+ if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
+- dbm = (u16) mw_to_dbm(vwrq->value);
++ return -EOPNOTSUPP;
+ } else
+ dbm = (u16) vwrq->value;
+
+@@ -1995,20 +1868,19 @@ static int wlan_set_txpow(struct net_dev
+
+ lbs_deb_wext("txpower set %d dbm\n", dbm);
+
+- ret = libertas_prepare_and_send_command(priv,
+- cmd_802_11_rf_tx_power,
+- cmd_act_tx_power_opt_set_low,
+- cmd_option_waitforrsp, 0, (void *)&dbm);
++ ret = lbs_prepare_and_send_command(priv,
++ CMD_802_11_RF_TX_POWER,
++ CMD_ACT_TX_POWER_OPT_SET_LOW,
++ CMD_OPTION_WAITFORRSP, 0, (void *)&dbm);
+
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
+-static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
++static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+@@ -2020,24 +1892,19 @@ static int wlan_get_essid(struct net_dev
+ /*
+ * Get the current SSID
+ */
+- if (adapter->connect_status == libertas_connected) {
+- memcpy(extra, adapter->curbssparams.ssid,
+- adapter->curbssparams.ssid_len);
+- extra[adapter->curbssparams.ssid_len] = '\0';
++ if (priv->connect_status == LBS_CONNECTED) {
++ memcpy(extra, priv->curbssparams.ssid,
++ priv->curbssparams.ssid_len);
++ extra[priv->curbssparams.ssid_len] = '\0';
+ } else {
+ memset(extra, 0, 32);
+- extra[adapter->curbssparams.ssid_len] = '\0';
++ extra[priv->curbssparams.ssid_len] = '\0';
+ }
+ /*
+ * If none, we may want to get the one that was set
+ */
+
+- /* To make the driver backward compatible with WPA supplicant v0.2.4 */
+- if (dwrq->length == 32) /* check with WPA supplicant buffer size */
+- dwrq->length = min_t(size_t, adapter->curbssparams.ssid_len,
+- IW_ESSID_MAX_SIZE);
+- else
+- dwrq->length = adapter->curbssparams.ssid_len + 1;
++ dwrq->length = priv->curbssparams.ssid_len;
+
+ dwrq->flags = 1; /* active */
+
+@@ -2045,11 +1912,10 @@ static int wlan_get_essid(struct net_dev
+ return 0;
+ }
+
+-static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
++static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ int ret = 0;
+ u8 ssid[IW_ESSID_MAX_SIZE];
+ u8 ssid_len = 0;
+@@ -2058,14 +1924,6 @@ static int wlan_set_essid(struct net_dev
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+- /*
+- * WE-20 and earlier NULL pad the end of the SSID and increment
+- * SSID length so it can be used like a string. WE-21 and later don't,
+- * but some userspace tools aren't able to cope with the change.
+- */
+- if ((in_ssid_len > 0) && (extra[in_ssid_len - 1] == '\0'))
+- in_ssid_len--;
+-
+ /* Check the size of the string */
+ if (in_ssid_len > IW_ESSID_MAX_SIZE) {
+ ret = -E2BIG;
+@@ -2090,10 +1948,10 @@ static int wlan_set_essid(struct net_dev
+ }
+
+ out:
+- mutex_lock(&adapter->lock);
++ mutex_lock(&priv->lock);
+ if (ret == 0) {
+ /* Get or create the current association request */
+- assoc_req = wlan_get_association_request(adapter);
++ assoc_req = lbs_get_association_request(priv);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ } else {
+@@ -2101,17 +1959,66 @@ out:
+ memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE);
+ assoc_req->ssid_len = ssid_len;
+ set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
+- wlan_postpone_association_work(priv);
++ lbs_postpone_association_work(priv);
+ }
+ }
+
+ /* Cancel the association request if there was an error */
+ if (ret != 0) {
+- wlan_cancel_association_work(priv);
++ lbs_cancel_association_work(priv);
++ }
++
++ mutex_unlock(&priv->lock);
++
++ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
++ return ret;
++}
++
++static int lbs_mesh_get_essid(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ struct lbs_private *priv = dev->priv;
++
++ lbs_deb_enter(LBS_DEB_WEXT);
++
++ memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len);
++
++ dwrq->length = priv->mesh_ssid_len;
++
++ dwrq->flags = 1; /* active */
++
++ lbs_deb_leave(LBS_DEB_WEXT);
++ return 0;
++}
++
++static int lbs_mesh_set_essid(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ struct lbs_private *priv = dev->priv;
++ int ret = 0;
++
++ lbs_deb_enter(LBS_DEB_WEXT);
++
++ /* Check the size of the string */
++ if (dwrq->length > IW_ESSID_MAX_SIZE) {
++ ret = -E2BIG;
++ goto out;
+ }
+
+- mutex_unlock(&adapter->lock);
++ if (!dwrq->flags || !dwrq->length) {
++ ret = -EINVAL;
++ goto out;
++ } else {
++ /* Specific SSID requested */
++ memcpy(priv->mesh_ssid, extra, dwrq->length);
++ priv->mesh_ssid_len = dwrq->length;
++ }
+
++ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
++ priv->curbssparams.channel);
++ out:
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+@@ -2125,59 +2032,59 @@ out:
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+-static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
++static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+ {
+- wlan_private *priv = dev->priv;
+- wlan_adapter *adapter = priv->adapter;
++ struct lbs_private *priv = dev->priv;
+ struct assoc_request * assoc_req;
+ int ret = 0;
++ DECLARE_MAC_BUF(mac);
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+ if (awrq->sa_family != ARPHRD_ETHER)
+ return -EINVAL;
+
+- lbs_deb_wext("ASSOC: WAP: sa_data " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
++ lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data));
+
+- mutex_lock(&adapter->lock);
++ mutex_lock(&priv->lock);
+
+ /* Get or create the current association request */
+- assoc_req = wlan_get_association_request(adapter);
++ assoc_req = lbs_get_association_request(priv);
+ if (!assoc_req) {
+- wlan_cancel_association_work(priv);
++ lbs_cancel_association_work(priv);
+ ret = -ENOMEM;
+ } else {
+ /* Copy the BSSID to the association request */
+ memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
+ set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
+- wlan_postpone_association_work(priv);
++ lbs_postpone_association_work(priv);
+ }
+
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
+
+ return ret;
+ }
+
+-void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
++void lbs_get_fwversion(struct lbs_private *priv, char *fwversion, int maxlen)
+ {
+ char fwver[32];
+
+- mutex_lock(&adapter->lock);
++ mutex_lock(&priv->lock);
+
+- if (adapter->fwreleasenumber[3] == 0)
++ if (priv->fwreleasenumber[3] == 0)
+ sprintf(fwver, "%u.%u.%u",
+- adapter->fwreleasenumber[2],
+- adapter->fwreleasenumber[1],
+- adapter->fwreleasenumber[0]);
++ priv->fwreleasenumber[2],
++ priv->fwreleasenumber[1],
++ priv->fwreleasenumber[0]);
+ else
+ sprintf(fwver, "%u.%u.%u.p%u",
+- adapter->fwreleasenumber[2],
+- adapter->fwreleasenumber[1],
+- adapter->fwreleasenumber[0],
+- adapter->fwreleasenumber[3]);
++ priv->fwreleasenumber[2],
++ priv->fwreleasenumber[1],
++ priv->fwreleasenumber[0],
++ priv->fwreleasenumber[3]);
+
+- mutex_unlock(&adapter->lock);
++ mutex_unlock(&priv->lock);
+ snprintf(fwversion, maxlen, fwver);
+ }
+
+@@ -2185,19 +2092,19 @@ void libertas_get_fwversion(wlan_adapter
+ /*
+ * iwconfig settable callbacks
+ */
+-static const iw_handler wlan_handler[] = {
++static const iw_handler lbs_handler[] = {
+ (iw_handler) NULL, /* SIOCSIWCOMMIT */
+- (iw_handler) wlan_get_name, /* SIOCGIWNAME */
++ (iw_handler) lbs_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+- (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
+- (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
+- (iw_handler) wlan_set_mode, /* SIOCSIWMODE */
+- (iw_handler) wlan_get_mode, /* SIOCGIWMODE */
++ (iw_handler) lbs_set_freq, /* SIOCSIWFREQ */
++ (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */
++ (iw_handler) lbs_set_mode, /* SIOCSIWMODE */
++ (iw_handler) lbs_get_mode, /* SIOCGIWMODE */
+ (iw_handler) NULL, /* SIOCSIWSENS */
+ (iw_handler) NULL, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* SIOCSIWRANGE */
+- (iw_handler) wlan_get_range, /* SIOCGIWRANGE */
++ (iw_handler) lbs_get_range, /* SIOCGIWRANGE */
+ (iw_handler) NULL, /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* SIOCSIWSTATS */
+@@ -2206,56 +2113,56 @@ static const iw_handler wlan_handler[] =
+ iw_handler_get_spy, /* SIOCGIWSPY */
+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+- (iw_handler) wlan_set_wap, /* SIOCSIWAP */
+- (iw_handler) wlan_get_wap, /* SIOCGIWAP */
++ (iw_handler) lbs_set_wap, /* SIOCSIWAP */
++ (iw_handler) lbs_get_wap, /* SIOCGIWAP */
+ (iw_handler) NULL, /* SIOCSIWMLME */
+ (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
+- (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
+- (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
+- (iw_handler) wlan_set_essid, /* SIOCSIWESSID */
+- (iw_handler) wlan_get_essid, /* SIOCGIWESSID */
+- (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */
+- (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */
++ (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */
++ (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */
++ (iw_handler) lbs_set_essid, /* SIOCSIWESSID */
++ (iw_handler) lbs_get_essid, /* SIOCGIWESSID */
++ (iw_handler) lbs_set_nick, /* SIOCSIWNICKN */
++ (iw_handler) lbs_get_nick, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+- (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
+- (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
+- (iw_handler) wlan_set_rts, /* SIOCSIWRTS */
+- (iw_handler) wlan_get_rts, /* SIOCGIWRTS */
+- (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
+- (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
+- (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */
+- (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */
+- (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */
+- (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */
+- (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */
+- (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */
+- (iw_handler) wlan_set_power, /* SIOCSIWPOWER */
+- (iw_handler) wlan_get_power, /* SIOCGIWPOWER */
++ (iw_handler) lbs_set_rate, /* SIOCSIWRATE */
++ (iw_handler) lbs_get_rate, /* SIOCGIWRATE */
++ (iw_handler) lbs_set_rts, /* SIOCSIWRTS */
++ (iw_handler) lbs_get_rts, /* SIOCGIWRTS */
++ (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */
++ (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */
++ (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */
++ (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */
++ (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */
++ (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */
++ (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */
++ (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */
++ (iw_handler) lbs_set_power, /* SIOCSIWPOWER */
++ (iw_handler) lbs_get_power, /* SIOCGIWPOWER */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+- (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */
+- (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */
+- (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */
+- (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */
+- (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
+- (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
++ (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */
++ (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */
++ (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */
++ (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */
++ (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
++ (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
+ (iw_handler) NULL, /* SIOCSIWPMKSA */
+ };
+
+ static const iw_handler mesh_wlan_handler[] = {
+ (iw_handler) NULL, /* SIOCSIWCOMMIT */
+- (iw_handler) wlan_get_name, /* SIOCGIWNAME */
++ (iw_handler) lbs_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+- (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
+- (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
++ (iw_handler) lbs_mesh_set_freq, /* SIOCSIWFREQ */
++ (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */
+ (iw_handler) NULL, /* SIOCSIWMODE */
+ (iw_handler) mesh_wlan_get_mode, /* SIOCGIWMODE */
+ (iw_handler) NULL, /* SIOCSIWSENS */
+ (iw_handler) NULL, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* SIOCSIWRANGE */
+- (iw_handler) wlan_get_range, /* SIOCGIWRANGE */
++ (iw_handler) lbs_get_range, /* SIOCGIWRANGE */
+ (iw_handler) NULL, /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* SIOCSIWSTATS */
+@@ -2268,46 +2175,97 @@ static const iw_handler mesh_wlan_handle
+ (iw_handler) NULL, /* SIOCGIWAP */
+ (iw_handler) NULL, /* SIOCSIWMLME */
+ (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
+- (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
+- (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
+- (iw_handler) NULL, /* SIOCSIWESSID */
+- (iw_handler) NULL, /* SIOCGIWESSID */
++ (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */
++ (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */
++ (iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */
++ (iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */
+ (iw_handler) NULL, /* SIOCSIWNICKN */
+ (iw_handler) mesh_get_nick, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+- (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
+- (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
+- (iw_handler) wlan_set_rts, /* SIOCSIWRTS */
+- (iw_handler) wlan_get_rts, /* SIOCGIWRTS */
+- (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
+- (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
+- (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */
+- (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */
+- (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */
+- (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */
+- (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */
+- (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */
+- (iw_handler) wlan_set_power, /* SIOCSIWPOWER */
+- (iw_handler) wlan_get_power, /* SIOCGIWPOWER */
++ (iw_handler) lbs_set_rate, /* SIOCSIWRATE */
++ (iw_handler) lbs_get_rate, /* SIOCGIWRATE */
++ (iw_handler) lbs_set_rts, /* SIOCSIWRTS */
++ (iw_handler) lbs_get_rts, /* SIOCGIWRTS */
++ (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */
++ (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */
++ (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */
++ (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */
++ (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */
++ (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */
++ (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */
++ (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */
++ (iw_handler) lbs_set_power, /* SIOCSIWPOWER */
++ (iw_handler) lbs_get_power, /* SIOCGIWPOWER */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+- (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */
+- (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */
+- (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */
+- (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */
+- (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
+- (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
++ (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */
++ (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */
++ (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */
++ (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */
++ (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
++ (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
+ (iw_handler) NULL, /* SIOCSIWPMKSA */
+ };
+-struct iw_handler_def libertas_handler_def = {
+- .num_standard = sizeof(wlan_handler) / sizeof(iw_handler),
+- .standard = (iw_handler *) wlan_handler,
+- .get_wireless_stats = wlan_get_wireless_stats,
++
++#define INT_PARAM (IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1)
++#define INT16_PARAM (IW_PRIV_TYPE_INT | 16)
++#define CHAR128_PARAM (IW_PRIV_TYPE_CHAR | 128)
++
++static const struct iw_priv_args lbs_private_args[] = {
++ /* { cmd, set_args, get_args, name } */
++ { LBS_SETNONE_GETNONE, 0, 0, "" },
++ { LBS_SUBCMD_FWT_RESET, 0, 0, "fwt_reset"},
++ { LBS_SUBCMD_BT_RESET, 0, 0, "bt_reset"},
++ { LBS_SETNONE_GETONEINT, 0, INT_PARAM, ""},
++ { LBS_SUBCMD_GET_REGION, 0, INT_PARAM, "getregioncode"},
++ { LBS_SUBCMD_FWT_CLEANUP, 0, INT_PARAM, "fwt_cleanup"},
++ { LBS_SUBCMD_FWT_TIME, 0, INT_PARAM, "fwt_time"},
++ { LBS_SUBCMD_MESH_GET_TTL, 0, INT_PARAM, "mesh_get_ttl"},
++ { LBS_SUBCMD_BT_GET_INVERT, 0, INT_PARAM, "bt_get_invert"},
++ { LBS_SUBCMD_MESH_GET_BCAST_RATE, 0, INT_PARAM, "mesh_get_bcastr"},
++ { LBS_SUBCMD_MESH_GET_RREQ_DELAY, 0, INT_PARAM, "get_rreq_delay"},
++ { LBS_SUBCMD_MESH_GET_ROUTE_EXP, 0, INT_PARAM, "get_route_exp"},
++ { LBS_SETONEINT_GETNONE, INT_PARAM, 0, ""},
++ { LBS_SUBCMD_SET_REGION, INT_PARAM, 0, "setregioncode"},
++ { LBS_SUBCMD_MESH_SET_TTL, INT_PARAM, 0, "mesh_set_ttl"},
++ { LBS_SUBCMD_BT_SET_INVERT, INT_PARAM, 0, "bt_set_invert"},
++ { LBS_SUBCMD_MESH_SET_BCAST_RATE, INT_PARAM, 0, "mesh_set_bcastr"},
++ { LBS_SUBCMD_MESH_SET_RREQ_DELAY, INT_PARAM, 0, "set_rreq_delay"},
++ { LBS_SUBCMD_MESH_SET_ROUTE_EXP, INT_PARAM, 0, "set_route_exp"},
++ { LBS_SUBCMD_MESH_SET_PRB_RSP_RETRY_LIMIT, INT_PARAM, 0,
++ "setprspretrylt"},
++ { LBS_SET128CHAR_GET128CHAR, CHAR128_PARAM, CHAR128_PARAM, ""},
++ { LBS_SUBCMD_BT_ADD, CHAR128_PARAM, CHAR128_PARAM, "bt_add"},
++ { LBS_SUBCMD_BT_DEL, CHAR128_PARAM, CHAR128_PARAM, "bt_del"},
++ { LBS_SUBCMD_BT_LIST, CHAR128_PARAM, CHAR128_PARAM, "bt_list"},
++ { LBS_SUBCMD_FWT_ADD, CHAR128_PARAM, CHAR128_PARAM, "fwt_add"},
++ { LBS_SUBCMD_FWT_DEL, CHAR128_PARAM, CHAR128_PARAM, "fwt_del"},
++ { LBS_SUBCMD_FWT_LOOKUP, CHAR128_PARAM, CHAR128_PARAM, "fwt_lookup"},
++ { LBS_SUBCMD_FWT_LIST_NEIGHBOR, CHAR128_PARAM, CHAR128_PARAM, "fwt_list_neigh"},
++ { LBS_SUBCMD_FWT_LIST, CHAR128_PARAM, CHAR128_PARAM, "fwt_list"},
++ { LBS_SUBCMD_FWT_LIST_ROUTE, CHAR128_PARAM, CHAR128_PARAM, "fwt_list_route"},
++ { LBS_SUBCMD_MESH_SET_LINK_COSTS, CHAR128_PARAM, CHAR128_PARAM, "set_link_costs"},
++ { LBS_SUBCMD_MESH_GET_LINK_COSTS, CHAR128_PARAM, CHAR128_PARAM, "get_link_costs"},
++ { LBS_SET_GET_SIXTEEN_INT, INT16_PARAM, INT16_PARAM, ""},
++ { LBS_LED_GPIO_CTRL, INT16_PARAM, INT16_PARAM, "ledgpio"},
++ { LBS_BCN_CTRL, INT16_PARAM, INT16_PARAM, "bcn_control"},
++ { LBS_LED_BEHAVIOR_CTRL, INT16_PARAM, INT16_PARAM, "ledbhv"},
++};
++
++
++struct iw_handler_def lbs_handler_def = {
++ .num_standard = ARRAY_SIZE(lbs_handler),
++ .standard = (iw_handler *) lbs_handler,
++ .get_wireless_stats = lbs_get_wireless_stats,
++ .num_private_args = ARRAY_SIZE(lbs_private_args),
++ .private_args = lbs_private_args,
+ };
+
+ struct iw_handler_def mesh_handler_def = {
+- .num_standard = sizeof(mesh_wlan_handler) / sizeof(iw_handler),
++ .num_standard = ARRAY_SIZE(mesh_wlan_handler),
+ .standard = (iw_handler *) mesh_wlan_handler,
+- .get_wireless_stats = wlan_get_wireless_stats,
++ .get_wireless_stats = lbs_get_wireless_stats,
++ .num_private_args = ARRAY_SIZE(lbs_private_args),
++ .private_args = lbs_private_args,
+ };
+diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/wext.h linux-2.6.22-300/drivers/net/wireless/libertas/wext.h
+--- linux-2.6.22-250/drivers/net/wireless/libertas/wext.h 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-300/drivers/net/wireless/libertas/wext.h 2008-06-05 18:10:06.000000000 -0400
+@@ -1,14 +1,11 @@
+ /**
+ * This file contains definition for IOCTL call.
+ */
+-#ifndef _WLAN_WEXT_H_
+-#define _WLAN_WEXT_H_
++#ifndef _LBS_WEXT_H_
++#define _LBS_WEXT_H_
+
+-#define SUBCMD_OFFSET 4
+-#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET))
+-
+-/** wlan_ioctl_regrdwr */
+-struct wlan_ioctl_regrdwr {
++/** lbs_ioctl_regrdwr */
++struct lbs_ioctl_regrdwr {
+ /** Which register to access */
+ u16 whichreg;
+ /** Read or Write */
+@@ -18,13 +15,9 @@ struct wlan_ioctl_regrdwr {
+ u32 value;
+ };
+
+-#define WLAN_LINKMODE_802_3 0
+-#define WLAN_LINKMODE_802_11 2
+-#define WLAN_RADIOMODE_NONE 0
+-#define WLAN_RADIOMODE_RADIOTAP 2
++#define LBS_MONITOR_OFF 0
+
+-extern struct iw_handler_def libertas_handler_def;
++extern struct iw_handler_def lbs_handler_def;
+ extern struct iw_handler_def mesh_handler_def;
+-int wlan_radio_ioctl(wlan_private * priv, u8 option);
+
+-#endif /* _WLAN_WEXT_H_ */
++#endif