From 812b660ca94c5dd21a8f0adc666be4dee3a825ae Mon Sep 17 00:00:00 2001
From: Ricardo Carrano <carrano@laptop.org>
Date: Thu, 17 Jul 2008 18:28:07 +0000
Subject: [PATCH] adding the patch file too

---
 linux-2.6-300-olpc.patch | 26873 +++++++++++++++++++++++++++++++++++++
 1 file changed, 26873 insertions(+)
 create mode 100644 linux-2.6-300-olpc.patch

diff --git a/linux-2.6-300-olpc.patch b/linux-2.6-300-olpc.patch
new file mode 100644
index 000000000..a09c015a5
--- /dev/null
+++ b/linux-2.6-300-olpc.patch
@@ -0,0 +1,26873 @@
+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, &regctrl, sizeof(regctrl));
++	memcpy(priv->prdeeprom, &regctrl, 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,
+ 				    &regctrl);
+ 
+ 	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 *)&param);
++
++	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 *)&param);
++	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 *)&param);
++
++	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
-- 
2.47.0