adding the patch file too libertas libertas
authorRicardo Carrano <carrano@laptop.org>
Thu, 17 Jul 2008 18:28:07 +0000 (18:28 +0000)
committerRicardo Carrano <carrano@laptop.org>
Thu, 17 Jul 2008 18:28:07 +0000 (18:28 +0000)
linux-2.6-300-olpc.patch [new file with mode: 0644]

diff --git a/linux-2.6-300-olpc.patch b/linux-2.6-300-olpc.patch
new file mode 100644 (file)
index 0000000..a09c015
--- /dev/null
@@ -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